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)
     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. */
     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(). */
     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 *);
     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)
 {
     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) {
         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;
 {
     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);
     }
 }
 
 }
 
 /* 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,
     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)) {
     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;
         }
 
         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)
     }
 }
 
+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. */
     bundle_set,
     bundle_remove,
     mirror_set,
+    mirror_get_stats,
     set_flood_vlans,
     is_mirror_output_bundle,
     forward_bpdu_changed,
 
     struct hmap_node hmap_node; /* In struct bridge's "mirrors" hmap. */
     struct bridge *bridge;
     char *name;
+    const struct ovsrec_mirror *cfg;
 };
 
 struct port {
 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,
     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);
 
             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;
                         iface_refresh_status(iface);
                     }
                 }
+
+                HMAP_FOR_EACH (m, hmap_node, &br->mirrors) {
+                    mirror_refresh_stats(m);
+                }
+
             }
             refresh_system_stats(cfg);
             refresh_controller_status();
         if (!m) {
             m = mirror_create(br, cfg);
         }
-        if (!mirror_configure(m, cfg)) {
+        m->cfg = cfg;
+        if (!mirror_configure(m)) {
             mirror_destroy(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. */
         }
     }
 }
+
+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);
+}