-/* Copyright (c) 2011, 2012, 2013 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"
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 {
{
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_get_l3(b) - (uint8_t *)b->data,
+ LACP_PDU_LEN);
if (pdu && pdu->subtype == 1
&& pdu->actor_type == 1 && pdu->actor_len == 20
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);
{
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;
}
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);
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);
}
{
/* 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
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());
+ }
}
}
: LACP_SLOW_TIME_TX);
timer_set_duration(&slave->tx, duration);
+ seq_change(connectivity_seq_get());
}
}
ovs_mutex_unlock(&mutex);
}
if (slave->status == LACP_DEFAULTED) {
+ if (lacp->fallback_ab) {
+ slave->attached = true;
+ }
continue;
}
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;
status = "defaulted";
break;
default:
- NOT_REACHED();
+ OVS_NOT_REACHED();
}
ds_put_format(ds, "\nslave: %s: %s %s\n", slave->name, status,