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

NMX selection method
Signed-off-by: Simon Horman <simon.hor...@netronome.com>
---
 lib/flow.c                   |  2 +-
 lib/flow.h                   | 14 ++++++++++++++
 ofproto/ofproto-dpif-xlate.c | 32 ++++++++++++++++++++++++++++++++
 ofproto/ofproto-dpif.c       | 12 ++++++++++++
 ofproto/ofproto-dpif.h       |  2 ++
 tests/ofproto-dpif.at        | 20 ++++++++++++++++++++
 6 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/lib/flow.c b/lib/flow.c
index 88794f0..c619390 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -2020,7 +2020,7 @@ miniflow_expand(const struct miniflow *src, struct flow 
*dst)
 
 /* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'flow'
  * were expanded into a "struct flow". */
-static uint32_t
+uint32_t
 miniflow_get(const struct miniflow *flow, unsigned int u32_ofs)
 {
     return (flow->map & UINT64_C(1) << u32_ofs)
diff --git a/lib/flow.h b/lib/flow.h
index ae955c3..7363c31 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -578,6 +578,7 @@ static inline uint16_t miniflow_get_vid(const struct 
miniflow *);
 static inline uint16_t miniflow_get_tcp_flags(const struct miniflow *);
 static inline ovs_be64 miniflow_get_metadata(const struct miniflow *);
 
+uint32_t miniflow_get(const struct miniflow *, unsigned int u32_ofs);
 bool miniflow_equal(const struct miniflow *a, const struct miniflow *b);
 bool miniflow_equal_in_minimask(const struct miniflow *a,
                                 const struct miniflow *b,
@@ -699,6 +700,19 @@ flow_union_with_miniflow(struct flow *dst, const struct 
miniflow *src)
     }
 }
 
+/* Perform a bitwise AND of miniflow 'src' flow data with the equivalent
+ * fields in 'dst', storing the result in 'dst'. */
+static inline void
+flow_intersection_with_miniflow(struct flow *dst, const struct miniflow *src)
+{
+    uint32_t *dst_u32 = (uint32_t *) dst;
+    unsigned int i;
+
+    for (i = 0; i < FLOW_U32S; i++) {
+        dst_u32[i] &= miniflow_get(src, i);
+    }
+}
+
 static inline struct pkt_metadata
 pkt_metadata_from_flow(const struct flow *flow)
 {
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index a794840..7baecc0 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -34,6 +34,7 @@
 #include "dpif.h"
 #include "dynamic-string.h"
 #include "in-band.h"
+#include "jhash.h"
 #include "lacp.h"
 #include "learn.h"
 #include "list.h"
@@ -3011,6 +3012,35 @@ 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;
+    const struct miniflow *fields;
+    struct ofputil_bucket *bucket;
+    struct flow flow;
+    uint32_t basis;
+
+    fields = group_dpif_get_fields(group);
+
+    flow = ctx->xin->flow;
+    flow_intersection_with_miniflow(&flow, fields);
+
+    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) {
+        // XXX: May partially mask fields of wc. Is this ok?
+        flow_union_with_miniflow(&wc->masks, fields);
+
+        xlate_group_bucket(ctx, bucket);
+        xlate_group_stats(ctx, group, bucket);
+    }
+}
+
 static bool
 xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
 {
@@ -3018,6 +3048,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 e56bd61..c7160e0 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4092,6 +4092,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 miniflow *
+group_dpif_get_fields(const struct group_dpif *group)
+{
+    return &group->up.fields.flow;
+}
 
 /* Sends 'packet' out 'ofport'.
  * May modify 'packet'.
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 0893d29..7db83ac 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -124,6 +124,8 @@ void group_dpif_get_buckets(const struct group_dpif *group,
                             const struct 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 miniflow *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 5349386..190d018 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -323,6 +323,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.1

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

Reply via email to