This is in preparation for supporting group mod and desc reply messages with an NMX selection method group experimenter property.
NMX selection method Signed-off-by: Simon Horman <simon.hor...@netronome.com> --- lib/nx-match.c | 52 ++++++++--- lib/nx-match.h | 1 + lib/ofp-util.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++++++--- lib/ofp-util.h | 16 ++++ ofproto/ofproto.c | 7 +- 5 files changed, 308 insertions(+), 24 deletions(-) diff --git a/lib/nx-match.c b/lib/nx-match.c index bc6682d..6b1d9d8 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -439,9 +439,18 @@ nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie, return 0; } +/* If bm is NULL then: + * - Parse a match by TLVs as values with optional masks and + * check that the pre-requisites of each TLV are satisfied. + * Else: + * - Parse a mask by parsing the fields of each TLV as a mask, + * disallowing masks in each TLV, ignoring pre-requisites and + * setting a bit in bm for each TLV that is present. The bit + * set corresponds to the id of the mf_field of the TLV. */ static enum ofperr nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, - struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask) + struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask, + struct mf_bitmap *bm) { struct ofpbuf b; @@ -474,11 +483,18 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, *cookie = value.be64; *cookie_mask = mask.be64; } - } else if (!mf_are_prereqs_ok(field, &match->flow)) { + } else if (!bm && !mf_are_prereqs_ok(field, &match->flow)) { error = OFPERR_OFPBMC_BAD_PREREQ; } else if (!mf_is_all_wild(field, &match->wc)) { error = OFPERR_OFPBMC_DUP_FIELD; } else { + if (bm) { + if (!is_all_ones(&mask, field->n_bytes)) { + /* Mask may not be masked */ + error = OFPERR_OFPBMC_BAD_VALUE; + } + bitmap_set1(bm->bm, field->id); + } mf_set(field, &value, &mask, match); } @@ -495,8 +511,8 @@ nx_pull_raw(const uint8_t *p, unsigned int match_len, bool strict, static enum ofperr nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, - struct match *match, - ovs_be64 *cookie, ovs_be64 *cookie_mask) + struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask, + struct mf_bitmap *bm) { uint8_t *p = NULL; @@ -510,7 +526,7 @@ nx_pull_match__(struct ofpbuf *b, unsigned int match_len, bool strict, } } - return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask); + return nx_pull_raw(p, match_len, strict, match, cookie, cookie_mask, bm); } /* Parses the nx_match formatted match description in 'b' with length @@ -525,7 +541,8 @@ enum ofperr nx_pull_match(struct ofpbuf *b, unsigned int match_len, struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask) { - return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask); + return nx_pull_match__(b, match_len, true, match, cookie, cookie_mask, + NULL); } /* Behaves the same as nx_pull_match(), but skips over unknown NXM headers, @@ -535,11 +552,13 @@ nx_pull_match_loose(struct ofpbuf *b, unsigned int match_len, struct match *match, ovs_be64 *cookie, ovs_be64 *cookie_mask) { - return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask); + return nx_pull_match__(b, match_len, false, match, cookie, cookie_mask, + NULL); } static enum ofperr -oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) +oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match, + struct mf_bitmap *bm) { struct ofp11_match_header *omh = ofpbuf_data(b); uint8_t *p; @@ -567,7 +586,7 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) } return nx_pull_raw(p + sizeof *omh, match_len - sizeof *omh, - strict, match, NULL, NULL); + strict, match, NULL, NULL, bm); } /* Parses the oxm formatted match description preceded by a struct @@ -579,7 +598,7 @@ oxm_pull_match__(struct ofpbuf *b, bool strict, struct match *match) enum ofperr oxm_pull_match(struct ofpbuf *b, struct match *match) { - return oxm_pull_match__(b, true, match); + return oxm_pull_match__(b, true, match, NULL); } /* Behaves the same as oxm_pull_match() with one exception. Skips over unknown @@ -587,7 +606,18 @@ oxm_pull_match(struct ofpbuf *b, struct match *match) enum ofperr oxm_pull_match_loose(struct ofpbuf *b, struct match *match) { - return oxm_pull_match__(b, false, match); + return oxm_pull_match__(b, false, match, NULL); +} + + +/* Parse a mask formated using OXM by parsing the fields of each TLV as a + * mask, disallowing masks in each TLV, ignoring pre-requisites and setting + * a bit in bm for each TLV that is present. The bit set corresponds to the + * id of the mf_field of the TLV. */ +enum ofperr +oxm_pull_mask(struct ofpbuf *b, struct match *match, struct mf_bitmap *bm) +{ + return oxm_pull_match__(b, true, match, bm); } /* nx_put_match() and helpers. diff --git a/lib/nx-match.h b/lib/nx-match.h index 62e73a0..ecc1aae 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -55,6 +55,7 @@ enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len, ovs_be64 *cookie_mask); enum ofperr oxm_pull_match(struct ofpbuf *, struct match *); enum ofperr oxm_pull_match_loose(struct ofpbuf *, struct match *); +enum ofperr oxm_pull_mask(struct ofpbuf *, struct match *, struct mf_bitmap *); 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); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 94047fa..4a78d81 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -38,6 +38,7 @@ #include "ofp-msgs.h" #include "ofp-util.h" #include "ofpbuf.h" +#include "openflow/netronome-ext.h" #include "packets.h" #include "random.h" #include "unaligned.h" @@ -59,6 +60,14 @@ struct ofp_prop_header { ovs_be16 len; }; +struct ofp_prop_experimenter { + ovs_be16 type; /* OFP*_EXPERIMENTER. */ + ovs_be16 length; /* Length in bytes of this property. */ + ovs_be32 experimenter; /* Experimenter ID which takes the same form as + * in struct ofp_experimenter_header. */ + ovs_be32 exp_type; /* Experimenter defined. */ +}; + /* Pulls a property, beginning with struct ofp_prop_header, from the beginning * of 'msg'. Stores the type of the property in '*typep' and, if 'property' is * nonnull, the entire property, including the header, in '*property'. Returns @@ -362,9 +371,9 @@ ofputil_match_to_ofp10_match(const struct match *match, memset(ofmatch->pad2, '\0', sizeof ofmatch->pad2); } -enum ofperr -ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match, - uint16_t *padded_match_len) +static enum ofperr +ofputil_pull_ofp11_match__(struct ofpbuf *buf, struct match *match, + uint16_t *padded_match_len, struct mf_bitmap *bm) { struct ofp11_match_header *omh = ofpbuf_data(buf); uint16_t match_len; @@ -379,6 +388,10 @@ ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match, case OFPMT_STANDARD: { struct ofp11_match *om; + if (bm) { + /* XXX: Not supported yet */ + return OFPERR_OFPBMC_BAD_TYPE; + } if (match_len != sizeof *om || ofpbuf_size(buf) < sizeof *om) { return OFPERR_OFPBMC_BAD_LEN; } @@ -393,13 +406,31 @@ ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match, if (padded_match_len) { *padded_match_len = ROUND_UP(match_len, 8); } - return oxm_pull_match(buf, match); + if (bm) { + return oxm_pull_mask(buf, match, bm); + } else { + return oxm_pull_match(buf, match); + } default: return OFPERR_OFPBMC_BAD_TYPE; } } +enum ofperr +ofputil_pull_ofp11_match(struct ofpbuf *buf, struct match *match, + uint16_t *padded_match_len) +{ + return ofputil_pull_ofp11_match__(buf, match, padded_match_len, false); +} + +enum ofperr +ofputil_pull_ofp11_mask(struct ofpbuf *buf, struct match *match, + struct mf_bitmap *bm) +{ + return ofputil_pull_ofp11_match__(buf, match, NULL, bm); +} + /* Converts the ofp11_match in 'ofmatch' into a struct match in 'match'. * Returns 0 if successful, otherwise an OFPERR_* value. */ enum ofperr @@ -7716,6 +7747,189 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length, return 0; } +static enum ofperr +parse_group_prop_nmx_selection_method(struct ofpbuf *payload, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp) +{ + struct nmx_group_prop_selection_method *prop = ofpbuf_data(payload); + size_t method_len; + enum ofperr error; + struct match match; + + switch (group_type) { + case OFPGT11_SELECT: + break; + case OFPGT11_ALL: + case OFPGT11_INDIRECT: + case OFPGT11_FF: + log_property(false, "nmx selection method property is only allowed " + "for select groups"); + return OFPERR_OFPBPC_BAD_VALUE; + default: + OVS_NOT_REACHED(); + } + + switch (group_cmd) { + case OFPGC15_ADD: + case OFPGC15_MODIFY: + break; + case OFPGC15_DELETE: + case OFPGC15_INSERT_BUCKET: + case OFPGC15_REMOVE_BUCKET: + log_property(false, "nmx selection method property is only allowed " + "for add and delete group modifications"); + return OFPERR_OFPBPC_BAD_VALUE; + default: + OVS_NOT_REACHED(); + } + + if (ofpbuf_size(payload) < sizeof *prop) { + log_property(false, "nmx selection method property length " + "%u is not valid", ofpbuf_size(payload)); + return OFPERR_OFPBPC_BAD_LEN; + } + + method_len = strnlen(prop->selection_method, NMX_MAX_SELECTION_METHOD_LEN); + + if (method_len == NMX_MAX_SELECTION_METHOD_LEN) { + log_property(false, "nmx selection method is not null terminated"); + return OFPERR_OFPBPC_BAD_VALUE; + } + + strcpy(gp->selection_method, prop->selection_method); + gp->selection_method_param = ntohll(prop->selection_method_param); + + if (!method_len && gp->selection_method_param) { + log_property(false, "nmx selection method parameter is non-zero but " + "selection method is empty"); + return OFPERR_OFPBPC_BAD_VALUE; + } + + ofpbuf_pull(payload, sizeof *prop); + + error = ofputil_pull_ofp11_mask(payload, &match, &gp->fields.bm); + if (error) { + log_property(false, "nmx selection method fields are invalid"); + return error; + } + if (!method_len) { + struct flow_wildcards catchall; + + flow_wildcards_init_catchall(&catchall); + + if (!flow_wildcards_equal(&match.wc, &catchall)) { + log_property(false, "nmx selection method parameter is non-zero " + "but non-catchall fields are provided"); + return OFPERR_OFPBPC_BAD_VALUE; + } + } + gp->fields.flow = match.flow; + + return 0; +} + +static enum ofperr +parse_group_prop_nmx(struct ofpbuf *payload, uint32_t exp_type, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp) +{ + enum ofperr error; + + switch (exp_type) { + case NMXT_SELECTION_METHOD: + error = parse_group_prop_nmx_selection_method(payload, group_type, + group_cmd, gp); + break; + + default: + log_property(false, "unknown group property nmx experimenter type " + "%"PRIu32, exp_type); + error = OFPERR_OFPBPC_BAD_TYPE; + break; + } + + return error; +} + +static enum ofperr +parse_ofp15_group_prop_exp(struct ofpbuf *payload, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp) +{ + struct ofp_prop_experimenter *prop = ofpbuf_data(payload); + uint16_t experimenter; + uint32_t exp_type; + enum ofperr error; + + if (ofpbuf_size(payload) < sizeof *prop) { + return OFPERR_OFPBPC_BAD_LEN; + } + + experimenter = ntohl(prop->experimenter); + exp_type = ntohl(prop->exp_type); + + switch (experimenter) { + case NMX_VENDOR_ID: + error = parse_group_prop_nmx(payload, exp_type, group_type, + group_cmd, gp); + break; + + default: + log_property(false, "unknown group property experimenter %"PRIu16, + experimenter); + error = OFPERR_OFPBPC_BAD_EXPERIMENTER; + break; + } + + return error; +} + +static enum ofperr +parse_ofp15_group_properties(struct ofpbuf *msg, + enum ofp11_group_type group_type, + enum ofp15_group_mod_command group_cmd, + struct ofputil_group_props *gp, + size_t properties_len) +{ + struct ofpbuf properties; + + ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len), + properties_len); + + while (ofpbuf_size(&properties) > 0) { + struct ofpbuf payload; + enum ofperr error; + uint16_t type; + + error = ofputil_pull_property(&properties, &payload, &type); + if (error) { + return error; + } + + switch (type) { + case OFPGPT15_EXPERIMENTER: + error = parse_ofp15_group_prop_exp(&payload, group_type, + group_cmd, gp); + break; + + default: + log_property(false, "unknown group property %"PRIu16, type); + error = OFPERR_OFPBPC_BAD_TYPE; + break; + } + + if (error) { + return error; + } + } + + return 0; +} + static int ofputil_decode_ofp11_group_desc_reply(struct ofputil_group_desc *gd, struct ofpbuf *msg, @@ -7759,6 +7973,7 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd, { struct ofp15_group_desc_stats *ogds; uint16_t length, bucket_list_len; + int error; if (!msg->frame) { ofpraw_pull_assert(msg); @@ -7790,9 +8005,22 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd, "bucket list length %u", bucket_list_len); return OFPERR_OFPBRC_BAD_LEN; } + error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, version, + &gd->buckets); + if (error) { + return error; + } - return ofputil_pull_ofp15_buckets(msg, bucket_list_len, version, - &gd->buckets); + /* By deffinition group desc messages don't have a group mod command. + * However, parse_group_prop_nmx_selection_method() checks to make sure + * that the command is OFPGC15_ADD or OFPGC15_DELETE to guard + * against group mod messages with other commands upplying + * a NMX selection method group experimenter property. + * Such properties are valid for group desc replies so + * claim that the group mod command is OFPGC15_ADD to + * satisfy the check in parse_group_prop_nmx_selection_method() */ + return parse_ofp15_group_properties(msg, gd->type, OFPGC15_ADD, &gd->props, + ofpbuf_size(msg)); } /* Converts a group description reply in 'msg' into an abstract @@ -7809,6 +8037,8 @@ int ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd, struct ofpbuf *msg, enum ofp_version version) { + memset(&gd->props, 0, sizeof gd->props); + switch (version) { case OFP11_VERSION: @@ -8048,14 +8278,14 @@ ofputil_pull_ofp15_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version, } bucket_list_len = ntohs(ogm->bucket_list_len); - if (bucket_list_len < ofpbuf_size(msg)) { - VLOG_WARN_RL(&bad_ofmsg_rl, "group has %u trailing bytes", - ofpbuf_size(msg) - bucket_list_len); - return OFPERR_OFPGMFC_BAD_BUCKET; + error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version, + &gm->buckets); + if (error) { + return error; } - return ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version, - &gm->buckets); + return parse_ofp15_group_properties(msg, gm->type, gm->command, &gm->props, + ofpbuf_size(msg)); } /* Converts OpenFlow group mod message 'oh' into an abstract group mod in @@ -8072,6 +8302,8 @@ ofputil_decode_group_mod(const struct ofp_header *oh, ofpbuf_use_const(&msg, oh, ntohs(oh->length)); ofpraw_pull_assert(&msg); + memset(&gm->props, 0, sizeof gm->props); + switch (ofp_version) { case OFP11_VERSION: diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 6fe2883..bea424a 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -27,6 +27,7 @@ #include "match.h" #include "meta-flow.h" #include "netdev.h" +#include "openflow/netronome-ext.h" #include "openflow/nicira-ext.h" #include "openvswitch/types.h" #include "type-props.h" @@ -217,6 +218,8 @@ void ofputil_match_to_ofp10_match(const struct match *, struct ofp10_match *); /* Work with ofp11_match. */ enum ofperr ofputil_pull_ofp11_match(struct ofpbuf *, struct match *, uint16_t *padded_match_len); +enum ofperr ofputil_pull_ofp11_mask(struct ofpbuf *, struct match *, + struct mf_bitmap *bm); enum ofperr ofputil_match_from_ofp11_match(const struct ofp11_match *, struct match *); int ofputil_put_ofp11_match(struct ofpbuf *, const struct match *, @@ -994,6 +997,17 @@ struct ofputil_bucket { }; /* Protocol-independent group_mod. */ +struct ofputil_group_props { + /* NMX selection method */ + char selection_method[NMX_MAX_SELECTION_METHOD_LEN]; + uint64_t selection_method_param; + struct { + struct flow flow; + struct mf_bitmap bm; + } fields; +}; + +/* Protocol-independent group_mod. */ struct ofputil_group_mod { uint16_t command; /* One of OFPGC15_*. */ uint8_t type; /* One of OFPGT11_*. */ @@ -1003,6 +1017,7 @@ struct ofputil_group_mod { * OFPGC15_REMOVE_BUCKET commands * execution.*/ struct list buckets; /* Contains "struct ofputil_bucket"s. */ + struct ofputil_group_props props; /* Group properties. */ }; /* Group stats reply, independent of protocol. */ @@ -1032,6 +1047,7 @@ struct ofputil_group_desc { uint8_t type; /* One of OFPGT_*. */ uint32_t group_id; /* Group identifier. */ struct list buckets; /* Contains "struct ofputil_bucket"s. */ + struct ofputil_group_props props; /* Group properties. */ }; void ofputil_bucket_list_destroy(struct list *buckets); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index b749ca6..99dd4e6 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -5770,7 +5770,12 @@ init_group(struct ofproto *ofproto, struct ofputil_group_mod *gm, *CONST_CAST(uint32_t *, &(*ofgroup)->n_buckets) = list_size(&(*ofgroup)->buckets); - CONST_CAST(char *, (*ofgroup)->selection_method)[0] = '\0'; + memcpy(CONST_CAST(char *, (*ofgroup)->selection_method), + gm->props.selection_method, NMX_MAX_SELECTION_METHOD_LEN); + *CONST_CAST(uint64_t *, &(*ofgroup)->selection_method_param) = + gm->props.selection_method_param; + miniflow_init(&(*ofgroup)->fields.flow, &gm->props.fields.flow); + (*ofgroup)->fields.bm = gm->props.fields.bm; /* Construct called BEFORE any locks are held. */ error = ofproto->ofproto_class->group_construct(*ofgroup); -- 2.1.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev