Skip to content

Commit 9d24de3

Browse files
author
Justin Pettit
committed
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.
1 parent 9ae7ddc commit 9d24de3

8 files changed

Lines changed: 171 additions & 22 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ post-v1.3.0
1111
- Added ability to match on TTL in IPv4 and IPv6 through NXM.
1212
- Added ability to modify ECN bits in IPv4.
1313
- Added ability to modify TTL in IPv4.
14+
- ovs-vswitchd:
15+
- Track packet and byte statistics sent on mirrors.
1416
- ovs-appctl:
1517
- New "fdb/flush" command to flush bridge's MAC learning table.
1618
- ovs-test:

ofproto/ofproto-dpif.c

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,16 @@ struct ofmirror {
134134
struct ofbundle *out; /* Output port or NULL. */
135135
int out_vlan; /* Output VLAN or -1. */
136136
mirror_mask_t dup_mirrors; /* Bitmap of mirrors with the same output. */
137+
138+
/* Counters. */
139+
int64_t packet_count; /* Number of packets sent. */
140+
int64_t byte_count; /* Number of bytes sent. */
137141
};
138142

139143
static void mirror_destroy(struct ofmirror *);
144+
static void update_mirror_stats(struct ofproto_dpif *ofproto,
145+
mirror_mask_t mirrors,
146+
uint64_t packets, uint64_t bytes);
140147

