]> git.proxmox.com Git - ovs.git/blobdiff - ofproto/bond.c
ofproto: Handle multipart requests with multiple parts.
[ovs.git] / ofproto / bond.c
index 5bb124bda5ad5074d0400b42fe808dd814601123..d2a8b1f89fb914a4947bf58e6bb7d08e6a7b9489 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
+ * Copyright (c) 2008-2017 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #include "openvswitch/list.h"
 #include "openvswitch/match.h"
 #include "openvswitch/ofp-actions.h"
-#include "openvswitch/ofp-util.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 #include "packets.h"
-#include "poll-loop.h"
+#include "openvswitch/poll-loop.h"
 #include "seq.h"
 #include "openvswitch/shash.h"
 #include "timeval.h"
@@ -88,13 +87,13 @@ struct bond_slave {
 
     struct netdev *netdev;      /* Network device, owned by the client. */
     uint64_t change_seq;        /* Tracks changes in 'netdev'. */
-    ofp_port_t  ofp_port;       /* OpenFlow port number. */
     char *name;                 /* Name (a copy of netdev_get_name(netdev)). */
+    ofp_port_t  ofp_port;       /* OpenFlow port number. */
 
     /* Link status. */
-    long long delay_expires;    /* Time after which 'enabled' may change. */
     bool enabled;               /* May be chosen for flows? */
     bool may_enable;            /* Client considers this slave bondable. */
+    long long delay_expires;    /* Time after which 'enabled' may change. */
 
     /* Rebalancing info.  Used only by bond_rebalance(). */
     struct ovs_list bal_node;   /* In bond_rebalance()'s 'bals' list. */
@@ -175,10 +174,6 @@ static void bond_link_status_update(struct bond_slave *)
     OVS_REQ_WRLOCK(rwlock);
 static void bond_choose_active_slave(struct bond *)
     OVS_REQ_WRLOCK(rwlock);
-static unsigned int bond_hash_src(const struct eth_addr mac,
-                                  uint16_t vlan, uint32_t basis);
-static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan,
-                                  uint32_t basis);
 static struct bond_entry *lookup_bond_entry(const struct bond *,
                                             const struct flow *,
                                             uint16_t vlan)
@@ -191,6 +186,7 @@ static struct bond_slave *choose_output_slave(const struct bond *,
                                               uint16_t vlan)
     OVS_REQ_RDLOCK(rwlock);
 static void update_recirc_rules__(struct bond *bond);
+static bool bond_is_falling_back_to_ab(const struct bond *);
 
 /* Attempts to parse 's' as the name of a bond balancing mode.  If successful,
  * stores the mode in '*balance' and returns true.  Otherwise returns false
@@ -372,7 +368,7 @@ update_recirc_rules__(struct bond *bond)
                                                    RECIRC_RULE_PRIORITY, 0,
                                                    &ofpacts, pr_op->pr_rule);
             if (error) {
-                char *err_s = match_to_string(&pr_op->match,
+                char *err_s = match_to_string(&pr_op->match, NULL,
                                               RECIRC_RULE_PRIORITY);
 
                 VLOG_ERR("failed to add post recirculation flow %s", err_s);
@@ -385,7 +381,7 @@ update_recirc_rules__(struct bond *bond)
                                                       &pr_op->match,
                                                       RECIRC_RULE_PRIORITY);
             if (error) {
-                char *err_s = match_to_string(&pr_op->match,
+                char *err_s = match_to_string(&pr_op->match, NULL,
                                               RECIRC_RULE_PRIORITY);
 
                 VLOG_ERR("failed to remove post recirculation flow %s", err_s);
@@ -393,7 +389,9 @@ update_recirc_rules__(struct bond *bond)
             }
 
             hmap_remove(&bond->pr_rule_ops, &pr_op->hmap_node);
-            *pr_op->pr_rule = NULL;
+            if (bond->hash) {
+                *pr_op->pr_rule = NULL;
+            }
             free(pr_op);
             break;
         }
@@ -651,6 +649,13 @@ bond_run(struct bond *bond, enum lacp_status lacp_status)
     if (bond->lacp_status != lacp_status) {
         bond->lacp_status = lacp_status;
         bond->bond_revalidate = true;
+
+        /* Change in LACP status can affect whether the bond is falling back to
+         * active-backup.  Make sure to create or destroy buckets if
+         * necessary.  */
+        if (bond_is_falling_back_to_ab(bond) || !bond->hash) {
+            bond_entry_reset(bond);
+        }
     }
 
     /* Enable slaves based on link status and LACP feedback. */
@@ -759,6 +764,15 @@ bond_compose_learning_packet(struct bond *bond, const struct eth_addr eth_src,
     return packet;
 }
 \f
