From: Justin Pettit Date: Sun, 20 Nov 2011 23:12:36 +0000 (-0800) Subject: ovs-vswitchd: Track packet and byte statistics sent on mirrors. X-Git-Tag: v1.4.0~78 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=9d24de3bca606e768dfd17f0676dd17c26241337;p=sliver-openvswitch.git ovs-vswitchd: Track packet and byte statistics sent on mirrors. 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. --- diff --git a/NEWS b/NEWS index 3a6eec7d0..5d0fb8dcf 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,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 96bd764d2..e3ec353c8 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -134,9 +134,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) @@ -213,6 +220,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. */ @@ -276,9 +284,9 @@ struct facet { uint64_t byte_count; /* Number of bytes received. */ /* Resubmit statistics. */ - 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. */ /* Accounting. */ uint64_t accounted_bytes; /* Bytes processed by facet_account(). */ @@ -294,6 +302,7 @@ struct facet { bool has_learn; /* Actions include NXAST_LEARN? */ bool has_normal; /* Actions output to OFPP_NORMAL? */ tag_type tags; /* Tags that would require revalidation. */ + mirror_mask_t mirrors; /* Bitmap of dependent mirrors. */ }; static struct facet *facet_create(struct rule_dpif *, const struct flow *); @@ -2034,6 +2043,24 @@ mirror_destroy(struct ofmirror *mirror) mirror_update_dups(ofproto); } +static int +mirror_get_stats(struct ofproto *ofproto_, void *aux, + uint64_t *packets, uint64_t *bytes) +{ + struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); + struct ofmirror *mirror = mirror_lookup(ofproto, aux); + + if (!mirror) { + *packets = *bytes = UINT64_MAX; + return 0; + } + + *packets = mirror->packet_count; + *bytes = mirror->byte_count; + + return 0; +} + static int set_flood_vlans(struct ofproto *ofproto_, unsigned long *flood_vlans) { @@ -3271,6 +3298,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 (new_actions) { i = 0; LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) { @@ -3289,7 +3317,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; } return true; @@ -3315,30 +3343,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); } } @@ -3362,7 +3393,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, const struct flow *flow, uint64_t packets, uint64_t bytes, @@ -3516,6 +3547,7 @@ subfacet_make_actions(struct ofproto_dpif *p, struct subfacet *subfacet, 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 (subfacet->actions_len != odp_actions->size || memcmp(subfacet->actions, odp_actions->data, odp_actions->size)) { @@ -4700,6 +4732,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->table_id = 0; @@ -5017,6 +5050,7 @@ output_mirrors(struct action_xlate_ctx *ctx, } mirrors &= ~m->dup_mirrors; + ctx->mirrors |= m->dup_mirrors; if (m->out) { output_normal(ctx, m->out, vlan); } else if (eth_dst_may_rspan(ctx->flow.dl_dst) @@ -5033,6 +5067,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. */ @@ -5964,6 +6026,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 558b8719c..db321c72f 100644 --- a/ofproto/ofproto-provider.h +++ b/ofproto/ofproto-provider.h @@ -1027,6 +1027,16 @@ 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. If a particular counter is + * not supported, the appropriate argument is set to UINT64_MAX. + * + * EOPNOTSUPP as a return value indicates that this ofproto_class does not + * support retrieving mirror statistics. */ + int (*mirror_get_stats)(struct ofproto *ofproto, void *aux, + uint64_t *packets, uint64_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 1a2009794..91b412af3 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -745,6 +745,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. If a particular counters is not supported, + * the appropriate argument is set to UINT64_MAX. */ +int +ofproto_mirror_get_stats(struct ofproto *ofproto, void *aux, + uint64_t *packets, uint64_t *bytes) +{ + if (!ofproto->ofproto_class->mirror_get_stats) { + *packets = *bytes = UINT64_MAX; + return EOPNOTSUPP; + } + + return ofproto->ofproto_class->mirror_get_stats(ofproto, aux, + packets, 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.h b/ofproto/ofproto.h index 4999c8280..fb001061a 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -304,6 +304,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, + uint64_t *packets, uint64_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 32885ebcf..aadb0c7a5 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -78,6 +78,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 { @@ -192,7 +193,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, @@ -291,6 +293,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); @@ -1870,6 +1873,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; @@ -1879,6 +1883,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(); @@ -3145,7 +3154,8 @@ bridge_configure_mirrors(struct bridge *br) if (!m) { m = mirror_create(br, cfg); } - if (!mirror_configure(m, cfg)) { + m->cfg = cfg; + if (!mirror_configure(m)) { mirror_destroy(m); } } @@ -3211,8 +3221,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. */ @@ -3555,3 +3566,31 @@ add_vlan_splinter_ports(struct bridge *br, } } } + +static void +mirror_refresh_stats(struct mirror *m) +{ + struct ofproto *ofproto = m->bridge->ofproto; + uint64_t tx_packets, tx_bytes; + char *keys[2]; + int64_t values[2]; + size_t stat_cnt = 0; + + if (ofproto_mirror_get_stats(ofproto, m, &tx_packets, &tx_bytes)) { + ovsrec_mirror_set_statistics(m->cfg, NULL, NULL, 0); + return; + } + + if (tx_packets != UINT64_MAX) { + keys[stat_cnt] = "tx_packets"; + values[stat_cnt] = tx_packets; + stat_cnt++; + } + if (tx_bytes != UINT64_MAX) { + keys[stat_cnt] = "tx_bytes"; + values[stat_cnt] = tx_bytes; + stat_cnt++; + } + + ovsrec_mirror_set_statistics(m->cfg, keys, values, stat_cnt); +} diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index e2f231c82..9d91b0f9a 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 55880b80e..bebebe058 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -2125,6 +2125,18 @@ + +

+ Key-value pairs that report mirror statistics. +

+ + Number of packets transmitted through this mirror. + + + Number of bytes transmitted through this mirror. + +
+ The overall purpose of these columns is described under Common Columns at the beginning of this document.