141148
/* A group of one or more OpenFlow ports. */
142149
#define OFBUNDLE_FLOOD ((struct ofbundle *) 1)
@@ -213,6 +220,7 @@ struct action_xlate_ctx {
213220
bool has_learn; /* Actions include NXAST_LEARN? */
214221
bool has_normal; /* Actions output to OFPP_NORMAL? */
215222
uint16_t nf_output_iface; /* Output interface index for NetFlow. */
223+
mirror_mask_t mirrors; /* Bitmap of associated mirrors. */
216224

217225
/* xlate_actions() initializes and uses these members, but the client has no
218226
* reason to look at them. */
@@ -276,9 +284,9 @@ struct facet {
276284
uint64_t byte_count; /* Number of bytes received. */
277285

278286
/* Resubmit statistics. */
279-
uint64_t rs_packet_count; /* Packets pushed to resubmit children. */
280-
uint64_t rs_byte_count; /* Bytes pushed to resubmit children. */
281-
long long int rs_used; /* Used time pushed to resubmit children. */
287+
uint64_t prev_packet_count; /* Number of packets from last stats push. */
288+
uint64_t prev_byte_count; /* Number of bytes from last stats push. */
289+
long long int prev_used; /* Used time from last stats push. */
282290

283291
/* Accounting. */
284292
uint64_t accounted_bytes; /* Bytes processed by facet_account(). */
@@ -294,6 +302,7 @@ struct facet {
294302
bool has_learn; /* Actions include NXAST_LEARN? */
295303
bool has_normal; /* Actions output to OFPP_NORMAL? */
296304
tag_type tags; /* Tags that would require revalidation. */
305+
mirror_mask_t mirrors; /* Bitmap of dependent mirrors. */
297306
};
298307

299308
static struct facet *facet_create(struct rule_dpif *, const struct flow *);
@@ -2034,6 +2043,24 @@ mirror_destroy(struct ofmirror *mirror)
20342043
mirror_update_dups(ofproto);
20352044
}
20362045

2046+
static int
2047+
mirror_get_stats(struct ofproto *ofproto_, void *aux,
2048+
uint64_t *packets, uint64_t *bytes)
2049+
{
2050+
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
2051+
struct ofmirror *mirror = mirror_lookup(ofproto, aux);
2052+
2053+
if (!mirror) {
2054+
*packets = *bytes = UINT64_MAX;
2055+
return 0;
2056+
}
2057+
2058+
*packets = mirror->packet_count;
2059+
*bytes = mirror->byte_count;
2060+
2061+
return 0;
2062+
}
2063+
20372064
static int
20382065
set_flood_vlans(struct ofproto *ofproto_, unsigned long *flood_vlans)
20392066
{
@@ -3271,6 +3298,7 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
32713298
facet->may_install = ctx.may_set_up_flow;
32723299
facet->has_learn = ctx.has_learn;
32733300
facet->has_normal = ctx.has_normal;
3301+
facet->mirrors = ctx.mirrors;
32743302
if (new_actions) {
32753303
i = 0;
32763304
LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
@@ -3289,7 +3317,7 @@ facet_revalidate(struct ofproto_dpif *ofproto, struct facet *facet)
32893317
list_push_back(&new_rule->facets, &facet->list_node);
32903318
facet->rule = new_rule;
32913319
facet->used = new_rule->up.created;
3292-
facet->rs_used = facet->used;
3320+
facet->prev_used = facet->used;
32933321
}
32943322

32953323
return true;
@@ -3315,30 +3343,33 @@ facet_reset_counters(struct facet *facet)
33153343
{
33163344
facet->packet_count = 0;
33173345
facet->byte_count = 0;
3318-
facet->rs_packet_count = 0;
3319-
facet->rs_byte_count = 0;
3346+
facet->prev_packet_count = 0;
3347+
facet->prev_byte_count = 0;
33203348
facet->accounted_bytes = 0;
33213349
}
33223350

33233351
static void
33243352
facet_push_stats(struct facet *facet)
33253353
{
3326-
uint64_t rs_packets, rs_bytes;
3354+
uint64_t new_packets, new_bytes;
33273355

3328-
assert(facet->packet_count >= facet->rs_packet_count);
3329-
assert(facet->byte_count >= facet->rs_byte_count);
3330-
assert(facet->used >= facet->rs_used);
3356+
assert(facet->packet_count >= facet->prev_packet_count);
3357+
assert(facet->byte_count >= facet->prev_byte_count);
3358+
assert(facet->used >= facet->prev_used);
33313359

3332-
rs_packets = facet->packet_count - facet->rs_packet_count;
3333-
rs_bytes = facet->byte_count - facet->rs_byte_count;
3360+
new_packets = facet->packet_count - facet->prev_packet_count;
3361+
new_bytes = facet->byte_count - facet->prev_byte_count;
33343362

3335-
if (rs_packets || rs_bytes || facet->used > facet->rs_used) {
3336-
facet->rs_packet_count = facet->packet_count;
3337-
facet->rs_byte_count = facet->byte_count;
3338-
facet->rs_used = facet->used;
3363+
if (new_packets || new_bytes || facet->used > facet->prev_used) {
3364+
facet->prev_packet_count = facet->packet_count;
3365+
facet->prev_byte_count = facet->byte_count;
3366+
facet->prev_used = facet->used;
33393367

33403368
flow_push_stats(facet->rule, &facet->flow,
3341-
rs_packets, rs_bytes, facet->used);
3369+
new_packets, new_bytes, facet->used);
3370+
3371+
update_mirror_stats(ofproto_dpif_cast(facet->rule->up.ofproto),
3372+
facet->mirrors, new_packets, new_bytes);
33423373
}
33433374
}
33443375

@@ -3362,7 +3393,7 @@ push_resubmit(struct action_xlate_ctx *ctx, struct rule_dpif *rule)
33623393
}
33633394

33643395
/* Pushes flow statistics to the rules which 'flow' resubmits into given
3365-
* 'rule''s actions. */
3396+
* 'rule''s actions and mirrors. */
33663397
static void
33673398
flow_push_stats(const struct rule_dpif *rule,
33683399
const struct flow *flow, uint64_t packets, uint64_t bytes,
@@ -3516,6 +3547,7 @@ subfacet_make_actions(struct ofproto_dpif *p, struct subfacet *subfacet,
35163547
facet->has_learn = ctx.has_learn;
35173548
facet->has_normal = ctx.has_normal;
35183549
facet->nf_flow.output_iface = ctx.nf_output_iface;
3550+
facet->mirrors = ctx.mirrors;
35193551

35203552
if (subfacet->actions_len != odp_actions->size
35213553
|| memcmp(subfacet->actions, odp_actions->data, odp_actions->size)) {
@@ -4700,6 +4732,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
47004732
ctx->has_learn = false;
47014733
ctx->has_normal = false;
47024734
ctx->nf_output_iface = NF_OUT_DROP;
4735+
ctx->mirrors = 0;
47034736
ctx->recurse = 0;
47044737
ctx->original_priority = ctx->flow.priority;
47054738
ctx->table_id = 0;
@@ -5017,6 +5050,7 @@ output_mirrors(struct action_xlate_ctx *ctx,
50175050
}
50185051

50195052
mirrors &= ~m->dup_mirrors;
5053+
ctx->mirrors |= m->dup_mirrors;
50205054
if (m->out) {
50215055
output_normal(ctx, m->out, vlan);
50225056
} else if (eth_dst_may_rspan(ctx->flow.dl_dst)
@@ -5033,6 +5067,34 @@ output_mirrors(struct action_xlate_ctx *ctx,
50335067
}
50345068
}
50355069

5070+
static void
5071+
update_mirror_stats(struct ofproto_dpif *ofproto, mirror_mask_t mirrors,
5072+
uint64_t packets, uint64_t bytes)
5073+
{
5074+
if (!mirrors) {
5075+
return;
5076+
}
5077+
5078+
for (; mirrors; mirrors &= mirrors - 1) {
5079+
struct ofmirror *m;
5080+
5081+
m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1];
5082+
5083+
if (!m) {
5084+
/* In normal circumstances 'm' will not be NULL. However,
5085+
* if mirrors are reconfigured, we can temporarily get out
5086+
* of sync in facet_revalidate(). We could "correct" the
5087+
* mirror list before reaching here, but doing that would
5088+
* not properly account the traffic stats we've currently
5089+
* accumulated for previous mirror configuration. */
5090+
continue;
5091+
}
5092+
5093+
m->packet_count += packets;
5094+
m->byte_count += bytes;
5095+
}
5096+
}
5097+
50365098
/* A VM broadcasts a gratuitous ARP to indicate that it has resumed after
50375099
* migration. Older Citrix-patched Linux DomU used gratuitous ARP replies to
50385100
* indicate this; newer upstream kernels use gratuitous ARP requests. */
@@ -5964,6 +6026,7 @@ const struct ofproto_class ofproto_dpif_class = {
59646026
bundle_set,
59656027
bundle_remove,
59666028
mirror_set,
6029+
mirror_get_stats,
59676030
set_flood_vlans,
59686031
is_mirror_output_bundle,
59696032
forward_bpdu_changed,

ofproto/ofproto-provider.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,16 @@ struct ofproto_class {
10271027
int (*mirror_set)(struct ofproto *ofproto, void *aux,
10281028
const struct ofproto_mirror_settings *s);
10291029

1030+
/* Retrieves statistics from mirror associated with client data
1031+
* pointer 'aux' in 'ofproto'. Stores packet and byte counts in
1032+
* 'packets' and 'bytes', respectively. If a particular counter is
1033+
* not supported, the appropriate argument is set to UINT64_MAX.
1034+
*
1035+
* EOPNOTSUPP as a return value indicates that this ofproto_class does not
1036+
* support retrieving mirror statistics. */
1037+
int (*mirror_get_stats)(struct ofproto *ofproto, void *aux,
1038+
uint64_t *packets, uint64_t *bytes);
1039+
10301040
/* Configures the VLANs whose bits are set to 1 in 'flood_vlans' as VLANs
10311041
* on which all packets are flooded, instead of using MAC learning. If
10321042
* 'flood_vlans' is NULL, then MAC learning applies to all VLANs.

ofproto/ofproto.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,23 @@ ofproto_mirror_unregister(struct ofproto *ofproto, void *aux)
745745
return ofproto_mirror_register(ofproto, aux, NULL);
746746
}
747747

748+
/* Retrieves statistics from mirror associated with client data pointer
749+
* 'aux' in 'ofproto'. Stores packet and byte counts in 'packets' and
750+
* 'bytes', respectively. If a particular counters is not supported,
751+
* the appropriate argument is set to UINT64_MAX. */
752+
int
753+
ofproto_mirror_get_stats(struct ofproto *ofproto, void *aux,
754+
uint64_t *packets, uint64_t *bytes)
755+
{
756+
if (!ofproto->ofproto_class->mirror_get_stats) {
757+
*packets = *bytes = UINT64_MAX;
758+
return EOPNOTSUPP;
759+
}
760+
761+
return ofproto->ofproto_class->mirror_get_stats(ofproto, aux,
762+
packets, bytes);
763+
}
764+
748765
/* Configures the VLANs whose bits are set to 1 in 'flood_vlans' as VLANs on
749766
* which all packets are flooded, instead of using MAC learning. If
750767
* 'flood_vlans' is NULL, then MAC learning applies to all VLANs.

ofproto/ofproto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ struct ofproto_mirror_settings {
304304
int ofproto_mirror_register(struct ofproto *, void *aux,
305305
const struct ofproto_mirror_settings *);
306306
int ofproto_mirror_unregister(struct ofproto *, void *aux);
307+
int ofproto_mirror_get_stats(struct ofproto *, void *aux,
308+
uint64_t *packets, uint64_t *bytes);
307309

308310
int ofproto_set_flood_vlans(struct ofproto *, unsigned long *flood_vlans);
309311
bool ofproto_is_mirror_output_bundle(const struct ofproto *, void *aux);

vswitchd/bridge.c

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ struct mirror {
7878
struct hmap_node hmap_node; /* In struct bridge's "mirrors" hmap. */
7979
struct bridge *bridge;
8080
char *name;
81+
const struct ovsrec_mirror *cfg;
8182
};
8283

8384
struct port {
@@ -192,7 +193,8 @@ static void bridge_configure_mirrors(struct bridge *);
192193
static struct mirror *mirror_create(struct bridge *,
193194
const struct ovsrec_mirror *);
194195
static void mirror_destroy(struct mirror *);
195-
static bool mirror_configure(struct mirror *, const struct ovsrec_mirror *);
196+
static bool mirror_configure(struct mirror *);
197+
static void mirror_refresh_stats(struct mirror *);
196198

197199
static void iface_configure_lacp(struct iface *, struct lacp_slave_settings *);
198200
static struct iface *iface_create(struct port *port,
@@ -291,6 +293,7 @@ bridge_init(const char *remote)
291293
ovsdb_idl_omit(idl, &ovsrec_queue_col_external_ids);
292294

293295
ovsdb_idl_omit(idl, &ovsrec_mirror_col_external_ids);
296+
ovsdb_idl_omit_alert(idl, &ovsrec_mirror_col_statistics);
294297

295298
ovsdb_idl_omit(idl, &ovsrec_netflow_col_external_ids);
296299

@@ -1870,6 +1873,7 @@ bridge_run(void)
18701873
txn = ovsdb_idl_txn_create(idl);
18711874
HMAP_FOR_EACH (br, node, &all_bridges) {
18721875
struct port *port;
1876+
struct mirror *m;
18731877

18741878
HMAP_FOR_EACH (port, hmap_node, &br->ports) {
18751879
struct iface *iface;
@@ -1879,6 +1883,11 @@ bridge_run(void)
18791883
iface_refresh_status(iface);
18801884
}
18811885
}
1886+
1887+
HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
1888+
mirror_refresh_stats(m);
1889+
}
1890+
18821891
}
18831892
refresh_system_stats(cfg);
18841893
refresh_controller_status();
@@ -3145,7 +3154,8 @@ bridge_configure_mirrors(struct bridge *br)
31453154
if (!m) {
31463155
m = mirror_create(br, cfg);
31473156
}
3148-
if (!mirror_configure(m, cfg)) {
3157+
m->cfg = cfg;
3158+
if (!mirror_configure(m)) {
31493159
mirror_destroy(m);
31503160
}
31513161
}
@@ -3211,8 +3221,9 @@ mirror_collect_ports(struct mirror *m,
32113221
}
32123222

32133223
static bool
3214-
mirror_configure(struct mirror *m, const struct ovsrec_mirror *cfg)
3224+
mirror_configure(struct mirror *m)
32153225
{
3226+
const struct ovsrec_mirror *cfg = m->cfg;
32163227
struct ofproto_mirror_settings s;
32173228

32183229
/* Set name. */
@@ -3555,3 +3566,31 @@ add_vlan_splinter_ports(struct bridge *br,
35553566
}
35563567
}
35573568
}
3569+
3570+
static void
3571+
mirror_refresh_stats(struct mirror *m)
3572+
{
3573+
struct ofproto *ofproto = m->bridge->ofproto;
3574+
uint64_t tx_packets, tx_bytes;
3575+
char *keys[2];
3576+
int64_t values[2];
3577+
size_t stat_cnt = 0;
3578+
3579+
if (ofproto_mirror_get_stats(ofproto, m, &tx_packets, &tx_bytes)) {
3580+
ovsrec_mirror_set_statistics(m->cfg, NULL, NULL, 0);
3581+
return;
3582+
}
3583+
3584+
if (tx_packets != UINT64_MAX) {
3585+
keys[stat_cnt] = "tx_packets";
3586+
values[stat_cnt] = tx_packets;
3587+
stat_cnt++;
3588+
}
3589+
if (tx_bytes != UINT64_MAX) {
3590+
keys[stat_cnt] = "tx_bytes";
3591+
values[stat_cnt] = tx_bytes;
3592+
stat_cnt++;
3593+
}
3594+
3595+
ovsrec_mirror_set_statistics(m->cfg, keys, values, stat_cnt);
3596+
}

vswitchd/vswitch.ovsschema

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{"name": "Open_vSwitch",
22
"version": "6.4.0",
3-
"cksum": "3757343995 15531",
3+
"cksum": "923041702 15687",
44
"tables": {
55
"Open_vSwitch": {
66
"columns": {
@@ -299,6 +299,10 @@
299299
"minInteger": 1,
300300
"maxInteger": 4095},
301301
"min": 0, "max": 1}},
302+
"statistics": {
303+
"type": {"key": "string", "value": "integer",
304+
"min": 0, "max": "unlimited"},
305+
"ephemeral": true},
302306
"external_ids": {
303307
"type": {"key": "string", "value": "string",
304308
"min": 0, "max": "unlimited"}}}},

0 commit comments

Comments
 (0)