Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/net/bonding/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 182 kB image not shown  

Quelle  bond_main.c   Sprache: C

 
// SPDX-License-Identifier: GPL-1.0+
/*
 * originally based on the dummy device.
 *
 * Copyright 1999, Thomas Davis, tadavis@lbl.gov.
 * Based on dummy.c, and eql.c devices.
 *
 * bonding.c: an Ethernet Bonding driver
 *
 * This is useful to talk to a Cisco EtherChannel compatible equipment:
 * Cisco 5500
 * Sun Trunking (Solaris)
 * Alteon AceDirector Trunks
 * Linux Bonding
 * and probably many L2 switches ...
 *
 * How it works:
 *    ifconfig bond0 ipaddress netmask up
 *      will setup a network device, with an ip address.  No mac address
 * will be assigned at this time.  The hw mac address will come from
 * the first slave bonded to the channel.  All slaves will then use
 * this hw mac address.
 *
 *    ifconfig bond0 down
 *         will release all slaves, marking them as down.
 *
 *    ifenslave bond0 eth0
 * will attach eth0 to bond0 as a slave.  eth0 hw mac address will either
 * a: be used as initial mac address
 * b: if a hw mac address already is there, eth0's hw mac address
 *    will then be set from bond0.
 *
 */


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/filter.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <net/ip.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/icmpv6.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/socket.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <asm/dma.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/igmp.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
#include <linux/smp.h>
#include <linux/if_ether.h>
#include <net/arp.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
#include <linux/phy.h>
#include <linux/jiffies.h>
#include <linux/preempt.h>
#include <net/route.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/pkt_sched.h>
#include <linux/rculist.h>
#include <net/flow_dissector.h>
#include <net/xfrm.h>
#include <net/bonding.h>
#include <net/bond_3ad.h>
#include <net/bond_alb.h>
#if IS_ENABLED(CONFIG_TLS_DEVICE)
#include <net/tls.h>
#endif
#include <net/ip6_route.h>
#include <net/netdev_lock.h>
#include <net/xdp.h>

#include "bonding_priv.h"

/*---------------------------- Module parameters ----------------------------*/

/* monitor all links that often (in milliseconds). <=0 disables monitoring */

static int max_bonds = BOND_DEFAULT_MAX_BONDS;
static int tx_queues = BOND_DEFAULT_TX_QUEUES;
static int num_peer_notif = 1;
static int miimon;
static int updelay;
static int downdelay;
static int use_carrier = 1;
static char *mode;
static char *primary;
static char *primary_reselect;
static char *lacp_rate;
static int min_links;
static char *ad_select;
static char *xmit_hash_policy;
static int arp_interval;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
static char *arp_validate;
static char *arp_all_targets;
static char *fail_over_mac;
static int all_slaves_active;
static struct bond_params bonding_defaults;
static int resend_igmp = BOND_DEFAULT_RESEND_IGMP;
static int packets_per_slave = 1;
static int lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL;

module_param(max_bonds, int, 0);
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
module_param(tx_queues, int, 0);
MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)");
module_param_named(num_grat_arp, num_peer_notif, int, 0644);
MODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on "
          "failover event (alias of num_unsol_na)");
module_param_named(num_unsol_na, num_peer_notif, int, 0644);
MODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on "
          "failover event (alias of num_grat_arp)");
module_param(miimon, int, 0);
MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
module_param(updelay, int, 0);
MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds");
module_param(downdelay, int, 0);
MODULE_PARM_DESC(downdelay, "Delay before considering link down, "
       "in milliseconds");
module_param(use_carrier, int, 0);
MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; "
         "0 for off, 1 for on (default)");
module_param(mode, charp, 0);
MODULE_PARM_DESC(mode, "Mode of operation; 0 for balance-rr, "
         "1 for active-backup, 2 for balance-xor, "
         "3 for broadcast, 4 for 802.3ad, 5 for balance-tlb, "
         "6 for balance-alb");
module_param(primary, charp, 0);
MODULE_PARM_DESC(primary, "Primary network device to use");
module_param(primary_reselect, charp, 0);
MODULE_PARM_DESC(primary_reselect, "Reselect primary slave "
       "once it comes up; "
       "0 for always (default), "
       "1 for only if speed of primary is "
       "better, "
       "2 for only on active slave "
       "failure");
module_param(lacp_rate, charp, 0);
MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner; "
       "0 for slow, 1 for fast");
module_param(ad_select, charp, 0);
MODULE_PARM_DESC(ad_select, "802.3ad aggregation selection logic; "
       "0 for stable (default), 1 for bandwidth, "
       "2 for count");
module_param(min_links, int, 0);
MODULE_PARM_DESC(min_links, "Minimum number of available links before turning on carrier");

module_param(xmit_hash_policy, charp, 0);
MODULE_PARM_DESC(xmit_hash_policy, "balance-alb, balance-tlb, balance-xor, 802.3ad hashing method; "
       "0 for layer 2 (default), 1 for layer 3+4, "
       "2 for layer 2+3, 3 for encap layer 2+3, "
       "4 for encap layer 3+4, 5 for vlan+srcmac");
module_param(arp_interval, int, 0);
MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
module_param_array(arp_ip_target, charp, NULL, 0);
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes; "
          "0 for none (default), 1 for active, "
          "2 for backup, 3 for all");
module_param(arp_all_targets, charp, 0);
MODULE_PARM_DESC(arp_all_targets, "fail on any/all arp targets timeout; 0 for any (default), 1 for all");
module_param(fail_over_mac, charp, 0);
MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to "
    "the same MAC; 0 for none (default), "
    "1 for active, 2 for follow");
module_param(all_slaves_active, int, 0);
MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface "
         "by setting active flag for all slaves; "
         "0 for never (default), 1 for always.");
module_param(resend_igmp, int, 0);
MODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on "
         "link failure");
module_param(packets_per_slave, int, 0);
MODULE_PARM_DESC(packets_per_slave, "Packets to send per slave in balance-rr "
        "mode; 0 for a random slave, 1 packet per "
        "slave (default), >1 packets per slave.");
module_param(lp_interval, uint, 0);
MODULE_PARM_DESC(lp_interval, "The number of seconds between instances where "
         "the bonding driver sends learning packets to "
         "each slaves peer switch. The default is 1.");

/*----------------------------- Global variables ----------------------------*/

#ifdef CONFIG_NET_POLL_CONTROLLER
atomic_t netpoll_block_tx = ATOMIC_INIT(0);
#endif

unsigned int bond_net_id __read_mostly;

DEFINE_STATIC_KEY_FALSE(bond_bcast_neigh_enabled);

static const struct flow_dissector_key flow_keys_bonding_keys[] = {
 {
  .key_id = FLOW_DISSECTOR_KEY_CONTROL,
  .offset = offsetof(struct flow_keys, control),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_BASIC,
  .offset = offsetof(struct flow_keys, basic),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS,
  .offset = offsetof(struct flow_keys, addrs.v4addrs),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS,
  .offset = offsetof(struct flow_keys, addrs.v6addrs),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_TIPC,
  .offset = offsetof(struct flow_keys, addrs.tipckey),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_PORTS,
  .offset = offsetof(struct flow_keys, ports),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_ICMP,
  .offset = offsetof(struct flow_keys, icmp),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_VLAN,
  .offset = offsetof(struct flow_keys, vlan),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL,
  .offset = offsetof(struct flow_keys, tags),
 },
 {
  .key_id = FLOW_DISSECTOR_KEY_GRE_KEYID,
  .offset = offsetof(struct flow_keys, keyid),
 },
};

static struct flow_dissector flow_keys_bonding __read_mostly;

/*-------------------------- Forward declarations ---------------------------*/

static int bond_init(struct net_device *bond_dev);
static void bond_uninit(struct net_device *bond_dev);
static void bond_get_stats(struct net_device *bond_dev,
      struct rtnl_link_stats64 *stats);
static void bond_slave_arr_handler(struct work_struct *work);
static bool bond_time_in_interval(struct bonding *bond, unsigned long last_act,
      int mod);
static void bond_netdev_notify_work(struct work_struct *work);

/*---------------------------- General routines -----------------------------*/

const char *bond_mode_name(int mode)
{
 static const char *names[] = {
  [BOND_MODE_ROUNDROBIN] = "load balancing (round-robin)",
  [BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)",
  [BOND_MODE_XOR] = "load balancing (xor)",
  [BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)",
  [BOND_MODE_8023AD] = "IEEE 802.3ad Dynamic link aggregation",
  [BOND_MODE_TLB] = "transmit load balancing",
  [BOND_MODE_ALB] = "adaptive load balancing",
 };

 if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_ALB)
  return "unknown";

 return names[mode];
}

/**
 * bond_dev_queue_xmit - Prepare skb for xmit.
 *
 * @bond: bond device that got this skb for tx.
 * @skb: hw accel VLAN tagged skb to transmit
 * @slave_dev: slave that is supposed to xmit this skbuff
 */

netdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
   struct net_device *slave_dev)
{
 skb->dev = slave_dev;

 BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
       sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
 skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);

 if (unlikely(netpoll_tx_running(bond->dev)))
  return bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb);

 return dev_queue_xmit(skb);
}

