ofproto: Device stats should include packets generated by userspace/controller
authorPravin B Shelar <pshelar@nicira.com>
Thu, 8 Dec 2011 21:25:06 +0000 (13:25 -0800)
committerPravin B Shelar <pshelar@nicira.com>
Thu, 8 Dec 2011 21:25:06 +0000 (13:25 -0800)
Following patch account packets consumed and composed in userspace
as received on and transmitted from local port.

Bug #7551

ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/ofproto.h

index bca9b8d027147e2fd41e4e948ef96a569507b233..a0b6c23cb528459b33f60a615cda1b64f03b7e6d 100644 (file)
@@ -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;
@@ -668,6 +670,7 @@ construct(struct ofproto *ofproto_, int *n_tablesp)
     hmap_init(&ofproto->realdev_vid_map);
 
     *n_tablesp = N_TABLES;
+    memset(&ofproto->stats, 0, sizeof ofproto->stats);
     return 0;
 }
 
@@ -2209,6 +2212,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 +2640,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 +3988,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;
 }
 \f
@@ -5903,6 +5966,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,
index 6576069f8f9de7dec264d5d28be707d210bdbd15..6c8583eacf8c9690e90e9f12f94a1a5ea397c064 100644 (file)
@@ -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
index b81bd6b84d08bb3e808bde9d1ee2ff869d560065..b0a1a66f591bd4fad8e2254e614dd9c08d45c14f 100644 (file)
@@ -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;
index ccd82025ad0c9f267e793ccd8d619b03ddd19b74..2d478784d53c699e8296b2f39762f65cf2626744 100644 (file)
@@ -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 *);