[ovs-dev] [bond 6/7] lacp: Require successful LACP negotiations when configured.

Ben Pfaff blp at nicira.com
Mon Jan 16 20:46:42 UTC 2012


I agree that this is much easier to understand.  It looks good to me.
Thank you.

On Fri, Jan 13, 2012 at 11:56:49AM -0800, Ethan Jackson wrote:
> Here's the original version of the patch that I'd written.  I had remvoed the
> LACP_CONFIGURED enum because I don't think it's strictly necessary.  The same
> behavior can be achieved by dropping all traffic on non-enabled slaves in the
> admissibility function.  However, I think this patch is *much* easier to
> understand so I'm proposing it now.
> 
> Ethan
> 
> ---
> In the original Open vSwitch LACP implementation, when no slaves
> found a LACP partner, the LACP module would attach all of them.
> This allowed the LACP bond to fall back to a standard bond when
> partnered with a non-LACP switch.  In practice, this has caused
> confusion with marginal benefit, so this feature is removed with
> this patch.
> 
> Signed-off-by: Ethan Jackson <ethan at nicira.com>
> ---
>  NEWS                   |    3 ++
>  lib/bond.c             |   91 ++++++++++++++++++++++++++++--------------------
>  lib/bond.h             |    3 +-
>  lib/lacp.c             |   30 ++++++++--------
>  lib/lacp.h             |    8 ++++-
>  ofproto/ofproto-dpif.c |    2 +-
>  tests/lacp.at          |    2 +-
>  vswitchd/vswitch.xml   |    8 ++--
>  8 files changed, 86 insertions(+), 61 deletions(-)
> 
> diff --git a/NEWS b/NEWS
> index b628e29..8ff87c4 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -1,5 +1,8 @@
>  post-v1.5.0
>  ------------------------
> +    - bonding
> +        - LACP bonds no longer fall back to balance-slb when negotiations fail.
> +          Instead they drop traffic.
>  
>  
>  v1.5.0 - xx xxx xxxx
> diff --git a/lib/bond.c b/lib/bond.c
> index a2105ca..50a1d5d 100644
> --- a/lib/bond.c
> +++ b/lib/bond.c
> @@ -26,6 +26,7 @@
>  #include "dynamic-string.h"
>  #include "flow.h"
>  #include "hmap.h"
> +#include "lacp.h"
>  #include "list.h"
>  #include "netdev.h"
>  #include "odp-util.h"
> @@ -92,7 +93,7 @@ struct bond {
>      struct bond_slave *active_slave;
>      tag_type no_slaves_tag;     /* Tag for flows when all slaves disabled. */
>      int updelay, downdelay;     /* Delay before slave goes up/down, in ms. */
> -    bool lacp_negotiated;       /* LACP negotiations were successful. */
> +    enum lacp_status lacp_status; /* Status of LACP negotiations. */
>      bool bond_revalidate;       /* True if flows need revalidation. */
>      uint32_t basis;             /* Basis for flow hash function. */
>  
> @@ -122,7 +123,6 @@ static void bond_enable_slave(struct bond_slave *, bool enable,
>                                struct tag_set *);
>  static void bond_link_status_update(struct bond_slave *, struct tag_set *);
>  static void bond_choose_active_slave(struct bond *, struct tag_set *);
> -static bool bond_is_tcp_hash(const struct bond *);
>  static unsigned int bond_hash_src(const uint8_t mac[ETH_ADDR_LEN],
>                                    uint16_t vlan, uint32_t basis);
>  static unsigned int bond_hash_tcp(const struct flow *, uint16_t vlan,
> @@ -402,13 +402,12 @@ bond_slave_set_may_enable(struct bond *bond, void *slave_, bool may_enable)
>   *
>   * The caller should check bond_should_send_learning_packets() afterward. */
>  void
> -bond_run(struct bond *bond, struct tag_set *tags, bool lacp_negotiated)
> +bond_run(struct bond *bond, struct tag_set *tags, enum lacp_status lacp_status)
>  {
>      struct bond_slave *slave;
> -    bool is_tcp_hash = bond_is_tcp_hash(bond);
>  
> -    if (bond->lacp_negotiated != lacp_negotiated) {
> -        bond->lacp_negotiated = lacp_negotiated;
> +    if (bond->lacp_status != lacp_status) {
> +        bond->lacp_status = lacp_status;
>          bond->bond_revalidate = true;
>      }
>  
> @@ -427,10 +426,6 @@ bond_run(struct bond *bond, struct tag_set *tags, bool lacp_negotiated)
>          bond->next_fake_iface_update = time_msec() + 1000;
>      }
>  
> -    if (is_tcp_hash != bond_is_tcp_hash(bond)) {
> -        bond->bond_revalidate = true;
> -    }
> -
>      if (bond->bond_revalidate) {
>          bond->bond_revalidate = false;
>  
> @@ -488,8 +483,9 @@ bond_wait(struct bond *bond)
>  static bool
>  may_send_learning_packets(const struct bond *bond)
>  {
> -    return !bond->lacp_negotiated && bond->balance != BM_AB &&
> -           bond->active_slave;
> +    return bond->lacp_status == LACP_DISABLED
> +        && bond->balance != BM_AB
> +        && bond->active_slave;
>  }
>  
>  /* Returns true if 'bond' needs the client to send out packets to assist with
> @@ -566,9 +562,14 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
>       * assume the remote switch is aware of the bond and will "do the right
>       * thing".  However, as a precaution we drop packets on disabled slaves
>       * because no correctly implemented partner switch should be sending
> -     * packets to them. */
> -    if (bond->lacp_negotiated) {
> -        return slave->enabled ? BV_ACCEPT : BV_DROP;
> +     * packets to them.
> +     *
> +     * If LACP is configured, but LACP negotiations have been unsuccessful, we
> +     * drop all incoming traffic. */
> +    switch (bond->lacp_status) {
> +    case LACP_NEGOTIATED: return slave->enabled ? BV_ACCEPT : BV_DROP;
> +    case LACP_CONFIGURED: return BV_DROP;
> +    case LACP_DISABLED: break;
>      }
>  
>      /* Drop all multicast packets on inactive slaves. */
> @@ -595,10 +596,11 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
>          return BV_ACCEPT;
>  
>      case BM_TCP:
> -        /* TCP balancing has degraded to SLB (otherwise the
> -         * bond->lacp_negotiated check above would have processed this).
> -         *
> -         * Fall through. */
> +        /* TCP balanced bonds require successful LACP negotiated. Based on the
> +         * above check, LACP is off on this bond.  Therfore, we drop all
> +         * incoming traffic. */
> +        return BV_DROP;
> +
>      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
> @@ -950,11 +952,6 @@ bond_print_details(struct ds *ds, const struct bond *bond)
>      ds_put_format(ds, "bond_mode: %s\n",
>                    bond_mode_to_string(bond->balance));
>  
> -    if (bond->balance != BM_AB) {
> -        ds_put_format(ds, "bond-hash-algorithm: %s\n",
> -                      bond_is_tcp_hash(bond) ? "balance-tcp" : "balance-slb");
> -    }
> -
>      ds_put_format(ds, "bond-hash-basis: %"PRIu32"\n", bond->basis);
>  
>      ds_put_format(ds, "updelay: %d ms\n", bond->updelay);
> @@ -965,8 +962,21 @@ bond_print_details(struct ds *ds, const struct bond *bond)
>                        bond->next_rebalance - time_msec());
>      }
>  
> -    ds_put_format(ds, "lacp_negotiated: %s\n",
> -                  bond->lacp_negotiated ? "true" : "false");
> +    ds_put_cstr(ds, "lacp_status: ");
> +    switch (bond->lacp_status) {
> +    case LACP_NEGOTIATED:
> +        ds_put_cstr(ds, "negotiated\n");
> +        break;
> +    case LACP_CONFIGURED:
> +        ds_put_cstr(ds, "configured\n");
> +        break;
> +    case LACP_DISABLED:
> +        ds_put_cstr(ds, "off\n");
> +        break;
> +    default:
> +        ds_put_cstr(ds, "<unknown>\n");
> +        break;
> +    }
>  
>      HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
>          shash_add(&slave_shash, slave->name, slave);
> @@ -1305,7 +1315,7 @@ bond_link_status_update(struct bond_slave *slave, struct tag_set *tags)
>              VLOG_INFO_RL(&rl, "interface %s: will not be %s",
>                           slave->name, up ? "disabled" : "enabled");
>          } else {
> -            int delay = (bond->lacp_negotiated ? 0
> +            int delay = (bond->lacp_status != LACP_DISABLED ? 0
>                           : up ? bond->updelay : bond->downdelay);
>              slave->delay_expires = time_msec() + delay;
>              if (delay) {
> @@ -1324,13 +1334,6 @@ bond_link_status_update(struct bond_slave *slave, struct tag_set *tags)
>      }
>  }
>  
> -static bool
> -bond_is_tcp_hash(const struct bond *bond)
> -{
> -    return (bond->balance == BM_TCP && bond->lacp_negotiated)
> -        || bond->balance == BM_STABLE;
> -}
> -
>  static unsigned int
>  bond_hash_src(const uint8_t mac[ETH_ADDR_LEN], uint16_t vlan, uint32_t basis)
>  {
> @@ -1352,9 +1355,9 @@ bond_hash_tcp(const struct flow *flow, uint16_t vlan, uint32_t basis)
>  static unsigned int
>  bond_hash(const struct bond *bond, const struct flow *flow, uint16_t vlan)
>  {
> -    assert(bond->balance != BM_AB);
> +    assert(bond->balance == BM_TCP || bond->balance == BM_SLB);
>  
> -    return (bond_is_tcp_hash(bond)
> +    return (bond->balance == BM_TCP
>              ? bond_hash_tcp(flow, vlan, bond->basis)
>              : bond_hash_src(flow->dl_src, vlan, bond->basis));
>  }
> @@ -1381,7 +1384,7 @@ choose_stb_slave(const struct bond *bond, const struct flow *flow,
>  
>      best = NULL;
>      best_hash = 0;
> -    flow_hash = bond_hash(bond, flow, vlan);
> +    flow_hash = bond_hash_tcp(flow, vlan, bond->basis);
>      HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
>          if (slave->enabled) {
>              uint32_t hash;
> @@ -1403,14 +1406,26 @@ choose_output_slave(const struct bond *bond, const struct flow *flow,
>  {
>      struct bond_entry *e;
>  
> +    if (bond->lacp_status == LACP_CONFIGURED) {
> +        /* LACP has been configured on this bond but negotiations were
> +         * unsuccussful.  Drop all traffic. */
> +        return NULL;
> +    }
> +
>      switch (bond->balance) {
>      case BM_AB:
>          return bond->active_slave;
>  
>      case BM_STABLE:
>          return choose_stb_slave(bond, flow, vlan);
> -    case BM_SLB:
> +
>      case BM_TCP:
> +        if (bond->lacp_status != LACP_NEGOTIATED) {
> +            /* Must have LACP negotiations for TCP balanced bonds. */
> +            return NULL;
> +        }
> +        /* Fall Through. */
> +    case BM_SLB:
>          e = lookup_bond_entry(bond, flow, vlan);
>          if (!e->slave || !e->slave->enabled) {
>              e->slave = CONTAINER_OF(hmap_random_node(&bond->slaves),
> diff --git a/lib/bond.h b/lib/bond.h
> index 1958029..9eb1b8f 100644
> --- a/lib/bond.h
> +++ b/lib/bond.h
> @@ -26,6 +26,7 @@
>  struct flow;
>  struct netdev;
>  struct ofpbuf;
> +enum lacp_status;
>  
>  /* How flows are balanced among bond slaves. */
>  enum bond_mode {
> @@ -68,7 +69,7 @@ void bond_slave_register(struct bond *, void *slave_,
>  void bond_slave_set_netdev(struct bond *, void *slave_, struct netdev *);
>  void bond_slave_unregister(struct bond *, const void *slave);
>  
> -void bond_run(struct bond *, struct tag_set *, bool lacp_negotiated);
> +void bond_run(struct bond *, struct tag_set *, enum lacp_status);
>  void bond_wait(struct bond *);
>  
>  void bond_slave_set_may_enable(struct bond *, void *slave_, bool may_enable);
> diff --git a/lib/lacp.c b/lib/lacp.c
> index 244b86e..c51fac6 100644
> --- a/lib/lacp.c
> +++ b/lib/lacp.c
> @@ -301,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
> @@ -384,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;
>      }
> @@ -504,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;
>          }
>  
> @@ -519,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) {
> @@ -531,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;
> diff --git a/lib/lacp.h b/lib/lacp.h
> index 1d717d6..293fc45 100644
> --- a/lib/lacp.h
> +++ b/lib/lacp.h
> @@ -29,6 +29,12 @@ enum lacp_time {
>      LACP_TIME_CUSTOM                  /* Nonstandard custom mode. */
>  };
>  
> +enum lacp_status {
> +    LACP_NEGOTIATED,                  /* Successful LACP negotations. */
> +    LACP_CONFIGURED,                  /* LACP is enabled but not negotiated. */
> +    LACP_DISABLED                     /* LACP is not enabled. */
> +};
> +
>  struct lacp_settings {
>      char *name;                       /* Name (for debugging). */
>      uint8_t id[ETH_ADDR_LEN];         /* System ID. Must be nonzero. */
> @@ -48,7 +54,7 @@ bool lacp_is_active(const struct lacp *);
>  
>  void lacp_process_packet(struct lacp *, const void *slave,
>                           const struct ofpbuf *packet);
> -bool lacp_negotiated(const struct lacp *);
> +enum lacp_status lacp_status(const struct lacp *);
>  
>  struct lacp_slave_settings {
>      char *name;                       /* Name (for debugging). */
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 6ecf71b..34dc903 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -1866,7 +1866,7 @@ bundle_run(struct ofbundle *bundle)
>          }
>  
>          bond_run(bundle->bond, &bundle->ofproto->revalidate_set,
> -                 lacp_negotiated(bundle->lacp));
> +                 lacp_status(bundle->lacp));
>          if (bond_should_send_learning_packets(bundle->bond)) {
>              bundle_send_learning_packets(bundle);
>          }
> diff --git a/tests/lacp.at b/tests/lacp.at
> index 16daa3d..947eb9c 100644
> --- a/tests/lacp.at
> +++ b/tests/lacp.at
> @@ -104,7 +104,7 @@ bond_mode: active-backup
>  bond-hash-basis: 0
>  updelay: 0 ms
>  downdelay: 0 ms
> -lacp_negotiated: true
> +lacp_status: negotiated
>  
>  slave p1: disabled
>  	may_enable: false
> diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
> index 585f678..dcc25d1 100644
> --- a/vswitchd/vswitch.xml
> +++ b/vswitchd/vswitch.xml
> @@ -757,8 +757,7 @@
>  
>        <p>
>          The following modes require the upstream switch to support 802.3ad with
> -        successful LACP negotiation.  If LACP negotiation fails then
> -        <code>balance-slb</code> style flow hashing is used as a fallback:
> +        successful LACP negotiation:
>        </p>
>  
>        <dl>
> @@ -861,8 +860,9 @@
>            connected to.  <code>active</code> ports are allowed to initiate LACP
>            negotiations.  <code>passive</code> ports are allowed to participate
>            in LACP negotiations initiated by a remote switch, but not allowed to
> -          initiate such negotiations themselves.  Defaults to <code>off</code>
> -          if unset.
> +          initiate such negotiations themselves.  If LACP is enabled on a port
> +          whose partner switch does not support LACP, the bond will be
> +          disabled.  Defaults to <code>off</code> if unset.
>          </column>
>  
>          <column name="other_config" key="lacp-system-id">
> -- 
> 1.7.7.1
> 
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev



More information about the dev mailing list