Support encoding of NTR selection method
authorSimon Horman <simon.horman@netronome.com>
Fri, 20 Mar 2015 04:50:31 +0000 (13:50 +0900)
committerBen Pfaff <blp@nicira.com>
Tue, 24 Mar 2015 16:22:12 +0000 (09:22 -0700)
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.horman@netronome.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/nx-match.c
lib/nx-match.h
lib/ofp-print.c
lib/ofp-util.c
ofproto/ofproto.c

index e27e50f..4b72460 100644 (file)
@@ -1067,6 +1067,84 @@ 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. */
+void
+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, ',');
+    }
+}
+
+/* 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)
 {
index 0992536..fe0b68c 100644 (file)
@@ -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);
+void 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). */
index b7c9a26..cec074f 100644 (file)
@@ -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,26 @@ 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;
+        oxm_format_field_array(s, &props->fields);
+        if (s->length == start) {
+            ds_truncate(s, mark);
+        }
+    }
+
     if (!p_buckets) {
         return;
     }
@@ -2226,8 +2246,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 +2400,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);
 }
 
index 34e6df4..7b68564 100644 (file)
@@ -7427,6 +7427,26 @@ ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket,
     ob->bucket_id = htonl(bucket_id);
 }
 
+static void
+ofputil_put_group_prop_ntr_selection_method(enum ofp_version ofp_version,
+                                            const struct ofputil_group_props *gp,
+                                            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, &gp->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,
@@ -7475,6 +7495,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,
+                                                    reply);
+    }
+
     ofpmp_postappend(replies, start_ogds);
 }
 
@@ -8138,6 +8164,11 @@ 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, b);
+    }
+
     id_pool_destroy(bucket_ids);
     return b;
 }
index ff1632f..a36a1f8 100644 (file)
@@ -5827,6 +5827,8 @@ append_group_desc(struct ofgroup *group, struct ovs_list *replies)
 
     gds.group_id = group->group_id;
     gds.type = group->type;
+    gds.props = group->props;
+
     ofputil_append_group_desc_reply(&gds, &group->buckets, replies);
 }