+
+static bool
+bond_is_falling_back_to_ab(const struct bond *bond)
+{
+    return (bond->lacp_fallback_ab
+            && (bond->balance == BM_SLB || bond->balance == BM_TCP)
+            && bond->lacp_status == LACP_CONFIGURED);
+}
+
 /* Checks whether a packet that arrived on 'slave_' within 'bond', with an
  * Ethernet destination address of 'eth_dst', should be admitted.
  *
@@ -827,6 +841,7 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
         if (!bond->lacp_fallback_ab) {
             goto out;
         }
+        /* fall through */
 
     case BM_AB:
         /* Drop all packets which arrive on backup slaves.  This is similar to
@@ -926,20 +941,11 @@ bond_recirculation_account(struct bond *bond)
     }
 }
 
-bool
-bond_may_recirc(const struct bond *bond, uint32_t *recirc_id,
-                uint32_t *hash_bias)
+static bool
+bond_may_recirc(const struct bond *bond)
 {
-    bool may_recirc = bond->balance == BM_TCP && bond->recirc_id;
-
-    if (recirc_id) {
-        *recirc_id = may_recirc ? bond->recirc_id : 0;
-    }
-    if (hash_bias) {
-        *hash_bias = may_recirc ? bond->basis : 0;
-    }
-
-    return may_recirc;
+    return (bond->balance == BM_TCP && bond->recirc_id
+            && !bond_is_falling_back_to_ab(bond));
 }
 
 static void
@@ -970,11 +976,25 @@ void
 bond_update_post_recirc_rules(struct bond *bond, uint32_t *recirc_id,
                               uint32_t *hash_basis)
 {
-    ovs_rwlock_wrlock(&rwlock);
-    if (bond_may_recirc(bond, recirc_id, hash_basis)) {
-        bond_update_post_recirc_rules__(bond, false);
+    bool may_recirc = bond_may_recirc(bond);
+
+    if (may_recirc) {
+        /* To avoid unnecessary locking, bond_may_recirc() is first
+         * called outside of the 'rwlock'. After acquiring the lock,
+         * check again to make sure bond configuration has not been changed. */
+        ovs_rwlock_wrlock(&rwlock);
+        may_recirc = bond_may_recirc(bond);
+        if (may_recirc) {
+            *recirc_id = bond->recirc_id;
+            *hash_basis = bond->basis;
+            bond_update_post_recirc_rules__(bond, false);
+        }
+        ovs_rwlock_unlock(&rwlock);
+    }
+
+    if (!may_recirc) {
+        *recirc_id = *hash_basis = 0;
     }
-    ovs_rwlock_unlock(&rwlock);
 }
 
 \f
@@ -984,7 +1004,8 @@ static bool
 bond_is_balanced(const struct bond *bond) OVS_REQ_RDLOCK(rwlock)
 {
     return bond->rebalance_interval
-        && (bond->balance == BM_SLB || bond->balance == BM_TCP);
+        && (bond->balance == BM_SLB || bond->balance == BM_TCP)
+        && !(bond->lacp_fallback_ab && bond->lacp_status == LACP_CONFIGURED);
 }
 
 /* Notifies 'bond' that 'n_bytes' bytes were sent in 'flow' within 'vlan'. */
@@ -1158,8 +1179,8 @@ bond_rebalance(struct bond *bond)
     }
     bond->next_rebalance = time_msec() + bond->rebalance_interval;
 