static bool bond_sk_check(struct bonding *bond)
{
 switch (BOND_MODE(bond)) {
 case BOND_MODE_8023AD:
 case BOND_MODE_XOR:
  if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
   return true;
  fallthrough;
 default:
  return false;
 }
}

bool bond_xdp_check(struct bonding *bond, int mode)
{
 switch (mode) {
 case BOND_MODE_ROUNDROBIN:
 case BOND_MODE_ACTIVEBACKUP:
  return true;
 case BOND_MODE_8023AD:
 case BOND_MODE_XOR:
  /* vlan+srcmac is not supported with XDP as in most cases the 802.1q
 * payload is not in the packet due to hardware offload.
 */

  if (bond->params.xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC)
   return true;
  fallthrough;
 default:
  return false;
 }
}

/*---------------------------------- VLAN -----------------------------------*/

/* In the following 2 functions, bond_vlan_rx_add_vid and bond_vlan_rx_kill_vid,
 * We don't protect the slave list iteration with a lock because:
 * a. This operation is performed in IOCTL context,
 * b. The operation is protected by the RTNL semaphore in the 8021q code,
 * c. Holding a lock with BH disabled while directly calling a base driver
 *    entry point is generally a BAD idea.
 *
 * The design of synchronization/protection for this operation in the 8021q
 * module is good for one or more VLAN devices over a single physical device
 * and cannot be extended for a teaming solution like bonding, so there is a
 * potential race condition here where a net device from the vlan group might
 * be referenced (either by a base driver or the 8021q code) while it is being
 * removed from the system. However, it turns out we're not making matters
 * worse, and if it works for regular VLAN usage it will work here too.
*/


/**
 * bond_vlan_rx_add_vid - Propagates adding an id to slaves
 * @bond_dev: bonding net device that got called
 * @proto: network protocol ID
 * @vid: vlan id being added
 */

static int bond_vlan_rx_add_vid(struct net_device *bond_dev,
    __be16 proto, u16 vid)
{
 struct bonding *bond = netdev_priv(bond_dev);
 struct slave *slave, *rollback_slave;
 struct list_head *iter;
 int res;

 bond_for_each_slave(bond, slave, iter) {
  res = vlan_vid_add(slave->dev, proto, vid);
  if (res)
   goto unwind;
 }

 return 0;

unwind:
 /* unwind to the slave that failed */
 bond_for_each_slave(bond, rollback_slave, iter) {
  if (rollback_slave == slave)
   break;

  vlan_vid_del(rollback_slave->dev, proto, vid);
 }

 return res;
}

/**
 * bond_vlan_rx_kill_vid - Propagates deleting an id to slaves
 * @bond_dev: bonding net device that got called
 * @proto: network protocol ID
 * @vid: vlan id being removed
 */

static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
     __be16 proto, u16 vid)
{
 struct bonding *bond = netdev_priv(bond_dev);
 struct list_head *iter;
 struct slave *slave;

 bond_for_each_slave(bond, slave, iter)
  vlan_vid_del(slave->dev, proto, vid);

 if (bond_is_lb(bond))
  bond_alb_clear_vlan(bond, vid);

 return 0;
}

/*---------------------------------- XFRM -----------------------------------*/

#ifdef CONFIG_XFRM_OFFLOAD
/**
 * bond_ipsec_dev - Get active device for IPsec offload
 * @xs: pointer to transformer state struct
 *
 * Context: caller must hold rcu_read_lock.
 *
 * Return: the device for ipsec offload, or NULL if not exist.
 **/

static struct net_device *bond_ipsec_dev(struct xfrm_state *xs)
{
 struct net_device *bond_dev = xs->xso.dev;
 struct bonding *bond;
 struct slave *slave;

 bond = netdev_priv(bond_dev);
 if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)
  return NULL;

 slave = rcu_dereference(bond->curr_active_slave);
 if (!slave)
  return NULL;

 if (!xs->xso.real_dev)
  return NULL;

 if (xs->xso.real_dev != slave->dev)
  pr_warn_ratelimited("%s: (slave %s): not same with IPsec offload real dev %s\n",
        bond_dev->name, slave->dev->name, xs->xso.real_dev->name);

 return slave->dev;
}

/**
 * bond_ipsec_add_sa - program device with a security association
 * @bond_dev: pointer to the bond net device
 * @xs: pointer to transformer state struct
 * @extack: extack point to fill failure reason
 **/

static int bond_ipsec_add_sa(struct net_device *bond_dev,
        struct xfrm_state *xs,
        struct netlink_ext_ack *extack)
{
 struct net_device *real_dev;
 netdevice_tracker tracker;
 struct bond_ipsec *ipsec;
 struct bonding *bond;
 struct slave *slave;
 int err;

 if (!bond_dev)
  return -EINVAL;

 rcu_read_lock();
 bond = netdev_priv(bond_dev);
 slave = rcu_dereference(bond->curr_active_slave);
 real_dev = slave ? slave->dev : NULL;
 netdev_hold(real_dev, &tracker, GFP_ATOMIC);
 rcu_read_unlock();
 if (!real_dev) {
  err = -ENODEV;
  goto out;
 }

 if (!real_dev->xfrmdev_ops ||
     !real_dev->xfrmdev_ops->xdo_dev_state_add ||
     netif_is_bond_master(real_dev)) {
  NL_SET_ERR_MSG_MOD(extack, "Slave does not support ipsec offload");
  err = -EINVAL;
  goto out;
 }

 ipsec = kmalloc(sizeof(*ipsec), GFP_KERNEL);
 if (!ipsec) {
  err = -ENOMEM;
  goto out;
 }

 err = real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev, xs, extack);
 if (!err) {
  xs->xso.real_dev = real_dev;
  ipsec->xs = xs;
  INIT_LIST_HEAD(&ipsec->list);
  mutex_lock(&bond->ipsec_lock);
  list_add(&ipsec->list, &bond->ipsec_list);
  mutex_unlock(&bond->ipsec_lock);
 } else {
  kfree(ipsec);
 }
out:
 netdev_put(real_dev, &tracker);
 return err;
}

static void bond_ipsec_add_sa_all(struct bonding *bond)
{
 struct net_device *bond_dev = bond->dev;
 struct net_device *real_dev;
 struct bond_ipsec *ipsec;
 struct slave *slave;

 slave = rtnl_dereference(bond->curr_active_slave);
 real_dev = slave ? slave->dev : NULL;
 if (!real_dev)
  return;

 mutex_lock(&bond->ipsec_lock);
 if (!real_dev->xfrmdev_ops ||
     !real_dev->xfrmdev_ops->xdo_dev_state_add ||
     netif_is_bond_master(real_dev)) {
  if (!list_empty(&bond->ipsec_list))
   slave_warn(bond_dev, real_dev,
       "%s: no slave xdo_dev_state_add\n",
       __func__);
  goto out;
 }

 list_for_each_entry(ipsec, &bond->ipsec_list, list) {
  /* If new state is added before ipsec_lock acquired */
  if (ipsec->xs->xso.real_dev == real_dev)
   continue;

  if (real_dev->xfrmdev_ops->xdo_dev_state_add(real_dev,
            ipsec->xs, NULL)) {
   slave_warn(bond_dev, real_dev, "%s: failed to add SA\n", __func__);
   continue;
  }

  spin_lock_bh(&ipsec->xs->lock);
  /* xs might have been killed by the user during the migration
 * to the new dev, but bond_ipsec_del_sa() should have done
 * nothing, as xso.real_dev is NULL.
 * Delete it from the device we just added it to. The pending
 * bond_ipsec_free_sa() call will do the rest of the cleanup.
 */

  if (ipsec->xs->km.state == XFRM_STATE_DEAD &&
      real_dev->xfrmdev_ops->xdo_dev_state_delete)
   real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev,
            ipsec->xs);
  ipsec->xs->xso.real_dev = real_dev;
  spin_unlock_bh(&ipsec->xs->lock);
 }
out:
 mutex_unlock(&bond->ipsec_lock);
}

/**
 * bond_ipsec_del_sa - clear out this specific SA
 * @bond_dev: pointer to the bond net device
 * @xs: pointer to transformer state struct
 **/

static void bond_ipsec_del_sa(struct net_device *bond_dev,
         struct xfrm_state *xs)
{
 struct net_device *real_dev;

 if (!bond_dev || !xs->xso.real_dev)
  return;

 real_dev = xs->xso.real_dev;

 if (!real_dev->xfrmdev_ops ||
     !real_dev->xfrmdev_ops->xdo_dev_state_delete ||
     netif_is_bond_master(real_dev)) {
  slave_warn(bond_dev, real_dev, "%s: no slave xdo_dev_state_delete\n", __func__);
  return;
 }

 real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev, xs);
}

