From 6527c598eabbd34aaa7284f4b052de667e13be2f Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Thu, 8 Dec 2011 13:25:06 -0800 Subject: [PATCH] ofproto: Device stats should include packets generated by userspace/controller Following patch account packets consumed and composed in userspace as received on and transmitted from local port. Bug #7551 --- ofproto/ofproto-dpif.c | 64 ++++++++++++++++++++++++++++++++++++++ ofproto/ofproto-provider.h | 4 +++ ofproto/ofproto.c | 17 +++++++++- ofproto/ofproto.h | 3 ++ 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index bca9b8d0..a0b6c23c 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; @@ -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; } @@ -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, diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h index 6576069f..6c8583ea 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 b81bd6b8..b0a1a66f 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 ccd82025..2d478784 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 *); -- 2.30.2