[ovs-dev] [PATCH RFC] ofproto: RFC extended statistics patch

mweglicx michalx.weglicki at intel.com
Fri Oct 9 12:49:33 UTC 2015


Implementation of new statistics extension:
- new counters definition based on RFC2819,
- new command line option for ovs-ofctl: port-dump-ext,
- new message definition has been created in nicira-ext.h,
- new raw types OFPRAW_NXST_PORT_REQUEST, OFPRAW_NXST_PORT_REPLY
  have been created.
- new extended statistics calculation is implemented only for
  dpdk-vhost-enabled ports.

Please note that this is just feature proposal, final patch will include
all relevant counters based on RFC2863, RFC3635 and RFC2819 in
nx_port_stats (defined in nicira-ext.h).

Signed-off-by: Michal Weglicki <michalx.weglicki at intel.com>
Signed-off-by: Timo Puha <timox.puha at intel.com>
---
 include/openflow/nicira-ext.h |  29 ++++++++
 lib/netdev-bsd.c              |  14 ++++
 lib/netdev-dpdk.c             |  44 +++++++++--
 lib/netdev-dummy.c            |  14 +++-
 lib/netdev-linux.c            |  19 +++++
 lib/netdev-vport.c            |  13 ++++
 lib/netdev.h                  |   8 ++
 lib/ofp-msgs.h                |  12 ++-
 lib/ofp-print.c               |  60 ++++++++++-----
 lib/ofp-util.c                | 166 ++++++++++++++++++++++++++++++++----------
 lib/ofp-util.h                |   2 +
 utilities/ovs-ofctl.c         |  69 ++++++++++++++----
 vswitchd/bridge.c             |  30 +++++---
 13 files changed, 386 insertions(+), 94 deletions(-)

diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index efb40fa..1cf45cb 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -576,6 +576,35 @@ struct nx_flow_removed {
 };
 OFP_ASSERT(sizeof(struct nx_flow_removed) == 40);
 
+/* Nicira vendor stats request of type NXST_PORT (analogous to OFPST_PORT
+ * request). */
+struct nx_port_stats_request {
+    ovs_be32 port_no;           /* OFPST_PORT message must request statistics
+                                 * either for a single port (specified in
+                                 * port_no) or for all ports (if port_no ==
+                                 * OFPP_ANY). */
+    uint8_t pad[4];             /* Align to 64-bits. */
+};
+
+OFP_ASSERT(sizeof (struct nx_port_stats_request) == 8);
+
+/* Body of reply to NXST_PORT request (analogous to OFPST_PORT reply).
+ * If a counter is unsupported, set the field to all ones. */
+struct nx_port_stats {
+    ovs_be32 port_no;
+    uint8_t pad[4];             /* Align to 64-bits. */
+    /* Below counters are just example used in RFC patch based on RFC2819.
+     * Final statistics extension should contain more counters based on
+     * RFC2819, RFC2863 and RFC3635. */
+    ovs_be64 rx_64_packets;
+    ovs_be64 rx_65_to_127_packets;
+    ovs_be64 rx_128_to_255_packets;
+    ovs_be64 rx_256_to_511_packets;
+    ovs_be64 rx_512_to_1023_packets;
+    ovs_be64 rx_1024_to_1518_packets;
+};
+OFP_ASSERT(sizeof(struct nx_port_stats) == 56);
+
 /* Nicira vendor stats request of type NXST_FLOW (analogous to OFPST_FLOW
  * request).
  *
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index 60e5615..153687a 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -896,6 +896,18 @@ netdev_bsd_get_carrier(const struct netdev *netdev_, bool *carrier)
     return error;
 }
 
+/* Initializes unused statistics to default values. */
+static void
+netdev_bsd_set_unused_stats(struct netdev_stats *dst)
+{
+    dst->rx_1024_to_1518_packets = UINT64_MAX;
+    dst->rx_512_to_1023_packets = UINT64_MAX;
+    dst->rx_256_to_511_packets = UINT64_MAX;
+    dst->rx_128_to_255_packets = UINT64_MAX;
+    dst->rx_65_to_127_packets = UINT64_MAX;
+    dst->rx_64_packets = UINT64_MAX;
+}
+
 static void
 convert_stats_system(struct netdev_stats *stats, const struct if_data *ifd)
 {
@@ -923,6 +935,7 @@ convert_stats_system(struct netdev_stats *stats, const struct if_data *ifd)
     stats->tx_fifo_errors = UINT64_MAX;
     stats->tx_heartbeat_errors = UINT64_MAX;
     stats->tx_window_errors = UINT64_MAX;
+    netdev_bsd_set_unused_stats(stats);
 }
 
 static void