static void bond_ipsec_del_sa_all(struct bonding *bond)
{
 struct net_device *bond_dev = bond->dev;
 struct net_device *real_dev;
 struct bond_ipsec *ipsec;
 struct slave *slave;

 slave = rtnl_dereference(bond->curr_active_slave);
 real_dev = slave ? slave->dev : NULL;
 if (!real_dev)
  return;

 mutex_lock(&bond->ipsec_lock);
 list_for_each_entry(ipsec, &bond->ipsec_list, list) {
  if (!ipsec->xs->xso.real_dev)
   continue;

  if (!real_dev->xfrmdev_ops ||
      !real_dev->xfrmdev_ops->xdo_dev_state_delete ||
      netif_is_bond_master(real_dev)) {
   slave_warn(bond_dev, real_dev,
       "%s: no slave xdo_dev_state_delete\n",
       __func__);
   continue;
  }

  spin_lock_bh(&ipsec->xs->lock);
  ipsec->xs->xso.real_dev = NULL;
  /* Don't double delete states killed by the user. */
  if (ipsec->xs->km.state != XFRM_STATE_DEAD)
   real_dev->xfrmdev_ops->xdo_dev_state_delete(real_dev,
            ipsec->xs);
  spin_unlock_bh(&ipsec->xs->lock);

  if (real_dev->xfrmdev_ops->xdo_dev_state_free)
   real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev,
          ipsec->xs);
 }
 mutex_unlock(&bond->ipsec_lock);
}

static void bond_ipsec_free_sa(struct net_device *bond_dev,
          struct xfrm_state *xs)
{
 struct net_device *real_dev;
 struct bond_ipsec *ipsec;
 struct bonding *bond;

 if (!bond_dev)
  return;

 bond = netdev_priv(bond_dev);

 mutex_lock(&bond->ipsec_lock);
 if (!xs->xso.real_dev)
  goto out;

 real_dev = xs->xso.real_dev;

 xs->xso.real_dev = NULL;
 if (real_dev->xfrmdev_ops &&
     real_dev->xfrmdev_ops->xdo_dev_state_free)
  real_dev->xfrmdev_ops->xdo_dev_state_free(real_dev, xs);
out:
 list_for_each_entry(ipsec, &bond->ipsec_list, list) {
  if (ipsec->xs == xs) {
   list_del(&ipsec->list);
   kfree(ipsec);
   break;
  }
 }
 mutex_unlock(&bond->ipsec_lock);
}

/**
 * bond_ipsec_offload_ok - can this packet use the xfrm hw offload
 * @skb: current data packet
 * @xs: pointer to transformer state struct
 **/

static bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
{
 struct net_device *real_dev;

 rcu_read_lock();
 real_dev = bond_ipsec_dev(xs);
 if (!real_dev || netif_is_bond_master(real_dev)) {
  rcu_read_unlock();
  return false;
 }

 rcu_read_unlock();
 return true;
}

/**
 * bond_advance_esn_state - ESN support for IPSec HW offload
 * @xs: pointer to transformer state struct
 **/

static void bond_advance_esn_state(struct xfrm_state *xs)
{
 struct net_device *real_dev;

 rcu_read_lock();
 real_dev = bond_ipsec_dev(xs);
 if (!real_dev)
  goto out;

 if (!real_dev->xfrmdev_ops ||
     !real_dev->xfrmdev_ops->xdo_dev_state_advance_esn) {
  pr_warn_ratelimited("%s: %s doesn't support xdo_dev_state_advance_esn\n", __func__, real_dev->name);
  goto out;
 }

 real_dev->xfrmdev_ops->xdo_dev_state_advance_esn(xs);
out:
 rcu_read_unlock();
}

/**
 * bond_xfrm_update_stats - Update xfrm state
 * @xs: pointer to transformer state struct
 **/

static void bond_xfrm_update_stats(struct xfrm_state *xs)
{
 struct net_device *real_dev;

 rcu_read_lock();
 real_dev = bond_ipsec_dev(xs);
 if (!real_dev)
  goto out;

 if (!real_dev->xfrmdev_ops ||
     !real_dev->xfrmdev_ops->xdo_dev_state_update_stats) {
  pr_warn_ratelimited("%s: %s doesn't support xdo_dev_state_update_stats\n", __func__, real_dev->name);
  goto out;
 }

 real_dev->xfrmdev_ops->xdo_dev_state_update_stats(xs);
out:
 rcu_read_unlock();
}

static const struct xfrmdev_ops bond_xfrmdev_ops = {
 .xdo_dev_state_add = bond_ipsec_add_sa,
 .xdo_dev_state_delete = bond_ipsec_del_sa,
 .xdo_dev_state_free = bond_ipsec_free_sa,
 .xdo_dev_offload_ok = bond_ipsec_offload_ok,
 .xdo_dev_state_advance_esn = bond_advance_esn_state,
 .xdo_dev_state_update_stats = bond_xfrm_update_stats,
};
#endif /* CONFIG_XFRM_OFFLOAD */

/*------------------------------- Link status -------------------------------*/

/* Set the carrier state for the master according to the state of its
 * slaves.  If any slaves are up, the master is up.  In 802.3ad mode,
 * do special 802.3ad magic.
 *
 * Returns zero if carrier state does not change, nonzero if it does.
 */

int bond_set_carrier(struct bonding *bond)
{
 struct list_head *iter;
 struct slave *slave;

 if (!bond_has_slaves(bond))
  goto down;

 if (BOND_MODE(bond) == BOND_MODE_8023AD)
  return bond_3ad_set_carrier(bond);

 bond_for_each_slave(bond, slave, iter) {
  if (slave->link == BOND_LINK_UP) {
   if (!netif_carrier_ok(bond->dev)) {
    netif_carrier_on(bond->dev);
    return 1;
   }
   return 0;
  }
 }

down:
 if (netif_carrier_ok(bond->dev)) {
  netif_carrier_off(bond->dev);
  return 1;
 }
 return 0;
}

/* Get link speed and duplex from the slave's base driver
 * using ethtool. If for some reason the call fails or the
 * values are invalid, set speed and duplex to -1,
 * and return. Return 1 if speed or duplex settings are
 * UNKNOWN; 0 otherwise.
 */

static int bond_update_speed_duplex(struct slave *slave)
{
 struct net_device *slave_dev = slave->dev;
 struct ethtool_link_ksettings ecmd;
 int res;

 slave->speed = SPEED_UNKNOWN;
 slave->duplex = DUPLEX_UNKNOWN;

 res = __ethtool_get_link_ksettings(slave_dev, &ecmd);
 if (res < 0)
  return 1;
 if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1))
  return 1;
 switch (ecmd.base.duplex) {
 case DUPLEX_FULL:
 case DUPLEX_HALF:
  break;
 default:
  return 1;
 }

 slave->speed = ecmd.base.speed;
 slave->duplex = ecmd.base.duplex;

 return 0;
}

const char *bond_slave_link_status(s8 link)
{
 switch (link) {
 case BOND_LINK_UP:
  return "up";
 case BOND_LINK_FAIL:
  return "going down";
 case BOND_LINK_DOWN:
  return "down";
 case BOND_LINK_BACK:
  return "going back";
 default:
  return "unknown";
 }
}

/* if <dev> supports MII link status reporting, check its link status.
 *
 * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(),
 * depending upon the setting of the use_carrier parameter.
 *
 * Return either BMSR_LSTATUS, meaning that the link is up (or we
 * can't tell and just pretend it is), or 0, meaning that the link is
 * down.
 *
 * If reporting is non-zero, instead of faking link up, return -1 if
 * both ETHTOOL and MII ioctls fail (meaning the device does not
 * support them).  If use_carrier is set, return whatever it says.
 * It'd be nice if there was a good way to tell if a driver supports
 * netif_carrier, but there really isn't.
 */

static int bond_check_dev_link(struct bonding *bond,
          struct net_device *slave_dev, int reporting)
{
 const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 struct mii_ioctl_data *mii;
 struct ifreq ifr;
 int ret;

 if (!reporting && !netif_running(slave_dev))
  return 0;

 if (bond->params.use_carrier)
  return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;

 /* Try to get link status using Ethtool first. */
 if (slave_dev->ethtool_ops->get_link) {
  netdev_lock_ops(slave_dev);
  ret = slave_dev->ethtool_ops->get_link(slave_dev);
  netdev_unlock_ops(slave_dev);

  return ret ? BMSR_LSTATUS : 0;
 }

