#include "cfm.h"
#include "classifier.h"
#include "coverage.h"
+#include "daemon.h"
#include "dirs.h"
#include "dpif.h"
#include "dynamic-string.h"
COVERAGE_DEFINE(bridge_flush);
COVERAGE_DEFINE(bridge_process_flow);
+COVERAGE_DEFINE(bridge_process_cfm);
+COVERAGE_DEFINE(bridge_process_lacp);
COVERAGE_DEFINE(bridge_reconfigure);
-
-enum lacp_status {
- LACP_STATUS_CURRENT, /* Partner is up to date. */
- LACP_STATUS_EXPIRED, /* Partner is out of date. Attempt to re-sync. */
- LACP_STATUS_DEFAULTED /* Partner information is unknown. */
-};
+COVERAGE_DEFINE(bridge_lacp_update);
struct dst {
uint16_t vlan;
static void dst_set_add(struct dst_set *, const struct dst *);
static void dst_set_free(struct dst_set *);
+enum lacp_status {
+ LACP_CURRENT = 0x01, /* Current State. */
+ LACP_EXPIRED = 0x02, /* Expired State. */
+ LACP_DEFAULTED = 0x04, /* Partner is defaulted. */
+ LACP_ATTACHED = 0x08, /* Attached. Interface may be choosen for flows. */
+};
+
struct iface {
/* These members are always valid. */
struct port *port; /* Containing port. */
const struct ovsrec_interface *cfg;
/* LACP information. */
- enum lacp_status lacp_status; /* LACP state machine status. */
+ enum lacp_status lacp_status; /* LACP status. */
uint16_t lacp_priority; /* LACP port priority. */
struct lacp_info lacp_actor; /* LACP actor information. */
struct lacp_info lacp_partner; /* LACP partner information. */
long long int lacp_tx; /* Next LACP message transmission time. */
long long int lacp_rx; /* Next LACP message receive time. */
- bool lacp_attached; /* Attached to its aggregator? LACP allows
- this link to be chosen for flows. */
};
#define BOND_MASK 0xff
}
free(managers);
+
+ /* ovs-vswitchd has completed initialization, so allow the process that
+ * forked us to exit successfully. */
+ daemonize_complete();
}
static const char *
if (iface->enabled) {
return i;
} else if (iface->delay_expires < next_delay_expiration
- && (iface->lacp_attached
+ && (iface->lacp_status & LACP_ATTACHED
|| !(port->lacp & LACP_NEGOTIATED))) {
best_down_slave = i;
next_delay_expiration = iface->delay_expires;
* They are not required to have synchronized partners because they
* have no partners at all. However, they will only be attached if
* negotiations failed on all interfaces in the bond. */
- up = iface->lacp_attached
+ up = iface->lacp_status & LACP_ATTACHED
&& (iface->lacp_partner.state & LACP_STATE_SYNC
- || iface->lacp_status == LACP_STATUS_DEFAULTED);
+ || iface->lacp_status & LACP_DEFAULTED);
}
return;
}
- if (iface->lacp_status == LACP_STATUS_CURRENT) {
+ if (iface->lacp_status & LACP_CURRENT) {
iface_set_lacp_expired(iface);
}
struct ofpbuf *actions, tag_type *tags,
uint16_t *nf_output_iface, void *br_)
{
- struct iface *iface;
struct bridge *br = br_;
COVERAGE_INC(bridge_process_flow);
+ return process_flow(br, flow, packet, actions, tags, nf_output_iface);
+}
+
+static bool
+bridge_special_ofhook_cb(const struct flow *flow,
+ const struct ofpbuf *packet, void *br_)
+{
+ struct iface *iface;
+ struct bridge *br = br_;
iface = iface_from_dp_ifidx(br, flow->in_port);
if (cfm_should_process_flow(flow)) {
- if (packet && iface->cfm) {
+
+ if (iface && packet && iface->cfm) {
+ COVERAGE_INC(bridge_process_cfm);
cfm_process_heartbeat(iface->cfm, packet);
}
return false;
} else if (flow->dl_type == htons(ETH_TYPE_LACP)) {
- if (packet) {
+
+ if (iface && packet) {
+ COVERAGE_INC(bridge_process_lacp);
lacp_process_packet(packet, iface);
}
return false;
}
- return process_flow(br, flow, packet, actions, tags, nf_output_iface);
+ return true;
}
static void
static struct ofhooks bridge_ofhooks = {
bridge_normal_ofhook_cb,
+ bridge_special_ofhook_cb,
bridge_account_flow_ofhook_cb,
bridge_account_checkpoint_ofhook_cb,
};
return;
}
- iface->lacp_status = LACP_STATUS_CURRENT;
+ iface->lacp_status |= LACP_CURRENT;
+ iface->lacp_status &= ~(LACP_EXPIRED | LACP_DEFAULTED);
iface->lacp_rx = time_msec() + LACP_SLOW_TIME_RX;
iface->lacp_actor.state = iface_get_lacp_state(iface);
size_t i;
struct iface *lead;
struct lacp_info lead_pri;
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
port->lacp_need_update = false;
+ COVERAGE_INC(bridge_lacp_update);
if (!port->lacp) {
return;
}
+ VLOG_DBG_RL(&rl, "port %s: re-evaluating LACP link status", port->name);
+
lead = NULL;
for (i = 0; i < port->n_ifaces; i++) {
struct iface *iface = port->ifaces[i];
struct lacp_info pri;
- iface->lacp_attached = true;
+ iface->lacp_status |= LACP_ATTACHED;
ofproto_revalidate(port->bridge->ofproto, iface->tag);
/* Don't allow loopback interfaces to send traffic or lead. */
if (eth_addr_equals(iface->lacp_partner.sysid,
iface->lacp_actor.sysid)) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
VLOG_WARN_RL(&rl, "iface %s: Loopback detected. Interface is "
"connected to its own bridge", iface->name);
- iface->lacp_attached = false;
+ iface->lacp_status &= ~LACP_ATTACHED;
continue;
}
- if (iface->lacp_status == LACP_STATUS_DEFAULTED) {
+ if (iface->lacp_status & LACP_DEFAULTED) {
continue;
}
for (i = 0; i < port->n_ifaces; i++) {
struct iface *iface = port->ifaces[i];
- if (iface->lacp_status == LACP_STATUS_DEFAULTED
+ if (iface->lacp_status & LACP_DEFAULTED
|| lead->lacp_partner.key != iface->lacp_partner.key
|| !eth_addr_equals(lead->lacp_partner.sysid,
iface->lacp_partner.sysid)) {
- iface->lacp_attached = false;
+ iface->lacp_status &= ~LACP_ATTACHED;
}
}
}
lacp_iface_may_tx(const struct iface *iface)
{
return iface->port->lacp & LACP_ACTIVE
- || iface->lacp_status != LACP_STATUS_DEFAULTED;
+ || iface->lacp_status & (LACP_CURRENT | LACP_EXPIRED);
}
static void
struct iface *iface = port->ifaces[j];
if (time_msec() > iface->lacp_rx) {
- if (iface->lacp_status == LACP_STATUS_CURRENT) {
+ if (iface->lacp_status & LACP_CURRENT) {
iface_set_lacp_expired(iface);
- } else if (iface->lacp_status == LACP_STATUS_EXPIRED) {
+ } else if (iface->lacp_status & LACP_EXPIRED) {
iface_set_lacp_defaulted(iface);
}
}
poll_timer_wait_until(iface->lacp_tx);
}
- if (iface->lacp_status != LACP_STATUS_DEFAULTED) {
+ if (iface->lacp_status & (LACP_CURRENT | LACP_EXPIRED)) {
poll_timer_wait_until(iface->lacp_rx);
}
}
bond_mode_to_string(port->bond_mode));
if (port->lacp) {
- ds_put_format(&ds, "\tlacp: %s\n",
+ ds_put_format(&ds, "lacp: %s\n",
port->lacp & LACP_ACTIVE ? "active" : "passive");
} else {
- ds_put_cstr(&ds, "\tlacp: off\n");
+ ds_put_cstr(&ds, "lacp: off\n");
}
if (port->bond_mode != BM_AB) {
struct flow flow;
/* Basic info. */
- ds_put_format(&ds, "slave %s: %s\n",
+ ds_put_format(&ds, "\nslave %s: %s\n",
iface->name, iface->enabled ? "enabled" : "disabled");
if (j == port->active_iface) {
ds_put_cstr(&ds, "\tactive slave\n");
if (port->lacp) {
ds_put_cstr(&ds, "\tstatus: ");
- if (iface->lacp_status == LACP_STATUS_CURRENT) {
+ if (iface->lacp_status & LACP_CURRENT) {
ds_put_cstr(&ds, "current ");
- } else if (iface->lacp_status == LACP_STATUS_EXPIRED) {
+ }
+
+ if (iface->lacp_status & LACP_EXPIRED) {
ds_put_cstr(&ds, "expired ");
- } else {
+ }
+
+ if (iface->lacp_status & LACP_DEFAULTED) {
ds_put_cstr(&ds, "defaulted ");
}
- if (iface->lacp_attached) {
+ if (iface->lacp_status & LACP_ATTACHED) {
ds_put_cstr(&ds, "attached ");
}
ds_put_cstr(&ds, "\tpartner state: ");
ds_put_lacp_state(&ds, iface->lacp_partner.state);
- ds_put_cstr(&ds, "\n\n");
+ ds_put_cstr(&ds, "\n");
}
if (port->bond_mode == BM_AB) {
bool key_changed;
if (!port->lacp || port->n_ifaces < 1) {
+ for (i = 0; i < port->n_ifaces; i++) {
+ iface_set_lacp_defaulted(port->ifaces[i]);
+ }
return;
}
static void
iface_set_lacp_defaulted(struct iface *iface)
{
- memset(&iface->lacp_partner, 0xff, sizeof iface->lacp_partner);
- iface->lacp_partner.state = 0;
+ memset(&iface->lacp_partner, 0, sizeof iface->lacp_partner);
- iface->lacp_status = LACP_STATUS_DEFAULTED;
+ iface->lacp_status |= LACP_DEFAULTED;
+ iface->lacp_status &= ~(LACP_CURRENT | LACP_EXPIRED);
iface->lacp_tx = 0;
iface->port->lacp_need_update = true;
}
static void
iface_set_lacp_expired(struct iface *iface)
{
- iface->lacp_status = LACP_STATUS_EXPIRED;
+ iface->lacp_status &= ~LACP_CURRENT;
+ iface->lacp_status |= LACP_EXPIRED;
iface->lacp_partner.state |= LACP_STATE_TIME;
iface->lacp_partner.state &= ~LACP_STATE_SYNC;
state |= LACP_STATE_ACT;
}
- if (iface->lacp_status == LACP_STATUS_DEFAULTED) {
- state |= LACP_STATE_DEF;
- } else if (iface->lacp_attached) {
+ if (iface->lacp_status & LACP_ATTACHED) {
state |= LACP_STATE_SYNC;
}
- if (iface->lacp_status == LACP_STATUS_EXPIRED) {
+ if (iface->lacp_status & LACP_DEFAULTED) {
+ state |= LACP_STATE_DEF;
+ }
+
+ if (iface->lacp_status & LACP_EXPIRED) {
state |= LACP_STATE_EXP;
}