@@ -957,6 +970,7 @@ convert_stats_tap(struct netdev_stats *stats, const struct if_data *ifd)
     stats->tx_fifo_errors = UINT64_MAX;
     stats->tx_heartbeat_errors = UINT64_MAX;
     stats->tx_window_errors = UINT64_MAX;
+    netdev_bsd_set_unused_stats(stats);
 }
 
 static void
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 93b0589..2b4f07e 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -950,13 +950,15 @@ netdev_dpdk_vhost_update_rx_counters(struct netdev_stats *stats,
                                      struct dp_packet **packets, int count)
 {
     int i;
+    unsigned size;
     struct dp_packet *packet;
 
     stats->rx_packets += count;
     for (i = 0; i < count; i++) {
         packet = packets[i];
+        size = dp_packet_size(packet);
 
-        if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) {
+        if (OVS_UNLIKELY(size < ETH_HEADER_LEN)) {
             /* This only protects the following multicast counting from
              * too short packets, but it does not stop the packet from
              * further processing. */
@@ -965,12 +967,32 @@ netdev_dpdk_vhost_update_rx_counters(struct netdev_stats *stats,
             continue;
         }
 
+        /* Hard-coded binary search for the size bucket. */
+        if (size < 256) {
+            if (size >= 128) {
+                stats->rx_128_to_255_packets++;
+            } else if (size <= 64) {
+                stats->rx_64_packets++;
+            } else {
+                stats->rx_65_to_127_packets++;
+            }
+        } else {
+            if (size >= 1024) {
+                stats->rx_1024_to_1518_packets++;
+            } else if (size < 512) {
+                stats->rx_256_to_511_packets++;
+            } else {
+                stats->rx_512_to_1023_packets++;
+            }
+        }
+
         struct eth_header *eh = (struct eth_header *) dp_packet_data(packet);
+
         if (OVS_UNLIKELY(eth_addr_is_multicast(eh->eth_dst))) {
             stats->multicast++;
         }
 
-        stats->rx_bytes += dp_packet_size(packet);
+        stats->rx_bytes += size;
     }
 }
 
@@ -1412,7 +1434,6 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
     struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
 
     ovs_mutex_lock(&dev->mutex);
-    memset(stats, 0, sizeof(*stats));
     /* Unsupported Stats */
     stats->collisions = UINT64_MAX;
     stats->rx_crc_errors = UINT64_MAX;
@@ -1438,6 +1459,14 @@ netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
     stats->tx_bytes = dev->stats.tx_bytes;
     stats->rx_errors = dev->stats.rx_errors;
     stats->rx_length_errors = dev->stats.rx_length_errors;
+
+    stats->rx_64_packets = dev->stats.rx_64_packets;
+    stats->rx_65_to_127_packets = dev->stats.rx_65_to_127_packets;
+    stats->rx_128_to_255_packets = dev->stats.rx_128_to_255_packets;
+    stats->rx_256_to_511_packets = dev->stats.rx_256_to_511_packets;
+    stats->rx_512_to_1023_packets = dev->stats.rx_512_to_1023_packets;
+    stats->rx_1024_to_1518_packets = dev->stats.rx_1024_to_1518_packets;
+
     rte_spinlock_unlock(&dev->stats_lock);
 
     ovs_mutex_unlock(&dev->mutex);
@@ -1456,8 +1485,6 @@ netdev_dpdk_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     ovs_mutex_lock(&dev->mutex);
     rte_eth_stats_get(dev->port_id, &rte_stats);
 
-    memset(stats, 0, sizeof(*stats));
-
     stats->rx_packets = rte_stats.ipackets;
     stats->tx_packets = rte_stats.opackets;
     stats->rx_bytes = rte_stats.ibytes;
@@ -1491,6 +1518,13 @@ netdev_dpdk_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
 
     ovs_mutex_unlock(&dev->mutex);
 
+    stats->rx_64_packets = UINT64_MAX;
+    stats->rx_65_to_127_packets = UINT64_MAX;
+    stats->rx_128_to_255_packets = UINT64_MAX;
+    stats->rx_256_to_511_packets = UINT64_MAX;
+    stats->rx_512_to_1023_packets = UINT64_MAX;
+    stats->rx_1024_to_1518_packets = UINT64_MAX;
+
     return 0;
 }
 
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 76815c2..b055abf 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1020,6 +1020,18 @@ netdev_dummy_set_mtu(const struct netdev *netdev, int mtu)
     return 0;
 }
 
