revalidator: Fix ukey stats cache updating.
[sliver-openvswitch.git] / lib / lacp.c
index de0b663..4aee64f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 #include <stdlib.h>
 
+#include "connectivity.h"
 #include "dynamic-string.h"
 #include "hash.h"
 #include "hmap.h"
 #include "ofpbuf.h"
 #include "packets.h"
 #include "poll-loop.h"
+#include "seq.h"
 #include "shash.h"
 #include "timer.h"
 #include "timeval.h"
@@ -102,8 +104,9 @@ 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;
+    struct ovs_refcount ref_cnt;
 };
 
 struct slave {
@@ -128,21 +131,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;
 
@@ -178,7 +181,8 @@ parse_lacp_packet(const struct ofpbuf *b)
 {
     const struct lacp_pdu *pdu;
 
-    pdu = ofpbuf_at(b, (uint8_t *)b->l3 - (uint8_t *)b->data, LACP_PDU_LEN);
+    pdu = ofpbuf_at(b, (uint8_t *)ofpbuf_l3(b) - (uint8_t *)ofpbuf_data(b),
+                    LACP_PDU_LEN);
 
     if (pdu && pdu->subtype == 1
         && pdu->actor_type == 1 && pdu->actor_len == 20
@@ -207,13 +211,13 @@ 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);
     }
 
     lacp = xzalloc(sizeof *lacp);
     hmap_init(&lacp->slaves);
-    atomic_init(&lacp->ref_cnt, 1);
+    ovs_refcount_init(&lacp->ref_cnt);
 
     ovs_mutex_lock(&mutex);
     list_push_back(all_lacps, &lacp->node);
@@ -226,9 +230,7 @@ lacp_ref(const struct lacp *lacp_)
 {
     struct lacp *lacp = CONST_CAST(struct lacp *, lacp_);
     if (lacp) {
-        int orig;
-        atomic_add(&lacp->ref_cnt, 1, &orig);
-        ovs_assert(orig > 0);
+        ovs_refcount_ref(&lacp->ref_cnt);
     }
     return lacp;
 }
@@ -237,15 +239,7 @@ lacp_ref(const struct lacp *lacp_)
 void
 lacp_unref(struct lacp *lacp) OVS_EXCLUDED(mutex)
 {
-    int orig;
-
-    if (!lacp) {
-        return;
-    }
-
-    atomic_sub(&lacp->ref_cnt, 1, &orig);
-    ovs_assert(orig > 0);
-    if (orig == 1) {
+    if (lacp && ovs_refcount_unref(&lacp->ref_cnt) == 1) {
         struct slave *slave, *next;
 
         ovs_mutex_lock(&mutex);
@@ -283,6 +277,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 +446,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
@@ -500,11 +502,16 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
     ovs_mutex_lock(&mutex);
     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
         if (timer_expired(&slave->rx)) {
+            enum slave_status old_status = slave->status;
+
             if (slave->status == LACP_CURRENT) {
                 slave_set_expired(slave);
             } else if (slave->status == LACP_EXPIRED) {
                 slave_set_defaulted(slave);
             }
+            if (slave->status != old_status) {
+                seq_change(connectivity_seq_get());
+            }
         }
     }
 
@@ -535,6 +542,7 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
                         : LACP_SLOW_TIME_TX);
 
             timer_set_duration(&slave->tx, duration);
+            seq_change(connectivity_seq_get());
         }
     }
     ovs_mutex_unlock(&mutex);
@@ -564,7 +572,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 +595,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 +614,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 +625,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 +649,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 +658,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 +669,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 +722,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 +747,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 +790,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 +840,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;
@@ -884,7 +896,7 @@ lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQ_WRLOCK(&mutex)
             status = "defaulted";
             break;
         default:
-            NOT_REACHED();
+            OVS_NOT_REACHED();
         }
 
         ds_put_format(ds, "\nslave: %s: %s %s\n", slave->name, status,