X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Flacp.c;h=eaf01c3c909c62bae294d14c976636f7f3022239;hb=3e42dfdc39de77a408afc4f812e01d9be5ceda66;hp=7a7ca6efeb6ff269e9e4f0ef487c46179eb352df;hpb=81aee5f901556e778069a70613d99a87ddcf2116;p=sliver-openvswitch.git diff --git a/lib/lacp.c b/lib/lacp.c index 7a7ca6efe..eaf01c3c9 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -48,10 +48,11 @@ struct lacp { struct hmap slaves; /* Slaves this LACP object controls. */ 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. */ + enum lacp_time lacp_time; /* Fast, Slow or Custom LACP time. */ + long long int custom_time; /* LACP_TIME_CUSTOM transmission rate. */ bool negotiated; /* True if LACP negotiations were successful. */ bool update; /* True if lacp_update() needs to be called. */ + bool heartbeat; /* LACP heartbeat mode. */ }; struct slave { @@ -61,6 +62,7 @@ struct slave { struct lacp *lacp; /* LACP object containing this slave. */ uint16_t port_id; /* Port ID. */ uint16_t port_priority; /* Port Priority. */ + uint16_t key; /* Aggregation Key. 0 if default. */ char *name; /* Name of this slave. */ enum slave_status status; /* Slave status. */ @@ -180,15 +182,16 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s) if (!eth_addr_equals(lacp->sys_id, s->id) || lacp->sys_priority != s->priority - || lacp->strict != s->strict) { + || lacp->heartbeat != s->heartbeat) { memcpy(lacp->sys_id, s->id, ETH_ADDR_LEN); lacp->sys_priority = s->priority; - lacp->strict = s->strict; + lacp->heartbeat = s->heartbeat; lacp->update = true; } lacp->active = s->active; - lacp->fast = s->fast; + lacp->lacp_time = s->lacp_time; + lacp->custom_time = MAX(TIME_UPDATE_INTERVAL, s->custom_time); } /* Returns true if 'lacp' is configured in active mode, false if 'lacp' is @@ -207,11 +210,23 @@ lacp_process_pdu(struct lacp *lacp, const void *slave_, const struct lacp_pdu *pdu) { struct slave *slave = slave_lookup(lacp, slave_); + long long int tx_rate; + + switch (lacp->lacp_time) { + case LACP_TIME_FAST: + tx_rate = LACP_FAST_TIME_TX; + break; + case LACP_TIME_SLOW: + tx_rate = LACP_SLOW_TIME_TX; + break; + case LACP_TIME_CUSTOM: + tx_rate = lacp->custom_time; + break; + default: NOT_REACHED(); + } 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 * tx_rate); slave->ntt_actor = pdu->partner; @@ -258,9 +273,12 @@ lacp_slave_register(struct lacp *lacp, void *slave_, slave->name = xstrdup(s->name); } - if (slave->port_id != s->id || slave->port_priority != s->priority) { + if (slave->port_id != s->id + || slave->port_priority != s->priority + || slave->key != s->key) { slave->port_id = s->id; slave->port_priority = s->priority; + slave->key = s->key; lacp->update = true; @@ -329,7 +347,7 @@ lacp_slave_get_port_id(const struct lacp *lacp, const void *slave_) bool lacp_slave_is_current(const struct lacp *lacp, const void *slave_) { - return slave_lookup(lacp, slave_)->status == LACP_CURRENT; + return slave_lookup(lacp, slave_)->status != LACP_DEFAULTED; } /* This function should be called periodically to update 'lacp'. */ @@ -364,15 +382,21 @@ lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) if (timer_expired(&slave->tx) || !info_tx_equal(&actor, &slave->ntt_actor)) { + long long int duration; slave->ntt_actor = actor; compose_lacp_pdu(&actor, &slave->partner, &pdu); send_pdu(slave->aux, &pdu); - timer_set_duration(&slave->tx, - (slave->partner.state & LACP_STATE_TIME - ? LACP_FAST_TIME_TX - : LACP_SLOW_TIME_TX)); + if (lacp->lacp_time == LACP_TIME_CUSTOM) { + duration = lacp->custom_time; + } else { + duration = (slave->partner.state & LACP_STATE_TIME + ? LACP_FAST_TIME_TX + : LACP_SLOW_TIME_TX); + } + + timer_set_duration(&slave->tx, duration); } } } @@ -405,6 +429,13 @@ lacp_update_attached(struct lacp *lacp) struct lacp_info lead_pri; static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10); + if (lacp->heartbeat) { + HMAP_FOR_EACH (slave, node, &lacp->slaves) { + slave->attached = slave->status != LACP_DEFAULTED; + } + return; + } + lacp->update = false; lead = NULL; @@ -445,10 +476,6 @@ lacp_update_attached(struct lacp *lacp) slave->attached = false; } } - } else if (lacp->strict) { - HMAP_FOR_EACH (slave, node, &lacp->slaves) { - slave->attached = false; - } } } @@ -488,22 +515,32 @@ slave_set_defaulted(struct slave *slave) static void slave_set_expired(struct slave *slave) { + struct lacp *lacp = slave->lacp; + 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); + + /* The spec says we should wait LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX. + * This doesn't make sense when using custom times which can be much + * smaller than LACP_FAST_TIME. */ + timer_set_duration(&slave->rx, (lacp->lacp_time == LACP_TIME_CUSTOM + ? lacp->custom_time + : LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX)); } static void slave_get_actor(struct slave *slave, struct lacp_info *actor) { + struct lacp *lacp = slave->lacp; + uint16_t key; uint8_t state = 0; - if (slave->lacp->active) { + if (lacp->active) { state |= LACP_STATE_ACT; } - if (slave->lacp->fast) { + if (lacp->lacp_time != LACP_TIME_SLOW) { state |= LACP_STATE_TIME; } @@ -519,20 +556,25 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor) state |= LACP_STATE_EXP; } - if (hmap_count(&slave->lacp->slaves) > 1) { + if (lacp->heartbeat || hmap_count(&lacp->slaves) > 1) { state |= LACP_STATE_AGG; } - if (slave->attached || !slave->lacp->negotiated) { + if (slave->attached || !lacp->negotiated) { state |= LACP_STATE_COL | LACP_STATE_DIST; } + key = lacp->key_slave->key; + if (!key) { + key = lacp->key_slave->port_id; + } + actor->state = state; - actor->key = htons(slave->lacp->key_slave->port_id); + actor->key = htons(key); actor->port_priority = htons(slave->port_priority); actor->port_id = htons(slave->port_id); - actor->sys_priority = htons(slave->lacp->sys_priority); - memcpy(&actor->sys_id, slave->lacp->sys_id, ETH_ADDR_LEN); + actor->sys_priority = htons(lacp->sys_priority); + memcpy(&actor->sys_id, lacp->sys_id, ETH_ADDR_LEN); } /* Given 'slave', populates 'priority' with data representing its LACP link @@ -674,8 +716,8 @@ lacp_unixctl_show(struct unixctl_conn *conn, ds_put_format(&ds, "lacp: %s\n", lacp->name); ds_put_format(&ds, "\tstatus: %s", lacp->active ? "active" : "passive"); - if (lacp->strict) { - ds_put_cstr(&ds, " strict"); + if (lacp->heartbeat) { + ds_put_cstr(&ds, " heartbeat"); } if (lacp->negotiated) { ds_put_cstr(&ds, " negotiated"); @@ -692,6 +734,21 @@ lacp_unixctl_show(struct unixctl_conn *conn, } ds_put_cstr(&ds, "\n"); + ds_put_cstr(&ds, "\tlacp_time: "); + switch (lacp->lacp_time) { + case LACP_TIME_FAST: + ds_put_cstr(&ds, "fast\n"); + break; + case LACP_TIME_SLOW: + ds_put_cstr(&ds, "slow\n"); + break; + case LACP_TIME_CUSTOM: + ds_put_format(&ds, "custom (%lld)\n", lacp->custom_time); + break; + default: + ds_put_cstr(&ds, "unknown\n"); + } + HMAP_FOR_EACH (slave, node, &lacp->slaves) { char *status; struct lacp_info actor;