Include NMX selection method experimenter group property in
in group mod request and group desc reply.

NMX selection method
Signed-off-by: Simon Horman <simon.hor...@netronome.com>
---
 lib/nx-match.c    | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 lib/nx-match.h    |   2 +
 lib/ofp-util.c    |  31 ++++++++
 ofproto/ofproto.c |   7 ++
 4 files changed, 241 insertions(+), 13 deletions(-)

diff --git a/lib/nx-match.c b/lib/nx-match.c
index 6b1d9d8..29055ca 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -699,6 +699,13 @@ nxm_put_64m(struct ofpbuf *b, enum mf_field_id field, enum 
ofp_version version,
 }
 
 static void
+nxm_put_64(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version,
+           ovs_be64 value)
+{
+    nxm_put_unmasked(b, field, version, &value, sizeof value);
+}
+
+static void
 nxm_put_eth_masked(struct ofpbuf *b,
                    enum mf_field_id field, enum ofp_version version,
                    const uint8_t value[ETH_ADDR_LEN],
@@ -708,25 +715,48 @@ nxm_put_eth_masked(struct ofpbuf *b,
 }
 
 static void
-nxm_put_ipv6(struct ofpbuf *b,
-             enum mf_field_id field, enum ofp_version version,
-             const struct in6_addr *value, const struct in6_addr *mask)
+nxm_put_eth(struct ofpbuf *b, enum mf_field_id field, enum ofp_version version,
+            const uint8_t value[ETH_ADDR_LEN])
+{
+    nxm_put_unmasked(b, field, version, value, ETH_ADDR_LEN);
+}
+
+static void
+nxm_put_ipv6_masked(struct ofpbuf *b,
+                    enum mf_field_id field, enum ofp_version version,
+                    const struct in6_addr *value, const struct in6_addr *mask)
 {
     nxm_put(b, field, version, value->s6_addr, mask->s6_addr,
             sizeof value->s6_addr);
 }
 
 static void
-nxm_put_frag(struct ofpbuf *b, const struct match *match,
+nxm_put_ipv6(struct ofpbuf *b,
+             enum mf_field_id field, enum ofp_version version,
+             const struct in6_addr *value)
+{
+    nxm_put_unmasked(b, field, version, value->s6_addr, sizeof value->s6_addr);
+}
+
+static void
+nxm_put_frag_masked(struct ofpbuf *b, uint8_t value, uint8_t mask,
              enum ofp_version version)
 {
-    uint8_t nw_frag = match->flow.nw_frag & FLOW_NW_FRAG_MASK;
-    uint8_t nw_frag_mask = match->wc.masks.nw_frag & FLOW_NW_FRAG_MASK;
+    uint8_t nw_frag = value & FLOW_NW_FRAG_MASK;
+    uint8_t nw_frag_mask = mask & FLOW_NW_FRAG_MASK;
 
     nxm_put_8m(b, MFF_IP_FRAG, version, nw_frag,
                nw_frag_mask == FLOW_NW_FRAG_MASK ? UINT8_MAX : nw_frag_mask);
 }
 
+static void
+nxm_put_frag(struct ofpbuf *b, uint8_t value, enum ofp_version version)
+{
+    uint8_t nw_frag = value & FLOW_NW_FRAG_MASK;
+
+    nxm_put_8(b, MFF_IP_FRAG, version, nw_frag);
+}
+
 /* Appends to 'b' a set of OXM or NXM matches for the IPv4 or IPv6 fields in
  * 'match'.  */
 static void
@@ -740,13 +770,13 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, 
enum ofp_version oxm)
         nxm_put_32m(b, MFF_IPV4_DST, oxm,
                     flow->nw_dst, match->wc.masks.nw_dst);
     } else {
-        nxm_put_ipv6(b, MFF_IPV6_SRC, oxm,
-                     &flow->ipv6_src, &match->wc.masks.ipv6_src);
-        nxm_put_ipv6(b, MFF_IPV6_DST, oxm,
-                     &flow->ipv6_dst, &match->wc.masks.ipv6_dst);
+        nxm_put_ipv6_masked(b, MFF_IPV6_SRC, oxm,
+                            &flow->ipv6_src, &match->wc.masks.ipv6_src);
+        nxm_put_ipv6_masked(b, MFF_IPV6_DST, oxm,
+                            &flow->ipv6_dst, &match->wc.masks.ipv6_dst);
     }
 
