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 <b...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev