From cdcf42c664eeb6b260693fc182c1782669f7d39e Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Mon, 18 Apr 2011 12:22:12 -0700 Subject: [PATCH] lacp: Implement custom timing mode. With this patch, the LACP module may be manually configured to use an arbitrary transmission rate set in the database. --- lib/lacp.c | 64 +++++++++++++++++++++++++++++++++++++------- lib/lacp.h | 9 ++++++- vswitchd/bridge.c | 17 ++++++++++-- vswitchd/vswitch.xml | 23 +++++++++++----- 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/lib/lacp.c b/lib/lacp.c index 38ce595a..a7f66a24 100644 --- a/lib/lacp.c +++ b/lib/lacp.c @@ -48,7 +48,8 @@ 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. */ + enum lacp_time lacp_time; /* Fast, Slow or Custom LACP time. */ + long long int custom_time; /* LACP_TIME_CUSTOM transmission rate. */ 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. */ @@ -188,7 +189,8 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s) } 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,10 +209,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_RX_MULTIPLIER * - (lacp->fast ? LACP_FAST_TIME_TX : LACP_SLOW_TIME_TX)); + timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * tx_rate); slave->ntt_actor = pdu->partner; @@ -363,15 +378,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); } } } @@ -487,10 +508,18 @@ 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_RX_MULTIPLIER * LACP_FAST_TIME_TX); + + /* 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 @@ -502,7 +531,7 @@ slave_get_actor(struct slave *slave, struct lacp_info *actor) state |= LACP_STATE_ACT; } - if (slave->lacp->fast) { + if (slave->lacp->lacp_time != LACP_TIME_SLOW) { state |= LACP_STATE_TIME; } @@ -691,6 +720,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; diff --git a/lib/lacp.h b/lib/lacp.h index dc2bede4..39656920 100644 --- a/lib/lacp.h +++ b/lib/lacp.h @@ -75,12 +75,19 @@ const struct lacp_pdu *parse_lacp_packet(const struct ofpbuf *); /* LACP Protocol Implementation. */ +enum lacp_time { + LACP_TIME_FAST, + LACP_TIME_SLOW, + LACP_TIME_CUSTOM +}; + struct lacp_settings { char *name; uint8_t id[ETH_ADDR_LEN]; uint16_t priority; bool active; - bool fast; + enum lacp_time lacp_time; + long long int custom_time; bool strict; }; diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index a87e2cc6..f5918be0 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -3126,6 +3126,8 @@ port_reconfigure_lacp(struct port *port) struct iface *iface; uint8_t sysid[ETH_ADDR_LEN]; const char *sysid_str; + const char *lacp_time; + long long int custom_time; int priority; if (!enable_lacp(port, &s.active)) { @@ -3150,12 +3152,23 @@ port_reconfigure_lacp(struct port *port) ? priority : UINT16_MAX - !list_is_short(&port->ifaces)); - s.fast = !strcmp(get_port_other_config(port->cfg, "lacp-time", "slow"), - "fast"); s.strict = !strcmp(get_port_other_config(port->cfg, "lacp-strict", "false"), "true"); + lacp_time = get_port_other_config(port->cfg, "lacp-time", "slow"); + custom_time = atoi(lacp_time); + if (!strcmp(lacp_time, "fast")) { + s.lacp_time = LACP_TIME_FAST; + } else if (!strcmp(lacp_time, "slow")) { + s.lacp_time = LACP_TIME_SLOW; + } else if (custom_time > 0) { + s.lacp_time = LACP_TIME_CUSTOM; + s.custom_time = custom_time; + } else { + s.lacp_time = LACP_TIME_SLOW; + } + if (!port->lacp) { port->lacp = lacp_create(); } diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 6070a1cd..4cdc1b1c 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -657,12 +657,23 @@ with the numerically lower priority. Must be a number between 1 and 65535.
lacp-time
-
The LACP timing which should be used on this - . Possible values are fast and - slow. By default slow is used. When - configured to be fast more frequent LACP heartbeats - will be requested causing connectivity problems to be detected more - quickly.
+
+

The LACP timing which should be used on this + . Possible values are fast, + slow and a positive number of milliseconds. By + default slow is used. When configured to be + fast LACP heartbeats are requested at a rate of once + per second causing connectivity problems to be detected more + quickly. In slow mode, heartbeats are requested at + a rate of once every 30 seconds.

+ +

Users may manually set a heartbeat transmission rate to increase + the fault detection speed further. When manually set, OVS + expects the partner switch to be configured with the same + transmission rate. Manually setting lacp-time to + something other than fast or slow is + not supported by the LACP specification.

+
lacp-strict
When true, configures this to require successful LACP negotiations to enable any slaves. -- 2.30.2