unixctl: New JSON RPC back-end.
[sliver-openvswitch.git] / lib / lacp.c
index 5303053..f7d5a82 100644 (file)
@@ -25,6 +25,7 @@
 #include "ofpbuf.h"
 #include "packets.h"
 #include "poll-loop.h"
+#include "shash.h"
 #include "timer.h"
 #include "timeval.h"
 #include "unixctl.h"
@@ -135,8 +136,7 @@ static bool slave_may_tx(const struct slave *);
 static struct slave *slave_lookup(const struct lacp *, const void *slave);
 static bool info_tx_equal(struct lacp_info *, struct lacp_info *);
 
-static void lacp_unixctl_show(struct unixctl_conn *, const char *args,
-                              void *aux);
+static unixctl_cb_func lacp_unixctl_show;
 
 /* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */
 static void
@@ -187,7 +187,8 @@ parse_lacp_packet(const struct ofpbuf *b)
 void
 lacp_init(void)
 {
-    unixctl_command_register("lacp/show", "[port]", lacp_unixctl_show, NULL);
+    unixctl_command_register("lacp/show", "[port]", 0, 1,
+                             lacp_unixctl_show, NULL);
 }
 
 /* Creates a LACP object. */
@@ -242,7 +243,9 @@ lacp_configure(struct lacp *lacp, const struct lacp_settings *s)
 
     lacp->active = s->active;
     lacp->lacp_time = s->lacp_time;
-    lacp->custom_time = MAX(TIME_UPDATE_INTERVAL, s->custom_time);
+    lacp->custom_time = (s->lacp_time == LACP_TIME_CUSTOM
+                         ? MAX(TIME_UPDATE_INTERVAL, s->custom_time)
+                         : 0);
 }
 
 /* Returns true if 'lacp' is configured in active mode, false if 'lacp' is
@@ -298,12 +301,17 @@ lacp_process_packet(struct lacp *lacp, const void *slave_,
     }
 }
 
-/* Returns true if 'lacp' has successfully negotiated with its partner.  False
- * if 'lacp' is NULL. */
-bool
-lacp_negotiated(const struct lacp *lacp)
+/* Returns the lacp_status of the given 'lacp' object (which may be NULL). */
+enum lacp_status
+lacp_status(const struct lacp *lacp)
 {
-    return lacp ? lacp->negotiated : false;
+    if (!lacp) {
+        return LACP_DISABLED;
+    } else if (lacp->negotiated) {
+        return LACP_NEGOTIATED;
+    } else {
+        return LACP_CONFIGURED;
+    }
 }
 
 /* Registers 'slave_' as subordinate to 'lacp'.  This should be called at least
@@ -381,12 +389,8 @@ lacp_slave_may_enable(const struct lacp *lacp, const void *slave_)
         struct slave *slave = slave_lookup(lacp, slave_);
 
         /* The slave may be enabled if it's attached to an aggregator and its
-         * partner is synchronized.  The only exception is defaulted slaves.
-         * They are not required to have synchronized partners because they
-         * have no partners at all.  They will only be attached if negotiations
-         * failed on all slaves in the bond. */
-        return slave->attached && (slave->partner.state & LACP_STATE_SYNC
-                                   || slave->status == LACP_DEFAULTED);
+         * partner is synchronized.*/
+        return slave->attached && (slave->partner.state & LACP_STATE_SYNC);
     } else {
         return true;
     }
@@ -501,14 +505,13 @@ lacp_update_attached(struct lacp *lacp)
     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
         struct lacp_info pri;
 
-        slave->attached = true;
+        slave->attached = false;
 
         /* XXX: In the future allow users to configure the expected system ID.
          * For now just special case loopback. */
         if (eth_addr_equals(slave->partner.sys_id, slave->lacp->sys_id)) {
             VLOG_WARN_RL(&rl, "slave %s: Loopback detected. Slave is "
                          "connected to its own bond", slave->name);
-            slave->attached = false;
             continue;
         }
 
@@ -516,6 +519,7 @@ lacp_update_attached(struct lacp *lacp)
             continue;
         }
 
+        slave->attached = true;
         slave_get_priority(slave, &pri);
 
         if (!lead || memcmp(&pri, &lead_pri, sizeof pri) < 0) {
@@ -528,8 +532,7 @@ lacp_update_attached(struct lacp *lacp)
 
     if (lead) {
         HMAP_FOR_EACH (slave, node, &lacp->slaves) {
-            if (slave->status == LACP_DEFAULTED
-                || lead->partner.key != slave->partner.key
+            if (lead->partner.key != slave->partner.key
                 || !eth_addr_equals(lead->partner.sys_id,
                                     slave->partner.sys_id)) {
                 slave->attached = false;
@@ -761,7 +764,11 @@ ds_put_lacp_state(struct ds *ds, uint8_t state)
 static void
 lacp_print_details(struct ds *ds, struct lacp *lacp)
 {
+    struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
+    const struct shash_node **sorted_slaves = NULL;
+
     struct slave *slave;
+    int i;
 
     ds_put_format(ds, "---- %s ----\n", lacp->name);
     ds_put_format(ds, "\tstatus: %s", lacp->active ? "active" : "passive");
@@ -799,9 +806,15 @@ lacp_print_details(struct ds *ds, struct lacp *lacp)
     }
 
     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
+        shash_add(&slave_shash, slave->name, slave);
+    }
+    sorted_slaves = shash_sort(&slave_shash);
+
+    for (i = 0; i < shash_count(&slave_shash); i++) {
         char *status;
         struct lacp_info actor;
 
+        slave = sorted_slaves[i]->data;
         slave_get_actor(slave, &actor);
         switch (slave->status) {
         case LACP_CURRENT:
@@ -850,19 +863,22 @@ lacp_print_details(struct ds *ds, struct lacp *lacp)
         ds_put_lacp_state(ds, slave->partner.state);
         ds_put_cstr(ds, "\n");
     }
+
+    shash_destroy(&slave_shash);
+    free(sorted_slaves);
 }
 
 static void
-lacp_unixctl_show(struct unixctl_conn *conn,
-                  const char *args, void *aux OVS_UNUSED)
+lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
+                  void *aux OVS_UNUSED)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
     struct lacp *lacp;
 
-    if (strlen(args)) {
-        lacp = lacp_find(args);
+    if (argc > 1) {
+        lacp = lacp_find(argv[1]);
         if (!lacp) {
-            unixctl_command_reply(conn, 501, "no such lacp object");
+            unixctl_command_reply_error(conn, "no such lacp object");
             return;
         }
         lacp_print_details(&ds, lacp);
@@ -872,6 +888,6 @@ lacp_unixctl_show(struct unixctl_conn *conn,
         }
     }
 
-    unixctl_command_reply(conn, 200, ds_cstr(&ds));
+    unixctl_command_reply(conn, ds_cstr(&ds));
     ds_destroy(&ds);
 }