Merge branch 'mainstream'
[sliver-openvswitch.git] / lib / bond.c
index 06dd362..dc0d76b 100644 (file)
@@ -99,6 +99,7 @@ struct bond {
 
     /* Legacy compatibility. */
     long long int next_fake_iface_update; /* LLONG_MAX if disabled. */
+    bool lacp_fallback_ab; /* Fallback to active-backup on LACP failure. */
 
     atomic_int ref_cnt;
 };
@@ -258,6 +259,11 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s)
     bond->updelay = s->up_delay;
     bond->downdelay = s->down_delay;
 
+    if (bond->lacp_fallback_ab != s->lacp_fallback_ab_cfg) {
+        bond->lacp_fallback_ab = s->lacp_fallback_ab_cfg;
+        revalidate = true;
+    }
+
     if (bond->rebalance_interval != s->rebalance_interval) {
         bond->rebalance_interval = s->rebalance_interval;
         revalidate = true;
@@ -475,7 +481,7 @@ bond_wait(struct bond *bond)
         poll_timer_wait_until(bond->next_fake_iface_update);
     }
 
-    if (!bond->bond_revalidate) {
+    if (bond->bond_revalidate) {
         poll_immediate_wake();
     }
     ovs_rwlock_unlock(&rwlock);
@@ -491,8 +497,9 @@ bond_wait(struct bond *bond)
 static bool
 may_send_learning_packets(const struct bond *bond)
 {
-    return bond->lacp_status == LACP_DISABLED
-        && (bond->balance == BM_SLB || bond->balance == BM_AB)
+    return ((bond->lacp_status == LACP_DISABLED
+        && (bond->balance == BM_SLB || bond->balance == BM_AB))
+        || (bond->lacp_fallback_ab && bond->lacp_status == LACP_CONFIGURED))
         && bond->active_slave;
 }
 
@@ -585,13 +592,15 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
      * packets to them.
      *
      * If LACP is configured, but LACP negotiations have been unsuccessful, we
-     * drop all incoming traffic. */
+     * drop all incoming traffic except if lacp_fallback_ab is enabled. */
     switch (bond->lacp_status) {
     case LACP_NEGOTIATED:
         verdict = slave->enabled ? BV_ACCEPT : BV_DROP;
         goto out;
     case LACP_CONFIGURED:
-        goto out;
+        if (!bond->lacp_fallback_ab) {
+            goto out;
+        }
     case LACP_DISABLED:
         break;
     }
@@ -604,6 +613,15 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
     }
 
     switch (bond->balance) {
+    case BM_TCP:
+        /* TCP balanced bonds require successful LACP negotiations. Based on the
+         * above check, LACP is off or lacp_fallback_ab is true on this bond.
+         * If lacp_fallback_ab is true fall through to BM_AB case else, we
+         * drop all incoming traffic. */
+        if (!bond->lacp_fallback_ab) {
+            goto out;
+        }
+
     case BM_AB:
         /* Drop all packets which arrive on backup slaves.  This is similar to
          * how Linux bonding handles active-backup bonds. */
@@ -618,12 +636,6 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
         verdict = BV_ACCEPT;
         goto out;
 
-    case BM_TCP:
-        /* TCP balanced bonds require successful LACP negotiated. Based on the
-         * above check, LACP is off on this bond.  Therfore, we drop all
-         * incoming traffic. */
-        goto out;
-
     case BM_SLB:
         /* Drop all packets for which we have learned a different input port,
          * because we probably sent the packet on one slave and got it back on
@@ -661,11 +673,14 @@ bond_choose_output_slave(struct bond *bond, const struct flow *flow,
                          struct flow_wildcards *wc, uint16_t vlan)
 {
     struct bond_slave *slave;
+    void *aux;
 
     ovs_rwlock_rdlock(&rwlock);
     slave = choose_output_slave(bond, flow, wc, vlan);
+    aux = slave ? slave->aux : NULL;
     ovs_rwlock_unlock(&rwlock);
-    return slave;
+
+    return aux;
 }
 \f
 /* Rebalancing. */
@@ -720,7 +735,7 @@ log_bals(struct bond *bond, const struct list *bals)
                     if (&e->list_node != list_front(&slave->entries)) {
                         ds_put_cstr(&ds, " + ");
                     }
-                    ds_put_format(&ds, "h%td: %"PRIu64"kB",
+                    ds_put_format(&ds, "h%"PRIdPTR": %"PRIu64"kB",
                                   e - bond->hash, e->tx_bytes / 1024);
                 }
                 ds_put_cstr(&ds, ")");
@@ -739,7 +754,7 @@ bond_shift_load(struct bond_entry *hash, struct bond_slave *to)
     struct bond *bond = from->bond;
     uint64_t delta = hash->tx_bytes;
 
-    VLOG_INFO("bond %s: shift %"PRIu64"kB of load (with hash %td) "
+    VLOG_INFO("bond %s: shift %"PRIu64"kB of load (with hash %"PRIdPTR") "
               "from %s to %s (now carrying %"PRIu64"kB and "
               "%"PRIu64"kB load, respectively)",
               bond->name, delta / 1024, hash - bond->hash,
@@ -752,6 +767,7 @@ bond_shift_load(struct bond_entry *hash, struct bond_slave *to)
     to->tx_bytes += delta;
 
     /* Arrange for flows to be revalidated. */
+    hash->slave = to;
     bond->bond_revalidate = true;
 }
 
@@ -1245,7 +1261,7 @@ bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[],
     uint32_t basis;
 
     if (vlan_s) {
-        if (sscanf(vlan_s, "%u", &vlan) != 1) {
+        if (!ovs_scan(vlan_s, "%u", &vlan)) {
             unixctl_command_reply_error(conn, "invalid vlan");
             return;
         }
@@ -1254,7 +1270,7 @@ bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[],
     }
 
     if (basis_s) {
-        if (sscanf(basis_s, "%"PRIu32, &basis) != 1) {
+        if (!ovs_scan(basis_s, "%"SCNu32, &basis)) {
             unixctl_command_reply_error(conn, "invalid basis");
             return;
         }
@@ -1262,8 +1278,7 @@ bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[],
         basis = 0;
     }
 
-    if (sscanf(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))
-        == ETH_ADDR_SCAN_COUNT) {
+    if (ovs_scan(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
         hash = bond_hash_src(mac, vlan, basis) & BOND_MASK;
 
         hash_cstr = xasprintf("%u", hash);
@@ -1412,14 +1427,20 @@ choose_output_slave(const struct bond *bond, const struct flow *flow,
                     struct flow_wildcards *wc, uint16_t vlan)
 {
     struct bond_entry *e;
+    int balance;
 
+    balance = bond->balance;
     if (bond->lacp_status == LACP_CONFIGURED) {
         /* LACP has been configured on this bond but negotiations were
-         * unsuccussful.  Drop all traffic. */
-        return NULL;
+         * unsuccussful. If lacp_fallback_ab is enabled use active-
+         * backup mode else drop all traffic. */
+        if (!bond->lacp_fallback_ab) {
+            return NULL;
+        }
+        balance = BM_AB;
     }
 
-    switch (bond->balance) {
+    switch (balance) {
     case BM_AB:
         return bond->active_slave;