+/* Initializes unused statistics to default values. */
+static void
+netdev_dummy_set_unused_stats(struct netdev_stats *dst)
+{
+    dst->rx_1024_to_1518_packets = UINT64_MAX;
+    dst->rx_512_to_1023_packets = UINT64_MAX;
+    dst->rx_256_to_511_packets = UINT64_MAX;
+    dst->rx_128_to_255_packets = UINT64_MAX;
+    dst->rx_65_to_127_packets = UINT64_MAX;
+    dst->rx_64_packets = UINT64_MAX;
+}
+
 static int
 netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
 {
@@ -1028,7 +1040,7 @@ netdev_dummy_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     ovs_mutex_lock(&dev->mutex);
     *stats = dev->stats;
     ovs_mutex_unlock(&dev->mutex);
-
+    netdev_dummy_set_unused_stats(stats);
     return 0;
 }
 
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 584e804..d892517 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -1550,6 +1550,18 @@ swap_uint64(uint64_t *a, uint64_t *b)
     *b = tmp;
 }
 
+/* Initializes unused statistics to default values. */
+static void
+netdev_linux_set_unused_stats(struct netdev_stats *dst)
+{
+    dst->rx_1024_to_1518_packets = UINT64_MAX;
+    dst->rx_512_to_1023_packets = UINT64_MAX;
+    dst->rx_256_to_511_packets = UINT64_MAX;
+    dst->rx_128_to_255_packets = UINT64_MAX;
+    dst->rx_65_to_127_packets = UINT64_MAX;
+    dst->rx_64_packets = UINT64_MAX;
+}
+
 /* Copies 'src' into 'dst', performing format conversion in the process.
  *
  * 'src' is allowed to be misaligned. */
@@ -1580,6 +1592,7 @@ netdev_stats_from_ovs_vport_stats(struct netdev_stats *dst,
     dst->tx_window_errors = 0;
 }
 
+
 static int
 get_stats_via_vport__(const struct netdev *netdev, struct netdev_stats *stats)
 {
@@ -1671,6 +1684,8 @@ netdev_linux_get_stats(const struct netdev *netdev_,
     }
     ovs_mutex_unlock(&netdev->mutex);
 
+    netdev_linux_set_unused_stats(stats);
+
     return error;
 }
 
@@ -1733,6 +1748,8 @@ netdev_tap_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
     }
     ovs_mutex_unlock(&netdev->mutex);
 
+    netdev_linux_set_unused_stats(stats);
+
     return error;
 }
 
@@ -1748,6 +1765,8 @@ netdev_internal_get_stats(const struct netdev *netdev_,
     error = netdev->vport_stats_error;
     ovs_mutex_unlock(&netdev->mutex);
 
+    netdev_linux_set_unused_stats(stats);
+
     return error;
 }
 
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index ff50563..c1ecad1 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -812,6 +812,18 @@ set_patch_config(struct netdev *dev_, const struct smap *args)
     return 0;
 }
 
+/* Initializes unused statistics to default values. */
+static void
+netdev_vport_set_unused_stats(struct netdev_stats *dst)
+{
+    dst->rx_1024_to_1518_packets = UINT64_MAX;
+    dst->rx_512_to_1023_packets = UINT64_MAX;
+    dst->rx_256_to_511_packets = UINT64_MAX;
+    dst->rx_128_to_255_packets = UINT64_MAX;
+    dst->rx_65_to_127_packets = UINT64_MAX;
+    dst->rx_64_packets = UINT64_MAX;
+}
+
 static int
 get_stats(const struct netdev *netdev, struct netdev_stats *stats)
 {
@@ -820,6 +832,7 @@ get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     ovs_mutex_lock(&dev->mutex);
     *stats = dev->stats;
     ovs_mutex_unlock(&dev->mutex);
+    netdev_vport_set_unused_stats(stats);
 
     return 0;
 }
diff --git a/lib/netdev.h b/lib/netdev.h
index 0fbcb65..107e81e 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -102,6 +102,14 @@ struct netdev_stats {
     uint64_t tx_fifo_errors;
     uint64_t tx_heartbeat_errors;
     uint64_t tx_window_errors;
+
+    /* Size bucket statistics. Based on RFC2819. */
+    uint64_t rx_64_packets;
+    uint64_t rx_65_to_127_packets;
+    uint64_t rx_128_to_255_packets;
+    uint64_t rx_256_to_511_packets;
+    uint64_t rx_512_to_1023_packets;
+    uint64_t rx_1024_to_1518_packets;
 };
 
 /* Configuration specific to tunnels. */
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index bce5283..4335ccd 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -443,6 +443,12 @@ enum ofpraw {
 
     /* NXT 1.0+ (26): struct nx_geneve_table_reply, struct nx_geneve_map[]. */
     OFPRAW_NXT_GENEVE_TABLE_REPLY,
+
+    /* NXST 1.0+ (3): struct nx_port_stats_request. */
+    OFPRAW_NXST_PORT_REQUEST,
+
+    /* NXST 1.0+ (3): struct nx_port_stats[]. */
+    OFPRAW_NXST_PORT_REPLY
 };
 
 /* Decoding messages into OFPRAW_* values. */
