Include NTR selection method experimenter group property in in group mod request and group desc reply.
NTR selection method Signed-off-by: Simon Horman <simon.hor...@netronome.com> --- v3 * Use fixed array for fields_array rather than constructing a list * Use NTR instead of NMX as Netronome extension prefix v2 * Use list of struct field_array of TLVs rather than OF1.1 match for fields field of NTR selection method property --- lib/nx-match.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/nx-match.h | 3 ++ lib/ofp-print.c | 40 ++++++++++++++++++++------ lib/ofp-util.c | 38 ++++++++++++++++++++++++- lib/ofp-util.h | 1 + ofproto/ofproto.c | 7 ++++- tests/ofp-print.at | 16 ++++++++--- 7 files changed, 173 insertions(+), 14 deletions(-) diff --git a/lib/nx-match.c b/lib/nx-match.c index e51c9a3..fc14de3 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -1070,6 +1070,88 @@ oxm_put_match(struct ofpbuf *b, const struct match *match, return match_len; } +/* Appends to 'b' the nx_match format that expresses the tlv corresponding + * to 'id'. If mask is not all-ones then it is also formated as the value + * of the tlv. */ +static void +nx_format_mask_tlv(struct ds *ds, enum mf_field_id id, + const union mf_value *mask) +{ + const struct mf_field *mf = mf_from_id(id); + + ds_put_format(ds, "%s", mf->name); + + if (!is_all_ones(mask, mf->n_bytes)) { + ds_put_char(ds, '='); + mf_format(mf, mask, NULL, ds); + } + + ds_put_char(ds, ','); +} + +/* Appends a string representation of 'fa_' to 'ds'. + * The TLVS value of 'fa_' is treated as a mask and + * only the name of fields is formated if it is all ones. + * + * Returns 0 on success, an ofperr value otherwise */ +int +oxm_format_field_array(struct ds *ds, const struct field_array *fa) +{ + size_t start_len = ds->length; + int i; + + for (i = 0; i < MFF_N_IDS; i++) { + if (bitmap_is_set(fa->used.bm, i)) { + nx_format_mask_tlv(ds, i, &fa->value[i]); + } + } + + if (ds->length > start_len) { + ds_chomp(ds, ','); + } + + return 0; +} + +/* Appends to 'b' a series of OXM TLVs corresponding to the series + * of enum mf_field_id and value tuples in 'fa_'. + * + * OXM differs slightly among versions of OpenFlow. Specify the OpenFlow + * version in use as 'version'. + * + * This function can cause 'b''s data to be reallocated. + * + * Returns the number of bytes appended to 'b'. May return zero. */ +int +oxm_put_field_array(struct ofpbuf *b, const struct field_array *fa, + enum ofp_version version) +{ + size_t start_len = b->size; + int i; + + /* Field arrays are only used with the group selection method + * property and group properties are only available in OpenFlow * 1.5+. + * So the following assertion should never fail. + * + * If support for older OpenFlow versions is desired then some care + * will need to be taken of different TLVs that handle the same + * flow fields. In particular: + * - VLAN_TCI, VLAN_VID and MFF_VLAN_PCP + * - IP_DSCP_MASK and DSCP_SHIFTED + * - REGS and XREGS + */ + ovs_assert(version >= OFP15_VERSION); + + for (i = 0; i < MFF_N_IDS; i++) { + if (bitmap_is_set(fa->used.bm, i)) { + nxm_put_unmasked(b, i, version, &fa->value[i], + mf_from_id(i)->n_bytes); + } + } + + return b->size - start_len; +} + static void nx_put_header__(struct ofpbuf *b, uint64_t header, bool masked) { diff --git a/lib/nx-match.h b/lib/nx-match.h index 0992536..6bd473a 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -60,6 +60,9 @@ enum ofperr oxm_pull_field_array(const void *, size_t fields_len, int nx_put_match(struct ofpbuf *, const struct match *, ovs_be64 cookie, ovs_be64 cookie_mask); int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version); +int oxm_format_field_array(struct ds *, const struct field_array *); +int oxm_put_field_array(struct ofpbuf *, const struct field_array *, + enum ofp_version version); /* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field * ID followed by a value and possibly a mask). */ diff --git a/lib/ofp-print.c b/lib/ofp-print.c index b7c9a26..9b6dceb 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -2156,8 +2156,8 @@ ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id, static void ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, - struct ovs_list *p_buckets, enum ofp_version ofp_version, - bool suppress_type) + struct ovs_list *p_buckets, struct ofputil_group_props *props, + enum ofp_version ofp_version, bool suppress_type) { struct ofputil_bucket *bucket; @@ -2169,6 +2169,28 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, ds_put_format(s, ",type=%s", type_str[type > 4 ? 4 : type]); } + if (props->selection_method[0]) { + size_t mark, start; + + ds_put_format(s, ",selection_method=%s,", props->selection_method); + if (props->selection_method_param) { + ds_put_format(s, "selection_method_param=%"PRIu64",", + props->selection_method_param); + } + + /* Allow rewinding to immediately before the trailing ',' */ + mark = s->length - 1; + + ds_put_cstr(s, "fields="); + start = s->length; + if (oxm_format_field_array(s, &props->fields)) { + ds_put_cstr(s, " ***formatting error***"); + } + if (s->length == start) { + ds_truncate(s, mark); + } + } + if (!p_buckets) { return; } @@ -2178,7 +2200,8 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, LIST_FOR_EACH (bucket, list_node, p_buckets) { ds_put_cstr(s, "bucket="); - ofp_print_bucket_id(s, "bucket_id:", bucket->bucket_id, ofp_version); + ofp_print_bucket_id(s, "bucket_id:", bucket->bucket_id, + ofp_version); if (bucket->weight != 1) { ds_put_format(s, "weight:%"PRIu16",", bucket->weight); } @@ -2186,7 +2209,8 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type, ds_put_format(s, "watch_port:%"PRIu32",", bucket->watch_port); } if (bucket->watch_group != OFPG11_ANY) { - ds_put_format(s, "watch_group:%"PRIu32",", bucket->watch_group); + ds_put_format(s, "watch_group:%"PRIu32",", + bucket->watch_group); } ds_put_cstr(s, "actions="); @@ -2226,8 +2250,8 @@ ofp_print_group_desc(struct ds *s, const struct ofp_header *oh) ds_put_char(s, '\n'); ds_put_char(s, ' '); - ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, oh->version, - false); + ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, &gd.props, + oh->version, false); ofputil_bucket_list_destroy(&gd.buckets); } } @@ -2380,8 +2404,8 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh) gm.command_bucket_id, oh->version); } - ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, oh->version, - bucket_command); + ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, &gm.props, + oh->version, bucket_command); ofputil_bucket_list_destroy(&gm.buckets); } diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 34e6df4..b9099b6 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7428,6 +7428,27 @@ ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket, } static void +ofputil_put_group_prop_ntr_selection_method(enum ofp_version ofp_version, + const struct ofputil_group_props *gp, + const struct field_array *fields, + struct ofpbuf *openflow) +{ + struct ntr_group_prop_selection_method *prop; + size_t start; + + start = openflow->size; + ofpbuf_put_zeros(openflow, sizeof *prop); + oxm_put_field_array(openflow, fields, ofp_version); + prop = ofpbuf_at_assert(openflow, start, sizeof *prop); + prop->type = htons(OFPGPT15_EXPERIMENTER); + prop->experimenter = htonl(NTR_VENDOR_ID); + prop->exp_type = htonl(NTRT_SELECTION_METHOD); + strcpy(prop->selection_method, gp->selection_method); + prop->selection_method_param = htonll(gp->selection_method_param); + end_property(openflow, start); +} + +static void ofputil_append_ofp11_group_desc_reply(const struct ofputil_group_desc *gds, const struct ovs_list *buckets, struct ovs_list *replies, @@ -7454,6 +7475,7 @@ ofputil_append_ofp11_group_desc_reply(const struct ofputil_group_desc *gds, static void ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds, const struct ovs_list *buckets, + const struct field_array *fields, struct ovs_list *replies, enum ofp_version version) { @@ -7475,6 +7497,12 @@ ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds, ogds->group_id = htonl(gds->group_id); ogds->bucket_list_len = htons(reply->size - start_buckets); + /* Add group properties */ + if (gds->props.selection_method[0]) { + ofputil_put_group_prop_ntr_selection_method(version, &gds->props, + fields, reply); + } + ofpmp_postappend(replies, start_ogds); } @@ -7484,6 +7512,7 @@ ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds, void ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds, const struct ovs_list *buckets, + const struct field_array *fields, struct ovs_list *replies) { enum ofp_version version = ofpmp_version(replies); @@ -7498,7 +7527,8 @@ ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds, break; case OFP15_VERSION: - ofputil_append_ofp15_group_desc_reply(gds, buckets, replies, version); + ofputil_append_ofp15_group_desc_reply(gds, buckets, fields, replies, + version); break; case OFP10_VERSION: @@ -8138,6 +8168,12 @@ ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version, ogm->command_bucket_id = htonl(gm->command_bucket_id); ogm->bucket_array_len = htons(b->size - start_ogm - sizeof *ogm); + /* Add group properties */ + if (gm->props.selection_method[0]) { + ofputil_put_group_prop_ntr_selection_method(ofp_version, &gm->props, + &gm->props.fields, b); + } + id_pool_destroy(bucket_ids); return b; } diff --git a/lib/ofp-util.h b/lib/ofp-util.h index ee3f1be..85ec65a 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -1095,6 +1095,7 @@ int ofputil_decode_group_desc_reply(struct ofputil_group_desc *, void ofputil_append_group_desc_reply(const struct ofputil_group_desc *, const struct ovs_list *buckets, + const struct field_array *fields, struct ovs_list *replies); struct ofputil_bundle_ctrl_msg { diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 08eed78..0fbfbd6 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -5827,7 +5827,12 @@ append_group_desc(struct ofgroup *group, struct ovs_list *replies) gds.group_id = group->group_id; gds.type = group->type; - ofputil_append_group_desc_reply(&gds, &group->buckets, replies); + + memcpy(gds.props.selection_method, group->selection_method, + NTR_MAX_SELECTION_METHOD_LEN); + gds.props.selection_method_param = group->selection_method_param; + ofputil_append_group_desc_reply(&gds, &group->buckets, + &group->fields, replies); } static enum ofperr diff --git a/tests/ofp-print.at b/tests/ofp-print.at index dc809e2..3978f65 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -2026,7 +2026,7 @@ AT_CLEANUP AT_SETUP([OFPST_GROUP_DESC reply - OF1.5]) AT_KEYWORDS([ofp-print OFPT_STATS_REPLY]) AT_CHECK([ovs-ofctl ofp-print "\ -06 13 00 98 00 00 00 02 00 07 00 00 00 00 00 00 \ +06 13 00 d8 00 00 00 02 00 07 00 00 00 00 00 00 \ 00 88 01 00 00 00 20 00 00 78 00 00 00 00 00 00 \ 00 28 00 10 00 00 00 00 00 00 00 10 00 00 00 01 \ 00 00 00 00 00 00 00 00 00 00 00 08 00 64 00 00 \ @@ -2037,9 +2037,14 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 28 00 10 00 00 00 02 00 00 00 10 00 00 00 03 \ 00 00 00 00 00 00 00 00 00 00 00 08 00 c8 00 00 \ 00 01 00 08 00 00 00 03 \ +ff ff 00 3b 00 00 15 40 00 00 00 01 00 00 00 00 \ +68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 00 \ +80 00 18 04 ff ff ff 00 80 00 1a 02 ff ff 80 00 \ +14 01 ff 00 00 00 00 00 \ "], [0], [dnl OFPST_GROUP_DESC reply (OF1.5) (xid=0x2): - group_id=8192,type=select,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 + group_id=8192,type=select,selection_method=hash,fields=ip_dst=255.255.255.0,tcp_src,nw_proto,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 ]) AT_CLEANUP @@ -2845,7 +2850,7 @@ AT_CLEANUP AT_SETUP([OFPT_GROUP_MOD add - OF1.5]) AT_KEYWORDS([ofp-print]) AT_CHECK([ovs-ofctl ofp-print "\ -06 0f 00 90 11 22 33 44 00 00 01 00 87 65 43 21 \ +06 0f 00 b8 11 22 33 44 00 00 01 00 87 65 43 21 \ 00 78 00 00 ff ff ff ff 00 28 00 10 00 00 00 00 \ 00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 00 \ 00 00 00 08 00 64 00 00 00 01 00 08 00 00 00 01 \ @@ -2854,9 +2859,12 @@ AT_CHECK([ovs-ofctl ofp-print "\ 00 01 00 08 00 00 00 02 00 28 00 10 00 00 00 02 \ 00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \ 00 00 00 08 00 c8 00 00 00 01 00 08 00 00 00 03 \ +ff ff 00 28 00 00 15 40 00 00 00 01 00 00 00 00 \ +72 61 6e 64 6f 6d 00 00 00 00 00 00 00 00 00 00 \ +00 00 00 00 00 00 00 07 \ "], [0], [dnl OFPT_GROUP_MOD (OF1.5) (xid=0x11223344): - ADD group_id=2271560481,type=select,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 + ADD group_id=2271560481,type=select,selection_method=random,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3 ]) AT_CLEANUP -- 2.1.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev