From fe7e574970ae0ba1b8515a329c9ce88f22365b95 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 30 Oct 2013 18:17:19 +0900 Subject: [PATCH] ofproto-dpif: Implement translation of select groups. 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 [blp@nicira.com replaced bucket selection by "highest random weight" method] Signed-off-by: Ben Pfaff --- ofproto/ofproto-dpif-xlate.c | 47 ++++++++++++++++++++++++++++++++++-- ofproto/ofproto.c | 4 +-- tests/ofproto-dpif.at | 24 ++++++++++++++++++ tests/ofproto.at | 2 +- 4 files changed, 72 insertions(+), 5 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index c54f4858c..5c22db365 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -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); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index d302c9bfd..34b06425b 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -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); diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 0da886567..643e072b5 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -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]) diff --git a/tests/ofproto.at b/tests/ofproto.at index deebf3b88..9ba593422 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -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 -- 2.47.0