 /* Ethtool can't be used, fallback to MII ioctls. */
 if (slave_ops->ndo_eth_ioctl) {
  /* TODO: set pointer to correct ioctl on a per team member
 *       bases to make this more efficient. that is, once
 *       we determine the correct ioctl, we will always
 *       call it and not the others for that team
 *       member.
 */


  /* We cannot assume that SIOCGMIIPHY will also read a
 * register; not all network drivers (e.g., e100)
 * support that.
 */


  /* Yes, the mii is overlaid on the ifreq.ifr_ifru */
  strscpy_pad(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
  mii = if_mii(&ifr);

  if (dev_eth_ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) {
   mii->reg_num = MII_BMSR;
   if (dev_eth_ioctl(slave_dev, &ifr, SIOCGMIIREG) == 0)
    return mii->val_out & BMSR_LSTATUS;
  }
 }

 /* If reporting, report that either there's no ndo_eth_ioctl,
 * or both SIOCGMIIREG and get_link failed (meaning that we
 * cannot report link status).  If not reporting, pretend
 * we're ok.
 */

 return reporting ? -1 : BMSR_LSTATUS;
}

/*----------------------------- Multicast list ------------------------------*/

/* Push the promiscuity flag down to appropriate slaves */
static int bond_set_promiscuity(struct bonding *bond, int inc)
{
 struct list_head *iter;
 int err = 0;

 if (bond_uses_primary(bond)) {
  struct slave *curr_active = rtnl_dereference(bond->curr_active_slave);

  if (curr_active)
   err = dev_set_promiscuity(curr_active->dev, inc);
 } else {
  struct slave *slave;

  bond_for_each_slave(bond, slave, iter) {
   err = dev_set_promiscuity(slave->dev, inc);
   if (err)
    return err;
  }
 }
 return err;
}

/* Push the allmulti flag down to all slaves */
static int bond_set_allmulti(struct bonding *bond, int inc)
{
 struct list_head *iter;
 int err = 0;

 if (bond_uses_primary(bond)) {
  struct slave *curr_active = rtnl_dereference(bond->curr_active_slave);

  if (curr_active)
   err = dev_set_allmulti(curr_active->dev, inc);
 } else {
  struct slave *slave;

  bond_for_each_slave(bond, slave, iter) {
   err = dev_set_allmulti(slave->dev, inc);
   if (err)
    return err;
  }
 }
 return err;
}

/* Retrieve the list of registered multicast addresses for the bonding
 * device and retransmit an IGMP JOIN request to the current active
 * slave.
 */

static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
{
 struct bonding *bond = container_of(work, struct bonding,
         mcast_work.work);

 if (!rtnl_trylock()) {
  queue_delayed_work(bond->wq, &bond->mcast_work, 1);
  return;
 }
 call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev);

 if (bond->igmp_retrans > 1) {
  bond->igmp_retrans--;
  queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5);
 }
 rtnl_unlock();
}

/* Flush bond's hardware addresses from slave */
static void bond_hw_addr_flush(struct net_device *bond_dev,
          struct net_device *slave_dev)
{
 struct bonding *bond = netdev_priv(bond_dev);

 dev_uc_unsync(slave_dev, bond_dev);
 dev_mc_unsync(slave_dev, bond_dev);

 if (BOND_MODE(bond) == BOND_MODE_8023AD)
  dev_mc_del(slave_dev, lacpdu_mcast_addr);
}

/*--------------------------- Active slave change ---------------------------*/

/* Update the hardware address list and promisc/allmulti for the new and
 * old active slaves (if any).  Modes that are not using primary keep all
 * slaves up date at all times; only the modes that use primary need to call
 * this function to swap these settings during a failover.
 */

static void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active,
         struct slave *old_active)
{
 if (old_active) {
  if (bond->dev->flags & IFF_PROMISC)
   dev_set_promiscuity(old_active->dev, -1);

  if (bond->dev->flags & IFF_ALLMULTI)
   dev_set_allmulti(old_active->dev, -1);

  if (bond->dev->flags & IFF_UP)
   bond_hw_addr_flush(bond->dev, old_active->dev);

  bond_slave_ns_maddrs_add(bond, old_active);
 }

 if (new_active) {
  /* FIXME: Signal errors upstream. */
  if (bond->dev->flags & IFF_PROMISC)
   dev_set_promiscuity(new_active->dev, 1);

  if (bond->dev->flags & IFF_ALLMULTI)
   dev_set_allmulti(new_active->dev, 1);

  if (bond->dev->flags & IFF_UP) {
   netif_addr_lock_bh(bond->dev);
   dev_uc_sync(new_active->dev, bond->dev);
   dev_mc_sync(new_active->dev, bond->dev);
   netif_addr_unlock_bh(bond->dev);
  }

  bond_slave_ns_maddrs_del(bond, new_active);
 }
}

/**
 * bond_set_dev_addr - clone slave's address to bond
 * @bond_dev: bond net device
 * @slave_dev: slave net device
 *
 * Should be called with RTNL held.
 */

static int bond_set_dev_addr(struct net_device *bond_dev,
        struct net_device *slave_dev)
{
 int err;

 slave_dbg(bond_dev, slave_dev, "bond_dev=%p slave_dev=%p slave_dev->addr_len=%d\n",
    bond_dev, slave_dev, slave_dev->addr_len);
 err = netif_pre_changeaddr_notify(bond_dev, slave_dev->dev_addr, NULL);
 if (err)
  return err;

 __dev_addr_set(bond_dev, slave_dev->dev_addr, slave_dev->addr_len);
 bond_dev->addr_assign_type = NET_ADDR_STOLEN;
 call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev);
 return 0;
}

static struct slave *bond_get_old_active(struct bonding *bond,
      struct slave *new_active)
{
 struct slave *slave;
 struct list_head *iter;

 bond_for_each_slave(bond, slave, iter) {
  if (slave == new_active)
   continue;

  if (ether_addr_equal(bond->dev->dev_addr, slave->dev->dev_addr))
   return slave;
 }

 return NULL;
}

/* bond_do_fail_over_mac
 *
 * Perform special MAC address swapping for fail_over_mac settings
 *
 * Called with RTNL
 */

static void bond_do_fail_over_mac(struct bonding *bond,
      struct slave *new_active,
      struct slave *old_active)
{
 u8 tmp_mac[MAX_ADDR_LEN];
 struct sockaddr_storage ss;
 int rv;

 switch (bond->params.fail_over_mac) {
 case BOND_FOM_ACTIVE:
  if (new_active) {
   rv = bond_set_dev_addr(bond->dev, new_active->dev);
   if (rv)
    slave_err(bond->dev, new_active->dev, "Error %d setting bond MAC from slave\n",
       -rv);
  }
  break;
 case BOND_FOM_FOLLOW:
  /* if new_active && old_active, swap them
 * if just old_active, do nothing (going to no active slave)
 * if just new_active, set new_active to bond's MAC
 */

  if (!new_active)
   return;

  if (!old_active)
   old_active = bond_get_old_active(bond, new_active);

  if (old_active) {
   bond_hw_addr_copy(tmp_mac, new_active->dev->dev_addr,
       new_active->dev->addr_len);
   bond_hw_addr_copy(ss.__data,
       old_active->dev->dev_addr,
       old_active->dev->addr_len);
   ss.ss_family = new_active->dev->type;
  } else {
   bond_hw_addr_copy(ss.__data, bond->dev->dev_addr,
       bond->dev->addr_len);
   ss.ss_family = bond->dev->type;
  }

  rv = dev_set_mac_address(new_active->dev, &ss, NULL);
  if (rv) {
   slave_err(bond->dev, new_active->dev, "Error %d setting MAC of new active slave\n",
      -rv);
   goto out;
  }

  if (!old_active)
   goto out;

  bond_hw_addr_copy(ss.__data, tmp_mac,
      new_active->dev->addr_len);
  ss.ss_family = old_active->dev->type;

  rv = dev_set_mac_address(old_active->dev, &ss, NULL);
  if (rv)
   slave_err(bond->dev, old_active->dev, "Error %d setting MAC of old active slave\n",
      -rv);
out:
  break;
 default:
  netdev_err(bond->dev, "bond_do_fail_over_mac impossible: bad policy %d\n",
      bond->params.fail_over_mac);
  break;
 }

}

/**
 * bond_choose_primary_or_current - select the primary or high priority slave
 * @bond: our bonding struct
 *
 * - Check if there is a primary link. If the primary link was set and is up,
 *   go on and do link reselection.
 *
 * - If primary link is not set or down, find the highest priority link.
 *   If the highest priority link is not current slave, set it as primary
 *   link and do link reselection.
 */

static struct slave *bond_choose_primary_or_current(struct bonding *bond)
{
 struct slave *prim = rtnl_dereference(bond->primary_slave);
 struct slave *curr = rtnl_dereference(bond->curr_active_slave);
 struct slave *slave, *hprio = NULL;
 struct list_head *iter;

 if (!prim || prim->link != BOND_LINK_UP) {
  bond_for_each_slave(bond, slave, iter) {
   if (slave->link == BOND_LINK_UP) {
    hprio = hprio ?: slave;
    if (slave->prio > hprio->prio)
     hprio = slave;
   }
  }

  if (hprio && hprio != curr) {
   prim = hprio;
   goto link_reselect;
  }

  if (!curr || curr->link != BOND_LINK_UP)
   return NULL;
  return curr;
 }

 if (bond->force_primary) {
  bond->force_primary = false;
  return prim;
 }

link_reselect:
 if (!curr || curr->link != BOND_LINK_UP)
  return prim;

 /* At this point, prim and curr are both up */
 switch (bond->params.primary_reselect) {
 case BOND_PRI_RESELECT_ALWAYS:
  return prim;
 case BOND_PRI_RESELECT_BETTER:
  if (prim->speed < curr->speed)
   return curr;
  if (prim->speed == curr->speed && prim->duplex <= curr->duplex)
   return curr;
  return prim;
 case BOND_PRI_RESELECT_FAILURE:
  return curr;
 default:
  netdev_err(bond->dev, "impossible primary_reselect %d\n",
      bond->params.primary_reselect);
  return curr;
 }
}

