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
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to