-    use_recirc = bond->ofproto->backer->support.odp.recirc &&
-                 bond_may_recirc(bond, NULL, NULL);
+    use_recirc = bond->ofproto->backer->rt_support.odp.recirc &&
+                 bond_may_recirc(bond);
 
     if (use_recirc) {
         bond_recirculation_account(bond);
@@ -1319,7 +1340,8 @@ bond_print_details(struct ds *ds, const struct bond *bond)
     ds_put_format(ds, "bond_mode: %s\n",
                   bond_mode_to_string(bond->balance));
 
-    may_recirc = bond_may_recirc(bond, &recirc_id, NULL);
+    may_recirc = bond_may_recirc(bond);
+    recirc_id = bond->recirc_id;
     ds_put_format(ds, "bond may use recirculation: %s, Recirc-ID : %d\n",
                   may_recirc ? "yes" : "no", may_recirc ? recirc_id: -1);
 
@@ -1371,15 +1393,15 @@ bond_print_details(struct ds *ds, const struct bond *bond)
         ds_put_format(ds, "\nslave %s: %s\n",
                       slave->name, slave->enabled ? "enabled" : "disabled");
         if (slave == bond->active_slave) {
-            ds_put_cstr(ds, "\tactive slave\n");
+            ds_put_cstr(ds, "  active slave\n");
         }
         if (slave->delay_expires != LLONG_MAX) {
-            ds_put_format(ds, "\t%s expires in %lld ms\n",
+            ds_put_format(ds, "  %s expires in %lld ms\n",
                           slave->enabled ? "downdelay" : "updelay",
                           slave->delay_expires - time_msec());
         }
 
-        ds_put_format(ds, "\tmay_enable: %s\n",
+        ds_put_format(ds, "  may_enable: %s\n",
                       slave->may_enable ? "true" : "false");
 
         if (!bond_is_balanced(bond)) {
@@ -1397,7 +1419,7 @@ bond_print_details(struct ds *ds, const struct bond *bond)
 
             be_tx_k = be->tx_bytes / 1024;
             if (be_tx_k) {
-                ds_put_format(ds, "\thash %d: %"PRIu64" kB load\n",
+                ds_put_format(ds, "  hash %d: %"PRIu64" kB load\n",
                           hash, be_tx_k);
             }
 
@@ -1611,7 +1633,7 @@ bond_unixctl_hash(struct unixctl_conn *conn, int argc, const char *argv[],
     }
 
     if (ovs_scan(mac_s, ETH_ADDR_SCAN_FMT, ETH_ADDR_SCAN_ARGS(mac))) {
-        hash = bond_hash_src(mac, vlan, basis) & BOND_MASK;
+        hash = hash_mac(mac, vlan, basis) & BOND_MASK;
 
         hash_cstr = xasprintf("%u", hash);
         unixctl_command_reply(conn, hash_cstr);
@@ -1642,7 +1664,7 @@ bond_init(void)
 static void
 bond_entry_reset(struct bond *bond)
 {
-    if (bond->balance != BM_AB) {
+    if (bond->balance != BM_AB && !bond_is_falling_back_to_ab(bond)) {
         size_t hash_len = BOND_BUCKETS * sizeof *bond->hash;
 
         if (!bond->hash) {
@@ -1677,6 +1699,8 @@ bond_slave_lookup(struct bond *bond, const void *slave_)
 static void
 bond_enable_slave(struct bond_slave *slave, bool enable)
 {
+    struct bond *bond = slave->bond;
+
     slave->delay_expires = LLONG_MAX;
     if (enable != slave->enabled) {
         slave->bond->bond_revalidate = true;
@@ -1686,6 +1710,7 @@ bond_enable_slave(struct bond_slave *slave, bool enable)
         if (enable) {
             ovs_list_insert(&slave->bond->enabled_slaves, &slave->list_node);
         } else {
+            bond->send_learning_packets = true;
             ovs_list_remove(&slave->list_node);
         }
         ovs_mutex_unlock(&slave->bond->mutex);
@@ -1711,8 +1736,7 @@ bond_link_status_update(struct bond_slave *slave)
             VLOG_INFO_RL(&rl, "interface %s: will not be %s",
                          slave->name, up ? "disabled" : "enabled");
         } else {
-            int delay = (bond->lacp_status != LACP_DISABLED ? 0
-                         : up ? bond->updelay : bond->downdelay);
+            int delay = up ? bond->updelay : bond->downdelay;
             slave->delay_expires = time_msec() + delay;
             if (delay) {
                 VLOG_INFO_RL(&rl, "interface %s: will be %s if it stays %s "
@@ -1730,32 +1754,14 @@ bond_link_status_update(struct bond_slave *slave)
     }
 }
 
-static unsigned int
-bond_hash_src(const struct eth_addr mac, uint16_t vlan, uint32_t basis)
-{
-    return hash_mac(mac, vlan, basis);
-}
-
-static unsigned int
-bond_hash_tcp(const struct flow *flow, uint16_t vlan, uint32_t basis)
-{
-    struct flow hash_flow = *flow;
-    hash_flow.vlan_tci = htons(vlan);
-
-    /* The symmetric quality of this hash function is not required, but
-     * flow_hash_symmetric_l4 already exists, and is sufficient for our
-     * purposes, so we use it out of convenience. */
-    return flow_hash_symmetric_l4(&hash_flow, basis);
-}
-
 static unsigned int
 bond_hash(const struct bond *bond, const struct flow *flow, uint16_t vlan)
 {
     ovs_assert(bond->balance == BM_TCP || bond->balance == BM_SLB);
 
     return (bond->balance == BM_TCP
-            ? bond_hash_tcp(flow, vlan, bond->basis)
-            : bond_hash_src(flow->dl_src, vlan, bond->basis));
+            ? flow_hash_5tuple(flow, bond->basis)
+            : hash_mac(flow->dl_src, vlan, bond->basis));
 }
 
 static struct bond_entry *
@@ -1814,11 +1820,11 @@ choose_output_slave(const struct bond *bond, const struct flow *flow,
             return NULL;
         }
         if (wc) {
-            flow_mask_hash_fields(flow, wc, NX_HASH_FIELDS_SYMMETRIC_L4);
+            flow_mask_hash_fields(flow, wc, NX_HASH_FIELDS_SYMMETRIC_L3L4_UDP);
         }
         /* Fall Through. */
     case BM_SLB:
-        if (wc) {
+        if (wc && balance == BM_SLB) {
             flow_mask_hash_fields(flow, wc, NX_HASH_FIELDS_ETH_SRC);
         }
         e = lookup_bond_entry(bond, flow, vlan);