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. */
};
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)
lacp->name = xstrdup(s->name);
}
- memcpy(lacp->sys_id, s->id, ETH_ADDR_LEN);
- lacp->sys_priority = s->priority;
+ 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;
}
struct slave *slave = slave_lookup(lacp, slave_);
slave->status = LACP_CURRENT;
- timer_set_duration(&slave->rx, (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;
if (slave) {
slave_destroy(slave);
+ lacp->update = true;
}
}
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)
\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;
- timer_set_duration(&slave->rx, LACP_FAST_TIME_RX);
+ timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX);
}
static void
}
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: ");