This commit adds support for tracking the number of packets and bytes
sent through a mirror. The numbers are kept in the new "statistics"
column on the mirror table in the "tx_packets" and "tx_bytes" keys.
---
NEWS | 2 +
ofproto/ofproto-dpif.c | 97 +++++++++++++++++++++++++++++++++++--------
ofproto/ofproto-provider.h | 9 ++++
ofproto/ofproto.c | 17 ++++++++
ofproto/ofproto.h | 2 +
vswitchd/bridge.c | 35 ++++++++++++++-
vswitchd/vswitch.ovsschema | 6 ++-
vswitchd/vswitch.xml | 12 +++++
8 files changed, 158 insertions(+), 22 deletions(-)
diff --git a/NEWS b/NEWS
index 3b0e9ac..aec514d 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@ post-v1.3.0
- Added ability to match on TTL in IPv4 and IPv6 through NXM.
- Added ability to modify ECN bits in IPv4.
- Added ability to modify TTL in IPv4.
+ - ovs-vswitchd:
+ - Track packet and byte statistics sent on mirrors.
- ovs-appctl:
- New "fdb/flush" command to flush bridge's MAC learning table.
- ovs-test:
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 650cb1f..ab65fd5 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -125,9 +125,16 @@ struct ofmirror {
struct ofbundle *out; /* Output port or NULL. */
int out_vlan; /* Output VLAN or -1. */
mirror_mask_t dup_mirrors; /* Bitmap of mirrors with the same output. */
+
+ /* Counters. */
+ int64_t packet_count; /* Number of packets sent. */
+ int64_t byte_count; /* Number of bytes sent. */
};
static void mirror_destroy(struct ofmirror *);
+static void update_mirror_stats(struct ofproto_dpif *ofproto,
+ mirror_mask_t mirrors,
+ uint64_t packets, uint64_t bytes);
/* A group of one or more OpenFlow ports. */
#define OFBUNDLE_FLOOD ((struct ofbundle *) 1)
@@ -204,6 +211,7 @@ struct action_xlate_ctx {
bool has_learn; /* Actions include NXAST_LEARN? */
bool has_normal; /* Actions output to OFPP_NORMAL? */
uint16_t nf_output_iface; /* Output interface index for NetFlow. */
+ mirror_mask_t mirrors; /* Bitmap of associated mirrors. */
/* xlate_actions() initializes and uses these members, but the client has no
* reason to look at them. */
@@ -243,9 +251,9 @@ struct facet {
uint64_t dp_packet_count; /* Last known packet count in the datapath. */
uint64_t dp_byte_count; /* Last known byte count in the datapath. */
- uint64_t rs_packet_count; /* Packets pushed to resubmit children. */
- uint64_t rs_byte_count; /* Bytes pushed to resubmit children. */
- long long int rs_used; /* Used time pushed to resubmit children. */
+ uint64_t prev_packet_count; /* Number of packets from last stats push. */
+ uint64_t prev_byte_count; /* Number of bytes from last stats push. */
+ long long int prev_used; /* Used time from last stats push. */
uint64_t accounted_bytes; /* Bytes processed by facet_account(). */
@@ -262,6 +270,7 @@ struct facet {
struct nlattr *actions; /* Datapath actions. */
tag_type tags; /* Tags. */
struct netflow_flow nf_flow; /* Per-flow NetFlow tracking data. */
+ mirror_mask_t mirrors; /* Bitmap of associated mirrors. */
};
static struct facet *facet_create(struct rule_dpif *, const struct flow *);
@@ -1928,6 +1937,22 @@ mirror_destroy(struct ofmirror *mirror)
mirror_update_dups(ofproto);
}
+static void
+mirror_get_stats(struct ofproto *ofproto_, void *aux,
+ int64_t *packets, int64_t *bytes)
+{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+ struct ofmirror *mirror = mirror_lookup(ofproto, aux);
+
+ if (!mirror) {
+ *packets = *bytes = 0;
+ return;
+ }
+
+ *packets = mirror->packet_count;
+ *bytes = mirror->byte_count;
+}
+
static int
set_flood_vlans(struct ofproto *ofproto_, unsigned long *flood_vlans)
{
@@ -2920,6 +2945,7 @@ facet_make_actions(struct ofproto_dpif *p, struct facet
*facet,
facet->has_learn = ctx.has_learn;
facet->has_normal = ctx.has_normal;
facet->nf_flow.output_iface = ctx.nf_output_iface;
+ facet->mirrors = ctx.mirrors;
if (facet->actions_len != odp_actions->size
|| memcmp(facet->actions, odp_actions->data, odp_actions->size)) {
@@ -3235,6 +3261,7 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct
facet *facet)
facet->may_install = ctx.may_set_up_flow;
facet->has_learn = ctx.has_learn;
facet->has_normal = ctx.has_normal;
+ facet->mirrors = ctx.mirrors;
if (actions_changed) {
free(facet->actions);
facet->actions_len = odp_actions->size;
@@ -3246,7 +3273,7 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct
facet *facet)
list_push_back(&new_rule->facets, &facet->list_node);
facet->rule = new_rule;
facet->used = new_rule->up.created;
- facet->rs_used = facet->used;
+ facet->prev_used = facet->used;
}
ofpbuf_delete(odp_actions);
@@ -3293,30 +3320,33 @@ facet_reset_counters(struct facet *facet)
{
facet->packet_count = 0;
facet->byte_count = 0;
- facet->rs_packet_count = 0;
- facet->rs_byte_count = 0;
+ facet->prev_packet_count = 0;
+ facet->prev_byte_count = 0;
facet->accounted_bytes = 0;
}
static void
facet_push_stats(struct facet *facet)
{
- uint64_t rs_packets, rs_bytes;
+ uint64_t new_packets, new_bytes;
- assert(facet->packet_count >= facet->rs_packet_count);
- assert(facet->byte_count >= facet->rs_byte_count);
- assert(facet->used >= facet->rs_used);
+ assert(facet->packet_count >= facet->prev_packet_count);
+ assert(facet->byte_count >= facet->prev_byte_count);
+ assert(facet->used >= facet->prev_used);
- rs_packets = facet->packet_count - facet->rs_packet_count;
- rs_bytes = facet->byte_count - facet->rs_byte_count;
+ new_packets = facet->packet_count - facet->prev_packet_count;
+ new_bytes = facet->byte_count - facet->prev_byte_count;
- if (rs_packets || rs_bytes || facet->used > facet->rs_used) {
- facet->rs_packet_count = facet->packet_count;
- facet->rs_byte_count = facet->byte_count;
- facet->rs_used = facet->used;
+ if (new_packets || new_bytes || facet->used > facet->prev_used) {
+ facet->prev_packet_count = facet->packet_count;
+ facet->prev_byte_count = facet->byte_count;
+ facet->prev_used = facet->used;
flow_push_stats(facet->rule, &facet->flow,
- rs_packets, rs_bytes, facet->used);
+ new_packets, new_bytes, facet->used);
+
+ update_mirror_stats(ofproto_dpif_cast(facet->rule->up.ofproto),
+ facet->mirrors, new_packets, new_bytes);
}
}
@@ -3340,7 +3370,7 @@ push_resubmit(struct action_xlate_ctx *ctx, struct
rule_dpif *rule)
}
/* Pushes flow statistics to the rules which 'flow' resubmits into given
- * 'rule''s actions. */
+ * 'rule''s actions and mirrors. */
static void
flow_push_stats(const struct rule_dpif *rule,
struct flow *flow, uint64_t packets, uint64_t bytes,
@@ -3895,6 +3925,7 @@ compose_output_action__(struct action_xlate_ctx *ctx,
uint16_t ofp_port,
ctx->sflow_n_outputs++;
ctx->nf_output_iface = ofp_port;
ctx->flow.nw_tos = flow_nw_tos;
+ ctx->mirrors = ofport->bundle->mirror_out;
}
static void
@@ -4425,6 +4456,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
ctx->has_learn = false;
ctx->has_normal = false;
ctx->nf_output_iface = NF_OUT_DROP;
+ ctx->mirrors = 0;
ctx->recurse = 0;
ctx->original_priority = ctx->flow.priority;
ctx->base_flow = ctx->flow;
@@ -4760,6 +4792,34 @@ output_mirrors(struct action_xlate_ctx *ctx,
}
}
+static void
+update_mirror_stats(struct ofproto_dpif *ofproto, mirror_mask_t mirrors,
+ uint64_t packets, uint64_t bytes)
+{
+ if (!mirrors) {
+ return;
+ }
+
+ for (; mirrors; mirrors &= mirrors - 1) {
+ struct ofmirror *m;
+
+ m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1];
+
+ if (!m) {
+ /* In normal circumstances 'm' will not be NULL. However,
+ * if mirrors are reconfigured, we can temporarily get out
+ * of sync in facet_revalidate(). We could "correct" the
+ * mirror list before reaching here, but doing that would
+ * not properly account the traffic stats we've currently
+ * accumulated for previous mirror configuration. */
+ continue;
+ }
+
+ m->packet_count += packets;
+ m->byte_count += bytes;
+ }
+}
+
/* A VM broadcasts a gratuitous ARP to indicate that it has resumed after
* migration. Older Citrix-patched Linux DomU used gratuitous ARP replies to
* indicate this; newer upstream kernels use gratuitous ARP requests. */
@@ -5485,6 +5545,7 @@ const struct ofproto_class ofproto_dpif_class = {
bundle_set,
bundle_remove,
mirror_set,
+ mirror_get_stats,
set_flood_vlans,
is_mirror_output_bundle,
forward_bpdu_changed,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index d303632..34d18f2 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -1018,6 +1018,15 @@ struct ofproto_class {
int (*mirror_set)(struct ofproto *ofproto, void *aux,
const struct ofproto_mirror_settings *s);
+ /* Retrieves statistics from mirror associated with client data pointer
+ * 'aux' in 'ofproto'. Stores packet and byte counts in 'packets' and
+ * 'bytes', respectively.
+ *
+ * EOPNOTSUPP as a return value indicates that this ofproto_class does not
+ * support STP. */
+ void (*mirror_get_stats)(struct ofproto *ofproto, void *aux,
+ int64_t *packets, int64_t *bytes);
+
/* Configures the VLANs whose bits are set to 1 in 'flood_vlans' as VLANs
* on which all packets are flooded, instead of using MAC learning. If
* 'flood_vlans' is NULL, then MAC learning applies to all VLANs.
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index af02a0e..1f3a077 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -742,6 +742,23 @@ ofproto_mirror_unregister(struct ofproto *ofproto, void
*aux)
return ofproto_mirror_register(ofproto, aux, NULL);
}
+/* Retrieves statistics from mirror associated with client data pointer
+ * 'aux' in 'ofproto'. Stores packet and byte counts in 'packets' and
+ * 'bytes', respectively. */
+int
+ofproto_mirror_get_stats(struct ofproto *ofproto, void *aux,
+ int64_t *packets, int64_t *bytes)
+{
+ if (!ofproto->ofproto_class->mirror_get_stats) {
+ *packets = *bytes = 0;
+ return EOPNOTSUPP;
+ }
+
+ ofproto->ofproto_class->mirror_get_stats(ofproto, aux,
+ packets, bytes);
+ return 0;
+}
+
/* Configures the VLANs whose bits are set to 1 in 'flood_vlans' as VLANs on
* which all packets are flooded, instead of using MAC learning. If
* 'flood_vlans' is NULL, then MAC learning applies to all VLANs.
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 74b3dec..6d4a42c 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -296,6 +296,8 @@ struct ofproto_mirror_settings {
int ofproto_mirror_register(struct ofproto *, void *aux,
const struct ofproto_mirror_settings *);
int ofproto_mirror_unregister(struct ofproto *, void *aux);
+int ofproto_mirror_get_stats(struct ofproto *, void *aux,
+ int64_t *packets, int64_t *bytes);
int ofproto_set_flood_vlans(struct ofproto *, unsigned long *flood_vlans);
bool ofproto_is_mirror_output_bundle(const struct ofproto *, void *aux);
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 3aac5ce..a00709d 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -77,6 +77,7 @@ struct mirror {
struct hmap_node hmap_node; /* In struct bridge's "mirrors" hmap. */
struct bridge *bridge;
char *name;
+ const struct ovsrec_mirror *cfg;
};
struct port {
@@ -190,7 +191,8 @@ static void bridge_configure_mirrors(struct bridge *);
static struct mirror *mirror_create(struct bridge *,
const struct ovsrec_mirror *);
static void mirror_destroy(struct mirror *);
-static bool mirror_configure(struct mirror *, const struct ovsrec_mirror *);
+static bool mirror_configure(struct mirror *);
+static void mirror_refresh_stats(struct mirror *);
static void iface_configure_lacp(struct iface *, struct lacp_slave_settings *);
static struct iface *iface_create(struct port *port,
@@ -268,6 +270,7 @@ bridge_init(const char *remote)
ovsdb_idl_omit(idl, &ovsrec_queue_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_mirror_col_external_ids);
+ ovsdb_idl_omit_alert(idl, &ovsrec_mirror_col_statistics);
ovsdb_idl_omit(idl, &ovsrec_netflow_col_external_ids);
@@ -1843,6 +1846,7 @@ bridge_run(void)
txn = ovsdb_idl_txn_create(idl);
HMAP_FOR_EACH (br, node, &all_bridges) {
struct port *port;
+ struct mirror *m;
HMAP_FOR_EACH (port, hmap_node, &br->ports) {
struct iface *iface;
@@ -1852,6 +1856,11 @@ bridge_run(void)
iface_refresh_status(iface);
}
}
+
+ HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
+ mirror_refresh_stats(m);
+ }
+
}
refresh_system_stats(cfg);
refresh_controller_status();
@@ -3114,7 +3123,7 @@ bridge_configure_mirrors(struct bridge *br)
if (!m) {
m = mirror_create(br, cfg);
}
- if (!mirror_configure(m, cfg)) {
+ if (!mirror_configure(m)) {
mirror_destroy(m);
}
}
@@ -3136,6 +3145,7 @@ mirror_create(struct bridge *br, const struct
ovsrec_mirror *cfg)
hmap_insert(&br->mirrors, &m->hmap_node, uuid_hash(&m->uuid));
m->bridge = br;
m->name = xstrdup(cfg->name);
+ m->cfg = cfg;
return m;
}
@@ -3180,8 +3190,9 @@ mirror_collect_ports(struct mirror *m,
}
static bool
-mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
+mirror_configure(struct mirror *m)
{
+ const struct ovsrec_mirror *cfg = m->cfg;
struct ofproto_mirror_settings s;
/* Set name. */
@@ -3257,3 +3268,21 @@ mirror_configure(struct mirror *m, const struct
ovsrec_mirror *cfg)
return true;
}
+
+static void
+mirror_refresh_stats(struct mirror *m)
+{
+ struct ofproto *ofproto = m->bridge->ofproto;
+ char *keys[2];
+ int64_t values[2];
+
+ if (ofproto_mirror_get_stats(ofproto, m, &values[0], &values[1])) {
+ ovsrec_mirror_set_statistics(m->cfg, NULL, NULL, 0);
+ return;
+ }
+
+ keys[0] = "tx_packets";
+ keys[1] = "tx_bytes";
+
+ ovsrec_mirror_set_statistics(m->cfg, keys, values, ARRAY_SIZE(values));
+}
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index e2f231c..9d91b0f 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
"version": "6.4.0",
- "cksum": "3757343995 15531",
+ "cksum": "923041702 15687",
"tables": {
"Open_vSwitch": {
"columns": {
@@ -299,6 +299,10 @@
"minInteger": 1,
"maxInteger": 4095},
"min": 0, "max": 1}},
+ "statistics": {
+ "type": {"key": "string", "value": "integer",
+ "min": 0, "max": "unlimited"},
+ "ephemeral": true},
"external_ids": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}}},
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 770e10a..397a8c7 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -2058,6 +2058,18 @@
</column>
</group>
+ <group title="Statistics: Mirror counters">
+ <p>
+ Key-value pairs that report mirror statistics.
+ </p>
+ <column name="statistics" key="tx_packets">
+ Number of packets transmitted through this mirror.
+ </column>
+ <column name="statistics" key="tx_bytes">
+ Number of bytes transmitted through this mirror.
+ </column>
+ </group>
+
<group title="Common Columns">
The overall purpose of these columns is described under <code>Common
Columns</code> at the beginning of this document.
--
1.7.4.1
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev