lacp: Implement custom timing mode.
authorEthan Jackson <ethan@nicira.com>
Mon, 18 Apr 2011 19:22:12 +0000 (12:22 -0700)
committerEthan Jackson <ethan@nicira.com>
Tue, 19 Apr 2011 20:49:36 +0000 (13:49 -0700)
With this patch, the LACP module may be manually configured to use
an arbitrary transmission rate set in the database.

lib/lacp.c
lib/lacp.h
vswitchd/bridge.c
vswitchd/vswitch.xml

index 38ce595..a7f66a2 100644 (file)
@@ -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;
index dc2bede..3965692 100644 (file)
@@ -75,12 +75,19 @@ const struct lacp_pdu *parse_lacp_packet(const struct ofpbuf *);
 \f
 /* 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;
 };
 
index a87e2cc..f5918be 100644 (file)
@@ -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();
     }
index 6070a1c..4cdc1b1 100644 (file)
             with the numerically lower priority.  Must be a number between 1
             and 65535.</dd>
           <dt><code>lacp-time</code></dt>
-          <dd> The LACP timing which should be used on this
-            <ref table="Port"/>.  Possible values are <code>fast</code> and
-            <code>slow</code>.  By default <code>slow</code> is used.  When
-            configured to be <code>fast</code> more frequent LACP heartbeats
-            will be requested causing connectivity problems to be detected more
-            quickly.</dd>
+          <dd>
+            <p>The LACP timing which should be used on this
+              <ref table="Port"/>.  Possible values are <code>fast</code>,
+              <code>slow</code> and a positive number of milliseconds.  By
+              default <code>slow</code> is used.  When configured to be
+              <code>fast</code> LACP heartbeats are requested at a rate of once
+              per second causing connectivity problems to be detected more
+              quickly.  In <code>slow</code> mode, heartbeats are requested at
+              a rate of once every 30 seconds.</p>
+
+            <p>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 <code>lacp-time</code> to
+              something other than <code>fast</code> or <code>slow</code> is
+              not supported by the LACP specification.</p>
+          </dd>
           <dt><code>lacp-strict</code></dt>
           <dd> When <code>true</code>, configures this <ref table="Port"/> to
             require successful LACP negotiations to enable any slaves.