/**
 * bond_find_best_slave - select the best available slave to be the active one
 * @bond: our bonding struct
 */

static struct slave *bond_find_best_slave(struct bonding *bond)
{
 struct slave *slave, *bestslave = NULL;
 struct list_head *iter;
 int mintime = bond->params.updelay;

 slave = bond_choose_primary_or_current(bond);
 if (slave)
  return slave;

 bond_for_each_slave(bond, slave, iter) {
  if (slave->link == BOND_LINK_UP)
   return slave;
  if (slave->link == BOND_LINK_BACK && bond_slave_is_up(slave) &&
      slave->delay < mintime) {
   mintime = slave->delay;
   bestslave = slave;
  }
 }

 return bestslave;
}

/* must be called in RCU critical section or with RTNL held */
static bool bond_should_notify_peers(struct bonding *bond)
{
 struct bond_up_slave *usable;
 struct slave *slave = NULL;

 if (!bond->send_peer_notif ||
     bond->send_peer_notif %
     max(1, bond->params.peer_notif_delay) != 0 ||
     !netif_carrier_ok(bond->dev))
  return false;

 /* The send_peer_notif is set by active-backup or 8023ad
 * mode, and cleared in bond_close() when changing mode.
 * It is safe to only check bond mode here.
 */

 if (BOND_MODE(bond) == BOND_MODE_8023AD) {
  usable = rcu_dereference_rtnl(bond->usable_slaves);
  if (!usable || !READ_ONCE(usable->count))
   return false;
 } else {
  slave = rcu_dereference_rtnl(bond->curr_active_slave);
  if (!slave || test_bit(__LINK_STATE_LINKWATCH_PENDING,
           &slave->dev->state))
   return false;
 }

 netdev_dbg(bond->dev, "bond_should_notify_peers: slave %s\n",
     slave ? slave->dev->name : "all");

 return true;
}

/**
 * bond_change_active_slave - change the active slave into the specified one
 * @bond: our bonding struct
 * @new_active: the new slave to make the active one
 *
 * Set the new slave to the bond's settings and unset them on the old
 * curr_active_slave.
 * Setting include flags, mc-list, promiscuity, allmulti, etc.
 *
 * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP,
 * because it is apparently the best available slave we have, even though its
 * updelay hasn't timed out yet.
 *
 * Caller must hold RTNL.
 */

void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
{
 struct slave *old_active;

 ASSERT_RTNL();

 old_active = rtnl_dereference(bond->curr_active_slave);

 if (old_active == new_active)
  return;

#ifdef CONFIG_XFRM_OFFLOAD
 bond_ipsec_del_sa_all(bond);
#endif /* CONFIG_XFRM_OFFLOAD */

 if (new_active) {
  new_active->last_link_up = jiffies;

  if (new_active->link == BOND_LINK_BACK) {
   if (bond_uses_primary(bond)) {
    slave_info(bond->dev, new_active->dev, "making interface the new active one %d ms earlier\n",
        (bond->params.updelay - new_active->delay) * bond->params.miimon);
   }

   new_active->delay = 0;
   bond_set_slave_link_state(new_active, BOND_LINK_UP,
        BOND_SLAVE_NOTIFY_NOW);

   if (BOND_MODE(bond) == BOND_MODE_8023AD)
    bond_3ad_handle_link_change(new_active, BOND_LINK_UP);

   if (bond_is_lb(bond))
    bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP);
  } else {
   if (bond_uses_primary(bond))
    slave_info(bond->dev, new_active->dev, "making interface the new active one\n");
  }
 }

 if (bond_uses_primary(bond))
  bond_hw_addr_swap(bond, new_active, old_active);

 if (bond_is_lb(bond)) {
  bond_alb_handle_active_change(bond, new_active);
  if (old_active)
   bond_set_slave_inactive_flags(old_active,
            BOND_SLAVE_NOTIFY_NOW);
  if (new_active)
   bond_set_slave_active_flags(new_active,
          BOND_SLAVE_NOTIFY_NOW);
 } else {
  rcu_assign_pointer(bond->curr_active_slave, new_active);
 }

 if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) {
  if (old_active)
   bond_set_slave_inactive_flags(old_active,
            BOND_SLAVE_NOTIFY_NOW);

  if (new_active) {
   bool should_notify_peers = false;

   bond_set_slave_active_flags(new_active,
          BOND_SLAVE_NOTIFY_NOW);

   if (bond->params.fail_over_mac)
    bond_do_fail_over_mac(bond, new_active,
            old_active);

   if (netif_running(bond->dev)) {
    bond->send_peer_notif =
     bond->params.num_peer_notif *
     max(1, bond->params.peer_notif_delay);
    should_notify_peers =
     bond_should_notify_peers(bond);
   }

   call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, bond->dev);
   if (should_notify_peers) {
    bond->send_peer_notif--;
    call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
        bond->dev);
   }
  }
 }

#ifdef CONFIG_XFRM_OFFLOAD
 bond_ipsec_add_sa_all(bond);
#endif /* CONFIG_XFRM_OFFLOAD */

 /* resend IGMP joins since active slave has changed or
 * all were sent on curr_active_slave.
 * resend only if bond is brought up with the affected
 * bonding modes and the retransmission is enabled
 */

 if (netif_running(bond->dev) && (bond->params.resend_igmp > 0) &&
     ((bond_uses_primary(bond) && new_active) ||
      BOND_MODE(bond) == BOND_MODE_ROUNDROBIN)) {
  bond->igmp_retrans = bond->params.resend_igmp;
  queue_delayed_work(bond->wq, &bond->mcast_work, 1);
 }
}

/**
 * bond_select_active_slave - select a new active slave, if needed
 * @bond: our bonding struct
 *
 * This functions should be called when one of the following occurs:
 * - The old curr_active_slave has been released or lost its link.
 * - The primary_slave has got its link back.
 * - A slave has got its link back and there's no old curr_active_slave.
 *
 * Caller must hold RTNL.
 */

void bond_select_active_slave(struct bonding *bond)
{
 struct slave *best_slave;
 int rv;

 ASSERT_RTNL();

 best_slave = bond_find_best_slave(bond);
 if (best_slave != rtnl_dereference(bond->curr_active_slave)) {
  bond_change_active_slave(bond, best_slave);
  rv = bond_set_carrier(bond);
  if (!rv)
   return;

  if (netif_carrier_ok(bond->dev))
   netdev_info(bond->dev, "active interface up!\n");
  else
   netdev_info(bond->dev, "now running without any active interface!\n");
 }
}

#ifdef CONFIG_NET_POLL_CONTROLLER
static inline int slave_enable_netpoll(struct slave *slave)
{
 struct netpoll *np;
 int err = 0;

 np = kzalloc(sizeof(*np), GFP_KERNEL);
 err = -ENOMEM;
 if (!np)
  goto out;

 err = __netpoll_setup(np, slave->dev);
 if (err) {
  kfree(np);
  goto out;
 }
 slave->np = np;
out:
 return err;
}
static inline void slave_disable_netpoll(struct slave *slave)
{
 struct netpoll *np = slave->np;

 if (!np)
  return;

 slave->np = NULL;

 __netpoll_free(np);
}

static void bond_poll_controller(struct net_device *bond_dev)
{
 struct bonding *bond = netdev_priv(bond_dev);
 struct slave *slave = NULL;
 struct list_head *iter;
 struct ad_info ad_info;

 if (BOND_MODE(bond) == BOND_MODE_8023AD)
  if (bond_3ad_get_active_agg_info(bond, &ad_info))
   return;

 bond_for_each_slave_rcu(bond, slave, iter) {
  if (!bond_slave_is_up(slave))
   continue;

  if (BOND_MODE(bond) == BOND_MODE_8023AD) {
   struct aggregator *agg =
       SLAVE_AD_INFO(slave)->port.aggregator;

   if (agg &&
       agg->aggregator_identifier != ad_info.aggregator_id)
    continue;
  }

  netpoll_poll_dev(slave->dev);
 }
}

static void bond_netpoll_cleanup(struct net_device *bond_dev)
{
 struct bonding *bond = netdev_priv(bond_dev);
 struct list_head *iter;
 struct slave *slave;

 bond_for_each_slave(bond, slave, iter)
  if (bond_slave_is_up(slave))
   slave_disable_netpoll(slave);
}

static int bond_netpoll_setup(struct net_device *dev)
{
 struct bonding *bond = netdev_priv(dev);
 struct list_head *iter;
 struct slave *slave;
 int err = 0;

 bond_for_each_slave(bond, slave, iter) {
  err = slave_enable_netpoll(slave);
  if (err) {
   bond_netpoll_cleanup(dev);
   break;
  }
 }
 return err;
}
#else
static inline int slave_enable_netpoll(struct slave *slave)
{
 return 0;
}
static inline void slave_disable_netpoll(struct slave *slave)
{
}
static void bond_netpoll_cleanup(struct net_device *bond_dev)
{
}
#endif

/*---------------------------------- IOCTL ----------------------------------*/

