Fast failover groups use the actions in the first bucket that is alive. Signed-off-by: Simon Horman <ho...@verge.net.au>
--- v8 * Do not set xlate->exit in xlate_ff_group() if no bucket is alive. The packet will be dropped anyway if there are no further actions and if there are further actions they should be processed. * Correct whitespace after LIST_FOR_EACH * Add rate-limited warning to bucket_is_alive() v7 * Make implementation of odp_port_is_alive() less verbose v6 * First post --- ofproto/ofproto-dpif-xlate.c | 92 +++++++++++++++++++++++++++++++++++++++++++- ofproto/ofproto-dpif-xlate.h | 3 +- ofproto/ofproto-dpif.c | 4 +- ofproto/ofproto.c | 1 + tests/ofproto-dpif.at | 12 ++++++ 5 files changed, 107 insertions(+), 5 deletions(-) diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 287bdce..7edb1d6 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -126,6 +126,7 @@ struct xport { struct xport *peer; /* Patch port peer or null. */ enum ofputil_port_config config; /* OpenFlow port configuration. */ + enum ofputil_port_state state; /* OpenFlow port state. */ int stp_port_no; /* STP port number or -1 if not in use. */ struct hmap skb_priorities; /* Map of 'skb_priority_to_dscp's. */ @@ -396,7 +397,8 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, const struct cfm *cfm, const struct bfd *bfd, struct ofport_dpif *peer, int stp_port_no, const struct ofproto_port_queue *qdscp_list, size_t n_qdscp, - enum ofputil_port_config config, bool is_tunnel, + enum ofputil_port_config config, + enum ofputil_port_state state, bool is_tunnel, bool may_enable) { struct xport *xport = xport_lookup(ofport); @@ -417,6 +419,7 @@ xlate_ofport_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, ovs_assert(xport->ofp_port == ofp_port); xport->config = config; + xport->state = state; xport->stp_port_no = stp_port_no; xport->is_tunnel = is_tunnel; xport->may_enable = may_enable; @@ -720,6 +723,78 @@ ofp_port_to_odp_port(const struct xbridge *xbridge, ofp_port_t ofp_port) } static bool +odp_port_is_alive(const struct xlate_ctx *ctx, ofp_port_t ofp_port) +{ + struct xport *xport; + + xport = get_ofp_port(ctx->xbridge, ofp_port); + if (!xport || xport->config & OFPUTIL_PC_PORT_DOWN || + xport->state & OFPUTIL_PS_LINK_DOWN) { + return false; + } + + return true; +} + +static const struct ofputil_bucket * +group_first_live_bucket(const struct xlate_ctx *, const struct group_dpif *, + int depth); + +static bool +group_is_alive(const struct xlate_ctx *ctx, uint32_t group_id, int depth) +{ + struct group_dpif *group; + bool hit; + + hit = group_dpif_lookup(ctx->xbridge->ofproto, group_id, &group); + if (!hit) { + return false; + } + + hit = group_first_live_bucket(ctx, group, depth) != NULL; + + group_dpif_release(group); + return hit; +} + +#define MAX_LIVENESS_RECURSION 128 /* Arbitrary limit */ + +static bool +bucket_is_alive(const struct xlate_ctx *ctx, + const struct ofputil_bucket *bucket, int depth) +{ + if (depth >= MAX_LIVENESS_RECURSION) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1); + + VLOG_WARN_RL(&rl, "bucket chaining exceeded %d links", + MAX_LIVENESS_RECURSION); + return false; + } + + return (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)); +} + +static const struct ofputil_bucket * +group_first_live_bucket(const struct xlate_ctx *ctx, + const struct group_dpif *group, int depth) +{ + 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, depth)) { + return bucket; + } + } + + return NULL; +} + +static bool xbundle_trunks_vlan(const struct xbundle *bundle, uint16_t vlan) { return (bundle->vlan_mode != PORT_VLAN_ACCESS @@ -1826,6 +1901,17 @@ xlate_all_group(struct xlate_ctx *ctx, struct group_dpif *group) } static void +xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group) +{ + const struct ofputil_bucket *bucket; + + bucket = group_first_live_bucket(ctx, group, 0); + if (bucket) { + xlate_group_bucket(ctx, bucket); + } +} + +static void xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group) { switch (group_dpif_get_type(group)) { @@ -1834,9 +1920,11 @@ xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group) xlate_all_group(ctx, group); break; case OFPGT11_SELECT: - case OFPGT11_FF: /* XXX not yet implemented */ break; + case OFPGT11_FF: + xlate_ff_group(ctx, group); + break; default: NOT_REACHED(); } diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index 667d42e..7dd3534 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -138,7 +138,8 @@ void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *, const struct netdev *, const struct cfm *, const struct bfd *, struct ofport_dpif *peer, int stp_port_no, const struct ofproto_port_queue *qdscp, - size_t n_qdscp, enum ofputil_port_config, bool is_tunnel, + size_t n_qdscp, enum ofputil_port_config, + enum ofputil_port_state, bool is_tunnel, bool may_enable) OVS_REQ_WRLOCK(xlate_rwlock); void xlate_ofport_remove(struct ofport_dpif *) OVS_REQ_WRLOCK(xlate_rwlock); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 341a63c..3bbe329 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -824,8 +824,8 @@ type_run(const char *type) ofport->up.netdev, ofport->cfm, ofport->bfd, ofport->peer, stp_port, ofport->qdscp, ofport->n_qdscp, - ofport->up.pp.config, ofport->is_tunnel, - ofport->may_enable); + ofport->up.pp.config, ofport->up.pp.state, + ofport->is_tunnel, ofport->may_enable); } ovs_rwlock_unlock(&xlate_rwlock); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 719aff0..618e472 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -531,6 +531,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type, ofproto->ogf.capabilities = OFPGFC_CHAINING; ofproto->ogf.max_groups[OFPGT11_ALL] = OFPG_MAX; ofproto->ogf.max_groups[OFPGT11_INDIRECT] = OFPG_MAX; + ofproto->ogf.max_groups[OFPGT11_FF] = OFPG_MAX; ofproto->ogf.actions[0] = #define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) ENUM | #include "ofp-util.def" diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index d99b190..366e4e1 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -113,6 +113,18 @@ AT_CHECK([tail -1 stdout], [0], OVS_VSWITCHD_STOP AT_CLEANUP +AT_SETUP([ofproto-dpif - fast failover group]) +OVS_VSWITCHD_START +ADD_OF_PORTS([br0], [1], [10], [11]) +AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=ff,bucket=watch_port:10,output:10,bucket=watch_port:11,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:05,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: drop +]) +OVS_VSWITCHD_STOP +AT_CLEANUP + AT_SETUP([ofproto-dpif - registers]) OVS_VSWITCHD_START ADD_OF_PORTS([br0], [20], [21], [22], [33], [90]) -- 1.8.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev