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

Reply via email to