static netdev_features_t bond_fix_features(struct net_device *dev,
        netdev_features_t features)
{
 struct bonding *bond = netdev_priv(dev);
 struct list_head *iter;
 netdev_features_t mask;
 struct slave *slave;

 mask = features;
 features = netdev_base_features(features);

 bond_for_each_slave(bond, slave, iter) {
  features = netdev_increment_features(features,
           slave->dev->features,
           mask);
 }
 features = netdev_add_tso_features(features, mask);

 return features;
}

#define BOND_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
     NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \
     NETIF_F_GSO_ENCAP_ALL | \
     NETIF_F_HIGHDMA | NETIF_F_LRO)

#define BOND_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
     NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE | \
     NETIF_F_GSO_PARTIAL)

#define BOND_MPLS_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
     NETIF_F_GSO_SOFTWARE)

#define BOND_GSO_PARTIAL_FEATURES (NETIF_F_GSO_ESP)


static void bond_compute_features(struct bonding *bond)
{
 netdev_features_t gso_partial_features = BOND_GSO_PARTIAL_FEATURES;
 unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
     IFF_XMIT_DST_RELEASE_PERM;
 netdev_features_t vlan_features = BOND_VLAN_FEATURES;
 netdev_features_t enc_features  = BOND_ENC_FEATURES;
#ifdef CONFIG_XFRM_OFFLOAD
 netdev_features_t xfrm_features  = BOND_XFRM_FEATURES;
#endif /* CONFIG_XFRM_OFFLOAD */
 netdev_features_t mpls_features  = BOND_MPLS_FEATURES;
 struct net_device *bond_dev = bond->dev;
 struct list_head *iter;
 struct slave *slave;
 unsigned short max_hard_header_len = ETH_HLEN;
 unsigned int tso_max_size = TSO_MAX_SIZE;
 u16 tso_max_segs = TSO_MAX_SEGS;

 if (!bond_has_slaves(bond))
  goto done;

 vlan_features = netdev_base_features(vlan_features);
 mpls_features = netdev_base_features(mpls_features);

 bond_for_each_slave(bond, slave, iter) {
  vlan_features = netdev_increment_features(vlan_features,
   slave->dev->vlan_features, BOND_VLAN_FEATURES);

  enc_features = netdev_increment_features(enc_features,
        slave->dev->hw_enc_features,
        BOND_ENC_FEATURES);

#ifdef CONFIG_XFRM_OFFLOAD
  xfrm_features = netdev_increment_features(xfrm_features,
         slave->dev->hw_enc_features,
         BOND_XFRM_FEATURES);
#endif /* CONFIG_XFRM_OFFLOAD */

  gso_partial_features = netdev_increment_features(gso_partial_features,
         slave->dev->gso_partial_features,
         BOND_GSO_PARTIAL_FEATURES);

  mpls_features = netdev_increment_features(mpls_features,
         slave->dev->mpls_features,
         BOND_MPLS_FEATURES);

  dst_release_flag &= slave->dev->priv_flags;
  if (slave->dev->hard_header_len > max_hard_header_len)
   max_hard_header_len = slave->dev->hard_header_len;

  tso_max_size = min(tso_max_size, slave->dev->tso_max_size);
  tso_max_segs = min(tso_max_segs, slave->dev->tso_max_segs);
 }
 bond_dev->hard_header_len = max_hard_header_len;

done:
 bond_dev->gso_partial_features = gso_partial_features;
 bond_dev->vlan_features = vlan_features;
 bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
        NETIF_F_HW_VLAN_CTAG_TX |
        NETIF_F_HW_VLAN_STAG_TX;
#ifdef CONFIG_XFRM_OFFLOAD
 bond_dev->hw_enc_features |= xfrm_features;
#endif /* CONFIG_XFRM_OFFLOAD */
 bond_dev->mpls_features = mpls_features;
 netif_set_tso_max_segs(bond_dev, tso_max_segs);
 netif_set_tso_max_size(bond_dev, tso_max_size);

 bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
 if ((bond_dev->priv_flags & IFF_XMIT_DST_RELEASE_PERM) &&
     dst_release_flag == (IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM))
  bond_dev->priv_flags |= IFF_XMIT_DST_RELEASE;

 netdev_change_features(bond_dev);
}

static void bond_setup_by_slave(struct net_device *bond_dev,
    struct net_device *slave_dev)
{
 bool was_up = !!(bond_dev->flags & IFF_UP);

 dev_close(bond_dev);

 bond_dev->header_ops     = slave_dev->header_ops;

 bond_dev->type      = slave_dev->type;
 bond_dev->hard_header_len   = slave_dev->hard_header_len;
 bond_dev->needed_headroom   = slave_dev->needed_headroom;
 bond_dev->addr_len     = slave_dev->addr_len;

 memcpy(bond_dev->broadcast, slave_dev->broadcast,
  slave_dev->addr_len);

 if (slave_dev->flags & IFF_POINTOPOINT) {
  bond_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
  bond_dev->flags |= (IFF_POINTOPOINT | IFF_NOARP);
 }
 if (was_up)
  dev_open(bond_dev, NULL);
}

/* On bonding slaves other than the currently active slave, suppress
 * duplicates except for alb non-mcast/bcast.
 */

static bool bond_should_deliver_exact_match(struct sk_buff *skb,
         struct slave *slave,
         struct bonding *bond)
{
 if (bond_is_slave_inactive(slave)) {
  if (BOND_MODE(bond) == BOND_MODE_ALB &&
      skb->pkt_type != PACKET_BROADCAST &&
      skb->pkt_type != PACKET_MULTICAST)
   return false;
  return true;
 }
 return false;
}

static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
{
 struct sk_buff *skb = *pskb;
 struct slave *slave;
 struct bonding *bond;
 int (*recv_probe)(const struct sk_buff *, struct bonding *,
     struct slave *);
 int ret = RX_HANDLER_ANOTHER;

 skb = skb_share_check(skb, GFP_ATOMIC);
 if (unlikely(!skb))
  return RX_HANDLER_CONSUMED;

 *pskb = skb;

 slave = bond_slave_get_rcu(skb->dev);
 bond = slave->bond;

 recv_probe = READ_ONCE(bond->recv_probe);
 if (recv_probe) {
  ret = recv_probe(skb, bond, slave);
  if (ret == RX_HANDLER_CONSUMED) {
   consume_skb(skb);
   return ret;
  }
 }

 /*
 * For packets determined by bond_should_deliver_exact_match() call to
 * be suppressed we want to make an exception for link-local packets.
 * This is necessary for e.g. LLDP daemons to be able to monitor
 * inactive slave links without being forced to bind to them
 * explicitly.
 *
 * At the same time, packets that are passed to the bonding master
 * (including link-local ones) can have their originating interface
 * determined via PACKET_ORIGDEV socket option.
 */

 if (bond_should_deliver_exact_match(skb, slave, bond)) {
  if (is_link_local_ether_addr(eth_hdr(skb)->h_dest))
   return RX_HANDLER_PASS;
  return RX_HANDLER_EXACT;
 }

 skb->dev = bond->dev;

 if (BOND_MODE(bond) == BOND_MODE_ALB &&
     netif_is_bridge_port(bond->dev) &&
     skb->pkt_type == PACKET_HOST) {

  if (unlikely(skb_cow_head(skb,
       skb->data - skb_mac_header(skb)))) {
   kfree_skb(skb);
   return RX_HANDLER_CONSUMED;
  }
  bond_hw_addr_copy(eth_hdr(skb)->h_dest, bond->dev->dev_addr,
      bond->dev->addr_len);
 }

 return ret;
}

static enum netdev_lag_tx_type bond_lag_tx_type(struct bonding *bond)
{
 switch (BOND_MODE(bond)) {
 case BOND_MODE_ROUNDROBIN:
  return NETDEV_LAG_TX_TYPE_ROUNDROBIN;
 case BOND_MODE_ACTIVEBACKUP:
  return NETDEV_LAG_TX_TYPE_ACTIVEBACKUP;
 case BOND_MODE_BROADCAST:
  return NETDEV_LAG_TX_TYPE_BROADCAST;
 case BOND_MODE_XOR:
 case BOND_MODE_8023AD:
  return NETDEV_LAG_TX_TYPE_HASH;
 default:
  return NETDEV_LAG_TX_TYPE_UNKNOWN;
 }
}

static enum netdev_lag_hash bond_lag_hash_type(struct bonding *bond,
            enum netdev_lag_tx_type type)
{
 if (type != NETDEV_LAG_TX_TYPE_HASH)
  return NETDEV_LAG_HASH_NONE;

 switch (bond->params.xmit_policy) {
 case BOND_XMIT_POLICY_LAYER2:
  return NETDEV_LAG_HASH_L2;
 case BOND_XMIT_POLICY_LAYER34:
  return NETDEV_LAG_HASH_L34;
 case BOND_XMIT_POLICY_LAYER23:
  return NETDEV_LAG_HASH_L23;
 case BOND_XMIT_POLICY_ENCAP23:
  return NETDEV_LAG_HASH_E23;
 case BOND_XMIT_POLICY_ENCAP34:
  return NETDEV_LAG_HASH_E34;
 case BOND_XMIT_POLICY_VLAN_SRCMAC:
  return NETDEV_LAG_HASH_VLAN_SRCMAC;
 default:
  return NETDEV_LAG_HASH_UNKNOWN;
 }
}

