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

Reply via email to