bond: Use active-backup mode on LACP failure.
[sliver-openvswitch.git] / lib / lacp.c
index de0b663..fce65b3 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -102,6 +102,7 @@ struct lacp {
     bool fast;               /* True if using fast probe interval. */
     bool negotiated;         /* True if LACP negotiations were successful. */
     bool update;             /* True if lacp_update() needs to be called. */
+    bool fallback_ab; /* True if fallback to active-backup on LACP failure. */
 
     atomic_int ref_cnt;
 };
@@ -128,21 +129,21 @@ static struct ovs_mutex mutex;
 static struct list all_lacps__ = LIST_INITIALIZER(&all_lacps__);
 static struct list *const all_lacps OVS_GUARDED_BY(mutex) = &all_lacps__;
 
-static void lacp_update_attached(struct lacp *) OVS_REQ_WRLOCK(mutex);
+static void lacp_update_attached(struct lacp *) OVS_REQUIRES(mutex);
 
-static void slave_destroy(struct slave *) OVS_REQ_WRLOCK(mutex);
-static void slave_set_defaulted(struct slave *) OVS_REQ_WRLOCK(mutex);
-static void slave_set_expired(struct slave *) OVS_REQ_WRLOCK(mutex);
+static void slave_destroy(struct slave *) OVS_REQUIRES(mutex);
+static void slave_set_defaulted(struct slave *) OVS_REQUIRES(mutex);
+static void slave_set_expired(struct slave *) OVS_REQUIRES(mutex);
 static void slave_get_actor(struct slave *, struct lacp_info *actor)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static void slave_get_priority(struct slave *, struct lacp_info *priority)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static bool slave_may_tx(const struct slave *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static struct slave *slave_lookup(const struct lacp *, const void *slave)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 static bool info_tx_equal(struct lacp_info *, struct lacp_info *)
-    OVS_REQ_WRLOCK(mutex);
+    OVS_REQUIRES(mutex);
 
 static unixctl_cb_func lacp_unixctl_show;
 
@@ -207,7 +208,7 @@ lacp_create(void) OVS_EXCLUDED(mutex)
     struct lacp *lacp;
 
     if (ovsthread_once_start(&once)) {
-        ovs_mutex_init(&mutex, PTHREAD_MUTEX_RECURSIVE);
+        ovs_mutex_init_recursive(&mutex);
         ovsthread_once_done(&once);
     }
 
@@ -283,6 +284,12 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s)
 
     lacp->active = s->active;
     lacp->fast = s->fast;
+
+    if (lacp->fallback_ab != s->fallback_ab_cfg) {
+        lacp->fallback_ab = s->fallback_ab_cfg;
+        lacp->update = true;
+    }
+
     ovs_mutex_unlock(&mutex);
 }
 
@@ -446,11 +453,13 @@ out:
 }
 
 static bool
-slave_may_enable__(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_may_enable__(struct slave *slave) OVS_REQUIRES(mutex)
 {
     /* The slave may be enabled if it's attached to an aggregator and its
      * partner is synchronized.*/
-    return slave->attached && (slave->partner.state & LACP_STATE_SYNC);
+    return slave->attached && (slave->partner.state & LACP_STATE_SYNC
+            || (slave->lacp && slave->lacp->fallback_ab
+                && slave->status == LACP_DEFAULTED));
 }
 
 /* This function should be called before enabling 'slave_' to send or receive
@@ -564,7 +573,7 @@ lacp_wait(struct lacp *lacp) OVS_EXCLUDED(mutex)
 /* Updates the attached status of all slaves controlled by 'lacp' and sets its
  * negotiated parameter to true if any slaves are attachable. */
 static void
-lacp_update_attached(struct lacp *lacp) OVS_REQ_WRLOCK(mutex)
+lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex)
 {
     struct slave *lead, *slave;
     struct lacp_info lead_pri;
@@ -587,6 +596,9 @@ lacp_update_attached(struct lacp *lacp) OVS_REQ_WRLOCK(mutex)
         }
 
         if (slave->status == LACP_DEFAULTED) {
+            if (lacp->fallback_ab) {
+                slave->attached = true;
+            }
             continue;
         }
 
@@ -603,7 +615,8 @@ lacp_update_attached(struct lacp *lacp) OVS_REQ_WRLOCK(mutex)
 
     if (lead) {
         HMAP_FOR_EACH (slave, node, &lacp->slaves) {
-            if (lead->partner.key != slave->partner.key
+            if ((lacp->fallback_ab && slave->status == LACP_DEFAULTED)
+                || lead->partner.key != slave->partner.key
                 || !eth_addr_equals(lead->partner.sys_id,
                                     slave->partner.sys_id)) {
                 slave->attached = false;
@@ -613,7 +626,7 @@ lacp_update_attached(struct lacp *lacp) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-slave_destroy(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_destroy(struct slave *slave) OVS_REQUIRES(mutex)
 {
     if (slave) {
         struct lacp *lacp = slave->lacp;
@@ -637,7 +650,7 @@ slave_destroy(struct slave *slave) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-slave_set_defaulted(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_set_defaulted(struct slave *slave) OVS_REQUIRES(mutex)
 {
     memset(&slave->partner, 0, sizeof slave->partner);
 
@@ -646,7 +659,7 @@ slave_set_defaulted(struct slave *slave) OVS_REQ_WRLOCK(mutex)
 }
 
 static void
-slave_set_expired(struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_set_expired(struct slave *slave) OVS_REQUIRES(mutex)
 {
     slave->status = LACP_EXPIRED;
     slave->partner.state |= LACP_STATE_TIME;
@@ -657,7 +670,7 @@ slave_set_expired(struct slave *slave) OVS_REQ_WRLOCK(mutex)
 
 static void
 slave_get_actor(struct slave *slave, struct lacp_info *actor)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     struct lacp *lacp = slave->lacp;
     uint16_t key;
@@ -710,7 +723,7 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor)
  * link. */
 static void
 slave_get_priority(struct slave *slave, struct lacp_info *priority)
-    OVS_REQ_WRLOCK(mutex)
+    OVS_REQUIRES(mutex)
 {
     uint16_t partner_priority, actor_priority;
 
@@ -735,13 +748,13 @@ slave_get_priority(struct slave *slave, struct lacp_info *priority)
 }
 
 static bool
-slave_may_tx(const struct slave *slave) OVS_REQ_WRLOCK(mutex)
+slave_may_tx(const struct slave *slave) OVS_REQUIRES(mutex)
 {
     return slave->lacp->active || slave->status != LACP_DEFAULTED;
 }
 
 static struct slave *
-slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQ_WRLOCK(mutex)
+slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQUIRES(mutex)
 {
     struct slave *slave;
 
@@ -778,7 +791,7 @@ info_tx_equal(struct lacp_info *a, struct lacp_info *b)
 }
 \f
 static struct lacp *
-lacp_find(const char *name) OVS_REQ_WRLOCK(&mutex)
+lacp_find(const char *name) OVS_REQUIRES(mutex)
 {
     struct lacp *lacp;
 
@@ -828,7 +841,7 @@ ds_put_lacp_state(struct ds *ds, uint8_t state)
 }
 
 static void
-lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQ_WRLOCK(&mutex)
+lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
 {
     struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
     const struct shash_node **sorted_slaves = NULL;