static int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave,
          struct netlink_ext_ack *extack)
{
 struct netdev_lag_upper_info lag_upper_info;
 enum netdev_lag_tx_type type;
 int err;

 type = bond_lag_tx_type(bond);
 lag_upper_info.tx_type = type;
 lag_upper_info.hash_type = bond_lag_hash_type(bond, type);

 err = netdev_master_upper_dev_link(slave->dev, bond->dev, slave,
        &lag_upper_info, extack);
 if (err)
  return err;

 slave->dev->flags |= IFF_SLAVE;
 return 0;
}

static void bond_upper_dev_unlink(struct bonding *bond, struct slave *slave)
{
 netdev_upper_dev_unlink(slave->dev, bond->dev);
 slave->dev->flags &= ~IFF_SLAVE;
}

static void slave_kobj_release(struct kobject *kobj)
{
 struct slave *slave = to_slave(kobj);
 struct bonding *bond = bond_get_bond_by_slave(slave);

 cancel_delayed_work_sync(&slave->notify_work);
 if (BOND_MODE(bond) == BOND_MODE_8023AD)
  kfree(SLAVE_AD_INFO(slave));

 kfree(slave);
}

static struct kobj_type slave_ktype = {
 .release = slave_kobj_release,
#ifdef CONFIG_SYSFS
 .sysfs_ops = &slave_sysfs_ops,
#endif
};

static int bond_kobj_init(struct slave *slave)
{
 int err;

 err = kobject_init_and_add(&slave->kobj, &slave_ktype,
       &(slave->dev->dev.kobj), "bonding_slave");
 if (err)
  kobject_put(&slave->kobj);

 return err;
}

static struct slave *bond_alloc_slave(struct bonding *bond,
          struct net_device *slave_dev)
{
 struct slave *slave = NULL;

 slave = kzalloc(sizeof(*slave), GFP_KERNEL);
 if (!slave)
  return NULL;

 slave->bond = bond;
 slave->dev = slave_dev;
 INIT_DELAYED_WORK(&slave->notify_work, bond_netdev_notify_work);

 if (bond_kobj_init(slave))
  return NULL;

 if (BOND_MODE(bond) == BOND_MODE_8023AD) {
  SLAVE_AD_INFO(slave) = kzalloc(sizeof(struct ad_slave_info),
            GFP_KERNEL);
  if (!SLAVE_AD_INFO(slave)) {
   kobject_put(&slave->kobj);
   return NULL;
  }
 }

 return slave;
}

static void bond_fill_ifbond(struct bonding *bond, struct ifbond *info)
{
 info->bond_mode = BOND_MODE(bond);
 info->miimon = bond->params.miimon;
 info->num_slaves = bond->slave_cnt;
}

static void bond_fill_ifslave(struct slave *slave, struct ifslave *info)
{
 strcpy(info->slave_name, slave->dev->name);
 info->link = slave->link;
 info->state = bond_slave_state(slave);
 info->link_failure_count = slave->link_failure_count;
}

static void bond_netdev_notify_work(struct work_struct *_work)
{
 struct slave *slave = container_of(_work, struct slave,
        notify_work.work);

 if (rtnl_trylock()) {
  struct netdev_bonding_info binfo;

  bond_fill_ifslave(slave, &binfo.slave);
  bond_fill_ifbond(slave->bond, &binfo.master);
  netdev_bonding_info_change(slave->dev, &binfo);
  rtnl_unlock();
 } else {
  queue_delayed_work(slave->bond->wq, &slave->notify_work, 1);
 }
}

void bond_queue_slave_event(struct slave *slave)
{
 queue_delayed_work(slave->bond->wq, &slave->notify_work, 0);
}

void bond_lower_state_changed(struct slave *slave)
{
 struct netdev_lag_lower_state_info info;

 info.link_up = slave->link == BOND_LINK_UP ||
         slave->link == BOND_LINK_FAIL;
 info.tx_enabled = bond_is_active_slave(slave);
 netdev_lower_state_changed(slave->dev, &info);
}

#define BOND_NL_ERR(bond_dev, extack, errmsg) do {  \
 if (extack)      \
  NL_SET_ERR_MSG(extack, errmsg);   \
 else       \
  netdev_err(bond_dev, "Error: %s\n", errmsg); \
while (0)

#define SLAVE_NL_ERR(bond_dev, slave_dev, extack, errmsg) do {  \
 if (extack)       \
  NL_SET_ERR_MSG(extack, errmsg);    \
 else        \
  slave_err(bond_dev, slave_dev, "Error: %s\n", errmsg); \
while (0)

/* The bonding driver uses ether_setup() to convert a master bond device
 * to ARPHRD_ETHER, that resets the target netdevice's flags so we always
 * have to restore the IFF_MASTER flag, and only restore IFF_SLAVE and IFF_UP
 * if they were set
 */

static void bond_ether_setup(struct net_device *bond_dev)
{
 unsigned int flags = bond_dev->flags & (IFF_SLAVE | IFF_UP);

 ether_setup(bond_dev);
 bond_dev->flags |= IFF_MASTER | flags;
 bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
}

void bond_xdp_set_features(struct net_device *bond_dev)
{
 struct bonding *bond = netdev_priv(bond_dev);
 xdp_features_t val = NETDEV_XDP_ACT_MASK;
 struct list_head *iter;
 struct slave *slave;

 ASSERT_RTNL();

 if (!bond_xdp_check(bond, BOND_MODE(bond)) || !bond_has_slaves(bond)) {
  xdp_clear_features_flag(bond_dev);
  return;
 }

 bond_for_each_slave(bond, slave, iter)
  val &= slave->dev->xdp_features;

 val &= ~NETDEV_XDP_ACT_XSK_ZEROCOPY;

 xdp_set_features_flag(bond_dev, val);
}

/* enslave device <slave> to bond device <master> */
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
   struct netlink_ext_ack *extack)
{
 struct bonding *bond = netdev_priv(bond_dev);
 const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
 struct slave *new_slave = NULL, *prev_slave;
 struct sockaddr_storage ss;
 int link_reporting;
 int res = 0, i;

 if (slave_dev->flags & IFF_MASTER &&
     !netif_is_bond_master(slave_dev)) {
  BOND_NL_ERR(bond_dev, extack,
       "Device type (master device) cannot be enslaved");
  return -EPERM;
 }

 if (!bond->params.use_carrier &&
     slave_dev->ethtool_ops->get_link == NULL &&
     slave_ops->ndo_eth_ioctl == NULL) {
  slave_warn(bond_dev, slave_dev, "no link monitoring support\n");
 }

 /* already in-use? */
 if (netdev_is_rx_handler_busy(slave_dev)) {
  SLAVE_NL_ERR(bond_dev, slave_dev, extack,
        "Device is in use and cannot be enslaved");
  return -EBUSY;
 }

 if (bond_dev == slave_dev) {
  BOND_NL_ERR(bond_dev, extack, "Cannot enslave bond to itself.");
  return -EPERM;
 }

