[ovs-dev] [of1.5 9/9] Implement OpenFlow 1.5 port desc stats request.

Ben Pfaff blp at nicira.com
Thu May 8 06:56:48 UTC 2014


OpenFlow 1.4 and earlier always send the description of every port in
response to an OFPMP_PORT_DESC request.  OpenFlow 1.5 proposes allowing
the controller to request a description of a single port.  This commit
implements a prototype.

EXT-69.
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 lib/ofp-msgs.h           |  9 +++++---
 lib/ofp-print.c          | 23 ++++++++++++++++++-
 lib/ofp-util.c           | 53 ++++++++++++++++++++++++++++++++++++++++++
 lib/ofp-util.h           |  7 +++++-
 ofproto/ofproto.c        | 60 ++++++++++++++++++++++++++++--------------------
 tests/ofp-print.at       | 11 ++++++++-
 tests/ofproto.at         | 34 +++++++++++++++++++++++++++
 utilities/ovs-ofctl.8.in | 16 +++++++++----
 utilities/ovs-ofctl.c    | 27 +++++++++++++++-------
 9 files changed, 197 insertions(+), 43 deletions(-)

diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index 5610793..b65b7ab 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -359,8 +359,10 @@ enum ofpraw {
     /* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */
     OFPRAW_OFPST13_TABLE_FEATURES_REPLY,
 
-    /* OFPST 1.0+ (13): void. */
-    OFPRAW_OFPST_PORT_DESC_REQUEST,
+    /* OFPST 1.0-1.4 (13): void. */
+    OFPRAW_OFPST10_PORT_DESC_REQUEST,
+    /* OFPST 1.5+ (13): ovs_be32. */
+    OFPRAW_OFPST15_PORT_DESC_REQUEST,
 
     /* OFPST 1.0 (13): struct ofp10_phy_port[]. */
     OFPRAW_OFPST10_PORT_DESC_REPLY,
@@ -586,7 +588,8 @@ enum ofptype {
 
     OFPTYPE_TABLE_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. */
 
-    OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST_PORT_DESC_REQUEST. */
+    OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST10_PORT_DESC_REQUEST.
+                                      * OFPRAW_OFPST15_PORT_DESC_REQUEST. */
 
     OFPTYPE_PORT_DESC_STATS_REPLY,   /* OFPRAW_OFPST10_PORT_DESC_REPLY.
                                       * OFPRAW_OFPST11_PORT_DESC_REPLY.
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index df9bcc3..30448d2 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -1900,6 +1900,23 @@ ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
 }
 
 static void
+ofp_print_ofpst_port_desc_request(struct ds *string,
+                                  const struct ofp_header *oh)
+{
+    enum ofperr error;
+    ofp_port_t port;
+
+    error = ofputil_decode_port_desc_stats_request(oh, &port);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
+
+    ds_put_cstr(string, " port=");
+    ofputil_format_port(port, string);
+}
+
+static void
 ofp_print_ofpst_port_desc_reply(struct ds *string,
                                 const struct ofp_header *oh)
 {
@@ -2917,7 +2934,6 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
         break;
 
     case OFPTYPE_DESC_STATS_REQUEST:
-    case OFPTYPE_PORT_DESC_STATS_REQUEST:
     case OFPTYPE_METER_FEATURES_STATS_REQUEST:
         ofp_print_stats_request(string, oh);
         break;
@@ -2972,6 +2988,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
         ofp_print_aggregate_stats_reply(string, oh);
         break;
 
+    case OFPTYPE_PORT_DESC_STATS_REQUEST:
+        ofp_print_stats_request(string, oh);
+        ofp_print_ofpst_port_desc_request(string, oh);
+        break;
+
     case OFPTYPE_PORT_DESC_STATS_REPLY:
         ofp_print_stats_reply(string, oh);
         ofp_print_ofpst_port_desc_reply(string, oh);
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 5fe3c05..92d3a2d 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -3958,6 +3958,59 @@ ofputil_put_phy_port(enum ofp_version ofp_version,
     }
 }
 
+enum ofperr
+ofputil_decode_port_desc_stats_request(const struct ofp_header *request,
+                                       ofp_port_t *port)
+{
+    struct ofpbuf b;
+    enum ofpraw raw;
+
+    ofpbuf_use_const(&b, request, ntohs(request->length));
+    raw = ofpraw_pull_assert(&b);
+    if (raw == OFPRAW_OFPST10_PORT_DESC_REQUEST) {
+        *port = OFPP_ANY;
+        return 0;
+    } else if (raw == OFPRAW_OFPST15_PORT_DESC_REQUEST) {
+        ovs_be32 *ofp11_port;
+
+        ofp11_port = ofpbuf_pull(&b, sizeof *ofp11_port);
+        return ofputil_port_from_ofp11(*ofp11_port, port);
+    } else {
+        OVS_NOT_REACHED();
+    }
+}
+
+struct ofpbuf *
+ofputil_encode_port_desc_stats_request(enum ofp_version ofp_version,
+                                       ofp_port_t port)
+{
+    struct ofpbuf *request;
+    ovs_be32 ofp11_port;
+
+    switch (ofp_version) {
+    case OFP10_VERSION:
+    case OFP11_VERSION:
+    case OFP12_VERSION:
+    case OFP13_VERSION:
+    case OFP14_VERSION:
+        request = ofpraw_alloc(OFPRAW_OFPST10_PORT_DESC_REQUEST,
+                               ofp_version, 0);
+        break;
+
+    case OFP15_VERSION:
+        request = ofpraw_alloc(OFPRAW_OFPST15_PORT_DESC_REQUEST,
+                               ofp_version, 0);
+        ofp11_port = ofputil_port_to_ofp11(port);
+        ofpbuf_put(request, &ofp11_port, sizeof ofp11_port);
+        break;
+
+    default:
+        OVS_NOT_REACHED();
+    }
+
+    return request;
+}
+
 void
 ofputil_append_port_desc_stats_reply(const struct ofputil_phy_port *pp,
                                      struct list *replies)
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 5308668..b5d8d4c 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -875,7 +875,12 @@ void ofputil_append_flow_update(const struct ofputil_flow_update *,
 uint32_t ofputil_decode_flow_monitor_cancel(const struct ofp_header *);
 struct ofpbuf *ofputil_encode_flow_monitor_cancel(uint32_t id);
 
-/* Encoding OpenFlow stats messages. */
+/* Port desc stats requests and replies. */
+enum ofperr ofputil_decode_port_desc_stats_request(const struct ofp_header *,
+                                                   ofp_port_t *portp);
+struct ofpbuf *ofputil_encode_port_desc_stats_request(
+    enum ofp_version ofp_version, ofp_port_t);
+
 void ofputil_append_port_desc_stats_reply(const struct ofputil_phy_port *pp,
                                           struct list *replies);
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 2978b5b..69de76f 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3170,52 +3170,62 @@ append_port_stat(struct ofport *port, struct list *replies)
     ofputil_append_port_stat(replies, &ops);
 }
 
-static enum ofperr
-handle_port_stats_request(struct ofconn *ofconn,
-                          const struct ofp_header *request)
+static void
+handle_port_request(struct ofconn *ofconn,
+                    const struct ofp_header *request, ofp_port_t port_no,
+                    void (*cb)(struct ofport *, struct list *replies))
 {
-    struct ofproto *p = ofconn_get_ofproto(ofconn);
+    struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
     struct ofport *port;
     struct list replies;
-    ofp_port_t port_no;
-    enum ofperr error;
-
-    error = ofputil_decode_port_stats_request(request, &port_no);
-    if (error) {
-        return error;
-    }
 
     ofpmp_init(&replies, request);
     if (port_no != OFPP_ANY) {
-        port = ofproto_get_port(p, port_no);
+        port = ofproto_get_port(ofproto, port_no);
         if (port) {
-            append_port_stat(port, &replies);
+            cb(port, &replies);
         }
     } else {
-        HMAP_FOR_EACH (port, hmap_node, &p->ports) {
-            append_port_stat(port, &replies);
+        HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
+            cb(port, &replies);
         }
     }
 
     ofconn_send_replies(ofconn, &replies);
-    return 0;
+}
+
+static enum ofperr
+handle_port_stats_request(struct ofconn *ofconn,
+                          const struct ofp_header *request)
+{
+    ofp_port_t port_no;
+    enum ofperr error;
+
+    error = ofputil_decode_port_stats_request(request, &port_no);
+    if (!error) {
+        handle_port_request(ofconn, request, port_no, append_port_stat);
+    }
+    return error;
+}
+
+static void
+append_port_desc(struct ofport *port, struct list *replies)
+{
+    ofputil_append_port_desc_stats_reply(&port->pp, replies);
 }
 
 static enum ofperr
 handle_port_desc_stats_request(struct ofconn *ofconn,
                                const struct ofp_header *request)
 {
-    struct ofproto *p = ofconn_get_ofproto(ofconn);
-    struct ofport *port;
-    struct list replies;
+    ofp_port_t port_no;
+    enum ofperr error;
 
-    ofpmp_init(&replies, request);
-    HMAP_FOR_EACH (port, hmap_node, &p->ports) {
-        ofputil_append_port_desc_stats_reply(&port->pp, &replies);
+    error = ofputil_decode_port_desc_stats_request(request, &port_no);
+    if (!error) {
+        handle_port_request(ofconn, request, port_no, append_port_desc);
     }
-
-    ofconn_send_replies(ofconn, &replies);
-    return 0;
+    return error;
 }
 
 static uint32_t
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 81f5fde..db17515 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -1866,7 +1866,16 @@ AT_CLEANUP
 AT_SETUP([OFPST_PORT_DESC request - OF1.0])
 AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
 AT_CHECK([ovs-ofctl ofp-print "0110000c00000001000d0000"], [0], [dnl
-OFPST_PORT_DESC request (xid=0x1):
+OFPST_PORT_DESC request (xid=0x1): port=ANY
+])
+AT_CLEANUP
+
+AT_SETUP([OFPST_PORT_DESC request - OF1.5])
+AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
+AT_CHECK([ovs-ofctl ofp-print "\
+06 12 00 14 00 00 00 02 00 0d 00 00 00 00 00 00 \
+00 00 00 05"], [0], [dnl
+OFPST_PORT_DESC request (OF1.5) (xid=0x2): port=5
 ])
 AT_CLEANUP
 
diff --git a/tests/ofproto.at b/tests/ofproto.at
index c1a6637..fb81bf1 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -131,6 +131,40 @@ OFPST_PORT_DESC reply (OF1.2):
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto - port-desc stats (OpenFlow 1.5)])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], 1, 2, 3)
+AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-ports-desc br0], [0], [stdout])
+AT_CHECK([STRIP_XIDS stdout | sed 's/00:0./00:0x/'], [0], [dnl
+OFPST_PORT_DESC reply (OF1.5):
+ 1(p1): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+ 2(p2): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+ 3(p3): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+ LOCAL(br0): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+])
+AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-ports-desc br0 2], [0], [stdout])
+AT_CHECK([STRIP_XIDS stdout | sed 's/00:0./00:0x/'], [0], [dnl
+OFPST_PORT_DESC reply (OF1.5):
+ 2(p2): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 dnl This is really bare-bones.
 dnl It at least checks request and reply serialization and deserialization.
 AT_SETUP([ofproto - queue stats - (OpenFlow 1.0)])
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 2ccb21a..55520ca 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -70,11 +70,19 @@ Prints to the console statistics for network devices associated with
 associated with that device will be printed.  \fInetdev\fR can be an
 OpenFlow assigned port number or device name, e.g. \fBeth0\fR.
 .
-.TP
-\fBdump\-ports\-desc \fIswitch\fR
+.IP "\fBdump\-ports\-desc \fIswitch\fR [\fIport\fR]"
 Prints to the console detailed information about network devices
-associated with \fIswitch\fR (version 1.7 or later).  This is a subset
-of the information provided by the \fBshow\fR command.
+associated with \fIswitch\fR.  To dump only a specific port, specify
+its number as \fIport\fR.  Otherwise, if \fIport\fR is omitted, or if
+it is specified as \fBANY\fR, then all ports are printed.  This is a
+subset of the information provided by the \fBshow\fR command.
+.IP
+If the connection to \fIswitch\fR negotiates OpenFlow 1.0, 1.2, or
+1.2, this command uses an OpenFlow extension only implemented in Open
+vSwitch (version 1.7 and later).
+.IP
+Only OpenFlow 1.5 and later support dumping a specific port.  Earlier
+versions of OpenFlow always dump all ports.
 .
 .IP "\fBmod\-port \fIswitch\fR \fIport\fR \fIaction\fR"
 Modify characteristics of port \fBport\fR in \fIswitch\fR.  \fIport\fR
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index c2baed3..f8693f6 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -305,7 +305,7 @@ usage(void)
            "  get-frags SWITCH            print fragment handling behavior\n"
            "  set-frags SWITCH FRAG_MODE  set fragment handling behavior\n"
            "  dump-ports SWITCH [PORT]    print port statistics\n"
-           "  dump-ports-desc SWITCH      print port descriptions\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"
            "  dump-aggregate SWITCH       print aggregate flow statistics\n"
@@ -651,8 +651,10 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
         /* The Features Reply may not contain all the ports, so send a
          * Port Description stats request, which doesn't have size
          * constraints. */
-        dump_trivial_stats_transaction(vconn_name,
-                                       OFPRAW_OFPST_PORT_DESC_REQUEST);
+        enum ofp_version version = vconn_get_version(vconn);
+
+        request = ofputil_encode_port_desc_stats_request(version, OFPP_ANY);
+        dump_stats_transaction(vconn, request);
     }
     dump_trivial_transaction(vconn_name, OFPRAW_OFPT_GET_CONFIG_REQUEST);
     vconn_close(vconn);
@@ -749,10 +751,10 @@ fetch_port_by_stats(const char *vconn_name,
     bool done = false;
     bool found = false;
 
-    request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, OFP10_VERSION, 0);
-    send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
-
     open_vconn(vconn_name, &vconn);
+    request = ofputil_encode_port_desc_stats_request(vconn_get_version(vconn),
+                                                     port_no);
+    send_xid = ((struct ofp_header *) ofpbuf_data(request))->xid;
     send_openflow_buffer(vconn, request);
     while (!done) {
         ovs_be32 recv_xid;
@@ -1609,7 +1611,16 @@ ofctl_dump_ports(int argc, char *argv[])
 static void
 ofctl_dump_ports_desc(int argc OVS_UNUSED, char *argv[])
 {
-    dump_trivial_stats_transaction(argv[1], OFPRAW_OFPST_PORT_DESC_REQUEST);
+    struct ofpbuf *request;
+    struct vconn *vconn;
+    ofp_port_t port;
+
+    open_vconn(argv[1], &vconn);
+    port = argc > 2 ? str_to_port_no(argv[1], argv[2]) : OFPP_ANY;
+    request = ofputil_encode_port_desc_stats_request(vconn_get_version(vconn),
+                                                     port);
+    dump_stats_transaction(vconn, request);
+    vconn_close(vconn);
 }
 
 static void
@@ -3493,7 +3504,7 @@ static const struct command all_commands[] = {
     { "meter-features", 1, 1, ofctl_meter_features },
     { "packet-out", 4, INT_MAX, ofctl_packet_out },
     { "dump-ports", 1, 2, ofctl_dump_ports },
-    { "dump-ports-desc", 1, 1, ofctl_dump_ports_desc },
+    { "dump-ports-desc", 1, 2, ofctl_dump_ports_desc },
     { "mod-port", 3, 3, ofctl_mod_port },
     { "mod-table", 3, 3, ofctl_mod_table },
     { "get-frags", 1, 1, ofctl_get_frags },
-- 
1.9.1




More information about the dev mailing list