This is intended as a usable demonstration of how
the NTR selection method extension might may be used.

NTR selection method
Signed-off-by: Simon Horman <simon.hor...@netronome.com>

---

v3
* Update new check in parse_group_prop_nmx_selection_method() to
  allow decoding hash selection method
* 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               |  2 +-
 lib/nx-match.h               |  3 +++
 lib/ofp-util.c               | 13 +++++--------
 ofproto/ofproto-dpif-xlate.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
 ofproto/ofproto-dpif.c       | 12 ++++++++++++
 ofproto/ofproto-dpif.h       |  2 ++
 tests/ofproto-dpif.at        | 20 ++++++++++++++++++++
 7 files changed, 88 insertions(+), 9 deletions(-)

diff --git a/lib/nx-match.c b/lib/nx-match.c
index fc14de3..df2d976 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -414,7 +414,7 @@ nx_pull_header(struct ofpbuf *b, const struct mf_field 
**field, bool *masked)
     return error;
 }
 
-static enum ofperr
+enum ofperr
 nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie,
                     const struct mf_field **field,
                     union mf_value *value, union mf_value *mask)
diff --git a/lib/nx-match.h b/lib/nx-match.h
index 6bd473a..3767fdf 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -70,6 +70,9 @@ enum ofperr nx_pull_entry(struct ofpbuf *, const struct 
mf_field **,
                           union mf_value *value, union mf_value *mask);
 enum ofperr nx_pull_header(struct ofpbuf *, const struct mf_field **,
                            bool *masked);
+enum ofperr nx_pull_match_entry(struct ofpbuf *b, bool allow_cookie,
+                                const struct mf_field **field,
+                                union mf_value *value, union mf_value *mask);
 void nx_put_entry(struct ofpbuf *, enum mf_field_id, enum ofp_version,
                   const union mf_value *value, const union mf_value *mask);
 void nx_put_header(struct ofpbuf *, enum mf_field_id, enum ofp_version,
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index b9099b6..433d807 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -7823,14 +7823,11 @@ parse_group_prop_ntr_selection_method(struct ofpbuf 
*payload,
         return OFPERR_OFPBPC_BAD_VALUE;
     }
 
-    /* Only allow selection method property if the selection_method field
-     * matches a suported method. As no methods are currently supported
-     * this check is a no-op that always fails. As selection methods are
-     * added they should be checked against the selection_method field
-     * here. */
-    log_property(false, "ntr selection method '%s' is not supported",
-                 prop->selection_method);
-    return OFPERR_OFPBPC_BAD_VALUE;
+    if (strcmp("hash", prop->selection_method)) {
+        log_property(false, "ntr selection method '%s' is not supported",
+                     prop->selection_method);
+        return OFPERR_OFPBPC_BAD_VALUE;
+    }
 
     strcpy(gp->selection_method, prop->selection_method);
     gp->selection_method_param = ntohll(prop->selection_method_param);
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 1a3d34c..63b7393 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -35,6 +35,7 @@
 #include "dpif.h"
 #include "dynamic-string.h"
 #include "in-band.h"
+#include "jhash.h"
 #include "lacp.h"
 #include "learn.h"
 #include "list.h"
@@ -3088,6 +3089,48 @@ xlate_default_select_group(struct xlate_ctx *ctx, struct 
group_dpif *group)
     }
 }
 
+static void
+xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+{
+    struct flow_wildcards *wc = &ctx->xout->wc;
+    uint64_t selection_method_param;
+    struct ofputil_bucket *bucket;
+    const struct field_array *fields;
+    struct flow flow;
+    uint32_t basis;
+    int i;
+
+    fields = group_dpif_get_fields(group);
+    flow = ctx->xin->flow;
+
+    for (i = 0; i < MFF_N_IDS; i++) {
+        if (bitmap_is_set(fields->used.bm, i)) {
+            int j;
+            union mf_value value;
+            const struct mf_field *mf = mf_from_id(i);
+
+            mf_get_value(mf, &flow, &value);
+            /* This seems inefficient but so is apply_mask() */
+            for (j = 0; j < mf->n_bytes; j++) {
+                ((uint8_t *) &value)[j] &= ((uint8_t *) &fields->value[i])[j];
+            }
+            mf_set_flow_value(mf, &value, &flow);
+
+            mf_mask_field(mf, &wc->masks);
+        }
+    }
+
+    selection_method_param = group_dpif_get_selection_method_param(group);
+
+    basis = (uint32_t)(selection_method_param & 0xffffffff);
+    basis = jhash_bytes(&flow, sizeof flow, basis);
+    bucket = group_best_live_bucket(ctx, group, basis);
+    if (bucket) {
+        xlate_group_bucket(ctx, bucket);
+        xlate_group_stats(ctx, group, bucket);
+    }
+}
+
 static bool
 xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
 {
@@ -3095,6 +3138,8 @@ xlate_select_group(struct xlate_ctx *ctx, struct 
group_dpif *group)
 
     if (selection_method[0] == '\0') {
         xlate_default_select_group(ctx, group);
+    } else if (!strcasecmp("hash", selection_method)) {
+        xlate_hash_fields_select_group(ctx, group);
     } else {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 4d2333f..7218d3d 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4256,6 +4256,18 @@ group_dpif_get_selection_method(const struct group_dpif 
*group)
 {
     return group->up.selection_method;
 }
+
+uint64_t
+group_dpif_get_selection_method_param(const struct group_dpif *group)
+{
+    return group->up.selection_method_param;
+}
+
+const struct field_array *
+group_dpif_get_fields(const struct group_dpif *group)
+{
+    return &group->up.fields;
+}
 
 /* Sends 'packet' out 'ofport'.
  * May modify 'packet'.
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index fd099a2..19c91f0 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -138,6 +138,8 @@ void group_dpif_get_buckets(const struct group_dpif *group,
                             const struct ovs_list **buckets);
 enum ofp11_group_type group_dpif_get_type(const struct group_dpif *group);
 const char *group_dpif_get_selection_method(const struct group_dpif *group);
+uint64_t group_dpif_get_selection_method_param(const struct group_dpif *group);
+const struct field_array *group_dpif_get_fields(const struct group_dpif 
*group);
 
 bool ofproto_has_vlan_splinters(const struct ofproto_dpif *);
 ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 4932fcc..fe65856 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -403,6 +403,26 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - select group with hash selection method])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [10], [11])
+AT_CHECK([ovs-ofctl -O OpenFlow15 add-group br0 
'group_id=1234,type=select,selection_method=hash,fields=eth_dst=ff:ff:ff:ff:ff:ff,bucket=output:10,bucket=output:11'])
+AT_CHECK([ovs-ofctl -O OpenFlow15 add-flow br0 'ip 
actions=write_actions(group:1234)'])
+
+# Try a bunch of different flows and make sure that they get distributed
+# at least somewhat.
+for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+    AT_CHECK([ovs-appctl ofproto/trace br0 
"in_port=1,dl_src=50:54:00:00:00:07,dl_dst=50:54:00:00:00:0$d,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0"],
 [0], [stdout])
+    tail -1 stdout >> results
+done
+sort results | uniq -c
+AT_CHECK([sort results | uniq], [0],
+  [Datapath actions: 10
+Datapath actions: 11
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - fast failover group])
 OVS_VSWITCHD_START
 ADD_OF_PORTS([br0], [1], [10], [11])
-- 
2.1.4

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

Reply via email to