-    nxm_put_frag(b, match, oxm);
+    nxm_put_frag_masked(b, flow->nw_frag, match->wc.masks.nw_frag, oxm);
 
     if (match->wc.masks.nw_tos & IP_DSCP_MASK) {
         if (oxm) {
@@ -810,8 +840,9 @@ nxm_put_ip(struct ofpbuf *b, const struct match *match, 
enum ofp_version oxm)
             }
             if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT) ||
                 flow->tp_src == htons(ND_NEIGHBOR_ADVERT)) {
-                nxm_put_ipv6(b, MFF_ND_TARGET, oxm,
-                             &flow->nd_target, &match->wc.masks.nd_target);
+                nxm_put_ipv6_masked(b, MFF_ND_TARGET, oxm,
+                                    &flow->nd_target,
+                                    &match->wc.masks.nd_target);
                 if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
                     nxm_put_eth_masked(b, MFF_ND_SLL, oxm,
                                        flow->arp_sha, match->wc.masks.arp_sha);
@@ -991,6 +1022,130 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const 
struct match *match,
     return match_len;
 }
 
+/* Appends to 'b' the nx_match format that expresses the tlv with
+ * 'id' in 'flow'. */
+static void
+nx_put_tlv(struct ofpbuf *b, enum ofp_version oxm,
+           const struct flow *flow, int id)
+{
+    const struct mf_field *mf;
+    union mf_value value;
+
+    mf = mf_from_id(id);
+    mf_get_value(mf, flow, &value);
+
+    if (id == MFF_IP_FRAG) {
+        nxm_put_frag(b, value.u8, oxm);
+    } else {
+        switch(mf->n_bytes) {
+        case 1:
+            nxm_put_8(b, id, oxm, value.u8);
+            break;
+        case 2:
+            nxm_put_16(b, id, oxm, value.be16);
+            break;
+        case 4:
+            nxm_put_32(b, id, oxm, value.be32);
+            break;
+        case ETH_ADDR_LEN:
+            nxm_put_eth(b, id, oxm, value.mac);
+            break;
+        case 8:
+            nxm_put_64(b, id, oxm, value.be64);
+            break;
+        case 16:
+            nxm_put_ipv6(b, id, oxm, &value.ipv6);
+            break;
+        }
+    }
+}
+
+/* Appends to 'b' the nx_match format that expresses 'flow'.
+ *
+ * Only 'flow' fields whose corresponding bit is set in bm are added to 'b'.
+ * All fields are added without any mask.
+ *
+ * Specify 'oxm' as 0 to express the match in NXM format; otherwise, specify
+ * 'oxm' as the OpenFlow version number for the OXM format to use.
+ *
+ * This function can cause 'b''s data to be reallocated.
+ *
+ * Returns the number of bytes appended to 'b', excluding padding. */
+static int
+nx_put_raw_bm(struct ofpbuf *b, enum ofp_version oxm,
+              const struct flow *flow, const struct mf_bitmap *bm)
+{
+    const size_t start_len = ofpbuf_size(b);
+    int match_len;
+    int i;
+    struct mf_bitmap done = MF_BITMAP_INITIALIZER;
+
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
+
+    for (i = 0; i < MFF_N_IDS; i++) {
+        int id = i;
+
+        if (!bitmap_is_set(bm->bm, id)) {
+            continue;
+        }
+
+        if (oxm) {
+            if (id == MFF_VLAN_TCI) {
+                /* The MFF_VLAN_TCI NXM TLV covers the MFF_VLAN_VID
+                 * and MFF_VLAN_PCP OXM TLVs. Handle the the latter directly
+                 * and translate the id for the former. */
+                if (flow->vlan_tci & htons(VLAN_VID_MASK | VLAN_CFI)) {
+                    nx_put_tlv(b, oxm, flow, MFF_VLAN_PCP);
+                }
+                bitmap_set1(done.bm, MFF_VLAN_PCP);
+                id = MFF_VLAN_VID;
+            } else if (id == IP_DSCP_MASK) {
+                /* The MFF_IP_DSCP_MASK NXM TLV covers the
+                 * MFF_IP_DSCP_SHIFTED OXM TLV. Translate the id accordingly. 
*/
+                id = MFF_IP_DSCP_SHIFTED;
+            }
+        } else {
+            if (id == MFF_VLAN_VID || id == MFF_VLAN_PCP) {
+                /* The MFF_VLAN_TCI NXM TLV covers the MFF_VLAN_VID
+                 * and MFF_VLAN_PCP OXM TLVs. ranslate the id accordingly. */
+                id = MFF_VLAN_TCI;
+            } else if (id == MFF_IP_DSCP_SHIFTED) {
+                /* The MFF_IP_DSCP_MASK_SHIFTED NXM TLV covers the
+                 * MFF_IP_DSCP OXM TLV. Translate the id accordingly. */
+                id = MFF_IP_DSCP;
+            }
+        }
+
+        if (oxm < OFP15_VERSION) {
+            if (id >= MFF_XREG0 && id < MFF_XREG0 + FLOW_N_XREGS) {
+                id = (id - MFF_XREG0) * 2 + MFF_REG0;
+                /* non-extended register corresponding to low word of
+                 * extended register */
+                nx_put_tlv(b, oxm, flow, id);
+                /* non-extended register corresponding to high word of
+                 * extended register */
+                id++;
+            }
+        } else {
+            if (id >= MFF_REG0 && id < MFF_REG0 + FLOW_N_REGS) {
+                /* extended register corresponding to two non-extended
+                 * registers */
+                id = (id - MFF_REG0) / 2 + MFF_XREG0;
+            }
+        }
+
+        if (bitmap_is_set(done.bm, id)) {
+            continue;
+        }
+        bitmap_set1(done.bm, id);
+
+        nx_put_tlv(b, oxm, flow, id);
+    }
+
+    match_len = ofpbuf_size(b) - start_len;
+    return match_len;
+}
+
 /* Appends to 'b' the nx_match format that expresses 'match', plus enough zero
  * bytes to pad the nx_match out to a multiple of 8.  For Flow Mod and Flow
  * Stats Requests messages, a 'cookie' and 'cookie_mask' may be supplied.
@@ -1043,6 +1198,39 @@ oxm_put_match(struct ofpbuf *b, const struct match 
*match,
     return match_len;
 }
 
+/* Appends to 'b' an struct ofp11_match_header followed by the OXM format that
+ * expresses 'flow', plus enough zero bytes to pad the data appended out to a
+ * multiple of 8.
+ *
+ * Only 'flow' fields whose corresponding bit is set in bm are added to 'b'.
+ * All fields are added without any mask.
+ *
+ * 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', excluding the padding.  Never
+ * returns zero. */
+int
+oxm_put_match_bm(struct ofpbuf *b, const struct flow *flow,
+                 const struct mf_bitmap *bm, enum ofp_version version)
+{
+    int match_len;
+    struct ofp11_match_header *omh;
+    size_t start_len = ofpbuf_size(b);
+
+    ofpbuf_put_uninit(b, sizeof *omh);
+    match_len = (nx_put_raw_bm(b, version, flow, bm) + sizeof *omh);
+    ofpbuf_put_zeros(b, PAD_SIZE(match_len, 8));
+
+    omh = ofpbuf_at(b, start_len, sizeof *omh);
+    omh->type = htons(OFPMT_OXM);
+    omh->length = htons(match_len);
+
+    return match_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 ecc1aae..f89a2cc 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -59,6 +59,8 @@ 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);
+int oxm_put_match_bm(struct ofpbuf *, const struct flow *,
+                     const struct mf_bitmap *, 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-util.c b/lib/ofp-util.c
index 4a78d81..9f301bc 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -7438,6 +7438,26 @@ ofputil_put_ofp15_bucket(const struct ofputil_bucket 
*bucket,
 }
 
 static void
+ofputil_put_group_prop_nmx_selection_method(enum ofp_version ofp_version,
+                                            const struct ofputil_group_props 
*gp,
+                                            struct ofpbuf *openflow)
+{
+    struct nmx_group_prop_selection_method *prop;
+    size_t start;
+
+    start = ofpbuf_size(openflow);
+    ofpbuf_put_zeros(openflow, sizeof *prop);
+    oxm_put_match_bm(openflow, &gp->fields.flow, &gp->fields.bm, ofp_version);
+    prop = ofpbuf_at_assert(openflow, start, sizeof *prop);
+    prop->type = htons(OFPGPT15_EXPERIMENTER);
+    prop->experimenter = htonl(NMX_VENDOR_ID);
+    prop->exp_type = htonl(NMXT_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,
                                       struct list *buckets,
                                       struct list *replies,
@@ -7485,6 +7505,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(ofpbuf_size(reply) - start_buckets);
 
+    /* Add group properties */
+    if (gds->props.selection_method[0]) {
+        ofputil_put_group_prop_nmx_selection_method(version, &gds->props,
+                                                    reply);
+    }
+
     ofpmp_postappend(replies, start_ogds);
 }
 
@@ -8132,6 +8158,11 @@ ofputil_encode_ofp15_group_mod(enum ofp_version 
ofp_version,
     ogm->command_bucket_id = htonl(gm->command_bucket_id);
     ogm->bucket_list_len = htons(ofpbuf_size(b) - start_ogm - sizeof *ogm);
 
+    /* Add group properties */
+    if (gm->props.selection_method[0]) {
+        ofputil_put_group_prop_nmx_selection_method(ofp_version, &gm->props, 
b);
+    }
+
     id_pool_destroy(bucket_ids);
     return b;
 }
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 99dd4e6..c6828a2 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -5668,6 +5668,13 @@ append_group_desc(struct ofgroup *group, struct list 
*replies)
 
     gds.group_id = group->group_id;
     gds.type = group->type;
+
+    memcpy(gds.props.selection_method, group->selection_method,
+           NMX_MAX_SELECTION_METHOD_LEN);
+    gds.props.selection_method_param = group->selection_method_param;
+    miniflow_expand(&group->fields.flow, &gds.props.fields.flow);
+    gds.props.fields.bm = group->fields.bm;
+
     ofputil_append_group_desc_reply(&gds, &group->buckets, replies);
 }
 
-- 
2.1.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to