[ovs-dev] [PATCH v2 1/2] ofproto: Device stats should include packets generated by userspace/controller

Pravin B Shelar pshelar at nicira.com
Thu Dec 8 20:53:33 UTC 2011


Fixed according to comments from Ben.
v1-v2:
        - updated comments
        - added UINT64_MAX check before updating stats
        - removed memset from ofproto_port_get_stats()

--8<--------------------------cut here-------------------------->8--

Following patch account packets consumed and composed in userspace
as received on and transmitted from local port.
---
 ofproto/ofproto-dpif.c     |   63 ++++++++++++++++++++++++++++++++++++++++++++
 ofproto/ofproto-provider.h |    4 +++
 ofproto/ofproto.c          |   17 +++++++++++-
 ofproto/ofproto.h          |    3 ++
 4 files changed, 86 insertions(+), 1 deletions(-)

diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index bca9b8d..9e6b32f 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -508,6 +508,8 @@ struct ofproto_dpif {
     struct list completions;
 
     bool has_bundle_action; /* True when the first bundle action appears. */
+    struct netdev_stats stats; /* To account packets generated and consumed in
+                                * userspace. */
 
     /* Spanning tree. */
     struct stp *stp;
@@ -2209,6 +2211,63 @@ port_del(struct ofproto *ofproto_, uint16_t ofp_port)
     return error;
 }
 
+static int
+port_get_stats(const struct ofport *ofport_, struct netdev_stats *stats)
+{
+    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+    int error;
+
+    error = netdev_get_stats(ofport->up.netdev, stats);
+
+    if (!error && ofport->odp_port == OVSP_LOCAL) {
+        struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
+
+        /* ofproto->stats.tx_packets represents packets that we created
+         * internally and sent to some port (e.g. packets sent with
+         * send_packet()).  Account for them as if they had come from
+         * OFPP_LOCAL and got forwarded. */
+
+        if (stats->rx_packets != UINT64_MAX) {
+            stats->rx_packets += ofproto->stats.tx_packets;
+        }
+
+        if (stats->rx_bytes != UINT64_MAX) {
+            stats->rx_bytes += ofproto->stats.tx_bytes;
+        }
+
+        /* ofproto->stats.rx_packets represents packets that were received on
+         * some port and we processed internally and dropped (e.g. STP).
+         * Account fro them as if they had been forwarded to OFPP_LOCAL. */
+
+        if (stats->tx_packets != UINT64_MAX) {
+            stats->tx_packets += ofproto->stats.rx_packets;
+        }
+
+        if (stats->tx_bytes != UINT64_MAX) {
+            stats->tx_bytes += ofproto->stats.rx_bytes;
+        }
+    }
+
+    return error;
+}
+
+/* Account packets for LOCAL port. */
+static void
+ofproto_update_local_port_stats(const struct ofproto *ofproto_,
+                                size_t tx_size, size_t rx_size)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+
+    if (rx_size) {
+        ofproto->stats.rx_packets++;
+        ofproto->stats.rx_bytes += rx_size;
+    }
+    if (tx_size) {
+        ofproto->stats.tx_packets++;
+        ofproto->stats.tx_bytes += tx_size;
+    }
+}
+
 struct port_dump_state {
     struct dpif_port_dump dump;
     bool done;
@@ -2580,6 +2639,8 @@ handle_miss_upcalls(struct ofproto_dpif *ofproto, struct dpif_upcall *upcalls,
 
         /* Handle 802.1ag, LACP, and STP specially. */
         if (process_special(ofproto, &flow, upcall->packet)) {
+            ofproto_update_local_port_stats(&ofproto->up,
+                                            0, upcall->packet->size);
             ofpbuf_delete(upcall->packet);
             ofproto->n_matches++;
             continue;
@@ -3926,6 +3987,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
         VLOG_WARN_RL(&rl, "%s: failed to send packet on port %"PRIu32" (%s)",
                      ofproto->up.name, odp_port, strerror(error));
     }
+    ofproto_update_local_port_stats(ofport->up.ofproto, packet->size, 0);
     return error;
 }
 
@@ -5903,6 +5965,7 @@ const struct ofproto_class ofproto_dpif_class = {
     port_query_by_name,
     port_add,
     port_del,
+    port_get_stats,
     port_dump_start,
     port_dump_next,
     port_dump_done,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 6576069..6c8583e 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -494,6 +494,10 @@ struct ofproto_class {
      * convenient. */
     int (*port_del)(struct ofproto *ofproto, uint16_t ofp_port);
 
+    /* Get port stats */
+    int (*port_get_stats)(const struct ofport *port,
+                          struct netdev_stats *stats);
+
     /* Port iteration functions.
      *
      * The client might not be entirely in control of the ports within an
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index b81bd6b..b0a1a66 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1478,6 +1478,21 @@ ofproto_get_port(const struct ofproto *ofproto, uint16_t ofp_port)
     return NULL;
 }
 
+int
+ofproto_port_get_stats(const struct ofport *port, struct netdev_stats *stats)
+{
+    struct ofproto *ofproto = port->ofproto;
+    int error;
+
+    if (ofproto->ofproto_class->port_get_stats) {
+        error = ofproto->ofproto_class->port_get_stats(port, stats);
+    } else {
+        error = EOPNOTSUPP;
+    }
+
+    return error;
+}
+
 static void
 update_port(struct ofproto *ofproto, const char *name)
 {
@@ -1950,7 +1965,7 @@ append_port_stat(struct ofport *port, struct list *replies)
     /* Intentionally ignore return value, since errors will set
      * 'stats' to all-1s, which is correct for OpenFlow, and
      * netdev_get_stats() will log errors. */
-    netdev_get_stats(port->netdev, &stats);
+    ofproto_port_get_stats(port, &stats);
 
     ops = ofputil_append_stats_reply(sizeof *ops, replies);
     ops->port_no = port->opp.port_no;
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index ccd8202..2d47878 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -37,7 +37,9 @@ struct cfm_settings;
 struct cls_rule;
 struct netdev;
 struct ofproto;
+struct ofport;
 struct shash;
+struct netdev_stats;
 
 struct ofproto_controller_info {
     bool is_connected;
@@ -187,6 +189,7 @@ int ofproto_port_dump_done(struct ofproto_port_dump *);
 
 int ofproto_port_add(struct ofproto *, struct netdev *, uint16_t *ofp_portp);
 int ofproto_port_del(struct ofproto *, uint16_t ofp_port);
+int ofproto_port_get_stats(const struct ofport *, struct netdev_stats *stats);
 
 int ofproto_port_query_by_name(const struct ofproto *, const char *devname,
                                struct ofproto_port *);
-- 
1.7.1




More information about the dev mailing list