ofproto-dpif: Implement translation of select groups.
authorSimon Horman <horms@verge.net.au>
Wed, 30 Oct 2013 09:17:19 +0000 (18:17 +0900)
committerBen Pfaff <blp@nicira.com>
Sun, 3 Nov 2013 02:18:40 +0000 (19:18 -0700)
Select bucket from those that are alive based on a hash of the destination
ethernet address of the packet.

Support for weights is proposed by a subsequent patch.

The selection is based on a hash of the destination ethernet
address of the flow. It should be possible to extend
this to cover a hash of user-specified elements of the flow.

Signed-off-by: Simon Horman <horms@verge.net.au>
[blp@nicira.com replaced bucket selection by "highest random weight"
 method]
Signed-off-by: Ben Pfaff <blp@nicira.com>
ofproto/ofproto-dpif-xlate.c
ofproto/ofproto.c
tests/ofproto-dpif.at
tests/ofproto.at

index c54f485..5c22db3 100644 (file)
@@ -772,7 +772,8 @@ bucket_is_alive(const struct xlate_ctx *ctx,
         return false;
     }
 
-    return (bucket->watch_port != OFPP_ANY &&
+    return !ofputil_bucket_has_liveness(bucket) ||
+           (bucket->watch_port != OFPP_ANY &&
             odp_port_is_alive(ctx, bucket->watch_port)) ||
            (bucket->watch_group != OFPG_ANY &&
             group_is_alive(ctx, bucket->watch_group, depth + 1));
@@ -795,6 +796,33 @@ group_first_live_bucket(const struct xlate_ctx *ctx,
     return NULL;
 }
 
+static const struct ofputil_bucket *
+group_best_live_bucket(const struct xlate_ctx *ctx,
+                       const struct group_dpif *group,
+                       uint32_t basis)
+{
+    const struct ofputil_bucket *best_bucket = NULL;
+    uint32_t best_score = 0;
+    int i = 0;
+
+    const struct ofputil_bucket *bucket;
+    const struct list *buckets;
+
+    group_dpif_get_buckets(group, &buckets);
+    LIST_FOR_EACH (bucket, list_node, buckets) {
+        if (bucket_is_alive(ctx, bucket, 0)) {
+            uint32_t score = hash_int(i, basis);
+            if (score >= best_score) {
+                best_bucket = bucket;
+                best_score = score;
+            }
+        }
+        i++;
+    }
+
+    return best_bucket;
+}
+
 static bool
 xbundle_trunks_vlan(const struct xbundle *bundle, uint16_t vlan)
 {
@@ -1911,6 +1939,21 @@ xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group)
     }
 }
 
+static void
+xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+{
+    struct flow_wildcards *wc = &ctx->xout->wc;
+    const struct ofputil_bucket *bucket;
+    uint32_t basis;
+
+    basis = hash_bytes(ctx->xin->flow.dl_dst, sizeof ctx->xin->flow.dl_dst, 0);
+    bucket = group_best_live_bucket(ctx, group, basis);
+    if (bucket) {
+        memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
+        xlate_group_bucket(ctx, bucket);
+    }
+}
+
 static void
 xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
 {
@@ -1920,7 +1963,7 @@ xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
         xlate_all_group(ctx, group);
         break;
     case OFPGT11_SELECT:
-        /* XXX not yet implemented */
+        xlate_select_group(ctx, group);
         break;
     case OFPGT11_FF:
         xlate_ff_group(ctx, group);
index d302c9b..34b0642 100644 (file)
@@ -531,8 +531,9 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     ovs_rwlock_init(&ofproto->groups_rwlock);
     hmap_init(&ofproto->groups);
     ovs_mutex_unlock(&ofproto_mutex);
-    ofproto->ogf.capabilities = OFPGFC_CHAINING;
+    ofproto->ogf.capabilities = OFPGFC_CHAINING | OFPGFC_SELECT_LIVENESS;
     ofproto->ogf.max_groups[OFPGT11_ALL] = OFPG_MAX;
+    ofproto->ogf.max_groups[OFPGT11_SELECT] = OFPG_MAX;
     ofproto->ogf.max_groups[OFPGT11_INDIRECT] = OFPG_MAX;
     ofproto->ogf.max_groups[OFPGT11_FF] = OFPG_MAX;
     ofproto->ogf.actions[0] =
@@ -2901,7 +2902,6 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
         goto exit_free_ofpacts;
     }
 
-
     /* Get payload. */
     if (po.buffer_id != UINT32_MAX) {
         error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
index 0da8865..643e072 100644 (file)
@@ -113,6 +113,30 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - select group])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [10], [11])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=select,bucket=output:10,bucket=output:11'])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=write_actions(group:1234)'])
+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:07,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])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: 10
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - select group with watch port])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [10], [11])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=select,bucket=watch_port:10,output:10,bucket=output:11'])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=write_actions(group:1234)'])
+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:07,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])
+AT_CHECK([tail -1 stdout], [0],
+  [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])
index deebf3b..9ba5934 100644 (file)
@@ -306,7 +306,7 @@ AT_CHECK([STRIP_XIDS stdout], [0], [dnl
 OFPST_GROUP_FEATURES reply (OF1.2):
  Group table:
     Types:  0x0
-    Capabilities:  0x4
+    Capabilities:  0x6
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP