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

Reply via email to