lacp: Remove LACP_[FAST|SLOW]_TIME_RX macros.
[sliver-openvswitch.git] / lib / lacp.c
index ee79677..38ce595 100644 (file)
@@ -49,6 +49,7 @@ struct lacp {
     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. */
 };
@@ -86,6 +87,51 @@ static bool info_tx_equal(struct lacp_info *, struct lacp_info *);
 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)
@@ -132,8 +178,15 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s)
         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;
 }
@@ -156,9 +209,8 @@ lacp_process_pdu(struct lacp *lacp, const void *slave_,
     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;
 
@@ -225,6 +277,7 @@ lacp_slave_unregister(struct lacp *lacp, const void *slave_)
 
     if (slave) {
         slave_destroy(slave);
+        lacp->update = true;
     }
 }
 
@@ -269,6 +322,15 @@ lacp_slave_get_port_id(const struct lacp *lacp, const void *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)
@@ -333,7 +395,7 @@ lacp_wait(struct lacp *lacp)
 \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)
@@ -382,6 +444,10 @@ lacp_update_attached(struct lacp *lacp)
                 slave->attached = false;
             }
         }
+    } else if (lacp->strict) {
+        HMAP_FOR_EACH (slave, node, &lacp->slaves) {
+            slave->attached = false;
+        }
     }
 }
 
@@ -424,7 +490,7 @@ slave_set_expired(struct slave *slave)
     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
@@ -605,9 +671,16 @@ lacp_unixctl_show(struct unixctl_conn *conn,
     }
 
     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: ");