 /* vlan challenged mutual exclusion */
 /* no need to lock since we're protected by rtnl_lock */
 if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) {
  slave_dbg(bond_dev, slave_dev, "is NETIF_F_VLAN_CHALLENGED\n");
  if (vlan_uses_dev(bond_dev)) {
   SLAVE_NL_ERR(bond_dev, slave_dev, extack,
         "Can not enslave VLAN challenged device to VLAN enabled bond");
   return -EPERM;
  } else {
   slave_warn(bond_dev, slave_dev, "enslaved VLAN challenged slave. Adding VLANs will be blocked as long as it is part of bond.\n");
  }
 } else {
  slave_dbg(bond_dev, slave_dev, "is !NETIF_F_VLAN_CHALLENGED\n");
 }

 if (slave_dev->features & NETIF_F_HW_ESP)
  slave_dbg(bond_dev, slave_dev, "is esp-hw-offload capable\n");

 /* Old ifenslave binaries are no longer supported.  These can
 * be identified with moderate accuracy by the state of the slave:
 * the current ifenslave will set the interface down prior to
 * enslaving it; the old ifenslave will not.
 */

 if (slave_dev->flags & IFF_UP) {
  SLAVE_NL_ERR(bond_dev, slave_dev, extack,
        "Device can not be enslaved while up");
  return -EPERM;
 }

 /* set bonding device ether type by slave - bonding netdevices are
 * created with ether_setup, so when the slave type is not ARPHRD_ETHER
 * there is a need to override some of the type dependent attribs/funcs.
 *
 * bond ether type mutual exclusion - don't allow slaves of dissimilar
 * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond
 */

 if (!bond_has_slaves(bond)) {
  if (bond_dev->type != slave_dev->type) {
   slave_dbg(bond_dev, slave_dev, "change device type from %d to %d\n",
      bond_dev->type, slave_dev->type);

   res = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
             bond_dev);
   res = notifier_to_errno(res);
   if (res) {
    slave_err(bond_dev, slave_dev, "refused to change device type\n");
    return -EBUSY;
   }

   /* Flush unicast and multicast addresses */
   dev_uc_flush(bond_dev);
   dev_mc_flush(bond_dev);

   if (slave_dev->type != ARPHRD_ETHER)
    bond_setup_by_slave(bond_dev, slave_dev);
   else
    bond_ether_setup(bond_dev);

   call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
       bond_dev);
  }
 } else if (bond_dev->type != slave_dev->type) {
  SLAVE_NL_ERR(bond_dev, slave_dev, extack,
        "Device type is different from other slaves");
  return -EINVAL;
 }

 if (slave_dev->type == ARPHRD_INFINIBAND &&
     BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
  SLAVE_NL_ERR(bond_dev, slave_dev, extack,
        "Only active-backup mode is supported for infiniband slaves");
  res = -EOPNOTSUPP;
  goto err_undo_flags;
 }

 if (!slave_ops->ndo_set_mac_address ||
     slave_dev->type == ARPHRD_INFINIBAND) {
  slave_warn(bond_dev, slave_dev, "The slave device specified does not support setting the MAC address\n");
  if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
      bond->params.fail_over_mac != BOND_FOM_ACTIVE) {
   if (!bond_has_slaves(bond)) {
    bond->params.fail_over_mac = BOND_FOM_ACTIVE;
    slave_warn(bond_dev, slave_dev, "Setting fail_over_mac to active for active-backup mode\n");
   } else {
    SLAVE_NL_ERR(bond_dev, slave_dev, extack,
          "Slave device does not support setting the MAC address, but fail_over_mac is not set to active");
    res = -EOPNOTSUPP;
    goto err_undo_flags;
   }
  }
 }

 call_netdevice_notifiers(NETDEV_JOIN, slave_dev);

 /* If this is the first slave, then we need to set the master's hardware
 * address to be the same as the slave's.
 */

 if (!bond_has_slaves(bond) &&
     bond->dev->addr_assign_type == NET_ADDR_RANDOM) {
  res = bond_set_dev_addr(bond->dev, slave_dev);
  if (res)
   goto err_undo_flags;
 }

 new_slave = bond_alloc_slave(bond, slave_dev);
 if (!new_slave) {
  res = -ENOMEM;
  goto err_undo_flags;
 }

 /* Set the new_slave's queue_id to be zero.  Queue ID mapping
 * is set via sysfs or module option if desired.
 */

 new_slave->queue_id = 0;

 /* Save slave's original mtu and then set it to match the bond */
 new_slave->original_mtu = slave_dev->mtu;
 res = dev_set_mtu(slave_dev, bond->dev->mtu);
 if (res) {
  slave_err(bond_dev, slave_dev, "Error %d calling dev_set_mtu\n", res);
  goto err_free;
 }

 /* Save slave's original ("permanent") mac address for modes
 * that need it, and for restoring it upon release, and then
 * set it to the master's address
 */

 bond_hw_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr,
     slave_dev->addr_len);

 if (!bond->params.fail_over_mac ||
     BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) {
  /* Set slave to master's mac address.  The application already
 * set the master's mac address to that of the first slave
 */

  memcpy(ss.__data, bond_dev->dev_addr, bond_dev->addr_len);
 } else if (bond->params.fail_over_mac == BOND_FOM_FOLLOW &&
     BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
     bond_has_slaves(bond) &&
     memcmp(slave_dev->dev_addr, bond_dev->dev_addr, bond_dev->addr_len) == 0) {
  /* Set slave to random address to avoid duplicate mac
 * address in later fail over.
 */

  eth_random_addr(ss.__data);
 } else {
  goto skip_mac_set;
 }

 ss.ss_family = slave_dev->type;
 res = dev_set_mac_address(slave_dev, &ss, extack);
 if (res) {
  slave_err(bond_dev, slave_dev, "Error %d calling set_mac_address\n", res);
  goto err_restore_mtu;
 }

skip_mac_set:

 /* set no_addrconf flag before open to prevent IPv6 addrconf */
 slave_dev->priv_flags |= IFF_NO_ADDRCONF;

 /* open the slave since the application closed it */
 res = dev_open(slave_dev, extack);
 if (res) {
  slave_err(bond_dev, slave_dev, "Opening slave failed\n");
  goto err_restore_mac;
 }

 slave_dev->priv_flags |= IFF_BONDING;
 /* initialize slave stats */
 dev_get_stats(new_slave->dev, &new_slave->slave_stats);

 if (bond_is_lb(bond)) {
  /* bond_alb_init_slave() must be called before all other stages since
 * it might fail and we do not want to have to undo everything
 */

  res = bond_alb_init_slave(bond, new_slave);
  if (res)
   goto err_close;
 }

 res = vlan_vids_add_by_dev(slave_dev, bond_dev);
 if (res) {
  slave_err(bond_dev, slave_dev, "Couldn't add bond vlan ids\n");
  goto err_close;
 }

 prev_slave = bond_last_slave(bond);

 new_slave->delay = 0;
 new_slave->link_failure_count = 0;

 if (bond_update_speed_duplex(new_slave) &&
     bond_needs_speed_duplex(bond))
  new_slave->link = BOND_LINK_DOWN;

 new_slave->last_rx = jiffies -
  (msecs_to_jiffies(bond->params.arp_interval) + 1);
 for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
  new_slave->target_last_arp_rx[i] = new_slave->last_rx;

 new_slave->last_tx = new_slave->last_rx;

 if (bond->params.miimon && !bond->params.use_carrier) {
  link_reporting = bond_check_dev_link(bond, slave_dev, 1);

  if ((link_reporting == -1) && !bond->params.arp_interval) {
   /* miimon is set but a bonded network driver
 * does not support ETHTOOL/MII and
 * arp_interval is not set.  Note: if
 * use_carrier is enabled, we will never go
 * here (because netif_carrier is always
 * supported); thus, we don't need to change
 * the messages for netif_carrier.
 */

   slave_warn(bond_dev, slave_dev, "MII and ETHTOOL support not available for slave, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n");
  } else if (link_reporting == -1) {
   /* unable get link status using mii/ethtool */
   slave_warn(bond_dev, slave_dev, "can't get link status from slave; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n");
  }
 }

 /* check for initial state */
 new_slave->link = BOND_LINK_NOCHANGE;
 if (bond->params.miimon) {
  if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) {
   if (bond->params.updelay) {
    bond_set_slave_link_state(new_slave,
         BOND_LINK_BACK,
         BOND_SLAVE_NOTIFY_NOW);
    new_slave->delay = bond->params.updelay;
   } else {
    bond_set_slave_link_state(new_slave,
         BOND_LINK_UP,
         BOND_SLAVE_NOTIFY_NOW);
   }
  } else {
   bond_set_slave_link_state(new_slave, BOND_LINK_DOWN,
        BOND_SLAVE_NOTIFY_NOW);
  }
 } else if (bond->params.arp_interval) {
  bond_set_slave_link_state(new_slave,
       (netif_carrier_ok(slave_dev) ?
       BOND_LINK_UP : BOND_LINK_DOWN),
       BOND_SLAVE_NOTIFY_NOW);
 } else {
  bond_set_slave_link_state(new_slave, BOND_LINK_UP,
       BOND_SLAVE_NOTIFY_NOW);
 }

 if (new_slave->link != BOND_LINK_DOWN)
  new_slave->last_link_up = jiffies;
 slave_dbg(bond_dev, slave_dev, "Initial state of slave is BOND_LINK_%s\n",
    new_slave->link == BOND_LINK_DOWN ? "DOWN" :
    (new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));

 if (bond_uses_primary(bond) && bond->params.primary[0]) {
  /* if there is a primary slave, remember it */
  if (strcmp(bond->params.primary, new_slave->dev->name) == 0) {
   rcu_assign_pointer(bond->primary_slave, new_slave);
   bond->force_primary = true;
  }
 }

 switch (BOND_MODE(bond)) {
 case BOND_MODE_ACTIVEBACKUP:
  bond_set_slave_inactive_flags(new_slave,
           BOND_SLAVE_NOTIFY_NOW);
  break;
 case BOND_MODE_8023AD:
  /* in 802.3ad mode, the internal mechanism
 * will activate the slaves in the selected
 * aggregator
 */

  bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
  /* if this is the first slave */
  if (!prev_slave) {
   SLAVE_AD_INFO(new_slave)->id = 1;
   /* Initialize AD with the number of times that the AD timer is called in 1 second
 * can be called only after the mac address of the bond is set
 */

   bond_3ad_initialize(bond);
  } else {
   SLAVE_AD_INFO(new_slave)->id =
    SLAVE_AD_INFO(prev_slave)->id + 1;
  }

  bond_3ad_bind_slave(new_slave);
  break;
 case BOND_MODE_TLB:
 case BOND_MODE_ALB:
  bond_set_active_slave(new_slave);
  bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW);
  break;
 default:
  slave_dbg(bond_dev, slave_dev, "This slave is always active in trunk mode\n");

  /* always active in trunk mode */
  bond_set_active_slave(new_slave);

  /* In trunking mode there is little meaning to curr_active_slave
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=88 G=91

¤ Dauer der Verarbeitung: 0.69 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.