@@ -590,11 +596,13 @@ enum ofptype {
                                       * OFPRAW_OFPST12_TABLE_REPLY.
                                       * OFPRAW_OFPST13_TABLE_REPLY. */
     OFPTYPE_PORT_STATS_REQUEST,      /* OFPRAW_OFPST10_PORT_REQUEST.
-                                      * OFPRAW_OFPST11_PORT_REQUEST. */
+                                      * OFPRAW_OFPST11_PORT_REQUEST.
+                                      * OFPRAW_NXST_PORT_REQUEST. */
     OFPTYPE_PORT_STATS_REPLY,        /* OFPRAW_OFPST10_PORT_REPLY.
                                       * OFPRAW_OFPST11_PORT_REPLY.
                                       * OFPRAW_OFPST13_PORT_REPLY.
-                                      * OFPRAW_OFPST14_PORT_REPLY. */
+                                      * OFPRAW_OFPST14_PORT_REPLY.
+                                      * OFPRAW_NXST_PORT_REPLY */
     OFPTYPE_QUEUE_STATS_REQUEST,     /* OFPRAW_OFPST10_QUEUE_REQUEST.
                                       * OFPRAW_OFPST11_QUEUE_REQUEST. */
     OFPTYPE_QUEUE_STATS_REPLY,       /* OFPRAW_OFPST10_QUEUE_REPLY.
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index d0c94ce..c7863e5 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -1565,6 +1565,7 @@ ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
                            int verbosity)
 {
     struct ofpbuf b;
+    enum ofpraw raw;
 
     ds_put_format(string, " %"PRIuSIZE" ports\n", ofputil_count_port_stats(oh));
     if (verbosity < 1) {
@@ -1590,26 +1591,45 @@ ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
         }
         ofputil_format_port(ps.port_no, string);
 
-        ds_put_cstr(string, ": rx ");
-        print_port_stat(string, "pkts=", ps.stats.rx_packets, 1);
-        print_port_stat(string, "bytes=", ps.stats.rx_bytes, 1);
-        print_port_stat(string, "drop=", ps.stats.rx_dropped, 1);
-        print_port_stat(string, "errs=", ps.stats.rx_errors, 1);
-        print_port_stat(string, "frame=", ps.stats.rx_frame_errors, 1);
-        print_port_stat(string, "over=", ps.stats.rx_over_errors, 1);
-        print_port_stat(string, "crc=", ps.stats.rx_crc_errors, 0);
-
-        ds_put_cstr(string, "           tx ");
-        print_port_stat(string, "pkts=", ps.stats.tx_packets, 1);
-        print_port_stat(string, "bytes=", ps.stats.tx_bytes, 1);
-        print_port_stat(string, "drop=", ps.stats.tx_dropped, 1);
-        print_port_stat(string, "errs=", ps.stats.tx_errors, 1);
-        print_port_stat(string, "coll=", ps.stats.collisions, 0);
-
-        if (ps.duration_sec != UINT32_MAX) {
-            ds_put_cstr(string, "           duration=");
-            ofp_print_duration(string, ps.duration_sec, ps.duration_nsec);
-            ds_put_char(string, '\n');
+        if (!ofpraw_decode(&raw, b.header)) {
+            if (raw != OFPRAW_NXST_PORT_REPLY) {
+                ds_put_cstr(string, ": rx ");
+                print_port_stat(string, "pkts=", ps.stats.rx_packets, 1);
+                print_port_stat(string, "bytes=", ps.stats.rx_bytes, 1);
+                print_port_stat(string, "drop=", ps.stats.rx_dropped, 1);
+                print_port_stat(string, "errs=", ps.stats.rx_errors, 1);
+                print_port_stat(string, "frame=", ps.stats.rx_frame_errors, 1);
+                print_port_stat(string, "over=", ps.stats.rx_over_errors, 1);
+                print_port_stat(string, "crc=", ps.stats.rx_crc_errors, 0);
+
+                ds_put_cstr(string, "           tx ");
+                print_port_stat(string, "pkts=", ps.stats.tx_packets, 1);
+                print_port_stat(string, "bytes=", ps.stats.tx_bytes, 1);
+                print_port_stat(string, "drop=", ps.stats.tx_dropped, 1);
+                print_port_stat(string, "errs=", ps.stats.tx_errors, 1);
+                print_port_stat(string, "coll=", ps.stats.collisions, 0);
+
+                if (ps.duration_sec != UINT32_MAX) {
+                    ds_put_cstr(string, "           duration=");
+                    ofp_print_duration(string, ps.duration_sec,
+                                       ps.duration_nsec);
+                    ds_put_char(string, '\n');
+                }
+            } else {
+                ds_put_cstr(string, ": rx ");
+                print_port_stat(string, "64_packets=", ps.stats.rx_64_packets,
+                                1);
+                print_port_stat(string, "65_to_127_packets=",
+                                ps.stats.rx_65_to_127_packets, 1);
+                print_port_stat(string, "128_to_255_packets=",
+                                ps.stats.rx_128_to_255_packets, 1);
+                print_port_stat(string, "256_to_511_packets=",
+                                ps.stats.rx_256_to_511_packets, 1);
+                print_port_stat(string, "512_to_1023_packets=",
+                                ps.stats.rx_512_to_1023_packets, 1);
+                print_port_stat(string, "1024_to_1518_packets=",
+                                ps.stats.rx_1024_to_1518_packets, 0);
+            }
         }
     }
 }
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index b9dbcda..cae432a 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -6798,6 +6798,25 @@ ofputil_encode_dump_ports_request(enum ofp_version ofp_version, ofp_port_t port)
     return request;
 }
 
+/* Encode a dump ports request for 'port', the encoded message
+ * will be for OpenFlow version 'ofp_version'. Returns message
+ * as a struct ofpbuf. Returns encoded message on success, NULL on error */
+struct ofpbuf *
+ofputil_encode_dump_ports_ext_request(enum ofp_version ofp_version,
+                                      ofp_port_t port)
+{
+    struct ofpbuf *request;
+    struct nx_port_stats_request *npsr;
+
+    request =
+        ofpraw_alloc(OFPRAW_NXST_PORT_REQUEST, ofp_version, NXM_TYPICAL_LEN);
+    ofpbuf_put_zeros(request, sizeof *npsr);
+    npsr = request->msg;
+    npsr->port_no = htons(ofp_to_u16(port));
+
+    return request;
+}
+
 static void
 ofputil_port_stats_to_ofp10(const struct ofputil_port_stats *ops,
                             struct ofp10_port_stats *ps10)
@@ -6819,6 +6838,20 @@ ofputil_port_stats_to_ofp10(const struct ofputil_port_stats *ops,
 }
 
 static void
+ofputil_port_stats_to_nx10(const struct ofputil_port_stats *ops,
+                            struct nx_port_stats *nx10stats)
+{
+    nx10stats->port_no = htons(ofp_to_u16(ops->port_no));
+    memset(nx10stats->pad, 0, sizeof nx10stats->pad);
+    nx10stats->rx_64_packets = htonll(ops->stats.rx_64_packets);
+    nx10stats->rx_65_to_127_packets = htonll(ops->stats.rx_65_to_127_packets);
+    nx10stats->rx_128_to_255_packets = htonll(ops->stats.rx_128_to_255_packets);
+    nx10stats->rx_256_to_511_packets = htonll(ops->stats.rx_256_to_511_packets);
+    nx10stats->rx_512_to_1023_packets = htonll(ops->stats.rx_512_to_1023_packets);
+    nx10stats->rx_1024_to_1518_packets = htonll(ops->stats.rx_1024_to_1518_packets);
+}
+
+static void
 ofputil_port_stats_to_ofp11(const struct ofputil_port_stats *ops,
                             struct ofp11_port_stats *ps11)
 {
@@ -6887,32 +6920,44 @@ void
 ofputil_append_port_stat(struct ovs_list *replies,
                          const struct ofputil_port_stats *ops)
 {
-    switch (ofpmp_version(replies)) {
-    case OFP13_VERSION: {
-        struct ofp13_port_stats *reply = ofpmp_append(replies, sizeof *reply);
-        ofputil_port_stats_to_ofp13(ops, reply);
-        break;
-    }
-    case OFP12_VERSION:
-    case OFP11_VERSION: {
-        struct ofp11_port_stats *reply = ofpmp_append(replies, sizeof *reply);
-        ofputil_port_stats_to_ofp11(ops, reply);
-        break;
-    }
+    enum ofpraw raw = OFPRAW_OFPST10_PORT_REQUEST;
 
-    case OFP10_VERSION: {
-        struct ofp10_port_stats *reply = ofpmp_append(replies, sizeof *reply);
-        ofputil_port_stats_to_ofp10(ops, reply);
-        break;
-    }
+    raw = ofpmp_decode_raw(replies);
 
-    case OFP14_VERSION:
-    case OFP15_VERSION:
-        ofputil_append_ofp14_port_stats(ops, replies);
-        break;
+    if (OFPRAW_NXST_PORT_REPLY == raw) {
+        struct nx_port_stats *reply;
 
-    default:
-        OVS_NOT_REACHED();
+        reply = ofpmp_append(replies, sizeof *reply);
+        ofputil_port_stats_to_nx10(ops, reply);
+    } else {
+
+        switch (ofpmp_version(replies)) {
+        case OFP13_VERSION: {
+            struct ofp13_port_stats *reply = ofpmp_append(replies, sizeof *reply);
+            ofputil_port_stats_to_ofp13(ops, reply);
+            break;
+        }
+        case OFP12_VERSION:
+        case OFP11_VERSION: {
+            struct ofp11_port_stats *reply = ofpmp_append(replies, sizeof *reply);
+            ofputil_port_stats_to_ofp11(ops, reply);
+            break;
+        }
+
+        case OFP10_VERSION: {
+            struct ofp10_port_stats *reply = ofpmp_append(replies, sizeof *reply);
+            ofputil_port_stats_to_ofp10(ops, reply);
+            break;
+        }
+
+        case OFP14_VERSION:
+        case OFP15_VERSION:
+            ofputil_append_ofp14_port_stats(ops, replies);
+            break;
+
+        default:
+            OVS_NOT_REACHED();
+        }
     }
 }
 
@@ -6942,6 +6987,27 @@ ofputil_port_stats_from_ofp10(struct ofputil_port_stats *ops,
 }
 
 static enum ofperr
+ofputil_port_stats_from_nx10(struct ofputil_port_stats *ops,
+                             const struct nx_port_stats *nx10stats)
+{
+    memset(ops, 0, sizeof *ops);
+
+    ops->port_no = u16_to_ofp(ntohs(nx10stats->port_no));
+    ops->stats.rx_64_packets = ntohll(nx10stats->rx_64_packets);
+    ops->stats.rx_65_to_127_packets = ntohll(nx10stats->rx_65_to_127_packets);
+    ops->stats.rx_128_to_255_packets =
+        ntohll(nx10stats->rx_128_to_255_packets);
+    ops->stats.rx_256_to_511_packets =
+        ntohll(nx10stats->rx_256_to_511_packets);
+    ops->stats.rx_512_to_1023_packets =
+        ntohll(nx10stats->rx_512_to_1023_packets);
+    ops->stats.rx_1024_to_1518_packets =
+        ntohll(nx10stats->rx_1024_to_1518_packets);
+
+    return 0;
+}
+
+static enum ofperr
 ofputil_port_stats_from_ofp11(struct ofputil_port_stats *ops,
                               const struct ofp11_port_stats *ps11)
 {
@@ -7115,13 +7181,13 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
         return ofputil_pull_ofp14_port_stats(ps, msg);
     } else if (raw == OFPRAW_OFPST13_PORT_REPLY) {
         const struct ofp13_port_stats *ps13;
-
         ps13 = ofpbuf_try_pull(msg, sizeof *ps13);
         if (!ps13) {
             goto bad_len;
         }
         return ofputil_port_stats_from_ofp13(ps, ps13);
     } else if (raw == OFPRAW_OFPST11_PORT_REPLY) {
+
         const struct ofp11_port_stats *ps11;
 
         ps11 = ofpbuf_try_pull(msg, sizeof *ps11);
@@ -7137,6 +7203,15 @@ ofputil_decode_port_stats(struct ofputil_port_stats *ps, struct ofpbuf *msg)
             goto bad_len;
         }
         return ofputil_port_stats_from_ofp10(ps, ps10);
+    } else if (raw == OFPRAW_NXST_PORT_REPLY) {
+        const struct nx_port_stats *nxstats;
+
+        nxstats = ofpbuf_try_pull(msg, sizeof *nxstats);
+        if (!nxstats) {
+            goto bad_len;
+        }
+        return ofputil_port_stats_from_nx10(ps, nxstats);
+
     } else {
         OVS_NOT_REACHED();
     }
@@ -7154,24 +7229,35 @@ enum ofperr
 ofputil_decode_port_stats_request(const struct ofp_header *request,
                                   ofp_port_t *ofp10_port)
 {
-    switch ((enum ofp_version)request->version) {
-    case OFP15_VERSION:
-    case OFP14_VERSION:
-    case OFP13_VERSION:
-    case OFP12_VERSION:
-    case OFP11_VERSION: {
-        const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
-        return ofputil_port_from_ofp11(psr11->port_no, ofp10_port);
-    }
+    enum ofpraw raw;
+    struct ofpbuf b;
 
-    case OFP10_VERSION: {
-        const struct ofp10_port_stats_request *psr10 = ofpmsg_body(request);
-        *ofp10_port = u16_to_ofp(ntohs(psr10->port_no));
-        return 0;
-    }
+    ofpbuf_use_const(&b, request, ntohs(request->length));
+    raw = ofpraw_pull_assert(&b);
 
-    default:
-        OVS_NOT_REACHED();
+    if (OFPRAW_NXST_PORT_REQUEST == raw) {
+        const struct nx_port_stats_request *nxpsr = ofpmsg_body(request);
+
+        *ofp10_port = u16_to_ofp(ntohs(nxpsr->port_no));
+        return 0;
+    } else {
+        switch ((enum ofp_version)request->version) {
+        case OFP15_VERSION:
+        case OFP14_VERSION:
+        case OFP13_VERSION:
+        case OFP12_VERSION:
+        case OFP11_VERSION: {
+            const struct ofp11_port_stats_request *psr11 = ofpmsg_body(request);
+            return ofputil_port_from_ofp11(psr11->port_no, ofp10_port);
+        }
+        case OFP10_VERSION: {
+            const struct ofp10_port_stats_request *psr10 = ofpmsg_body(request);
+            *ofp10_port = u16_to_ofp(ntohs(psr10->port_no));
+            return 0;
+        }
+        default:
+            OVS_NOT_REACHED();
+        }
     }
 }
 
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 8914342..3211c9e 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -999,6 +999,8 @@ struct ofputil_port_stats {
 
 struct ofpbuf *ofputil_encode_dump_ports_request(enum ofp_version ofp_version,
                                                  ofp_port_t port);
+struct ofpbuf *ofputil_encode_dump_ports_ext_request(enum ofp_version ofp_version,
+                                                 ofp_port_t port);
 void ofputil_append_port_stat(struct ovs_list *replies,
                               const struct ofputil_port_stats *ops);
 size_t ofputil_count_port_stats(const struct ofp_header *);
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 0c315c1..2dd8783 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -349,6 +349,7 @@ usage(void)
            "  set-frags SWITCH FRAG_MODE  set fragment handling behavior\n"
            "      FRAG_MODE: normal, drop, reassemble, nx-match\n"
            "  dump-ports SWITCH [PORT]    print port statistics\n"
+           "  dump-ports-ext SWITCH [PORT]    print port extended statistics\n"
            "  dump-ports-desc SWITCH [PORT]  print port descriptions\n"
            "  dump-flows SWITCH           print all flow entries\n"
            "  dump-flows SWITCH FLOW      print matching FLOWs\n"
@@ -1036,12 +1037,28 @@ try_set_protocol(struct vconn *vconn, enum ofputil_protocol want,
     }
 }
 
+static void
+set_protocol_print_error(enum ofputil_protocol usable_protocols)
+{
+    char *usable_s;
+
+    usable_s = ofputil_protocols_to_string(usable_protocols);
+    if (usable_protocols & allowed_protocols) {
+        ovs_fatal(0, "switch does not support any of the usable flow "
+                  "formats (%s)", usable_s);
+    } else {
+        char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
+
+        ovs_fatal(0, "none of the usable flow formats (%s) is among the "
+                  "allowed flow formats (%s)", usable_s, allowed_s);
+    }
+}
+
 static enum ofputil_protocol
 set_protocol_for_flow_dump(struct vconn *vconn,
                            enum ofputil_protocol cur_protocol,
                            enum ofputil_protocol usable_protocols)
 {
-    char *usable_s;
     int i;
 
     for (i = 0; i < ofputil_n_flow_dump_protocols; i++) {
@@ -1052,15 +1069,8 @@ set_protocol_for_flow_dump(struct vconn *vconn,
         }
     }
 
-    usable_s = ofputil_protocols_to_string(usable_protocols);
-    if (usable_protocols & allowed_protocols) {
-        ovs_fatal(0, "switch does not support any of the usable flow "
-                  "formats (%s)", usable_s);
-    } else {
-        char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
-        ovs_fatal(0, "none of the usable flow formats (%s) is among the "
-                  "allowed flow formats (%s)", usable_s, allowed_s);
-    }
+    set_protocol_print_error(usable_protocols);
+    return OFPUTIL_P_NONE;
 }
 
 static struct vconn *
@@ -1782,21 +1792,50 @@ ofctl_snoop(struct ovs_cmdl_context *ctx)
     monitor_vconn(vconn, false);
 }
 
+static struct vconn *
+prepare_dump_ports(const char *name, ofp_port_t port,
+                   struct ofpbuf **requestp, bool extended_stats)
+{
+    struct vconn *vconn;
+
+    open_vconn(name, &vconn);
+    if (extended_stats) {
+        *requestp =
+            ofputil_encode_dump_ports_ext_request(vconn_get_version(vconn),
+                                                  port);
+    } else {
+        *requestp =
+            ofputil_encode_dump_ports_request(vconn_get_version(vconn), port);
+    }
+    return vconn;
+}
+
 static void
-ofctl_dump_ports(struct ovs_cmdl_context *ctx)
+ofctl_dump_ports__(int argc, char *argv[], bool extended_stats)
 {
     struct ofpbuf *request;
     struct vconn *vconn;
     ofp_port_t port;
 
-    open_vconn(ctx->argv[1], &vconn);
-    port = ctx->argc > 2 ? str_to_port_no(ctx->argv[1], ctx->argv[2]) : OFPP_ANY;
-    request = ofputil_encode_dump_ports_request(vconn_get_version(vconn), port);
+    port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_ANY;
+    vconn = prepare_dump_ports(argv[1], port, &request, extended_stats);
     dump_stats_transaction(vconn, request);
     vconn_close(vconn);
 }
 
 static void
+ofctl_dump_ports(struct ovs_cmdl_context *ctx)
+{
+    ofctl_dump_ports__(ctx->argc, ctx->argv, false);
+}
+
+static void
+ofctl_dump_ports_ext(struct ovs_cmdl_context *ctx)
+{
+    ofctl_dump_ports__(ctx->argc, ctx->argv, true);
+}
+
+static void
 ofctl_dump_ports_desc(struct ovs_cmdl_context *ctx)
 {
     struct ofpbuf *request;
@@ -3738,6 +3777,8 @@ static const struct ovs_cmdl_command all_commands[] = {
       4, INT_MAX, ofctl_packet_out },
     { "dump-ports", "switch [port]",
       1, 2, ofctl_dump_ports },
+    { "dump-ports-ext", "switch [port]",
+      1, 2, ofctl_dump_ports_ext },
     { "dump-ports-desc", "switch [port]",
       1, 2, ofctl_dump_ports_desc },
     { "mod-port", "switch iface act",
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 232a334..714c617 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -2335,18 +2335,24 @@ static void
 iface_refresh_stats(struct iface *iface)
 {
 #define IFACE_STATS                             \
-    IFACE_STAT(rx_packets,      "rx_packets")   \
-    IFACE_STAT(tx_packets,      "tx_packets")   \
-    IFACE_STAT(rx_bytes,        "rx_bytes")     \
-    IFACE_STAT(tx_bytes,        "tx_bytes")     \
-    IFACE_STAT(rx_dropped,      "rx_dropped")   \
-    IFACE_STAT(tx_dropped,      "tx_dropped")   \
-    IFACE_STAT(rx_errors,       "rx_errors")    \
-    IFACE_STAT(tx_errors,       "tx_errors")    \
-    IFACE_STAT(rx_frame_errors, "rx_frame_err") \
-    IFACE_STAT(rx_over_errors,  "rx_over_err")  \
-    IFACE_STAT(rx_crc_errors,   "rx_crc_err")   \
-    IFACE_STAT(collisions,      "collisions")
+    IFACE_STAT(rx_packets,              "rx_packets")               \
+    IFACE_STAT(tx_packets,              "tx_packets")               \
+    IFACE_STAT(rx_bytes,                "rx_bytes")                 \
+    IFACE_STAT(tx_bytes,                "tx_bytes")                 \
+    IFACE_STAT(rx_dropped,              "rx_dropped")               \
+    IFACE_STAT(tx_dropped,              "tx_dropped")               \
+    IFACE_STAT(rx_errors,               "rx_errors")                \
+    IFACE_STAT(tx_errors,               "tx_errors")                \
+    IFACE_STAT(rx_frame_errors,         "rx_frame_err")             \
+    IFACE_STAT(rx_over_errors,          "rx_over_err")              \
+    IFACE_STAT(rx_crc_errors,           "rx_crc_err")               \
+    IFACE_STAT(collisions,              "collisions")               \
+    IFACE_STAT(rx_64_packets,           "rx_64_packets")            \
+    IFACE_STAT(rx_65_to_127_packets,    "rx_65_to_127_packets")     \
+    IFACE_STAT(rx_128_to_255_packets,   "rx_128_to_255_packets")    \
+    IFACE_STAT(rx_256_to_511_packets,   "rx_256_to_511_packets")    \
+    IFACE_STAT(rx_512_to_1023_packets,  "rx_512_to_1023_packets")   \
+    IFACE_STAT(rx_1024_to_1518_packets, "rx_1024_to_1518_packets")
 
 #define IFACE_STAT(MEMBER, NAME) + 1
     enum { N_IFACE_STATS = IFACE_STATS };
-- 
1.9.3




More information about the dev mailing list