Fast failover groups use the actions in
the first bucket that is alive.
Signed-off-by: Simon Horman <[email protected]>
---
v6
* First post
---
ofproto/ofproto-dpif-xlate.c | 97 +++++++++++++++++++++++++++++++++++++++++++-
ofproto/ofproto-dpif-xlate.h | 3 +-
ofproto/ofproto-dpif.c | 4 +-
ofproto/ofproto.c | 1 +
tests/ofproto-dpif.at | 12 ++++++
5 files changed, 112 insertions(+), 5 deletions(-)
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 76860a5..0196d13 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. */
@@ -392,7 +393,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);
@@ -413,6 +415,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;
@@ -716,6 +719,81 @@ 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) {
+ return false;
+ }
+
+ if (xport->config & OFPUTIL_PC_PORT_DOWN) {
+ return false;
+ }
+
+ if (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) {
+ 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
@@ -1825,6 +1903,19 @@ 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);
+ } else {
+ ctx->exit = true;
+ }
+}
+
+static void
xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
{
switch (group_dpif_get_type(group)) {
@@ -1832,8 +1923,10 @@ xlate_group_action__(struct xlate_ctx *ctx, struct
group_dpif *group)
case OFPGT11_INDIRECT:
xlate_all_group(ctx, group);
break;
- case OFPGT11_SELECT:
case OFPGT11_FF:
+ xlate_ff_group(ctx, group);
+ break;
+ case OFPGT11_SELECT:
default:
/* XXX not yet implemented */
break;
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 40712f9..8a87734 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 457a736..a164529 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 1709fcc..b67868a 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -525,6 +525,7 @@ ofproto_create(const char *datapath_name, const char
*datapath_type,
ovs_mutex_unlock(&ofproto_mutex);
ofproto->ogf.max_groups[OFPGT11_ALL] = OFPG_MAX;
ofproto->ogf.max_groups[OFPGT11_INDIRECT] = OFPG_MAX;
+ ofproto->ogf.max_groups[OFPGT11_FF] = OFPG_MAX;
error = ofproto->ofproto_class->construct(ofproto);
if (error) {
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index c7868fb..722c34e 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -109,6 +109,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
[email protected]
http://openvswitch.org/mailman/listinfo/dev