#include "ofpbuf.h"
#include "packets.h"
#include "poll-loop.h"
+#include "timer.h"
#include "timeval.h"
#include "unixctl.h"
#include "vlog.h"
struct slave *key_slave; /* Slave whose ID will be the aggregation key. */
bool fast; /* Fast or Slow LACP time. */
+ bool strict; /* True if in strict mode. */
bool negotiated; /* True if LACP negotiations were successful. */
bool update; /* True if lacp_update() needs to be called. */
};
enum slave_status status; /* Slave status. */
bool attached; /* Attached. Traffic may flow. */
- bool enabled; /* Enabled. Traffic is flowing. */
struct lacp_info partner; /* Partner information. */
struct lacp_info ntt_actor; /* Used to decide if we Need To Transmit. */
- long long int tx; /* Next message transmission time. */
- long long int rx; /* Expected message receive time. */
+ struct timer tx; /* Next message transmission timer. */
+ struct timer rx; /* Expected message receive timer. */
};
static struct list all_lacps = LIST_INITIALIZER(&all_lacps);
static void lacp_unixctl_show(struct unixctl_conn *, const char *args,
void *aux);
+/* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */
+void
+compose_lacp_pdu(const struct lacp_info *actor,
+ const struct lacp_info *partner, struct lacp_pdu *pdu)
+{
+ memset(pdu, 0, sizeof *pdu);
+
+ pdu->subtype = 1;
+ pdu->version = 1;
+
+ pdu->actor_type = 1;
+ pdu->actor_len = 20;
+ pdu->actor = *actor;
+
+ pdu->partner_type = 2;
+ pdu->partner_len = 20;
+ pdu->partner = *partner;
+
+ pdu->collector_type = 3;
+ pdu->collector_len = 16;
+ pdu->collector_delay = htons(0);
+}
+
+/* Parses 'b' which represents a packet containing a LACP PDU. This function
+ * returns NULL if 'b' is malformed, or does not represent a LACP PDU format
+ * supported by OVS. Otherwise, it returns a pointer to the lacp_pdu contained
+ * within 'b'. */
+const struct lacp_pdu *
+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);
+
+ if (pdu && pdu->subtype == 1
+ && pdu->actor_type == 1 && pdu->actor_len == 20
+ && pdu->partner_type == 2 && pdu->partner_len == 20) {
+ return pdu;
+ } else {
+ return NULL;
+ }
+}
+\f
+/* LACP Protocol Implementation. */
+
/* Initializes the lacp module. */
void
lacp_init(void)
}
}
-/* Configures 'lacp' with the given 'name', 'sys_id', 'sys_priority', and
- * 'active' parameters. */
+/* Configures 'lacp' with settings from 's'. */
void
-lacp_configure(struct lacp *lacp, const char *name,
- uint8_t sys_id[ETH_ADDR_LEN], uint16_t sys_priority,
- bool active, bool fast)
+lacp_configure(struct lacp *lacp, const struct lacp_settings *s)
{
- if (!lacp->name || strcmp(name, lacp->name)) {
+ if (!lacp->name || strcmp(s->name, lacp->name)) {
free(lacp->name);
- lacp->name = xstrdup(name);
+ lacp->name = xstrdup(s->name);
}
- memcpy(lacp->sys_id, sys_id, ETH_ADDR_LEN);
- lacp->sys_priority = sys_priority;
- lacp->active = active;
- lacp->fast = fast;
+ if (!eth_addr_equals(lacp->sys_id, s->id)
+ || lacp->sys_priority != s->priority
+ || lacp->strict != s->strict) {
+ memcpy(lacp->sys_id, s->id, ETH_ADDR_LEN);
+ lacp->sys_priority = s->priority;
+ lacp->strict = s->strict;
+ lacp->update = true;
+ }
+
+ lacp->active = s->active;
+ lacp->fast = s->fast;
+}
+
+/* Returns true if 'lacp' is configured in active mode, false if 'lacp' is
+ * configured for passive mode. */
+bool
+lacp_is_active(const struct lacp *lacp)
+{
+ return lacp->active;
}
/* Processes 'pdu', a parsed LACP packet received on 'slave_'. This function
struct slave *slave = slave_lookup(lacp, slave_);
slave->status = LACP_CURRENT;
- slave->rx = time_msec() + (lacp->fast
- ? LACP_FAST_TIME_RX
- : LACP_SLOW_TIME_RX);
+ timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER *
+ (lacp->fast ? LACP_FAST_TIME_TX : LACP_SLOW_TIME_TX));
slave->ntt_actor = pdu->partner;
/* Registers 'slave_' as subordinate to 'lacp'. This should be called at least
* once per slave in a LACP managed bond. Should also be called whenever a
- * slave's name, port_id, or port_priority change. */
+ * slave's settings change. */
void
-lacp_slave_register(struct lacp *lacp, void *slave_, const char *name,
- uint16_t port_id, uint16_t port_priority)
+lacp_slave_register(struct lacp *lacp, void *slave_,
+ const struct lacp_slave_settings *s)
{
struct slave *slave = slave_lookup(lacp, slave_);
}
}
- if (!slave->name || strcmp(name, slave->name)) {
+ if (!slave->name || strcmp(s->name, slave->name)) {
free(slave->name);
- slave->name = xstrdup(name);
+ slave->name = xstrdup(s->name);
}
- if (slave->port_id != port_id || slave->port_priority != port_priority) {
-
- slave->port_id = port_id;
- slave->port_priority = port_priority;
+ if (slave->port_id != s->id || slave->port_priority != s->priority) {
+ slave->port_id = s->id;
+ slave->port_priority = s->priority;
lacp->update = true;
if (slave) {
slave_destroy(slave);
+ lacp->update = true;
}
}
-/* Should be called regularly to indicate whether 'slave_' is enabled. An
- * enabled slave is allowed to send and receive traffic. Generally a slave
- * should not be enabled if its carrier is down, or lacp_slave_may_enable()
- * indicates it should not be enabled. */
-void
-lacp_slave_enable(struct lacp *lacp, void *slave_, bool enabled)
-{
- slave_lookup(lacp, slave_)->enabled = enabled;
-}
-
/* This function should be called whenever the carrier status of 'slave_' has
* changed. */
void
}
}
+/* Returns the port ID used for 'slave_' in LACP communications. */
+uint16_t
+lacp_slave_get_port_id(const struct lacp *lacp, const void *slave_)
+{
+ struct slave *slave = slave_lookup(lacp, slave_);
+ return slave->port_id;
+}
+
+/* Returns true if partner information on 'slave_' is up to date. 'slave_'
+ * not being current, generally indicates a connectivity problem, or a
+ * misconfigured (or broken) partner. */
+bool
+lacp_slave_is_current(const struct lacp *lacp, const void *slave_)
+{
+ return slave_lookup(lacp, slave_)->status == LACP_CURRENT;
+}
+
/* This function should be called periodically to update 'lacp'. */
void
lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu)
struct slave *slave;
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
- if (time_msec() >= slave->rx) {
+ if (timer_expired(&slave->rx)) {
if (slave->status == LACP_CURRENT) {
slave_set_expired(slave);
} else if (slave->status == LACP_EXPIRED) {
slave_get_actor(slave, &actor);
- if (time_msec() >= slave->tx
+ if (timer_expired(&slave->tx)
|| !info_tx_equal(&actor, &slave->ntt_actor)) {
slave->ntt_actor = actor;
compose_lacp_pdu(&actor, &slave->partner, &pdu);
send_pdu(slave->aux, &pdu);
- slave->tx = time_msec() +
- (slave->partner.state & LACP_STATE_TIME
- ? LACP_FAST_TIME_TX
- : LACP_SLOW_TIME_TX);
+ timer_set_duration(&slave->tx,
+ (slave->partner.state & LACP_STATE_TIME
+ ? LACP_FAST_TIME_TX
+ : LACP_SLOW_TIME_TX));
}
}
}
HMAP_FOR_EACH (slave, node, &lacp->slaves) {
if (slave_may_tx(slave)) {
- poll_timer_wait_until(slave->tx);
+ timer_wait(&slave->tx);
}
if (slave->status != LACP_DEFAULTED) {
- poll_timer_wait_until(slave->rx);
+ timer_wait(&slave->rx);
}
}
}
\f
/* Static Helpers. */
-/* Updates the attached status of all slaves controlled b 'lacp' and sets its
+/* 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)
slave->attached = false;
}
}
+ } else if (lacp->strict) {
+ HMAP_FOR_EACH (slave, node, &lacp->slaves) {
+ slave->attached = false;
+ }
}
}
slave->status = LACP_EXPIRED;
slave->partner.state |= LACP_STATE_TIME;
slave->partner.state &= ~LACP_STATE_SYNC;
-
- slave->rx = time_msec() + LACP_FAST_TIME_RX;
+ timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX);
}
static void
state |= LACP_STATE_AGG;
}
- if (slave->enabled) {
+ if (slave->attached || !slave->lacp->negotiated) {
state |= LACP_STATE_COL | LACP_STATE_DIST;
}
}
ds_put_format(&ds, "lacp: %s\n", lacp->name);
- ds_put_format(&ds, "\tstatus: %s %s\n",
- lacp->active ? "active" : "passive",
- lacp->negotiated ? "negotiated" : "");
+
+ ds_put_format(&ds, "\tstatus: %s", lacp->active ? "active" : "passive");
+ if (lacp->strict) {
+ ds_put_cstr(&ds, " strict");
+ }
+ if (lacp->negotiated) {
+ ds_put_cstr(&ds, " negotiated");
+ }
+ ds_put_cstr(&ds, "\n");
+
ds_put_format(&ds, "\tsys_id: " ETH_ADDR_FMT "\n", ETH_ADDR_ARGS(lacp->sys_id));
ds_put_format(&ds, "\tsys_priority: %u\n", lacp->sys_priority);
ds_put_cstr(&ds, "\taggregation key: ");
NOT_REACHED();
}
- ds_put_format(&ds, "\nslave: %s: %s %s %s\n", slave->name, status,
- slave->attached ? "attached" : "detached",
- slave->enabled ? "enabled" : "disabled");
+ ds_put_format(&ds, "\nslave: %s: %s %s\n", slave->name, status,
+ slave->attached ? "attached" : "detached");
ds_put_format(&ds, "\tport_id: %u\n", slave->port_id);
ds_put_format(&ds, "\tport_priority: %u\n", slave->port_priority);