OpenFlow 1.4 and earlier always send the description of every group in response to an OFPMP_GROUP_DESC request. OpenFlow 1.5 proposes allowing the controller to request a description of a single group. This commit implements a prototype.
EXT-69. Signed-off-by: Ben Pfaff <b...@nicira.com> --- lib/ofp-msgs.h | 9 ++++--- lib/ofp-print.c | 10 ++++++++ lib/ofp-util.c | 38 +++++++++++++++++++++++++--- lib/ofp-util.h | 5 +++- ofproto/ofproto.c | 66 +++++++++++++++++++++++++----------------------- tests/ofp-print.at | 13 ++++++++-- tests/ofproto.at | 5 ++++ utilities/ovs-ofctl.8.in | 14 +++++++--- utilities/ovs-ofctl.c | 12 ++++++--- 9 files changed, 123 insertions(+), 49 deletions(-) diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h index b548f6b..5610793 100644 --- a/lib/ofp-msgs.h +++ b/lib/ofp-msgs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013 Nicira, Inc. + * Copyright (c) 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -321,8 +321,10 @@ enum ofpraw { /* OFPST 1.3+ (6): uint8_t[8][]. */ OFPRAW_OFPST13_GROUP_REPLY, - /* OFPST 1.1+ (7): void. */ + /* OFPST 1.1-1.4 (7): void. */ OFPRAW_OFPST11_GROUP_DESC_REQUEST, + /* OFPST 1.5+ (7): ovs_be32. */ + OFPRAW_OFPST15_GROUP_DESC_REQUEST, /* OFPST 1.1+ (7): uint8_t[8][]. */ OFPRAW_OFPST11_GROUP_DESC_REPLY, @@ -559,7 +561,8 @@ enum ofptype { OFPTYPE_GROUP_STATS_REPLY, /* OFPRAW_OFPST11_GROUP_REPLY. * OFPRAW_OFPST13_GROUP_REPLY. */ - OFPTYPE_GROUP_DESC_STATS_REQUEST, /* OFPRAW_OFPST11_GROUP_DESC_REQUEST. */ + OFPTYPE_GROUP_DESC_STATS_REQUEST, /* OFPRAW_OFPST11_GROUP_DESC_REQUEST. + * OFPRAW_OFPST15_GROUP_DESC_REQUEST. */ OFPTYPE_GROUP_DESC_STATS_REPLY, /* OFPRAW_OFPST11_GROUP_DESC_REPLY. */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 3d4b8f81..df9bcc3 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -2356,6 +2356,15 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, } static void +ofp_print_ofpst_group_desc_request(struct ds *string, + const struct ofp_header *oh) +{ + uint32_t group_id = ofputil_decode_group_desc_request(oh); + ds_put_cstr(string, " group_id="); + ofputil_format_group(group_id, string); +} + +static void ofp_print_group_desc(struct ds *s, const struct ofp_header *oh) { struct ofpbuf b; @@ -2782,6 +2791,7 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw, case OFPTYPE_GROUP_DESC_STATS_REQUEST: ofp_print_stats_request(string, oh); + ofp_print_ofpst_group_desc_request(string, oh); break; case OFPTYPE_GROUP_DESC_STATS_REPLY: diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 4ec323d..5fe3c05 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -6388,16 +6388,40 @@ ofputil_encode_group_stats_request(enum ofp_version ofp_version, return request; } +/* Decodes the OpenFlow group description request in 'oh', returning the group + * whose description is requested, or OFPG_ALL if stats for all groups was + * requested. */ +uint32_t +ofputil_decode_group_desc_request(const struct ofp_header *oh) +{ + struct ofpbuf request; + enum ofpraw raw; + + ofpbuf_use_const(&request, oh, ntohs(oh->length)); + raw = ofpraw_pull_assert(&request); + if (raw == OFPRAW_OFPST11_GROUP_DESC_REQUEST) { + return OFPG_ALL; + } else if (raw == OFPRAW_OFPST15_GROUP_DESC_REQUEST) { + ovs_be32 *group_id = ofpbuf_pull(&request, sizeof *group_id); + return ntohl(*group_id); + } else { + OVS_NOT_REACHED(); + } +} + /* Returns an OpenFlow group description request for OpenFlow version - * 'ofp_version', that requests stats for group 'group_id'. (Use OFPG_ALL to - * request stats for all groups.) + * 'ofp_version', that requests stats for group 'group_id'. Use OFPG_ALL to + * request stats for all groups (OpenFlow 1.4 and earlier always request all + * groups). * * Group descriptions include the bucket and action configuration for each * group. */ struct ofpbuf * -ofputil_encode_group_desc_request(enum ofp_version ofp_version) +ofputil_encode_group_desc_request(enum ofp_version ofp_version, + uint32_t group_id) { struct ofpbuf *request; + ovs_be32 gid; switch (ofp_version) { case OFP10_VERSION: @@ -6407,8 +6431,14 @@ ofputil_encode_group_desc_request(enum ofp_version ofp_version) case OFP12_VERSION: case OFP13_VERSION: case OFP14_VERSION: + request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST, + ofp_version, 0); + break; case OFP15_VERSION: - request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST, ofp_version, 0); + request = ofpraw_alloc(OFPRAW_OFPST15_GROUP_DESC_REQUEST, + ofp_version, 0); + gid = htonl(group_id); + ofpbuf_put(request, &gid, sizeof gid); break; default: OVS_NOT_REACHED(); diff --git a/lib/ofp-util.h b/lib/ofp-util.h index ce10bfc..5308668 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -1130,13 +1130,16 @@ enum ofperr ofputil_decode_group_mod(const struct ofp_header *, int ofputil_decode_group_stats_reply(struct ofpbuf *, struct ofputil_group_stats *); +uint32_t ofputil_decode_group_desc_request(const struct ofp_header *); +struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version, + uint32_t group_id); + int ofputil_decode_group_desc_reply(struct ofputil_group_desc *, struct ofpbuf *, enum ofp_version); void ofputil_append_group_desc_reply(const struct ofputil_group_desc *, struct list *buckets, struct list *replies); -struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version); struct ofputil_bundle_ctrl_msg { uint32_t bundle_id; diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 557f124..2978b5b 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -5448,64 +5448,66 @@ append_group_stats(struct ofgroup *group, struct list *replies) free(ogs.bucket_stats); } -static enum ofperr -handle_group_stats_request(struct ofconn *ofconn, - const struct ofp_header *request) +static void +handle_group_request(struct ofconn *ofconn, + const struct ofp_header *request, uint32_t group_id, + void (*cb)(struct ofgroup *, struct list *replies)) { struct ofproto *ofproto = ofconn_get_ofproto(ofconn); - struct list replies; - enum ofperr error; struct ofgroup *group; - uint32_t group_id; - - error = ofputil_decode_group_stats_request(request, &group_id); - if (error) { - return error; - } + struct list replies; ofpmp_init(&replies, request); - if (group_id == OFPG_ALL) { ovs_rwlock_rdlock(&ofproto->groups_rwlock); HMAP_FOR_EACH (group, hmap_node, &ofproto->groups) { ovs_rwlock_rdlock(&group->rwlock); - append_group_stats(group, &replies); + cb(group, &replies); ovs_rwlock_unlock(&group->rwlock); } ovs_rwlock_unlock(&ofproto->groups_rwlock); } else { if (ofproto_group_lookup(ofproto, group_id, &group)) { - append_group_stats(group, &replies); + cb(group, &replies); ofproto_group_release(group); } } - ofconn_send_replies(ofconn, &replies); - - return 0; } static enum ofperr -handle_group_desc_stats_request(struct ofconn *ofconn, - const struct ofp_header *request) +handle_group_stats_request(struct ofconn *ofconn, + const struct ofp_header *request) { - struct ofproto *ofproto = ofconn_get_ofproto(ofconn); - struct list replies; - struct ofputil_group_desc gds; - struct ofgroup *group; - - ofpmp_init(&replies, request); + uint32_t group_id; + enum ofperr error; - ovs_rwlock_rdlock(&ofproto->groups_rwlock); - HMAP_FOR_EACH (group, hmap_node, &ofproto->groups) { - gds.group_id = group->group_id; - gds.type = group->type; - ofputil_append_group_desc_reply(&gds, &group->buckets, &replies); + error = ofputil_decode_group_stats_request(request, &group_id); + if (error) { + return error; } - ovs_rwlock_unlock(&ofproto->groups_rwlock); - ofconn_send_replies(ofconn, &replies); + handle_group_request(ofconn, request, group_id, append_group_stats); + return 0; +} + +static void +append_group_desc(struct ofgroup *group, struct list *replies) +{ + struct ofputil_group_desc gds; + gds.group_id = group->group_id; + gds.type = group->type; + ofputil_append_group_desc_reply(&gds, &group->buckets, replies); +} + +static enum ofperr +handle_group_desc_stats_request(struct ofconn *ofconn, + const struct ofp_header *request) +{ + handle_group_request(ofconn, request, + ofputil_decode_group_desc_request(request), + append_group_desc); return 0; } diff --git a/tests/ofp-print.at b/tests/ofp-print.at index 640d114..81f5fde 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -1798,11 +1798,20 @@ OFPST_GROUP reply (OF1.3) (xid=0x2): ]) AT_CLEANUP -AT_SETUP([OFPST_GROUP_DESC request]) +AT_SETUP([OFPST_GROUP_DESC request - OF1.1]) AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST]) AT_CHECK([ovs-ofctl ofp-print "\ 02 12 00 10 00 00 00 02 00 07 00 00 00 00 00 00 \ -"], [0], [OFPST_GROUP_DESC request (OF1.1) (xid=0x2): +"], [0], [OFPST_GROUP_DESC request (OF1.1) (xid=0x2): group_id=ALL +]) +AT_CLEANUP + +AT_SETUP([OFPST_GROUP_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 07 00 00 00 00 00 00 \ +00 00 00 01 +"], [0], [OFPST_GROUP_DESC request (OF1.5) (xid=0x2): group_id=1 ]) AT_CLEANUP diff --git a/tests/ofproto.at b/tests/ofproto.at index 2ffe653..c1a6637 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -206,6 +206,11 @@ group_id=1234,type=all,bucket=output:10 group_id=1235,type=all,bucket=output:10 ]) AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-groups br0 groups.txt]) +AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout]) +AT_CHECK([STRIP_XIDS stdout], [0], [dnl +OFPST_GROUP_DESC reply (OF1.5): + group_id=1234,type=all,bucket=actions=output:10 +]) AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn del-groups br0 group_id=1234]) AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn dump-groups br0], [0], [stdout]) AT_CHECK([STRIP_XIDS stdout], [0], [dnl diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 9923715..2ccb21a 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -204,9 +204,15 @@ the switch itself (with the \fBprotocols\fR column in the \fBBridge\fR table). For more information, see ``Q: What versions of OpenFlow does Open vSwitch support?'' in the Open vSwitch FAQ. . -.IP "\fBdump\-groups \fIswitch" -Prints to the console all group entries in \fIswitch\fR's tables. Each line -of output is a group entry as described in \fBGroup Syntax\fR below. +.IP "\fBdump\-groups \fIswitch\fR [\fIgroup\fR]" +Prints group entries in \fIswitch\fR's tables to console. To dump +only a specific group, specify its number as \fIgroup\fR. Otherwise, +if \fIgroup\fR is omitted, or if it is specified as \fBALL\fR, then +all groups are printed. Each line of output is a group entry as +described in \fBGroup Syntax\fR below. +.IP +Only OpenFlow 1.5 and later support dumping a specific group. Earlier +versions of OpenFlow always dump all groups. . .IP "\fBdump\-group\-features \fIswitch" Prints to the console the group features of the \fIswitch\fR. @@ -1830,7 +1836,7 @@ of each field is honoured. .PP .IP \fBgroup_id=\fIid\fR The integer group id of group. -When this field is specified in \fBdel-groups\fR or \fBdump-groups\fR, +When this field is specified in \fBdel\-groups\fR or \fBdump\-groups\fR, the keyword "all" may be used to designate all groups. . This field is required. diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 2776613..c2baed3 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -327,7 +327,7 @@ usage(void) " mod-group SWITCH GROUP modify specific group\n" " del-groups SWITCH [GROUP] delete matching GROUPs\n" " dump-group-features SWITCH print group features\n" - " dump-groups SWITCH print group description\n" + " dump-groups SWITCH [GROUP] print group description\n" " dump-group-stats SWITCH [GROUP] print group statistics\n" " queue-get-config SWITCH PORT print queue information for port\n" " add-meter SWITCH METER add meter described by METER\n" @@ -2162,10 +2162,16 @@ ofctl_dump_group_desc(int argc OVS_UNUSED, char *argv[]) { struct ofpbuf *request; struct vconn *vconn; + uint32_t group_id; open_vconn(argv[1], &vconn); - request = ofputil_encode_group_desc_request(vconn_get_version(vconn)); + if (argc < 3 || !ofputil_group_from_string(argv[2], &group_id)) { + group_id = OFPG11_ALL; + } + + request = ofputil_encode_group_desc_request(vconn_get_version(vconn), + group_id); if (request) { dump_stats_transaction(vconn, request); } @@ -3503,7 +3509,7 @@ static const struct command all_commands[] = { { "add-groups", 1, 2, ofctl_add_groups }, { "mod-group", 1, 2, ofctl_mod_group }, { "del-groups", 1, 2, ofctl_del_groups }, - { "dump-groups", 1, 1, ofctl_dump_group_desc }, + { "dump-groups", 1, 2, ofctl_dump_group_desc }, { "dump-group-stats", 1, 2, ofctl_dump_group_stats }, { "dump-group-features", 1, 1, ofctl_dump_group_features }, { "help", 0, INT_MAX, ofctl_help }, -- 1.9.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev