[ovs-dev] [of1.5 v2 17/20] Implement OpenFlow 1.5 port desc stats request.
Ben Pfaff
blp at nicira.com
Sat May 10 02:40:33 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 | 21 ++++++++++++-----
9 files changed, 193 insertions(+), 41 deletions(-)
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index 4c330cd..5eb067d 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -367,8 +367,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,
@@ -598,7 +600,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 0ad06f0..790d586 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 847c75e..4bf101a 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -3928,6 +3928,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 0410a22..f0b6604 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 a7a2470..b98e9e5 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 956aa66..cfb604e 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -1943,7 +1943,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 ec4839c..dde715e 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -144,6 +144,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 16d6d93..fc264c7 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 3b78ca5..986c18f 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"
@@ -648,7 +648,7 @@ ofctl_show(int argc OVS_UNUSED, char *argv[])
ofpbuf_delete(reply);
if (!has_ports) {
- request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST, version, 0);
+ 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);
@@ -761,8 +761,8 @@ fetch_port_by_stats(struct vconn *vconn,
bool done = false;
bool found = false;
- request = ofpraw_alloc(OFPRAW_OFPST_PORT_DESC_REQUEST,
- vconn_get_version(vconn), 0);
+ 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);
@@ -1620,7 +1620,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
@@ -3504,7 +3513,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