162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * originally based on the dummy device. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 1999, Thomas Davis, tadavis@lbl.gov. 662306a36Sopenharmony_ci * Based on dummy.c, and eql.c devices. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * bonding.c: an Ethernet Bonding driver 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This is useful to talk to a Cisco EtherChannel compatible equipment: 1162306a36Sopenharmony_ci * Cisco 5500 1262306a36Sopenharmony_ci * Sun Trunking (Solaris) 1362306a36Sopenharmony_ci * Alteon AceDirector Trunks 1462306a36Sopenharmony_ci * Linux Bonding 1562306a36Sopenharmony_ci * and probably many L2 switches ... 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * How it works: 1862306a36Sopenharmony_ci * ifconfig bond0 ipaddress netmask up 1962306a36Sopenharmony_ci * will setup a network device, with an ip address. No mac address 2062306a36Sopenharmony_ci * will be assigned at this time. The hw mac address will come from 2162306a36Sopenharmony_ci * the first slave bonded to the channel. All slaves will then use 2262306a36Sopenharmony_ci * this hw mac address. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * ifconfig bond0 down 2562306a36Sopenharmony_ci * will release all slaves, marking them as down. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * ifenslave bond0 eth0 2862306a36Sopenharmony_ci * will attach eth0 to bond0 as a slave. eth0 hw mac address will either 2962306a36Sopenharmony_ci * a: be used as initial mac address 3062306a36Sopenharmony_ci * b: if a hw mac address already is there, eth0's hw mac address 3162306a36Sopenharmony_ci * will then be set from bond0. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/kernel.h> 3662306a36Sopenharmony_ci#include <linux/module.h> 3762306a36Sopenharmony_ci#include <linux/types.h> 3862306a36Sopenharmony_ci#include <linux/fcntl.h> 3962306a36Sopenharmony_ci#include <linux/filter.h> 4062306a36Sopenharmony_ci#include <linux/interrupt.h> 4162306a36Sopenharmony_ci#include <linux/ptrace.h> 4262306a36Sopenharmony_ci#include <linux/ioport.h> 4362306a36Sopenharmony_ci#include <linux/in.h> 4462306a36Sopenharmony_ci#include <net/ip.h> 4562306a36Sopenharmony_ci#include <linux/ip.h> 4662306a36Sopenharmony_ci#include <linux/icmp.h> 4762306a36Sopenharmony_ci#include <linux/icmpv6.h> 4862306a36Sopenharmony_ci#include <linux/tcp.h> 4962306a36Sopenharmony_ci#include <linux/udp.h> 5062306a36Sopenharmony_ci#include <linux/slab.h> 5162306a36Sopenharmony_ci#include <linux/string.h> 5262306a36Sopenharmony_ci#include <linux/init.h> 5362306a36Sopenharmony_ci#include <linux/timer.h> 5462306a36Sopenharmony_ci#include <linux/socket.h> 5562306a36Sopenharmony_ci#include <linux/ctype.h> 5662306a36Sopenharmony_ci#include <linux/inet.h> 5762306a36Sopenharmony_ci#include <linux/bitops.h> 5862306a36Sopenharmony_ci#include <linux/io.h> 5962306a36Sopenharmony_ci#include <asm/dma.h> 6062306a36Sopenharmony_ci#include <linux/uaccess.h> 6162306a36Sopenharmony_ci#include <linux/errno.h> 6262306a36Sopenharmony_ci#include <linux/netdevice.h> 6362306a36Sopenharmony_ci#include <linux/inetdevice.h> 6462306a36Sopenharmony_ci#include <linux/igmp.h> 6562306a36Sopenharmony_ci#include <linux/etherdevice.h> 6662306a36Sopenharmony_ci#include <linux/skbuff.h> 6762306a36Sopenharmony_ci#include <net/sock.h> 6862306a36Sopenharmony_ci#include <linux/rtnetlink.h> 6962306a36Sopenharmony_ci#include <linux/smp.h> 7062306a36Sopenharmony_ci#include <linux/if_ether.h> 7162306a36Sopenharmony_ci#include <net/arp.h> 7262306a36Sopenharmony_ci#include <linux/mii.h> 7362306a36Sopenharmony_ci#include <linux/ethtool.h> 7462306a36Sopenharmony_ci#include <linux/if_vlan.h> 7562306a36Sopenharmony_ci#include <linux/if_bonding.h> 7662306a36Sopenharmony_ci#include <linux/phy.h> 7762306a36Sopenharmony_ci#include <linux/jiffies.h> 7862306a36Sopenharmony_ci#include <linux/preempt.h> 7962306a36Sopenharmony_ci#include <net/route.h> 8062306a36Sopenharmony_ci#include <net/net_namespace.h> 8162306a36Sopenharmony_ci#include <net/netns/generic.h> 8262306a36Sopenharmony_ci#include <net/pkt_sched.h> 8362306a36Sopenharmony_ci#include <linux/rculist.h> 8462306a36Sopenharmony_ci#include <net/flow_dissector.h> 8562306a36Sopenharmony_ci#include <net/xfrm.h> 8662306a36Sopenharmony_ci#include <net/bonding.h> 8762306a36Sopenharmony_ci#include <net/bond_3ad.h> 8862306a36Sopenharmony_ci#include <net/bond_alb.h> 8962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_TLS_DEVICE) 9062306a36Sopenharmony_ci#include <net/tls.h> 9162306a36Sopenharmony_ci#endif 9262306a36Sopenharmony_ci#include <net/ip6_route.h> 9362306a36Sopenharmony_ci#include <net/xdp.h> 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#include "bonding_priv.h" 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/*---------------------------- Module parameters ----------------------------*/ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* monitor all links that often (in milliseconds). <=0 disables monitoring */ 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int max_bonds = BOND_DEFAULT_MAX_BONDS; 10262306a36Sopenharmony_cistatic int tx_queues = BOND_DEFAULT_TX_QUEUES; 10362306a36Sopenharmony_cistatic int num_peer_notif = 1; 10462306a36Sopenharmony_cistatic int miimon; 10562306a36Sopenharmony_cistatic int updelay; 10662306a36Sopenharmony_cistatic int downdelay; 10762306a36Sopenharmony_cistatic int use_carrier = 1; 10862306a36Sopenharmony_cistatic char *mode; 10962306a36Sopenharmony_cistatic char *primary; 11062306a36Sopenharmony_cistatic char *primary_reselect; 11162306a36Sopenharmony_cistatic char *lacp_rate; 11262306a36Sopenharmony_cistatic int min_links; 11362306a36Sopenharmony_cistatic char *ad_select; 11462306a36Sopenharmony_cistatic char *xmit_hash_policy; 11562306a36Sopenharmony_cistatic int arp_interval; 11662306a36Sopenharmony_cistatic char *arp_ip_target[BOND_MAX_ARP_TARGETS]; 11762306a36Sopenharmony_cistatic char *arp_validate; 11862306a36Sopenharmony_cistatic char *arp_all_targets; 11962306a36Sopenharmony_cistatic char *fail_over_mac; 12062306a36Sopenharmony_cistatic int all_slaves_active; 12162306a36Sopenharmony_cistatic struct bond_params bonding_defaults; 12262306a36Sopenharmony_cistatic int resend_igmp = BOND_DEFAULT_RESEND_IGMP; 12362306a36Sopenharmony_cistatic int packets_per_slave = 1; 12462306a36Sopenharmony_cistatic int lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cimodule_param(max_bonds, int, 0); 12762306a36Sopenharmony_ciMODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); 12862306a36Sopenharmony_cimodule_param(tx_queues, int, 0); 12962306a36Sopenharmony_ciMODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)"); 13062306a36Sopenharmony_cimodule_param_named(num_grat_arp, num_peer_notif, int, 0644); 13162306a36Sopenharmony_ciMODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on " 13262306a36Sopenharmony_ci "failover event (alias of num_unsol_na)"); 13362306a36Sopenharmony_cimodule_param_named(num_unsol_na, num_peer_notif, int, 0644); 13462306a36Sopenharmony_ciMODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on " 13562306a36Sopenharmony_ci "failover event (alias of num_grat_arp)"); 13662306a36Sopenharmony_cimodule_param(miimon, int, 0); 13762306a36Sopenharmony_ciMODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); 13862306a36Sopenharmony_cimodule_param(updelay, int, 0); 13962306a36Sopenharmony_ciMODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); 14062306a36Sopenharmony_cimodule_param(downdelay, int, 0); 14162306a36Sopenharmony_ciMODULE_PARM_DESC(downdelay, "Delay before considering link down, " 14262306a36Sopenharmony_ci "in milliseconds"); 14362306a36Sopenharmony_cimodule_param(use_carrier, int, 0); 14462306a36Sopenharmony_ciMODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; " 14562306a36Sopenharmony_ci "0 for off, 1 for on (default)"); 14662306a36Sopenharmony_cimodule_param(mode, charp, 0); 14762306a36Sopenharmony_ciMODULE_PARM_DESC(mode, "Mode of operation; 0 for balance-rr, " 14862306a36Sopenharmony_ci "1 for active-backup, 2 for balance-xor, " 14962306a36Sopenharmony_ci "3 for broadcast, 4 for 802.3ad, 5 for balance-tlb, " 15062306a36Sopenharmony_ci "6 for balance-alb"); 15162306a36Sopenharmony_cimodule_param(primary, charp, 0); 15262306a36Sopenharmony_ciMODULE_PARM_DESC(primary, "Primary network device to use"); 15362306a36Sopenharmony_cimodule_param(primary_reselect, charp, 0); 15462306a36Sopenharmony_ciMODULE_PARM_DESC(primary_reselect, "Reselect primary slave " 15562306a36Sopenharmony_ci "once it comes up; " 15662306a36Sopenharmony_ci "0 for always (default), " 15762306a36Sopenharmony_ci "1 for only if speed of primary is " 15862306a36Sopenharmony_ci "better, " 15962306a36Sopenharmony_ci "2 for only on active slave " 16062306a36Sopenharmony_ci "failure"); 16162306a36Sopenharmony_cimodule_param(lacp_rate, charp, 0); 16262306a36Sopenharmony_ciMODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner; " 16362306a36Sopenharmony_ci "0 for slow, 1 for fast"); 16462306a36Sopenharmony_cimodule_param(ad_select, charp, 0); 16562306a36Sopenharmony_ciMODULE_PARM_DESC(ad_select, "802.3ad aggregation selection logic; " 16662306a36Sopenharmony_ci "0 for stable (default), 1 for bandwidth, " 16762306a36Sopenharmony_ci "2 for count"); 16862306a36Sopenharmony_cimodule_param(min_links, int, 0); 16962306a36Sopenharmony_ciMODULE_PARM_DESC(min_links, "Minimum number of available links before turning on carrier"); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cimodule_param(xmit_hash_policy, charp, 0); 17262306a36Sopenharmony_ciMODULE_PARM_DESC(xmit_hash_policy, "balance-alb, balance-tlb, balance-xor, 802.3ad hashing method; " 17362306a36Sopenharmony_ci "0 for layer 2 (default), 1 for layer 3+4, " 17462306a36Sopenharmony_ci "2 for layer 2+3, 3 for encap layer 2+3, " 17562306a36Sopenharmony_ci "4 for encap layer 3+4, 5 for vlan+srcmac"); 17662306a36Sopenharmony_cimodule_param(arp_interval, int, 0); 17762306a36Sopenharmony_ciMODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); 17862306a36Sopenharmony_cimodule_param_array(arp_ip_target, charp, NULL, 0); 17962306a36Sopenharmony_ciMODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); 18062306a36Sopenharmony_cimodule_param(arp_validate, charp, 0); 18162306a36Sopenharmony_ciMODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes; " 18262306a36Sopenharmony_ci "0 for none (default), 1 for active, " 18362306a36Sopenharmony_ci "2 for backup, 3 for all"); 18462306a36Sopenharmony_cimodule_param(arp_all_targets, charp, 0); 18562306a36Sopenharmony_ciMODULE_PARM_DESC(arp_all_targets, "fail on any/all arp targets timeout; 0 for any (default), 1 for all"); 18662306a36Sopenharmony_cimodule_param(fail_over_mac, charp, 0); 18762306a36Sopenharmony_ciMODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to " 18862306a36Sopenharmony_ci "the same MAC; 0 for none (default), " 18962306a36Sopenharmony_ci "1 for active, 2 for follow"); 19062306a36Sopenharmony_cimodule_param(all_slaves_active, int, 0); 19162306a36Sopenharmony_ciMODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface " 19262306a36Sopenharmony_ci "by setting active flag for all slaves; " 19362306a36Sopenharmony_ci "0 for never (default), 1 for always."); 19462306a36Sopenharmony_cimodule_param(resend_igmp, int, 0); 19562306a36Sopenharmony_ciMODULE_PARM_DESC(resend_igmp, "Number of IGMP membership reports to send on " 19662306a36Sopenharmony_ci "link failure"); 19762306a36Sopenharmony_cimodule_param(packets_per_slave, int, 0); 19862306a36Sopenharmony_ciMODULE_PARM_DESC(packets_per_slave, "Packets to send per slave in balance-rr " 19962306a36Sopenharmony_ci "mode; 0 for a random slave, 1 packet per " 20062306a36Sopenharmony_ci "slave (default), >1 packets per slave."); 20162306a36Sopenharmony_cimodule_param(lp_interval, uint, 0); 20262306a36Sopenharmony_ciMODULE_PARM_DESC(lp_interval, "The number of seconds between instances where " 20362306a36Sopenharmony_ci "the bonding driver sends learning packets to " 20462306a36Sopenharmony_ci "each slaves peer switch. The default is 1."); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/*----------------------------- Global variables ----------------------------*/ 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 20962306a36Sopenharmony_ciatomic_t netpoll_block_tx = ATOMIC_INIT(0); 21062306a36Sopenharmony_ci#endif 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ciunsigned int bond_net_id __read_mostly; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic const struct flow_dissector_key flow_keys_bonding_keys[] = { 21562306a36Sopenharmony_ci { 21662306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_CONTROL, 21762306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, control), 21862306a36Sopenharmony_ci }, 21962306a36Sopenharmony_ci { 22062306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_BASIC, 22162306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, basic), 22262306a36Sopenharmony_ci }, 22362306a36Sopenharmony_ci { 22462306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, 22562306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, addrs.v4addrs), 22662306a36Sopenharmony_ci }, 22762306a36Sopenharmony_ci { 22862306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, 22962306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, addrs.v6addrs), 23062306a36Sopenharmony_ci }, 23162306a36Sopenharmony_ci { 23262306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_TIPC, 23362306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, addrs.tipckey), 23462306a36Sopenharmony_ci }, 23562306a36Sopenharmony_ci { 23662306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_PORTS, 23762306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, ports), 23862306a36Sopenharmony_ci }, 23962306a36Sopenharmony_ci { 24062306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_ICMP, 24162306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, icmp), 24262306a36Sopenharmony_ci }, 24362306a36Sopenharmony_ci { 24462306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_VLAN, 24562306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, vlan), 24662306a36Sopenharmony_ci }, 24762306a36Sopenharmony_ci { 24862306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL, 24962306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, tags), 25062306a36Sopenharmony_ci }, 25162306a36Sopenharmony_ci { 25262306a36Sopenharmony_ci .key_id = FLOW_DISSECTOR_KEY_GRE_KEYID, 25362306a36Sopenharmony_ci .offset = offsetof(struct flow_keys, keyid), 25462306a36Sopenharmony_ci }, 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic struct flow_dissector flow_keys_bonding __read_mostly; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/*-------------------------- Forward declarations ---------------------------*/ 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int bond_init(struct net_device *bond_dev); 26262306a36Sopenharmony_cistatic void bond_uninit(struct net_device *bond_dev); 26362306a36Sopenharmony_cistatic void bond_get_stats(struct net_device *bond_dev, 26462306a36Sopenharmony_ci struct rtnl_link_stats64 *stats); 26562306a36Sopenharmony_cistatic void bond_slave_arr_handler(struct work_struct *work); 26662306a36Sopenharmony_cistatic bool bond_time_in_interval(struct bonding *bond, unsigned long last_act, 26762306a36Sopenharmony_ci int mod); 26862306a36Sopenharmony_cistatic void bond_netdev_notify_work(struct work_struct *work); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/*---------------------------- General routines -----------------------------*/ 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ciconst char *bond_mode_name(int mode) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci static const char *names[] = { 27562306a36Sopenharmony_ci [BOND_MODE_ROUNDROBIN] = "load balancing (round-robin)", 27662306a36Sopenharmony_ci [BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)", 27762306a36Sopenharmony_ci [BOND_MODE_XOR] = "load balancing (xor)", 27862306a36Sopenharmony_ci [BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)", 27962306a36Sopenharmony_ci [BOND_MODE_8023AD] = "IEEE 802.3ad Dynamic link aggregation", 28062306a36Sopenharmony_ci [BOND_MODE_TLB] = "transmit load balancing", 28162306a36Sopenharmony_ci [BOND_MODE_ALB] = "adaptive load balancing", 28262306a36Sopenharmony_ci }; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_ALB) 28562306a36Sopenharmony_ci return "unknown"; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci return names[mode]; 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci/** 29162306a36Sopenharmony_ci * bond_dev_queue_xmit - Prepare skb for xmit. 29262306a36Sopenharmony_ci * 29362306a36Sopenharmony_ci * @bond: bond device that got this skb for tx. 29462306a36Sopenharmony_ci * @skb: hw accel VLAN tagged skb to transmit 29562306a36Sopenharmony_ci * @slave_dev: slave that is supposed to xmit this skbuff 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cinetdev_tx_t bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, 29862306a36Sopenharmony_ci struct net_device *slave_dev) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci skb->dev = slave_dev; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(skb->queue_mapping) != 30362306a36Sopenharmony_ci sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping)); 30462306a36Sopenharmony_ci skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (unlikely(netpoll_tx_running(bond->dev))) 30762306a36Sopenharmony_ci return bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return dev_queue_xmit(skb); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic bool bond_sk_check(struct bonding *bond) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 31562306a36Sopenharmony_ci case BOND_MODE_8023AD: 31662306a36Sopenharmony_ci case BOND_MODE_XOR: 31762306a36Sopenharmony_ci if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) 31862306a36Sopenharmony_ci return true; 31962306a36Sopenharmony_ci fallthrough; 32062306a36Sopenharmony_ci default: 32162306a36Sopenharmony_ci return false; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic bool bond_xdp_check(struct bonding *bond) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 32862306a36Sopenharmony_ci case BOND_MODE_ROUNDROBIN: 32962306a36Sopenharmony_ci case BOND_MODE_ACTIVEBACKUP: 33062306a36Sopenharmony_ci return true; 33162306a36Sopenharmony_ci case BOND_MODE_8023AD: 33262306a36Sopenharmony_ci case BOND_MODE_XOR: 33362306a36Sopenharmony_ci /* vlan+srcmac is not supported with XDP as in most cases the 802.1q 33462306a36Sopenharmony_ci * payload is not in the packet due to hardware offload. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if (bond->params.xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC) 33762306a36Sopenharmony_ci return true; 33862306a36Sopenharmony_ci fallthrough; 33962306a36Sopenharmony_ci default: 34062306a36Sopenharmony_ci return false; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/*---------------------------------- VLAN -----------------------------------*/ 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* In the following 2 functions, bond_vlan_rx_add_vid and bond_vlan_rx_kill_vid, 34762306a36Sopenharmony_ci * We don't protect the slave list iteration with a lock because: 34862306a36Sopenharmony_ci * a. This operation is performed in IOCTL context, 34962306a36Sopenharmony_ci * b. The operation is protected by the RTNL semaphore in the 8021q code, 35062306a36Sopenharmony_ci * c. Holding a lock with BH disabled while directly calling a base driver 35162306a36Sopenharmony_ci * entry point is generally a BAD idea. 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * The design of synchronization/protection for this operation in the 8021q 35462306a36Sopenharmony_ci * module is good for one or more VLAN devices over a single physical device 35562306a36Sopenharmony_ci * and cannot be extended for a teaming solution like bonding, so there is a 35662306a36Sopenharmony_ci * potential race condition here where a net device from the vlan group might 35762306a36Sopenharmony_ci * be referenced (either by a base driver or the 8021q code) while it is being 35862306a36Sopenharmony_ci * removed from the system. However, it turns out we're not making matters 35962306a36Sopenharmony_ci * worse, and if it works for regular VLAN usage it will work here too. 36062306a36Sopenharmony_ci*/ 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/** 36362306a36Sopenharmony_ci * bond_vlan_rx_add_vid - Propagates adding an id to slaves 36462306a36Sopenharmony_ci * @bond_dev: bonding net device that got called 36562306a36Sopenharmony_ci * @proto: network protocol ID 36662306a36Sopenharmony_ci * @vid: vlan id being added 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_cistatic int bond_vlan_rx_add_vid(struct net_device *bond_dev, 36962306a36Sopenharmony_ci __be16 proto, u16 vid) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 37262306a36Sopenharmony_ci struct slave *slave, *rollback_slave; 37362306a36Sopenharmony_ci struct list_head *iter; 37462306a36Sopenharmony_ci int res; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 37762306a36Sopenharmony_ci res = vlan_vid_add(slave->dev, proto, vid); 37862306a36Sopenharmony_ci if (res) 37962306a36Sopenharmony_ci goto unwind; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ciunwind: 38562306a36Sopenharmony_ci /* unwind to the slave that failed */ 38662306a36Sopenharmony_ci bond_for_each_slave(bond, rollback_slave, iter) { 38762306a36Sopenharmony_ci if (rollback_slave == slave) 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci vlan_vid_del(rollback_slave->dev, proto, vid); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return res; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/** 39762306a36Sopenharmony_ci * bond_vlan_rx_kill_vid - Propagates deleting an id to slaves 39862306a36Sopenharmony_ci * @bond_dev: bonding net device that got called 39962306a36Sopenharmony_ci * @proto: network protocol ID 40062306a36Sopenharmony_ci * @vid: vlan id being removed 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_cistatic int bond_vlan_rx_kill_vid(struct net_device *bond_dev, 40362306a36Sopenharmony_ci __be16 proto, u16 vid) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 40662306a36Sopenharmony_ci struct list_head *iter; 40762306a36Sopenharmony_ci struct slave *slave; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) 41062306a36Sopenharmony_ci vlan_vid_del(slave->dev, proto, vid); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (bond_is_lb(bond)) 41362306a36Sopenharmony_ci bond_alb_clear_vlan(bond, vid); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/*---------------------------------- XFRM -----------------------------------*/ 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 42162306a36Sopenharmony_ci/** 42262306a36Sopenharmony_ci * bond_ipsec_add_sa - program device with a security association 42362306a36Sopenharmony_ci * @xs: pointer to transformer state struct 42462306a36Sopenharmony_ci * @extack: extack point to fill failure reason 42562306a36Sopenharmony_ci **/ 42662306a36Sopenharmony_cistatic int bond_ipsec_add_sa(struct xfrm_state *xs, 42762306a36Sopenharmony_ci struct netlink_ext_ack *extack) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci struct net_device *bond_dev = xs->xso.dev; 43062306a36Sopenharmony_ci struct bond_ipsec *ipsec; 43162306a36Sopenharmony_ci struct bonding *bond; 43262306a36Sopenharmony_ci struct slave *slave; 43362306a36Sopenharmony_ci int err; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci if (!bond_dev) 43662306a36Sopenharmony_ci return -EINVAL; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci rcu_read_lock(); 43962306a36Sopenharmony_ci bond = netdev_priv(bond_dev); 44062306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 44162306a36Sopenharmony_ci if (!slave) { 44262306a36Sopenharmony_ci rcu_read_unlock(); 44362306a36Sopenharmony_ci return -ENODEV; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (!slave->dev->xfrmdev_ops || 44762306a36Sopenharmony_ci !slave->dev->xfrmdev_ops->xdo_dev_state_add || 44862306a36Sopenharmony_ci netif_is_bond_master(slave->dev)) { 44962306a36Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Slave does not support ipsec offload"); 45062306a36Sopenharmony_ci rcu_read_unlock(); 45162306a36Sopenharmony_ci return -EINVAL; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci ipsec = kmalloc(sizeof(*ipsec), GFP_ATOMIC); 45562306a36Sopenharmony_ci if (!ipsec) { 45662306a36Sopenharmony_ci rcu_read_unlock(); 45762306a36Sopenharmony_ci return -ENOMEM; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci xs->xso.real_dev = slave->dev; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci err = slave->dev->xfrmdev_ops->xdo_dev_state_add(xs, extack); 46262306a36Sopenharmony_ci if (!err) { 46362306a36Sopenharmony_ci ipsec->xs = xs; 46462306a36Sopenharmony_ci INIT_LIST_HEAD(&ipsec->list); 46562306a36Sopenharmony_ci spin_lock_bh(&bond->ipsec_lock); 46662306a36Sopenharmony_ci list_add(&ipsec->list, &bond->ipsec_list); 46762306a36Sopenharmony_ci spin_unlock_bh(&bond->ipsec_lock); 46862306a36Sopenharmony_ci } else { 46962306a36Sopenharmony_ci kfree(ipsec); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci rcu_read_unlock(); 47262306a36Sopenharmony_ci return err; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic void bond_ipsec_add_sa_all(struct bonding *bond) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct net_device *bond_dev = bond->dev; 47862306a36Sopenharmony_ci struct bond_ipsec *ipsec; 47962306a36Sopenharmony_ci struct slave *slave; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci rcu_read_lock(); 48262306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 48362306a36Sopenharmony_ci if (!slave) 48462306a36Sopenharmony_ci goto out; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (!slave->dev->xfrmdev_ops || 48762306a36Sopenharmony_ci !slave->dev->xfrmdev_ops->xdo_dev_state_add || 48862306a36Sopenharmony_ci netif_is_bond_master(slave->dev)) { 48962306a36Sopenharmony_ci spin_lock_bh(&bond->ipsec_lock); 49062306a36Sopenharmony_ci if (!list_empty(&bond->ipsec_list)) 49162306a36Sopenharmony_ci slave_warn(bond_dev, slave->dev, 49262306a36Sopenharmony_ci "%s: no slave xdo_dev_state_add\n", 49362306a36Sopenharmony_ci __func__); 49462306a36Sopenharmony_ci spin_unlock_bh(&bond->ipsec_lock); 49562306a36Sopenharmony_ci goto out; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci spin_lock_bh(&bond->ipsec_lock); 49962306a36Sopenharmony_ci list_for_each_entry(ipsec, &bond->ipsec_list, list) { 50062306a36Sopenharmony_ci ipsec->xs->xso.real_dev = slave->dev; 50162306a36Sopenharmony_ci if (slave->dev->xfrmdev_ops->xdo_dev_state_add(ipsec->xs, NULL)) { 50262306a36Sopenharmony_ci slave_warn(bond_dev, slave->dev, "%s: failed to add SA\n", __func__); 50362306a36Sopenharmony_ci ipsec->xs->xso.real_dev = NULL; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci spin_unlock_bh(&bond->ipsec_lock); 50762306a36Sopenharmony_ciout: 50862306a36Sopenharmony_ci rcu_read_unlock(); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/** 51262306a36Sopenharmony_ci * bond_ipsec_del_sa - clear out this specific SA 51362306a36Sopenharmony_ci * @xs: pointer to transformer state struct 51462306a36Sopenharmony_ci **/ 51562306a36Sopenharmony_cistatic void bond_ipsec_del_sa(struct xfrm_state *xs) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci struct net_device *bond_dev = xs->xso.dev; 51862306a36Sopenharmony_ci struct bond_ipsec *ipsec; 51962306a36Sopenharmony_ci struct bonding *bond; 52062306a36Sopenharmony_ci struct slave *slave; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (!bond_dev) 52362306a36Sopenharmony_ci return; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci rcu_read_lock(); 52662306a36Sopenharmony_ci bond = netdev_priv(bond_dev); 52762306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!slave) 53062306a36Sopenharmony_ci goto out; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (!xs->xso.real_dev) 53362306a36Sopenharmony_ci goto out; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci WARN_ON(xs->xso.real_dev != slave->dev); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (!slave->dev->xfrmdev_ops || 53862306a36Sopenharmony_ci !slave->dev->xfrmdev_ops->xdo_dev_state_delete || 53962306a36Sopenharmony_ci netif_is_bond_master(slave->dev)) { 54062306a36Sopenharmony_ci slave_warn(bond_dev, slave->dev, "%s: no slave xdo_dev_state_delete\n", __func__); 54162306a36Sopenharmony_ci goto out; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci slave->dev->xfrmdev_ops->xdo_dev_state_delete(xs); 54562306a36Sopenharmony_ciout: 54662306a36Sopenharmony_ci spin_lock_bh(&bond->ipsec_lock); 54762306a36Sopenharmony_ci list_for_each_entry(ipsec, &bond->ipsec_list, list) { 54862306a36Sopenharmony_ci if (ipsec->xs == xs) { 54962306a36Sopenharmony_ci list_del(&ipsec->list); 55062306a36Sopenharmony_ci kfree(ipsec); 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci spin_unlock_bh(&bond->ipsec_lock); 55562306a36Sopenharmony_ci rcu_read_unlock(); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic void bond_ipsec_del_sa_all(struct bonding *bond) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct net_device *bond_dev = bond->dev; 56162306a36Sopenharmony_ci struct bond_ipsec *ipsec; 56262306a36Sopenharmony_ci struct slave *slave; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci rcu_read_lock(); 56562306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 56662306a36Sopenharmony_ci if (!slave) { 56762306a36Sopenharmony_ci rcu_read_unlock(); 56862306a36Sopenharmony_ci return; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci spin_lock_bh(&bond->ipsec_lock); 57262306a36Sopenharmony_ci list_for_each_entry(ipsec, &bond->ipsec_list, list) { 57362306a36Sopenharmony_ci if (!ipsec->xs->xso.real_dev) 57462306a36Sopenharmony_ci continue; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (!slave->dev->xfrmdev_ops || 57762306a36Sopenharmony_ci !slave->dev->xfrmdev_ops->xdo_dev_state_delete || 57862306a36Sopenharmony_ci netif_is_bond_master(slave->dev)) { 57962306a36Sopenharmony_ci slave_warn(bond_dev, slave->dev, 58062306a36Sopenharmony_ci "%s: no slave xdo_dev_state_delete\n", 58162306a36Sopenharmony_ci __func__); 58262306a36Sopenharmony_ci } else { 58362306a36Sopenharmony_ci slave->dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs); 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci ipsec->xs->xso.real_dev = NULL; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci spin_unlock_bh(&bond->ipsec_lock); 58862306a36Sopenharmony_ci rcu_read_unlock(); 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci/** 59262306a36Sopenharmony_ci * bond_ipsec_offload_ok - can this packet use the xfrm hw offload 59362306a36Sopenharmony_ci * @skb: current data packet 59462306a36Sopenharmony_ci * @xs: pointer to transformer state struct 59562306a36Sopenharmony_ci **/ 59662306a36Sopenharmony_cistatic bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct net_device *bond_dev = xs->xso.dev; 59962306a36Sopenharmony_ci struct net_device *real_dev; 60062306a36Sopenharmony_ci struct slave *curr_active; 60162306a36Sopenharmony_ci struct bonding *bond; 60262306a36Sopenharmony_ci int err; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci bond = netdev_priv(bond_dev); 60562306a36Sopenharmony_ci rcu_read_lock(); 60662306a36Sopenharmony_ci curr_active = rcu_dereference(bond->curr_active_slave); 60762306a36Sopenharmony_ci real_dev = curr_active->dev; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { 61062306a36Sopenharmony_ci err = false; 61162306a36Sopenharmony_ci goto out; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (!xs->xso.real_dev) { 61562306a36Sopenharmony_ci err = false; 61662306a36Sopenharmony_ci goto out; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (!real_dev->xfrmdev_ops || 62062306a36Sopenharmony_ci !real_dev->xfrmdev_ops->xdo_dev_offload_ok || 62162306a36Sopenharmony_ci netif_is_bond_master(real_dev)) { 62262306a36Sopenharmony_ci err = false; 62362306a36Sopenharmony_ci goto out; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci err = real_dev->xfrmdev_ops->xdo_dev_offload_ok(skb, xs); 62762306a36Sopenharmony_ciout: 62862306a36Sopenharmony_ci rcu_read_unlock(); 62962306a36Sopenharmony_ci return err; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic const struct xfrmdev_ops bond_xfrmdev_ops = { 63362306a36Sopenharmony_ci .xdo_dev_state_add = bond_ipsec_add_sa, 63462306a36Sopenharmony_ci .xdo_dev_state_delete = bond_ipsec_del_sa, 63562306a36Sopenharmony_ci .xdo_dev_offload_ok = bond_ipsec_offload_ok, 63662306a36Sopenharmony_ci}; 63762306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci/*------------------------------- Link status -------------------------------*/ 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/* Set the carrier state for the master according to the state of its 64262306a36Sopenharmony_ci * slaves. If any slaves are up, the master is up. In 802.3ad mode, 64362306a36Sopenharmony_ci * do special 802.3ad magic. 64462306a36Sopenharmony_ci * 64562306a36Sopenharmony_ci * Returns zero if carrier state does not change, nonzero if it does. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ciint bond_set_carrier(struct bonding *bond) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci struct list_head *iter; 65062306a36Sopenharmony_ci struct slave *slave; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (!bond_has_slaves(bond)) 65362306a36Sopenharmony_ci goto down; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 65662306a36Sopenharmony_ci return bond_3ad_set_carrier(bond); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 65962306a36Sopenharmony_ci if (slave->link == BOND_LINK_UP) { 66062306a36Sopenharmony_ci if (!netif_carrier_ok(bond->dev)) { 66162306a36Sopenharmony_ci netif_carrier_on(bond->dev); 66262306a36Sopenharmony_ci return 1; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci return 0; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cidown: 66962306a36Sopenharmony_ci if (netif_carrier_ok(bond->dev)) { 67062306a36Sopenharmony_ci netif_carrier_off(bond->dev); 67162306a36Sopenharmony_ci return 1; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci return 0; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci/* Get link speed and duplex from the slave's base driver 67762306a36Sopenharmony_ci * using ethtool. If for some reason the call fails or the 67862306a36Sopenharmony_ci * values are invalid, set speed and duplex to -1, 67962306a36Sopenharmony_ci * and return. Return 1 if speed or duplex settings are 68062306a36Sopenharmony_ci * UNKNOWN; 0 otherwise. 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_cistatic int bond_update_speed_duplex(struct slave *slave) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct net_device *slave_dev = slave->dev; 68562306a36Sopenharmony_ci struct ethtool_link_ksettings ecmd; 68662306a36Sopenharmony_ci int res; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci slave->speed = SPEED_UNKNOWN; 68962306a36Sopenharmony_ci slave->duplex = DUPLEX_UNKNOWN; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci res = __ethtool_get_link_ksettings(slave_dev, &ecmd); 69262306a36Sopenharmony_ci if (res < 0) 69362306a36Sopenharmony_ci return 1; 69462306a36Sopenharmony_ci if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) 69562306a36Sopenharmony_ci return 1; 69662306a36Sopenharmony_ci switch (ecmd.base.duplex) { 69762306a36Sopenharmony_ci case DUPLEX_FULL: 69862306a36Sopenharmony_ci case DUPLEX_HALF: 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci default: 70162306a36Sopenharmony_ci return 1; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci slave->speed = ecmd.base.speed; 70562306a36Sopenharmony_ci slave->duplex = ecmd.base.duplex; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return 0; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ciconst char *bond_slave_link_status(s8 link) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci switch (link) { 71362306a36Sopenharmony_ci case BOND_LINK_UP: 71462306a36Sopenharmony_ci return "up"; 71562306a36Sopenharmony_ci case BOND_LINK_FAIL: 71662306a36Sopenharmony_ci return "going down"; 71762306a36Sopenharmony_ci case BOND_LINK_DOWN: 71862306a36Sopenharmony_ci return "down"; 71962306a36Sopenharmony_ci case BOND_LINK_BACK: 72062306a36Sopenharmony_ci return "going back"; 72162306a36Sopenharmony_ci default: 72262306a36Sopenharmony_ci return "unknown"; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci/* if <dev> supports MII link status reporting, check its link status. 72762306a36Sopenharmony_ci * 72862306a36Sopenharmony_ci * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), 72962306a36Sopenharmony_ci * depending upon the setting of the use_carrier parameter. 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * Return either BMSR_LSTATUS, meaning that the link is up (or we 73262306a36Sopenharmony_ci * can't tell and just pretend it is), or 0, meaning that the link is 73362306a36Sopenharmony_ci * down. 73462306a36Sopenharmony_ci * 73562306a36Sopenharmony_ci * If reporting is non-zero, instead of faking link up, return -1 if 73662306a36Sopenharmony_ci * both ETHTOOL and MII ioctls fail (meaning the device does not 73762306a36Sopenharmony_ci * support them). If use_carrier is set, return whatever it says. 73862306a36Sopenharmony_ci * It'd be nice if there was a good way to tell if a driver supports 73962306a36Sopenharmony_ci * netif_carrier, but there really isn't. 74062306a36Sopenharmony_ci */ 74162306a36Sopenharmony_cistatic int bond_check_dev_link(struct bonding *bond, 74262306a36Sopenharmony_ci struct net_device *slave_dev, int reporting) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci const struct net_device_ops *slave_ops = slave_dev->netdev_ops; 74562306a36Sopenharmony_ci int (*ioctl)(struct net_device *, struct ifreq *, int); 74662306a36Sopenharmony_ci struct ifreq ifr; 74762306a36Sopenharmony_ci struct mii_ioctl_data *mii; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (!reporting && !netif_running(slave_dev)) 75062306a36Sopenharmony_ci return 0; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (bond->params.use_carrier) 75362306a36Sopenharmony_ci return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* Try to get link status using Ethtool first. */ 75662306a36Sopenharmony_ci if (slave_dev->ethtool_ops->get_link) 75762306a36Sopenharmony_ci return slave_dev->ethtool_ops->get_link(slave_dev) ? 75862306a36Sopenharmony_ci BMSR_LSTATUS : 0; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci /* Ethtool can't be used, fallback to MII ioctls. */ 76162306a36Sopenharmony_ci ioctl = slave_ops->ndo_eth_ioctl; 76262306a36Sopenharmony_ci if (ioctl) { 76362306a36Sopenharmony_ci /* TODO: set pointer to correct ioctl on a per team member 76462306a36Sopenharmony_ci * bases to make this more efficient. that is, once 76562306a36Sopenharmony_ci * we determine the correct ioctl, we will always 76662306a36Sopenharmony_ci * call it and not the others for that team 76762306a36Sopenharmony_ci * member. 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* We cannot assume that SIOCGMIIPHY will also read a 77162306a36Sopenharmony_ci * register; not all network drivers (e.g., e100) 77262306a36Sopenharmony_ci * support that. 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* Yes, the mii is overlaid on the ifreq.ifr_ifru */ 77662306a36Sopenharmony_ci strscpy_pad(ifr.ifr_name, slave_dev->name, IFNAMSIZ); 77762306a36Sopenharmony_ci mii = if_mii(&ifr); 77862306a36Sopenharmony_ci if (ioctl(slave_dev, &ifr, SIOCGMIIPHY) == 0) { 77962306a36Sopenharmony_ci mii->reg_num = MII_BMSR; 78062306a36Sopenharmony_ci if (ioctl(slave_dev, &ifr, SIOCGMIIREG) == 0) 78162306a36Sopenharmony_ci return mii->val_out & BMSR_LSTATUS; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* If reporting, report that either there's no ndo_eth_ioctl, 78662306a36Sopenharmony_ci * or both SIOCGMIIREG and get_link failed (meaning that we 78762306a36Sopenharmony_ci * cannot report link status). If not reporting, pretend 78862306a36Sopenharmony_ci * we're ok. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci return reporting ? -1 : BMSR_LSTATUS; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/*----------------------------- Multicast list ------------------------------*/ 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci/* Push the promiscuity flag down to appropriate slaves */ 79662306a36Sopenharmony_cistatic int bond_set_promiscuity(struct bonding *bond, int inc) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct list_head *iter; 79962306a36Sopenharmony_ci int err = 0; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (bond_uses_primary(bond)) { 80262306a36Sopenharmony_ci struct slave *curr_active = rtnl_dereference(bond->curr_active_slave); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (curr_active) 80562306a36Sopenharmony_ci err = dev_set_promiscuity(curr_active->dev, inc); 80662306a36Sopenharmony_ci } else { 80762306a36Sopenharmony_ci struct slave *slave; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 81062306a36Sopenharmony_ci err = dev_set_promiscuity(slave->dev, inc); 81162306a36Sopenharmony_ci if (err) 81262306a36Sopenharmony_ci return err; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci return err; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci/* Push the allmulti flag down to all slaves */ 81962306a36Sopenharmony_cistatic int bond_set_allmulti(struct bonding *bond, int inc) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci struct list_head *iter; 82262306a36Sopenharmony_ci int err = 0; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (bond_uses_primary(bond)) { 82562306a36Sopenharmony_ci struct slave *curr_active = rtnl_dereference(bond->curr_active_slave); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (curr_active) 82862306a36Sopenharmony_ci err = dev_set_allmulti(curr_active->dev, inc); 82962306a36Sopenharmony_ci } else { 83062306a36Sopenharmony_ci struct slave *slave; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 83362306a36Sopenharmony_ci err = dev_set_allmulti(slave->dev, inc); 83462306a36Sopenharmony_ci if (err) 83562306a36Sopenharmony_ci return err; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci return err; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci/* Retrieve the list of registered multicast addresses for the bonding 84262306a36Sopenharmony_ci * device and retransmit an IGMP JOIN request to the current active 84362306a36Sopenharmony_ci * slave. 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_cistatic void bond_resend_igmp_join_requests_delayed(struct work_struct *work) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct bonding *bond = container_of(work, struct bonding, 84862306a36Sopenharmony_ci mcast_work.work); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (!rtnl_trylock()) { 85162306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->mcast_work, 1); 85262306a36Sopenharmony_ci return; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_RESEND_IGMP, bond->dev); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci if (bond->igmp_retrans > 1) { 85762306a36Sopenharmony_ci bond->igmp_retrans--; 85862306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->mcast_work, HZ/5); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci rtnl_unlock(); 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci/* Flush bond's hardware addresses from slave */ 86462306a36Sopenharmony_cistatic void bond_hw_addr_flush(struct net_device *bond_dev, 86562306a36Sopenharmony_ci struct net_device *slave_dev) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci dev_uc_unsync(slave_dev, bond_dev); 87062306a36Sopenharmony_ci dev_mc_unsync(slave_dev, bond_dev); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 87362306a36Sopenharmony_ci dev_mc_del(slave_dev, lacpdu_mcast_addr); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci/*--------------------------- Active slave change ---------------------------*/ 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci/* Update the hardware address list and promisc/allmulti for the new and 87962306a36Sopenharmony_ci * old active slaves (if any). Modes that are not using primary keep all 88062306a36Sopenharmony_ci * slaves up date at all times; only the modes that use primary need to call 88162306a36Sopenharmony_ci * this function to swap these settings during a failover. 88262306a36Sopenharmony_ci */ 88362306a36Sopenharmony_cistatic void bond_hw_addr_swap(struct bonding *bond, struct slave *new_active, 88462306a36Sopenharmony_ci struct slave *old_active) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci if (old_active) { 88762306a36Sopenharmony_ci if (bond->dev->flags & IFF_PROMISC) 88862306a36Sopenharmony_ci dev_set_promiscuity(old_active->dev, -1); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (bond->dev->flags & IFF_ALLMULTI) 89162306a36Sopenharmony_ci dev_set_allmulti(old_active->dev, -1); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (bond->dev->flags & IFF_UP) 89462306a36Sopenharmony_ci bond_hw_addr_flush(bond->dev, old_active->dev); 89562306a36Sopenharmony_ci } 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (new_active) { 89862306a36Sopenharmony_ci /* FIXME: Signal errors upstream. */ 89962306a36Sopenharmony_ci if (bond->dev->flags & IFF_PROMISC) 90062306a36Sopenharmony_ci dev_set_promiscuity(new_active->dev, 1); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (bond->dev->flags & IFF_ALLMULTI) 90362306a36Sopenharmony_ci dev_set_allmulti(new_active->dev, 1); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (bond->dev->flags & IFF_UP) { 90662306a36Sopenharmony_ci netif_addr_lock_bh(bond->dev); 90762306a36Sopenharmony_ci dev_uc_sync(new_active->dev, bond->dev); 90862306a36Sopenharmony_ci dev_mc_sync(new_active->dev, bond->dev); 90962306a36Sopenharmony_ci netif_addr_unlock_bh(bond->dev); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci/** 91562306a36Sopenharmony_ci * bond_set_dev_addr - clone slave's address to bond 91662306a36Sopenharmony_ci * @bond_dev: bond net device 91762306a36Sopenharmony_ci * @slave_dev: slave net device 91862306a36Sopenharmony_ci * 91962306a36Sopenharmony_ci * Should be called with RTNL held. 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_cistatic int bond_set_dev_addr(struct net_device *bond_dev, 92262306a36Sopenharmony_ci struct net_device *slave_dev) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci int err; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "bond_dev=%p slave_dev=%p slave_dev->addr_len=%d\n", 92762306a36Sopenharmony_ci bond_dev, slave_dev, slave_dev->addr_len); 92862306a36Sopenharmony_ci err = dev_pre_changeaddr_notify(bond_dev, slave_dev->dev_addr, NULL); 92962306a36Sopenharmony_ci if (err) 93062306a36Sopenharmony_ci return err; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci __dev_addr_set(bond_dev, slave_dev->dev_addr, slave_dev->addr_len); 93362306a36Sopenharmony_ci bond_dev->addr_assign_type = NET_ADDR_STOLEN; 93462306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, bond_dev); 93562306a36Sopenharmony_ci return 0; 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic struct slave *bond_get_old_active(struct bonding *bond, 93962306a36Sopenharmony_ci struct slave *new_active) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci struct slave *slave; 94262306a36Sopenharmony_ci struct list_head *iter; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 94562306a36Sopenharmony_ci if (slave == new_active) 94662306a36Sopenharmony_ci continue; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (ether_addr_equal(bond->dev->dev_addr, slave->dev->dev_addr)) 94962306a36Sopenharmony_ci return slave; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return NULL; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci/* bond_do_fail_over_mac 95662306a36Sopenharmony_ci * 95762306a36Sopenharmony_ci * Perform special MAC address swapping for fail_over_mac settings 95862306a36Sopenharmony_ci * 95962306a36Sopenharmony_ci * Called with RTNL 96062306a36Sopenharmony_ci */ 96162306a36Sopenharmony_cistatic void bond_do_fail_over_mac(struct bonding *bond, 96262306a36Sopenharmony_ci struct slave *new_active, 96362306a36Sopenharmony_ci struct slave *old_active) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci u8 tmp_mac[MAX_ADDR_LEN]; 96662306a36Sopenharmony_ci struct sockaddr_storage ss; 96762306a36Sopenharmony_ci int rv; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci switch (bond->params.fail_over_mac) { 97062306a36Sopenharmony_ci case BOND_FOM_ACTIVE: 97162306a36Sopenharmony_ci if (new_active) { 97262306a36Sopenharmony_ci rv = bond_set_dev_addr(bond->dev, new_active->dev); 97362306a36Sopenharmony_ci if (rv) 97462306a36Sopenharmony_ci slave_err(bond->dev, new_active->dev, "Error %d setting bond MAC from slave\n", 97562306a36Sopenharmony_ci -rv); 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci break; 97862306a36Sopenharmony_ci case BOND_FOM_FOLLOW: 97962306a36Sopenharmony_ci /* if new_active && old_active, swap them 98062306a36Sopenharmony_ci * if just old_active, do nothing (going to no active slave) 98162306a36Sopenharmony_ci * if just new_active, set new_active to bond's MAC 98262306a36Sopenharmony_ci */ 98362306a36Sopenharmony_ci if (!new_active) 98462306a36Sopenharmony_ci return; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (!old_active) 98762306a36Sopenharmony_ci old_active = bond_get_old_active(bond, new_active); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (old_active) { 99062306a36Sopenharmony_ci bond_hw_addr_copy(tmp_mac, new_active->dev->dev_addr, 99162306a36Sopenharmony_ci new_active->dev->addr_len); 99262306a36Sopenharmony_ci bond_hw_addr_copy(ss.__data, 99362306a36Sopenharmony_ci old_active->dev->dev_addr, 99462306a36Sopenharmony_ci old_active->dev->addr_len); 99562306a36Sopenharmony_ci ss.ss_family = new_active->dev->type; 99662306a36Sopenharmony_ci } else { 99762306a36Sopenharmony_ci bond_hw_addr_copy(ss.__data, bond->dev->dev_addr, 99862306a36Sopenharmony_ci bond->dev->addr_len); 99962306a36Sopenharmony_ci ss.ss_family = bond->dev->type; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci rv = dev_set_mac_address(new_active->dev, 100362306a36Sopenharmony_ci (struct sockaddr *)&ss, NULL); 100462306a36Sopenharmony_ci if (rv) { 100562306a36Sopenharmony_ci slave_err(bond->dev, new_active->dev, "Error %d setting MAC of new active slave\n", 100662306a36Sopenharmony_ci -rv); 100762306a36Sopenharmony_ci goto out; 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (!old_active) 101162306a36Sopenharmony_ci goto out; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci bond_hw_addr_copy(ss.__data, tmp_mac, 101462306a36Sopenharmony_ci new_active->dev->addr_len); 101562306a36Sopenharmony_ci ss.ss_family = old_active->dev->type; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci rv = dev_set_mac_address(old_active->dev, 101862306a36Sopenharmony_ci (struct sockaddr *)&ss, NULL); 101962306a36Sopenharmony_ci if (rv) 102062306a36Sopenharmony_ci slave_err(bond->dev, old_active->dev, "Error %d setting MAC of old active slave\n", 102162306a36Sopenharmony_ci -rv); 102262306a36Sopenharmony_ciout: 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci default: 102562306a36Sopenharmony_ci netdev_err(bond->dev, "bond_do_fail_over_mac impossible: bad policy %d\n", 102662306a36Sopenharmony_ci bond->params.fail_over_mac); 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci/** 103362306a36Sopenharmony_ci * bond_choose_primary_or_current - select the primary or high priority slave 103462306a36Sopenharmony_ci * @bond: our bonding struct 103562306a36Sopenharmony_ci * 103662306a36Sopenharmony_ci * - Check if there is a primary link. If the primary link was set and is up, 103762306a36Sopenharmony_ci * go on and do link reselection. 103862306a36Sopenharmony_ci * 103962306a36Sopenharmony_ci * - If primary link is not set or down, find the highest priority link. 104062306a36Sopenharmony_ci * If the highest priority link is not current slave, set it as primary 104162306a36Sopenharmony_ci * link and do link reselection. 104262306a36Sopenharmony_ci */ 104362306a36Sopenharmony_cistatic struct slave *bond_choose_primary_or_current(struct bonding *bond) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct slave *prim = rtnl_dereference(bond->primary_slave); 104662306a36Sopenharmony_ci struct slave *curr = rtnl_dereference(bond->curr_active_slave); 104762306a36Sopenharmony_ci struct slave *slave, *hprio = NULL; 104862306a36Sopenharmony_ci struct list_head *iter; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci if (!prim || prim->link != BOND_LINK_UP) { 105162306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 105262306a36Sopenharmony_ci if (slave->link == BOND_LINK_UP) { 105362306a36Sopenharmony_ci hprio = hprio ?: slave; 105462306a36Sopenharmony_ci if (slave->prio > hprio->prio) 105562306a36Sopenharmony_ci hprio = slave; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci if (hprio && hprio != curr) { 106062306a36Sopenharmony_ci prim = hprio; 106162306a36Sopenharmony_ci goto link_reselect; 106262306a36Sopenharmony_ci } 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci if (!curr || curr->link != BOND_LINK_UP) 106562306a36Sopenharmony_ci return NULL; 106662306a36Sopenharmony_ci return curr; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (bond->force_primary) { 107062306a36Sopenharmony_ci bond->force_primary = false; 107162306a36Sopenharmony_ci return prim; 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cilink_reselect: 107562306a36Sopenharmony_ci if (!curr || curr->link != BOND_LINK_UP) 107662306a36Sopenharmony_ci return prim; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci /* At this point, prim and curr are both up */ 107962306a36Sopenharmony_ci switch (bond->params.primary_reselect) { 108062306a36Sopenharmony_ci case BOND_PRI_RESELECT_ALWAYS: 108162306a36Sopenharmony_ci return prim; 108262306a36Sopenharmony_ci case BOND_PRI_RESELECT_BETTER: 108362306a36Sopenharmony_ci if (prim->speed < curr->speed) 108462306a36Sopenharmony_ci return curr; 108562306a36Sopenharmony_ci if (prim->speed == curr->speed && prim->duplex <= curr->duplex) 108662306a36Sopenharmony_ci return curr; 108762306a36Sopenharmony_ci return prim; 108862306a36Sopenharmony_ci case BOND_PRI_RESELECT_FAILURE: 108962306a36Sopenharmony_ci return curr; 109062306a36Sopenharmony_ci default: 109162306a36Sopenharmony_ci netdev_err(bond->dev, "impossible primary_reselect %d\n", 109262306a36Sopenharmony_ci bond->params.primary_reselect); 109362306a36Sopenharmony_ci return curr; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci/** 109862306a36Sopenharmony_ci * bond_find_best_slave - select the best available slave to be the active one 109962306a36Sopenharmony_ci * @bond: our bonding struct 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_cistatic struct slave *bond_find_best_slave(struct bonding *bond) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci struct slave *slave, *bestslave = NULL; 110462306a36Sopenharmony_ci struct list_head *iter; 110562306a36Sopenharmony_ci int mintime = bond->params.updelay; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci slave = bond_choose_primary_or_current(bond); 110862306a36Sopenharmony_ci if (slave) 110962306a36Sopenharmony_ci return slave; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 111262306a36Sopenharmony_ci if (slave->link == BOND_LINK_UP) 111362306a36Sopenharmony_ci return slave; 111462306a36Sopenharmony_ci if (slave->link == BOND_LINK_BACK && bond_slave_is_up(slave) && 111562306a36Sopenharmony_ci slave->delay < mintime) { 111662306a36Sopenharmony_ci mintime = slave->delay; 111762306a36Sopenharmony_ci bestslave = slave; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return bestslave; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic bool bond_should_notify_peers(struct bonding *bond) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct slave *slave; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci rcu_read_lock(); 112962306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 113062306a36Sopenharmony_ci rcu_read_unlock(); 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci if (!slave || !bond->send_peer_notif || 113362306a36Sopenharmony_ci bond->send_peer_notif % 113462306a36Sopenharmony_ci max(1, bond->params.peer_notif_delay) != 0 || 113562306a36Sopenharmony_ci !netif_carrier_ok(bond->dev) || 113662306a36Sopenharmony_ci test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) 113762306a36Sopenharmony_ci return false; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci netdev_dbg(bond->dev, "bond_should_notify_peers: slave %s\n", 114062306a36Sopenharmony_ci slave ? slave->dev->name : "NULL"); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci return true; 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci/** 114662306a36Sopenharmony_ci * bond_change_active_slave - change the active slave into the specified one 114762306a36Sopenharmony_ci * @bond: our bonding struct 114862306a36Sopenharmony_ci * @new_active: the new slave to make the active one 114962306a36Sopenharmony_ci * 115062306a36Sopenharmony_ci * Set the new slave to the bond's settings and unset them on the old 115162306a36Sopenharmony_ci * curr_active_slave. 115262306a36Sopenharmony_ci * Setting include flags, mc-list, promiscuity, allmulti, etc. 115362306a36Sopenharmony_ci * 115462306a36Sopenharmony_ci * If @new's link state is %BOND_LINK_BACK we'll set it to %BOND_LINK_UP, 115562306a36Sopenharmony_ci * because it is apparently the best available slave we have, even though its 115662306a36Sopenharmony_ci * updelay hasn't timed out yet. 115762306a36Sopenharmony_ci * 115862306a36Sopenharmony_ci * Caller must hold RTNL. 115962306a36Sopenharmony_ci */ 116062306a36Sopenharmony_civoid bond_change_active_slave(struct bonding *bond, struct slave *new_active) 116162306a36Sopenharmony_ci{ 116262306a36Sopenharmony_ci struct slave *old_active; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci ASSERT_RTNL(); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci old_active = rtnl_dereference(bond->curr_active_slave); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (old_active == new_active) 116962306a36Sopenharmony_ci return; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 117262306a36Sopenharmony_ci bond_ipsec_del_sa_all(bond); 117362306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (new_active) { 117662306a36Sopenharmony_ci new_active->last_link_up = jiffies; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci if (new_active->link == BOND_LINK_BACK) { 117962306a36Sopenharmony_ci if (bond_uses_primary(bond)) { 118062306a36Sopenharmony_ci slave_info(bond->dev, new_active->dev, "making interface the new active one %d ms earlier\n", 118162306a36Sopenharmony_ci (bond->params.updelay - new_active->delay) * bond->params.miimon); 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci new_active->delay = 0; 118562306a36Sopenharmony_ci bond_set_slave_link_state(new_active, BOND_LINK_UP, 118662306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 118962306a36Sopenharmony_ci bond_3ad_handle_link_change(new_active, BOND_LINK_UP); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci if (bond_is_lb(bond)) 119262306a36Sopenharmony_ci bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); 119362306a36Sopenharmony_ci } else { 119462306a36Sopenharmony_ci if (bond_uses_primary(bond)) 119562306a36Sopenharmony_ci slave_info(bond->dev, new_active->dev, "making interface the new active one\n"); 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (bond_uses_primary(bond)) 120062306a36Sopenharmony_ci bond_hw_addr_swap(bond, new_active, old_active); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (bond_is_lb(bond)) { 120362306a36Sopenharmony_ci bond_alb_handle_active_change(bond, new_active); 120462306a36Sopenharmony_ci if (old_active) 120562306a36Sopenharmony_ci bond_set_slave_inactive_flags(old_active, 120662306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 120762306a36Sopenharmony_ci if (new_active) 120862306a36Sopenharmony_ci bond_set_slave_active_flags(new_active, 120962306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 121062306a36Sopenharmony_ci } else { 121162306a36Sopenharmony_ci rcu_assign_pointer(bond->curr_active_slave, new_active); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) { 121562306a36Sopenharmony_ci if (old_active) 121662306a36Sopenharmony_ci bond_set_slave_inactive_flags(old_active, 121762306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci if (new_active) { 122062306a36Sopenharmony_ci bool should_notify_peers = false; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci bond_set_slave_active_flags(new_active, 122362306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (bond->params.fail_over_mac) 122662306a36Sopenharmony_ci bond_do_fail_over_mac(bond, new_active, 122762306a36Sopenharmony_ci old_active); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (netif_running(bond->dev)) { 123062306a36Sopenharmony_ci bond->send_peer_notif = 123162306a36Sopenharmony_ci bond->params.num_peer_notif * 123262306a36Sopenharmony_ci max(1, bond->params.peer_notif_delay); 123362306a36Sopenharmony_ci should_notify_peers = 123462306a36Sopenharmony_ci bond_should_notify_peers(bond); 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, bond->dev); 123862306a36Sopenharmony_ci if (should_notify_peers) { 123962306a36Sopenharmony_ci bond->send_peer_notif--; 124062306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, 124162306a36Sopenharmony_ci bond->dev); 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 124762306a36Sopenharmony_ci bond_ipsec_add_sa_all(bond); 124862306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci /* resend IGMP joins since active slave has changed or 125162306a36Sopenharmony_ci * all were sent on curr_active_slave. 125262306a36Sopenharmony_ci * resend only if bond is brought up with the affected 125362306a36Sopenharmony_ci * bonding modes and the retransmission is enabled 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ci if (netif_running(bond->dev) && (bond->params.resend_igmp > 0) && 125662306a36Sopenharmony_ci ((bond_uses_primary(bond) && new_active) || 125762306a36Sopenharmony_ci BOND_MODE(bond) == BOND_MODE_ROUNDROBIN)) { 125862306a36Sopenharmony_ci bond->igmp_retrans = bond->params.resend_igmp; 125962306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->mcast_work, 1); 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci/** 126462306a36Sopenharmony_ci * bond_select_active_slave - select a new active slave, if needed 126562306a36Sopenharmony_ci * @bond: our bonding struct 126662306a36Sopenharmony_ci * 126762306a36Sopenharmony_ci * This functions should be called when one of the following occurs: 126862306a36Sopenharmony_ci * - The old curr_active_slave has been released or lost its link. 126962306a36Sopenharmony_ci * - The primary_slave has got its link back. 127062306a36Sopenharmony_ci * - A slave has got its link back and there's no old curr_active_slave. 127162306a36Sopenharmony_ci * 127262306a36Sopenharmony_ci * Caller must hold RTNL. 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_civoid bond_select_active_slave(struct bonding *bond) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct slave *best_slave; 127762306a36Sopenharmony_ci int rv; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci ASSERT_RTNL(); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci best_slave = bond_find_best_slave(bond); 128262306a36Sopenharmony_ci if (best_slave != rtnl_dereference(bond->curr_active_slave)) { 128362306a36Sopenharmony_ci bond_change_active_slave(bond, best_slave); 128462306a36Sopenharmony_ci rv = bond_set_carrier(bond); 128562306a36Sopenharmony_ci if (!rv) 128662306a36Sopenharmony_ci return; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (netif_carrier_ok(bond->dev)) 128962306a36Sopenharmony_ci netdev_info(bond->dev, "active interface up!\n"); 129062306a36Sopenharmony_ci else 129162306a36Sopenharmony_ci netdev_info(bond->dev, "now running without any active interface!\n"); 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 129662306a36Sopenharmony_cistatic inline int slave_enable_netpoll(struct slave *slave) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct netpoll *np; 129962306a36Sopenharmony_ci int err = 0; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci np = kzalloc(sizeof(*np), GFP_KERNEL); 130262306a36Sopenharmony_ci err = -ENOMEM; 130362306a36Sopenharmony_ci if (!np) 130462306a36Sopenharmony_ci goto out; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci err = __netpoll_setup(np, slave->dev); 130762306a36Sopenharmony_ci if (err) { 130862306a36Sopenharmony_ci kfree(np); 130962306a36Sopenharmony_ci goto out; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci slave->np = np; 131262306a36Sopenharmony_ciout: 131362306a36Sopenharmony_ci return err; 131462306a36Sopenharmony_ci} 131562306a36Sopenharmony_cistatic inline void slave_disable_netpoll(struct slave *slave) 131662306a36Sopenharmony_ci{ 131762306a36Sopenharmony_ci struct netpoll *np = slave->np; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (!np) 132062306a36Sopenharmony_ci return; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci slave->np = NULL; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci __netpoll_free(np); 132562306a36Sopenharmony_ci} 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_cistatic void bond_poll_controller(struct net_device *bond_dev) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 133062306a36Sopenharmony_ci struct slave *slave = NULL; 133162306a36Sopenharmony_ci struct list_head *iter; 133262306a36Sopenharmony_ci struct ad_info ad_info; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 133562306a36Sopenharmony_ci if (bond_3ad_get_active_agg_info(bond, &ad_info)) 133662306a36Sopenharmony_ci return; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 133962306a36Sopenharmony_ci if (!bond_slave_is_up(slave)) 134062306a36Sopenharmony_ci continue; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 134362306a36Sopenharmony_ci struct aggregator *agg = 134462306a36Sopenharmony_ci SLAVE_AD_INFO(slave)->port.aggregator; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (agg && 134762306a36Sopenharmony_ci agg->aggregator_identifier != ad_info.aggregator_id) 134862306a36Sopenharmony_ci continue; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci netpoll_poll_dev(slave->dev); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci} 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_cistatic void bond_netpoll_cleanup(struct net_device *bond_dev) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 135862306a36Sopenharmony_ci struct list_head *iter; 135962306a36Sopenharmony_ci struct slave *slave; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) 136262306a36Sopenharmony_ci if (bond_slave_is_up(slave)) 136362306a36Sopenharmony_ci slave_disable_netpoll(slave); 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 136962306a36Sopenharmony_ci struct list_head *iter; 137062306a36Sopenharmony_ci struct slave *slave; 137162306a36Sopenharmony_ci int err = 0; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 137462306a36Sopenharmony_ci err = slave_enable_netpoll(slave); 137562306a36Sopenharmony_ci if (err) { 137662306a36Sopenharmony_ci bond_netpoll_cleanup(dev); 137762306a36Sopenharmony_ci break; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci return err; 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci#else 138362306a36Sopenharmony_cistatic inline int slave_enable_netpoll(struct slave *slave) 138462306a36Sopenharmony_ci{ 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_cistatic inline void slave_disable_netpoll(struct slave *slave) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_cistatic void bond_netpoll_cleanup(struct net_device *bond_dev) 139162306a36Sopenharmony_ci{ 139262306a36Sopenharmony_ci} 139362306a36Sopenharmony_ci#endif 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci/*---------------------------------- IOCTL ----------------------------------*/ 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_cistatic netdev_features_t bond_fix_features(struct net_device *dev, 139862306a36Sopenharmony_ci netdev_features_t features) 139962306a36Sopenharmony_ci{ 140062306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 140162306a36Sopenharmony_ci struct list_head *iter; 140262306a36Sopenharmony_ci netdev_features_t mask; 140362306a36Sopenharmony_ci struct slave *slave; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci mask = features; 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci features &= ~NETIF_F_ONE_FOR_ALL; 140862306a36Sopenharmony_ci features |= NETIF_F_ALL_FOR_ALL; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 141162306a36Sopenharmony_ci features = netdev_increment_features(features, 141262306a36Sopenharmony_ci slave->dev->features, 141362306a36Sopenharmony_ci mask); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci features = netdev_add_tso_features(features, mask); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci return features; 141862306a36Sopenharmony_ci} 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci#define BOND_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ 142162306a36Sopenharmony_ci NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \ 142262306a36Sopenharmony_ci NETIF_F_HIGHDMA | NETIF_F_LRO) 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci#define BOND_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ 142562306a36Sopenharmony_ci NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE) 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci#define BOND_MPLS_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \ 142862306a36Sopenharmony_ci NETIF_F_GSO_SOFTWARE) 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_cistatic void bond_compute_features(struct bonding *bond) 143262306a36Sopenharmony_ci{ 143362306a36Sopenharmony_ci unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | 143462306a36Sopenharmony_ci IFF_XMIT_DST_RELEASE_PERM; 143562306a36Sopenharmony_ci netdev_features_t vlan_features = BOND_VLAN_FEATURES; 143662306a36Sopenharmony_ci netdev_features_t enc_features = BOND_ENC_FEATURES; 143762306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 143862306a36Sopenharmony_ci netdev_features_t xfrm_features = BOND_XFRM_FEATURES; 143962306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 144062306a36Sopenharmony_ci netdev_features_t mpls_features = BOND_MPLS_FEATURES; 144162306a36Sopenharmony_ci struct net_device *bond_dev = bond->dev; 144262306a36Sopenharmony_ci struct list_head *iter; 144362306a36Sopenharmony_ci struct slave *slave; 144462306a36Sopenharmony_ci unsigned short max_hard_header_len = ETH_HLEN; 144562306a36Sopenharmony_ci unsigned int tso_max_size = TSO_MAX_SIZE; 144662306a36Sopenharmony_ci u16 tso_max_segs = TSO_MAX_SEGS; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (!bond_has_slaves(bond)) 144962306a36Sopenharmony_ci goto done; 145062306a36Sopenharmony_ci vlan_features &= NETIF_F_ALL_FOR_ALL; 145162306a36Sopenharmony_ci mpls_features &= NETIF_F_ALL_FOR_ALL; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 145462306a36Sopenharmony_ci vlan_features = netdev_increment_features(vlan_features, 145562306a36Sopenharmony_ci slave->dev->vlan_features, BOND_VLAN_FEATURES); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci enc_features = netdev_increment_features(enc_features, 145862306a36Sopenharmony_ci slave->dev->hw_enc_features, 145962306a36Sopenharmony_ci BOND_ENC_FEATURES); 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 146262306a36Sopenharmony_ci xfrm_features = netdev_increment_features(xfrm_features, 146362306a36Sopenharmony_ci slave->dev->hw_enc_features, 146462306a36Sopenharmony_ci BOND_XFRM_FEATURES); 146562306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci mpls_features = netdev_increment_features(mpls_features, 146862306a36Sopenharmony_ci slave->dev->mpls_features, 146962306a36Sopenharmony_ci BOND_MPLS_FEATURES); 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci dst_release_flag &= slave->dev->priv_flags; 147262306a36Sopenharmony_ci if (slave->dev->hard_header_len > max_hard_header_len) 147362306a36Sopenharmony_ci max_hard_header_len = slave->dev->hard_header_len; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci tso_max_size = min(tso_max_size, slave->dev->tso_max_size); 147662306a36Sopenharmony_ci tso_max_segs = min(tso_max_segs, slave->dev->tso_max_segs); 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci bond_dev->hard_header_len = max_hard_header_len; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_cidone: 148162306a36Sopenharmony_ci bond_dev->vlan_features = vlan_features; 148262306a36Sopenharmony_ci bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL | 148362306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | 148462306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_TX; 148562306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 148662306a36Sopenharmony_ci bond_dev->hw_enc_features |= xfrm_features; 148762306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 148862306a36Sopenharmony_ci bond_dev->mpls_features = mpls_features; 148962306a36Sopenharmony_ci netif_set_tso_max_segs(bond_dev, tso_max_segs); 149062306a36Sopenharmony_ci netif_set_tso_max_size(bond_dev, tso_max_size); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci bond_dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; 149362306a36Sopenharmony_ci if ((bond_dev->priv_flags & IFF_XMIT_DST_RELEASE_PERM) && 149462306a36Sopenharmony_ci dst_release_flag == (IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM)) 149562306a36Sopenharmony_ci bond_dev->priv_flags |= IFF_XMIT_DST_RELEASE; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci netdev_change_features(bond_dev); 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cistatic void bond_setup_by_slave(struct net_device *bond_dev, 150162306a36Sopenharmony_ci struct net_device *slave_dev) 150262306a36Sopenharmony_ci{ 150362306a36Sopenharmony_ci bool was_up = !!(bond_dev->flags & IFF_UP); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci dev_close(bond_dev); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci bond_dev->header_ops = slave_dev->header_ops; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci bond_dev->type = slave_dev->type; 151062306a36Sopenharmony_ci bond_dev->hard_header_len = slave_dev->hard_header_len; 151162306a36Sopenharmony_ci bond_dev->needed_headroom = slave_dev->needed_headroom; 151262306a36Sopenharmony_ci bond_dev->addr_len = slave_dev->addr_len; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci memcpy(bond_dev->broadcast, slave_dev->broadcast, 151562306a36Sopenharmony_ci slave_dev->addr_len); 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci if (slave_dev->flags & IFF_POINTOPOINT) { 151862306a36Sopenharmony_ci bond_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); 151962306a36Sopenharmony_ci bond_dev->flags |= (IFF_POINTOPOINT | IFF_NOARP); 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci if (was_up) 152262306a36Sopenharmony_ci dev_open(bond_dev, NULL); 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci/* On bonding slaves other than the currently active slave, suppress 152662306a36Sopenharmony_ci * duplicates except for alb non-mcast/bcast. 152762306a36Sopenharmony_ci */ 152862306a36Sopenharmony_cistatic bool bond_should_deliver_exact_match(struct sk_buff *skb, 152962306a36Sopenharmony_ci struct slave *slave, 153062306a36Sopenharmony_ci struct bonding *bond) 153162306a36Sopenharmony_ci{ 153262306a36Sopenharmony_ci if (bond_is_slave_inactive(slave)) { 153362306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ALB && 153462306a36Sopenharmony_ci skb->pkt_type != PACKET_BROADCAST && 153562306a36Sopenharmony_ci skb->pkt_type != PACKET_MULTICAST) 153662306a36Sopenharmony_ci return false; 153762306a36Sopenharmony_ci return true; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci return false; 154062306a36Sopenharmony_ci} 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_cistatic rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) 154362306a36Sopenharmony_ci{ 154462306a36Sopenharmony_ci struct sk_buff *skb = *pskb; 154562306a36Sopenharmony_ci struct slave *slave; 154662306a36Sopenharmony_ci struct bonding *bond; 154762306a36Sopenharmony_ci int (*recv_probe)(const struct sk_buff *, struct bonding *, 154862306a36Sopenharmony_ci struct slave *); 154962306a36Sopenharmony_ci int ret = RX_HANDLER_ANOTHER; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 155262306a36Sopenharmony_ci if (unlikely(!skb)) 155362306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci *pskb = skb; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci slave = bond_slave_get_rcu(skb->dev); 155862306a36Sopenharmony_ci bond = slave->bond; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci recv_probe = READ_ONCE(bond->recv_probe); 156162306a36Sopenharmony_ci if (recv_probe) { 156262306a36Sopenharmony_ci ret = recv_probe(skb, bond, slave); 156362306a36Sopenharmony_ci if (ret == RX_HANDLER_CONSUMED) { 156462306a36Sopenharmony_ci consume_skb(skb); 156562306a36Sopenharmony_ci return ret; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /* 157062306a36Sopenharmony_ci * For packets determined by bond_should_deliver_exact_match() call to 157162306a36Sopenharmony_ci * be suppressed we want to make an exception for link-local packets. 157262306a36Sopenharmony_ci * This is necessary for e.g. LLDP daemons to be able to monitor 157362306a36Sopenharmony_ci * inactive slave links without being forced to bind to them 157462306a36Sopenharmony_ci * explicitly. 157562306a36Sopenharmony_ci * 157662306a36Sopenharmony_ci * At the same time, packets that are passed to the bonding master 157762306a36Sopenharmony_ci * (including link-local ones) can have their originating interface 157862306a36Sopenharmony_ci * determined via PACKET_ORIGDEV socket option. 157962306a36Sopenharmony_ci */ 158062306a36Sopenharmony_ci if (bond_should_deliver_exact_match(skb, slave, bond)) { 158162306a36Sopenharmony_ci if (is_link_local_ether_addr(eth_hdr(skb)->h_dest)) 158262306a36Sopenharmony_ci return RX_HANDLER_PASS; 158362306a36Sopenharmony_ci return RX_HANDLER_EXACT; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci skb->dev = bond->dev; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ALB && 158962306a36Sopenharmony_ci netif_is_bridge_port(bond->dev) && 159062306a36Sopenharmony_ci skb->pkt_type == PACKET_HOST) { 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci if (unlikely(skb_cow_head(skb, 159362306a36Sopenharmony_ci skb->data - skb_mac_header(skb)))) { 159462306a36Sopenharmony_ci kfree_skb(skb); 159562306a36Sopenharmony_ci return RX_HANDLER_CONSUMED; 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci bond_hw_addr_copy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, 159862306a36Sopenharmony_ci bond->dev->addr_len); 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci return ret; 160262306a36Sopenharmony_ci} 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_cistatic enum netdev_lag_tx_type bond_lag_tx_type(struct bonding *bond) 160562306a36Sopenharmony_ci{ 160662306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 160762306a36Sopenharmony_ci case BOND_MODE_ROUNDROBIN: 160862306a36Sopenharmony_ci return NETDEV_LAG_TX_TYPE_ROUNDROBIN; 160962306a36Sopenharmony_ci case BOND_MODE_ACTIVEBACKUP: 161062306a36Sopenharmony_ci return NETDEV_LAG_TX_TYPE_ACTIVEBACKUP; 161162306a36Sopenharmony_ci case BOND_MODE_BROADCAST: 161262306a36Sopenharmony_ci return NETDEV_LAG_TX_TYPE_BROADCAST; 161362306a36Sopenharmony_ci case BOND_MODE_XOR: 161462306a36Sopenharmony_ci case BOND_MODE_8023AD: 161562306a36Sopenharmony_ci return NETDEV_LAG_TX_TYPE_HASH; 161662306a36Sopenharmony_ci default: 161762306a36Sopenharmony_ci return NETDEV_LAG_TX_TYPE_UNKNOWN; 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic enum netdev_lag_hash bond_lag_hash_type(struct bonding *bond, 162262306a36Sopenharmony_ci enum netdev_lag_tx_type type) 162362306a36Sopenharmony_ci{ 162462306a36Sopenharmony_ci if (type != NETDEV_LAG_TX_TYPE_HASH) 162562306a36Sopenharmony_ci return NETDEV_LAG_HASH_NONE; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci switch (bond->params.xmit_policy) { 162862306a36Sopenharmony_ci case BOND_XMIT_POLICY_LAYER2: 162962306a36Sopenharmony_ci return NETDEV_LAG_HASH_L2; 163062306a36Sopenharmony_ci case BOND_XMIT_POLICY_LAYER34: 163162306a36Sopenharmony_ci return NETDEV_LAG_HASH_L34; 163262306a36Sopenharmony_ci case BOND_XMIT_POLICY_LAYER23: 163362306a36Sopenharmony_ci return NETDEV_LAG_HASH_L23; 163462306a36Sopenharmony_ci case BOND_XMIT_POLICY_ENCAP23: 163562306a36Sopenharmony_ci return NETDEV_LAG_HASH_E23; 163662306a36Sopenharmony_ci case BOND_XMIT_POLICY_ENCAP34: 163762306a36Sopenharmony_ci return NETDEV_LAG_HASH_E34; 163862306a36Sopenharmony_ci case BOND_XMIT_POLICY_VLAN_SRCMAC: 163962306a36Sopenharmony_ci return NETDEV_LAG_HASH_VLAN_SRCMAC; 164062306a36Sopenharmony_ci default: 164162306a36Sopenharmony_ci return NETDEV_LAG_HASH_UNKNOWN; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic int bond_master_upper_dev_link(struct bonding *bond, struct slave *slave, 164662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci struct netdev_lag_upper_info lag_upper_info; 164962306a36Sopenharmony_ci enum netdev_lag_tx_type type; 165062306a36Sopenharmony_ci int err; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci type = bond_lag_tx_type(bond); 165362306a36Sopenharmony_ci lag_upper_info.tx_type = type; 165462306a36Sopenharmony_ci lag_upper_info.hash_type = bond_lag_hash_type(bond, type); 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci err = netdev_master_upper_dev_link(slave->dev, bond->dev, slave, 165762306a36Sopenharmony_ci &lag_upper_info, extack); 165862306a36Sopenharmony_ci if (err) 165962306a36Sopenharmony_ci return err; 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci slave->dev->flags |= IFF_SLAVE; 166262306a36Sopenharmony_ci return 0; 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_cistatic void bond_upper_dev_unlink(struct bonding *bond, struct slave *slave) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci netdev_upper_dev_unlink(slave->dev, bond->dev); 166862306a36Sopenharmony_ci slave->dev->flags &= ~IFF_SLAVE; 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cistatic void slave_kobj_release(struct kobject *kobj) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci struct slave *slave = to_slave(kobj); 167462306a36Sopenharmony_ci struct bonding *bond = bond_get_bond_by_slave(slave); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci cancel_delayed_work_sync(&slave->notify_work); 167762306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 167862306a36Sopenharmony_ci kfree(SLAVE_AD_INFO(slave)); 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci kfree(slave); 168162306a36Sopenharmony_ci} 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_cistatic struct kobj_type slave_ktype = { 168462306a36Sopenharmony_ci .release = slave_kobj_release, 168562306a36Sopenharmony_ci#ifdef CONFIG_SYSFS 168662306a36Sopenharmony_ci .sysfs_ops = &slave_sysfs_ops, 168762306a36Sopenharmony_ci#endif 168862306a36Sopenharmony_ci}; 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_cistatic int bond_kobj_init(struct slave *slave) 169162306a36Sopenharmony_ci{ 169262306a36Sopenharmony_ci int err; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci err = kobject_init_and_add(&slave->kobj, &slave_ktype, 169562306a36Sopenharmony_ci &(slave->dev->dev.kobj), "bonding_slave"); 169662306a36Sopenharmony_ci if (err) 169762306a36Sopenharmony_ci kobject_put(&slave->kobj); 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci return err; 170062306a36Sopenharmony_ci} 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_cistatic struct slave *bond_alloc_slave(struct bonding *bond, 170362306a36Sopenharmony_ci struct net_device *slave_dev) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci struct slave *slave = NULL; 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci slave = kzalloc(sizeof(*slave), GFP_KERNEL); 170862306a36Sopenharmony_ci if (!slave) 170962306a36Sopenharmony_ci return NULL; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci slave->bond = bond; 171262306a36Sopenharmony_ci slave->dev = slave_dev; 171362306a36Sopenharmony_ci INIT_DELAYED_WORK(&slave->notify_work, bond_netdev_notify_work); 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci if (bond_kobj_init(slave)) 171662306a36Sopenharmony_ci return NULL; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 171962306a36Sopenharmony_ci SLAVE_AD_INFO(slave) = kzalloc(sizeof(struct ad_slave_info), 172062306a36Sopenharmony_ci GFP_KERNEL); 172162306a36Sopenharmony_ci if (!SLAVE_AD_INFO(slave)) { 172262306a36Sopenharmony_ci kobject_put(&slave->kobj); 172362306a36Sopenharmony_ci return NULL; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci return slave; 172862306a36Sopenharmony_ci} 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_cistatic void bond_fill_ifbond(struct bonding *bond, struct ifbond *info) 173162306a36Sopenharmony_ci{ 173262306a36Sopenharmony_ci info->bond_mode = BOND_MODE(bond); 173362306a36Sopenharmony_ci info->miimon = bond->params.miimon; 173462306a36Sopenharmony_ci info->num_slaves = bond->slave_cnt; 173562306a36Sopenharmony_ci} 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_cistatic void bond_fill_ifslave(struct slave *slave, struct ifslave *info) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci strcpy(info->slave_name, slave->dev->name); 174062306a36Sopenharmony_ci info->link = slave->link; 174162306a36Sopenharmony_ci info->state = bond_slave_state(slave); 174262306a36Sopenharmony_ci info->link_failure_count = slave->link_failure_count; 174362306a36Sopenharmony_ci} 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cistatic void bond_netdev_notify_work(struct work_struct *_work) 174662306a36Sopenharmony_ci{ 174762306a36Sopenharmony_ci struct slave *slave = container_of(_work, struct slave, 174862306a36Sopenharmony_ci notify_work.work); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (rtnl_trylock()) { 175162306a36Sopenharmony_ci struct netdev_bonding_info binfo; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci bond_fill_ifslave(slave, &binfo.slave); 175462306a36Sopenharmony_ci bond_fill_ifbond(slave->bond, &binfo.master); 175562306a36Sopenharmony_ci netdev_bonding_info_change(slave->dev, &binfo); 175662306a36Sopenharmony_ci rtnl_unlock(); 175762306a36Sopenharmony_ci } else { 175862306a36Sopenharmony_ci queue_delayed_work(slave->bond->wq, &slave->notify_work, 1); 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci} 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_civoid bond_queue_slave_event(struct slave *slave) 176362306a36Sopenharmony_ci{ 176462306a36Sopenharmony_ci queue_delayed_work(slave->bond->wq, &slave->notify_work, 0); 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_civoid bond_lower_state_changed(struct slave *slave) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci struct netdev_lag_lower_state_info info; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci info.link_up = slave->link == BOND_LINK_UP || 177262306a36Sopenharmony_ci slave->link == BOND_LINK_FAIL; 177362306a36Sopenharmony_ci info.tx_enabled = bond_is_active_slave(slave); 177462306a36Sopenharmony_ci netdev_lower_state_changed(slave->dev, &info); 177562306a36Sopenharmony_ci} 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci#define BOND_NL_ERR(bond_dev, extack, errmsg) do { \ 177862306a36Sopenharmony_ci if (extack) \ 177962306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, errmsg); \ 178062306a36Sopenharmony_ci else \ 178162306a36Sopenharmony_ci netdev_err(bond_dev, "Error: %s\n", errmsg); \ 178262306a36Sopenharmony_ci} while (0) 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci#define SLAVE_NL_ERR(bond_dev, slave_dev, extack, errmsg) do { \ 178562306a36Sopenharmony_ci if (extack) \ 178662306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, errmsg); \ 178762306a36Sopenharmony_ci else \ 178862306a36Sopenharmony_ci slave_err(bond_dev, slave_dev, "Error: %s\n", errmsg); \ 178962306a36Sopenharmony_ci} while (0) 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci/* The bonding driver uses ether_setup() to convert a master bond device 179262306a36Sopenharmony_ci * to ARPHRD_ETHER, that resets the target netdevice's flags so we always 179362306a36Sopenharmony_ci * have to restore the IFF_MASTER flag, and only restore IFF_SLAVE and IFF_UP 179462306a36Sopenharmony_ci * if they were set 179562306a36Sopenharmony_ci */ 179662306a36Sopenharmony_cistatic void bond_ether_setup(struct net_device *bond_dev) 179762306a36Sopenharmony_ci{ 179862306a36Sopenharmony_ci unsigned int flags = bond_dev->flags & (IFF_SLAVE | IFF_UP); 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci ether_setup(bond_dev); 180162306a36Sopenharmony_ci bond_dev->flags |= IFF_MASTER | flags; 180262306a36Sopenharmony_ci bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING; 180362306a36Sopenharmony_ci} 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_civoid bond_xdp_set_features(struct net_device *bond_dev) 180662306a36Sopenharmony_ci{ 180762306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 180862306a36Sopenharmony_ci xdp_features_t val = NETDEV_XDP_ACT_MASK; 180962306a36Sopenharmony_ci struct list_head *iter; 181062306a36Sopenharmony_ci struct slave *slave; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci ASSERT_RTNL(); 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci if (!bond_xdp_check(bond) || !bond_has_slaves(bond)) { 181562306a36Sopenharmony_ci xdp_clear_features_flag(bond_dev); 181662306a36Sopenharmony_ci return; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) 182062306a36Sopenharmony_ci val &= slave->dev->xdp_features; 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci val &= ~NETDEV_XDP_ACT_XSK_ZEROCOPY; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci xdp_set_features_flag(bond_dev, val); 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci/* enslave device <slave> to bond device <master> */ 182862306a36Sopenharmony_ciint bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev, 182962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 183262306a36Sopenharmony_ci const struct net_device_ops *slave_ops = slave_dev->netdev_ops; 183362306a36Sopenharmony_ci struct slave *new_slave = NULL, *prev_slave; 183462306a36Sopenharmony_ci struct sockaddr_storage ss; 183562306a36Sopenharmony_ci int link_reporting; 183662306a36Sopenharmony_ci int res = 0, i; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci if (slave_dev->flags & IFF_MASTER && 183962306a36Sopenharmony_ci !netif_is_bond_master(slave_dev)) { 184062306a36Sopenharmony_ci BOND_NL_ERR(bond_dev, extack, 184162306a36Sopenharmony_ci "Device type (master device) cannot be enslaved"); 184262306a36Sopenharmony_ci return -EPERM; 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (!bond->params.use_carrier && 184662306a36Sopenharmony_ci slave_dev->ethtool_ops->get_link == NULL && 184762306a36Sopenharmony_ci slave_ops->ndo_eth_ioctl == NULL) { 184862306a36Sopenharmony_ci slave_warn(bond_dev, slave_dev, "no link monitoring support\n"); 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci /* already in-use? */ 185262306a36Sopenharmony_ci if (netdev_is_rx_handler_busy(slave_dev)) { 185362306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 185462306a36Sopenharmony_ci "Device is in use and cannot be enslaved"); 185562306a36Sopenharmony_ci return -EBUSY; 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci if (bond_dev == slave_dev) { 185962306a36Sopenharmony_ci BOND_NL_ERR(bond_dev, extack, "Cannot enslave bond to itself."); 186062306a36Sopenharmony_ci return -EPERM; 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci /* vlan challenged mutual exclusion */ 186462306a36Sopenharmony_ci /* no need to lock since we're protected by rtnl_lock */ 186562306a36Sopenharmony_ci if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { 186662306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "is NETIF_F_VLAN_CHALLENGED\n"); 186762306a36Sopenharmony_ci if (vlan_uses_dev(bond_dev)) { 186862306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 186962306a36Sopenharmony_ci "Can not enslave VLAN challenged device to VLAN enabled bond"); 187062306a36Sopenharmony_ci return -EPERM; 187162306a36Sopenharmony_ci } else { 187262306a36Sopenharmony_ci slave_warn(bond_dev, slave_dev, "enslaved VLAN challenged slave. Adding VLANs will be blocked as long as it is part of bond.\n"); 187362306a36Sopenharmony_ci } 187462306a36Sopenharmony_ci } else { 187562306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "is !NETIF_F_VLAN_CHALLENGED\n"); 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (slave_dev->features & NETIF_F_HW_ESP) 187962306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "is esp-hw-offload capable\n"); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci /* Old ifenslave binaries are no longer supported. These can 188262306a36Sopenharmony_ci * be identified with moderate accuracy by the state of the slave: 188362306a36Sopenharmony_ci * the current ifenslave will set the interface down prior to 188462306a36Sopenharmony_ci * enslaving it; the old ifenslave will not. 188562306a36Sopenharmony_ci */ 188662306a36Sopenharmony_ci if (slave_dev->flags & IFF_UP) { 188762306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 188862306a36Sopenharmony_ci "Device can not be enslaved while up"); 188962306a36Sopenharmony_ci return -EPERM; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci /* set bonding device ether type by slave - bonding netdevices are 189362306a36Sopenharmony_ci * created with ether_setup, so when the slave type is not ARPHRD_ETHER 189462306a36Sopenharmony_ci * there is a need to override some of the type dependent attribs/funcs. 189562306a36Sopenharmony_ci * 189662306a36Sopenharmony_ci * bond ether type mutual exclusion - don't allow slaves of dissimilar 189762306a36Sopenharmony_ci * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond 189862306a36Sopenharmony_ci */ 189962306a36Sopenharmony_ci if (!bond_has_slaves(bond)) { 190062306a36Sopenharmony_ci if (bond_dev->type != slave_dev->type) { 190162306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "change device type from %d to %d\n", 190262306a36Sopenharmony_ci bond_dev->type, slave_dev->type); 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci res = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE, 190562306a36Sopenharmony_ci bond_dev); 190662306a36Sopenharmony_ci res = notifier_to_errno(res); 190762306a36Sopenharmony_ci if (res) { 190862306a36Sopenharmony_ci slave_err(bond_dev, slave_dev, "refused to change device type\n"); 190962306a36Sopenharmony_ci return -EBUSY; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci /* Flush unicast and multicast addresses */ 191362306a36Sopenharmony_ci dev_uc_flush(bond_dev); 191462306a36Sopenharmony_ci dev_mc_flush(bond_dev); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (slave_dev->type != ARPHRD_ETHER) 191762306a36Sopenharmony_ci bond_setup_by_slave(bond_dev, slave_dev); 191862306a36Sopenharmony_ci else 191962306a36Sopenharmony_ci bond_ether_setup(bond_dev); 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE, 192262306a36Sopenharmony_ci bond_dev); 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci } else if (bond_dev->type != slave_dev->type) { 192562306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 192662306a36Sopenharmony_ci "Device type is different from other slaves"); 192762306a36Sopenharmony_ci return -EINVAL; 192862306a36Sopenharmony_ci } 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci if (slave_dev->type == ARPHRD_INFINIBAND && 193162306a36Sopenharmony_ci BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { 193262306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 193362306a36Sopenharmony_ci "Only active-backup mode is supported for infiniband slaves"); 193462306a36Sopenharmony_ci res = -EOPNOTSUPP; 193562306a36Sopenharmony_ci goto err_undo_flags; 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci if (!slave_ops->ndo_set_mac_address || 193962306a36Sopenharmony_ci slave_dev->type == ARPHRD_INFINIBAND) { 194062306a36Sopenharmony_ci slave_warn(bond_dev, slave_dev, "The slave device specified does not support setting the MAC address\n"); 194162306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP && 194262306a36Sopenharmony_ci bond->params.fail_over_mac != BOND_FOM_ACTIVE) { 194362306a36Sopenharmony_ci if (!bond_has_slaves(bond)) { 194462306a36Sopenharmony_ci bond->params.fail_over_mac = BOND_FOM_ACTIVE; 194562306a36Sopenharmony_ci slave_warn(bond_dev, slave_dev, "Setting fail_over_mac to active for active-backup mode\n"); 194662306a36Sopenharmony_ci } else { 194762306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 194862306a36Sopenharmony_ci "Slave device does not support setting the MAC address, but fail_over_mac is not set to active"); 194962306a36Sopenharmony_ci res = -EOPNOTSUPP; 195062306a36Sopenharmony_ci goto err_undo_flags; 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci } 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_JOIN, slave_dev); 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci /* If this is the first slave, then we need to set the master's hardware 195862306a36Sopenharmony_ci * address to be the same as the slave's. 195962306a36Sopenharmony_ci */ 196062306a36Sopenharmony_ci if (!bond_has_slaves(bond) && 196162306a36Sopenharmony_ci bond->dev->addr_assign_type == NET_ADDR_RANDOM) { 196262306a36Sopenharmony_ci res = bond_set_dev_addr(bond->dev, slave_dev); 196362306a36Sopenharmony_ci if (res) 196462306a36Sopenharmony_ci goto err_undo_flags; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci new_slave = bond_alloc_slave(bond, slave_dev); 196862306a36Sopenharmony_ci if (!new_slave) { 196962306a36Sopenharmony_ci res = -ENOMEM; 197062306a36Sopenharmony_ci goto err_undo_flags; 197162306a36Sopenharmony_ci } 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci /* Set the new_slave's queue_id to be zero. Queue ID mapping 197462306a36Sopenharmony_ci * is set via sysfs or module option if desired. 197562306a36Sopenharmony_ci */ 197662306a36Sopenharmony_ci new_slave->queue_id = 0; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci /* Save slave's original mtu and then set it to match the bond */ 197962306a36Sopenharmony_ci new_slave->original_mtu = slave_dev->mtu; 198062306a36Sopenharmony_ci res = dev_set_mtu(slave_dev, bond->dev->mtu); 198162306a36Sopenharmony_ci if (res) { 198262306a36Sopenharmony_ci slave_err(bond_dev, slave_dev, "Error %d calling dev_set_mtu\n", res); 198362306a36Sopenharmony_ci goto err_free; 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci /* Save slave's original ("permanent") mac address for modes 198762306a36Sopenharmony_ci * that need it, and for restoring it upon release, and then 198862306a36Sopenharmony_ci * set it to the master's address 198962306a36Sopenharmony_ci */ 199062306a36Sopenharmony_ci bond_hw_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr, 199162306a36Sopenharmony_ci slave_dev->addr_len); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci if (!bond->params.fail_over_mac || 199462306a36Sopenharmony_ci BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { 199562306a36Sopenharmony_ci /* Set slave to master's mac address. The application already 199662306a36Sopenharmony_ci * set the master's mac address to that of the first slave 199762306a36Sopenharmony_ci */ 199862306a36Sopenharmony_ci memcpy(ss.__data, bond_dev->dev_addr, bond_dev->addr_len); 199962306a36Sopenharmony_ci ss.ss_family = slave_dev->type; 200062306a36Sopenharmony_ci res = dev_set_mac_address(slave_dev, (struct sockaddr *)&ss, 200162306a36Sopenharmony_ci extack); 200262306a36Sopenharmony_ci if (res) { 200362306a36Sopenharmony_ci slave_err(bond_dev, slave_dev, "Error %d calling set_mac_address\n", res); 200462306a36Sopenharmony_ci goto err_restore_mtu; 200562306a36Sopenharmony_ci } 200662306a36Sopenharmony_ci } 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci /* set no_addrconf flag before open to prevent IPv6 addrconf */ 200962306a36Sopenharmony_ci slave_dev->priv_flags |= IFF_NO_ADDRCONF; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci /* open the slave since the application closed it */ 201262306a36Sopenharmony_ci res = dev_open(slave_dev, extack); 201362306a36Sopenharmony_ci if (res) { 201462306a36Sopenharmony_ci slave_err(bond_dev, slave_dev, "Opening slave failed\n"); 201562306a36Sopenharmony_ci goto err_restore_mac; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci slave_dev->priv_flags |= IFF_BONDING; 201962306a36Sopenharmony_ci /* initialize slave stats */ 202062306a36Sopenharmony_ci dev_get_stats(new_slave->dev, &new_slave->slave_stats); 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci if (bond_is_lb(bond)) { 202362306a36Sopenharmony_ci /* bond_alb_init_slave() must be called before all other stages since 202462306a36Sopenharmony_ci * it might fail and we do not want to have to undo everything 202562306a36Sopenharmony_ci */ 202662306a36Sopenharmony_ci res = bond_alb_init_slave(bond, new_slave); 202762306a36Sopenharmony_ci if (res) 202862306a36Sopenharmony_ci goto err_close; 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci res = vlan_vids_add_by_dev(slave_dev, bond_dev); 203262306a36Sopenharmony_ci if (res) { 203362306a36Sopenharmony_ci slave_err(bond_dev, slave_dev, "Couldn't add bond vlan ids\n"); 203462306a36Sopenharmony_ci goto err_close; 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci prev_slave = bond_last_slave(bond); 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci new_slave->delay = 0; 204062306a36Sopenharmony_ci new_slave->link_failure_count = 0; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci if (bond_update_speed_duplex(new_slave) && 204362306a36Sopenharmony_ci bond_needs_speed_duplex(bond)) 204462306a36Sopenharmony_ci new_slave->link = BOND_LINK_DOWN; 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci new_slave->last_rx = jiffies - 204762306a36Sopenharmony_ci (msecs_to_jiffies(bond->params.arp_interval) + 1); 204862306a36Sopenharmony_ci for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) 204962306a36Sopenharmony_ci new_slave->target_last_arp_rx[i] = new_slave->last_rx; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci new_slave->last_tx = new_slave->last_rx; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (bond->params.miimon && !bond->params.use_carrier) { 205462306a36Sopenharmony_ci link_reporting = bond_check_dev_link(bond, slave_dev, 1); 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci if ((link_reporting == -1) && !bond->params.arp_interval) { 205762306a36Sopenharmony_ci /* miimon is set but a bonded network driver 205862306a36Sopenharmony_ci * does not support ETHTOOL/MII and 205962306a36Sopenharmony_ci * arp_interval is not set. Note: if 206062306a36Sopenharmony_ci * use_carrier is enabled, we will never go 206162306a36Sopenharmony_ci * here (because netif_carrier is always 206262306a36Sopenharmony_ci * supported); thus, we don't need to change 206362306a36Sopenharmony_ci * the messages for netif_carrier. 206462306a36Sopenharmony_ci */ 206562306a36Sopenharmony_ci 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"); 206662306a36Sopenharmony_ci } else if (link_reporting == -1) { 206762306a36Sopenharmony_ci /* unable get link status using mii/ethtool */ 206862306a36Sopenharmony_ci 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"); 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci } 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci /* check for initial state */ 207362306a36Sopenharmony_ci new_slave->link = BOND_LINK_NOCHANGE; 207462306a36Sopenharmony_ci if (bond->params.miimon) { 207562306a36Sopenharmony_ci if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) { 207662306a36Sopenharmony_ci if (bond->params.updelay) { 207762306a36Sopenharmony_ci bond_set_slave_link_state(new_slave, 207862306a36Sopenharmony_ci BOND_LINK_BACK, 207962306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 208062306a36Sopenharmony_ci new_slave->delay = bond->params.updelay; 208162306a36Sopenharmony_ci } else { 208262306a36Sopenharmony_ci bond_set_slave_link_state(new_slave, 208362306a36Sopenharmony_ci BOND_LINK_UP, 208462306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 208562306a36Sopenharmony_ci } 208662306a36Sopenharmony_ci } else { 208762306a36Sopenharmony_ci bond_set_slave_link_state(new_slave, BOND_LINK_DOWN, 208862306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 208962306a36Sopenharmony_ci } 209062306a36Sopenharmony_ci } else if (bond->params.arp_interval) { 209162306a36Sopenharmony_ci bond_set_slave_link_state(new_slave, 209262306a36Sopenharmony_ci (netif_carrier_ok(slave_dev) ? 209362306a36Sopenharmony_ci BOND_LINK_UP : BOND_LINK_DOWN), 209462306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 209562306a36Sopenharmony_ci } else { 209662306a36Sopenharmony_ci bond_set_slave_link_state(new_slave, BOND_LINK_UP, 209762306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 209862306a36Sopenharmony_ci } 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci if (new_slave->link != BOND_LINK_DOWN) 210162306a36Sopenharmony_ci new_slave->last_link_up = jiffies; 210262306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "Initial state of slave is BOND_LINK_%s\n", 210362306a36Sopenharmony_ci new_slave->link == BOND_LINK_DOWN ? "DOWN" : 210462306a36Sopenharmony_ci (new_slave->link == BOND_LINK_UP ? "UP" : "BACK")); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci if (bond_uses_primary(bond) && bond->params.primary[0]) { 210762306a36Sopenharmony_ci /* if there is a primary slave, remember it */ 210862306a36Sopenharmony_ci if (strcmp(bond->params.primary, new_slave->dev->name) == 0) { 210962306a36Sopenharmony_ci rcu_assign_pointer(bond->primary_slave, new_slave); 211062306a36Sopenharmony_ci bond->force_primary = true; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 211562306a36Sopenharmony_ci case BOND_MODE_ACTIVEBACKUP: 211662306a36Sopenharmony_ci bond_set_slave_inactive_flags(new_slave, 211762306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 211862306a36Sopenharmony_ci break; 211962306a36Sopenharmony_ci case BOND_MODE_8023AD: 212062306a36Sopenharmony_ci /* in 802.3ad mode, the internal mechanism 212162306a36Sopenharmony_ci * will activate the slaves in the selected 212262306a36Sopenharmony_ci * aggregator 212362306a36Sopenharmony_ci */ 212462306a36Sopenharmony_ci bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW); 212562306a36Sopenharmony_ci /* if this is the first slave */ 212662306a36Sopenharmony_ci if (!prev_slave) { 212762306a36Sopenharmony_ci SLAVE_AD_INFO(new_slave)->id = 1; 212862306a36Sopenharmony_ci /* Initialize AD with the number of times that the AD timer is called in 1 second 212962306a36Sopenharmony_ci * can be called only after the mac address of the bond is set 213062306a36Sopenharmony_ci */ 213162306a36Sopenharmony_ci bond_3ad_initialize(bond); 213262306a36Sopenharmony_ci } else { 213362306a36Sopenharmony_ci SLAVE_AD_INFO(new_slave)->id = 213462306a36Sopenharmony_ci SLAVE_AD_INFO(prev_slave)->id + 1; 213562306a36Sopenharmony_ci } 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci bond_3ad_bind_slave(new_slave); 213862306a36Sopenharmony_ci break; 213962306a36Sopenharmony_ci case BOND_MODE_TLB: 214062306a36Sopenharmony_ci case BOND_MODE_ALB: 214162306a36Sopenharmony_ci bond_set_active_slave(new_slave); 214262306a36Sopenharmony_ci bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW); 214362306a36Sopenharmony_ci break; 214462306a36Sopenharmony_ci default: 214562306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "This slave is always active in trunk mode\n"); 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci /* always active in trunk mode */ 214862306a36Sopenharmony_ci bond_set_active_slave(new_slave); 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci /* In trunking mode there is little meaning to curr_active_slave 215162306a36Sopenharmony_ci * anyway (it holds no special properties of the bond device), 215262306a36Sopenharmony_ci * so we can change it without calling change_active_interface() 215362306a36Sopenharmony_ci */ 215462306a36Sopenharmony_ci if (!rcu_access_pointer(bond->curr_active_slave) && 215562306a36Sopenharmony_ci new_slave->link == BOND_LINK_UP) 215662306a36Sopenharmony_ci rcu_assign_pointer(bond->curr_active_slave, new_slave); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci break; 215962306a36Sopenharmony_ci } /* switch(bond_mode) */ 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 216262306a36Sopenharmony_ci if (bond->dev->npinfo) { 216362306a36Sopenharmony_ci if (slave_enable_netpoll(new_slave)) { 216462306a36Sopenharmony_ci slave_info(bond_dev, slave_dev, "master_dev is using netpoll, but new slave device does not support netpoll\n"); 216562306a36Sopenharmony_ci res = -EBUSY; 216662306a36Sopenharmony_ci goto err_detach; 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci } 216962306a36Sopenharmony_ci#endif 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci if (!(bond_dev->features & NETIF_F_LRO)) 217262306a36Sopenharmony_ci dev_disable_lro(slave_dev); 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci res = netdev_rx_handler_register(slave_dev, bond_handle_frame, 217562306a36Sopenharmony_ci new_slave); 217662306a36Sopenharmony_ci if (res) { 217762306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "Error %d calling netdev_rx_handler_register\n", res); 217862306a36Sopenharmony_ci goto err_detach; 217962306a36Sopenharmony_ci } 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci res = bond_master_upper_dev_link(bond, new_slave, extack); 218262306a36Sopenharmony_ci if (res) { 218362306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "Error %d calling bond_master_upper_dev_link\n", res); 218462306a36Sopenharmony_ci goto err_unregister; 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci bond_lower_state_changed(new_slave); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci res = bond_sysfs_slave_add(new_slave); 219062306a36Sopenharmony_ci if (res) { 219162306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "Error %d calling bond_sysfs_slave_add\n", res); 219262306a36Sopenharmony_ci goto err_upper_unlink; 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci /* If the mode uses primary, then the following is handled by 219662306a36Sopenharmony_ci * bond_change_active_slave(). 219762306a36Sopenharmony_ci */ 219862306a36Sopenharmony_ci if (!bond_uses_primary(bond)) { 219962306a36Sopenharmony_ci /* set promiscuity level to new slave */ 220062306a36Sopenharmony_ci if (bond_dev->flags & IFF_PROMISC) { 220162306a36Sopenharmony_ci res = dev_set_promiscuity(slave_dev, 1); 220262306a36Sopenharmony_ci if (res) 220362306a36Sopenharmony_ci goto err_sysfs_del; 220462306a36Sopenharmony_ci } 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci /* set allmulti level to new slave */ 220762306a36Sopenharmony_ci if (bond_dev->flags & IFF_ALLMULTI) { 220862306a36Sopenharmony_ci res = dev_set_allmulti(slave_dev, 1); 220962306a36Sopenharmony_ci if (res) { 221062306a36Sopenharmony_ci if (bond_dev->flags & IFF_PROMISC) 221162306a36Sopenharmony_ci dev_set_promiscuity(slave_dev, -1); 221262306a36Sopenharmony_ci goto err_sysfs_del; 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci if (bond_dev->flags & IFF_UP) { 221762306a36Sopenharmony_ci netif_addr_lock_bh(bond_dev); 221862306a36Sopenharmony_ci dev_mc_sync_multiple(slave_dev, bond_dev); 221962306a36Sopenharmony_ci dev_uc_sync_multiple(slave_dev, bond_dev); 222062306a36Sopenharmony_ci netif_addr_unlock_bh(bond_dev); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 222362306a36Sopenharmony_ci dev_mc_add(slave_dev, lacpdu_mcast_addr); 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci bond->slave_cnt++; 222862306a36Sopenharmony_ci bond_compute_features(bond); 222962306a36Sopenharmony_ci bond_set_carrier(bond); 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci if (bond_uses_primary(bond)) { 223262306a36Sopenharmony_ci block_netpoll_tx(); 223362306a36Sopenharmony_ci bond_select_active_slave(bond); 223462306a36Sopenharmony_ci unblock_netpoll_tx(); 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci if (bond_mode_can_use_xmit_hash(bond)) 223862306a36Sopenharmony_ci bond_update_slave_arr(bond, NULL); 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci if (!slave_dev->netdev_ops->ndo_bpf || 224262306a36Sopenharmony_ci !slave_dev->netdev_ops->ndo_xdp_xmit) { 224362306a36Sopenharmony_ci if (bond->xdp_prog) { 224462306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 224562306a36Sopenharmony_ci "Slave does not support XDP"); 224662306a36Sopenharmony_ci res = -EOPNOTSUPP; 224762306a36Sopenharmony_ci goto err_sysfs_del; 224862306a36Sopenharmony_ci } 224962306a36Sopenharmony_ci } else if (bond->xdp_prog) { 225062306a36Sopenharmony_ci struct netdev_bpf xdp = { 225162306a36Sopenharmony_ci .command = XDP_SETUP_PROG, 225262306a36Sopenharmony_ci .flags = 0, 225362306a36Sopenharmony_ci .prog = bond->xdp_prog, 225462306a36Sopenharmony_ci .extack = extack, 225562306a36Sopenharmony_ci }; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci if (dev_xdp_prog_count(slave_dev) > 0) { 225862306a36Sopenharmony_ci SLAVE_NL_ERR(bond_dev, slave_dev, extack, 225962306a36Sopenharmony_ci "Slave has XDP program loaded, please unload before enslaving"); 226062306a36Sopenharmony_ci res = -EOPNOTSUPP; 226162306a36Sopenharmony_ci goto err_sysfs_del; 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci res = slave_dev->netdev_ops->ndo_bpf(slave_dev, &xdp); 226562306a36Sopenharmony_ci if (res < 0) { 226662306a36Sopenharmony_ci /* ndo_bpf() sets extack error message */ 226762306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "Error %d calling ndo_bpf\n", res); 226862306a36Sopenharmony_ci goto err_sysfs_del; 226962306a36Sopenharmony_ci } 227062306a36Sopenharmony_ci if (bond->xdp_prog) 227162306a36Sopenharmony_ci bpf_prog_inc(bond->xdp_prog); 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci bond_xdp_set_features(bond_dev); 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n", 227762306a36Sopenharmony_ci bond_is_active_slave(new_slave) ? "an active" : "a backup", 227862306a36Sopenharmony_ci new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci /* enslave is successful */ 228162306a36Sopenharmony_ci bond_queue_slave_event(new_slave); 228262306a36Sopenharmony_ci return 0; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci/* Undo stages on error */ 228562306a36Sopenharmony_cierr_sysfs_del: 228662306a36Sopenharmony_ci bond_sysfs_slave_del(new_slave); 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_cierr_upper_unlink: 228962306a36Sopenharmony_ci bond_upper_dev_unlink(bond, new_slave); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_cierr_unregister: 229262306a36Sopenharmony_ci netdev_rx_handler_unregister(slave_dev); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_cierr_detach: 229562306a36Sopenharmony_ci vlan_vids_del_by_dev(slave_dev, bond_dev); 229662306a36Sopenharmony_ci if (rcu_access_pointer(bond->primary_slave) == new_slave) 229762306a36Sopenharmony_ci RCU_INIT_POINTER(bond->primary_slave, NULL); 229862306a36Sopenharmony_ci if (rcu_access_pointer(bond->curr_active_slave) == new_slave) { 229962306a36Sopenharmony_ci block_netpoll_tx(); 230062306a36Sopenharmony_ci bond_change_active_slave(bond, NULL); 230162306a36Sopenharmony_ci bond_select_active_slave(bond); 230262306a36Sopenharmony_ci unblock_netpoll_tx(); 230362306a36Sopenharmony_ci } 230462306a36Sopenharmony_ci /* either primary_slave or curr_active_slave might've changed */ 230562306a36Sopenharmony_ci synchronize_rcu(); 230662306a36Sopenharmony_ci slave_disable_netpoll(new_slave); 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_cierr_close: 230962306a36Sopenharmony_ci if (!netif_is_bond_master(slave_dev)) 231062306a36Sopenharmony_ci slave_dev->priv_flags &= ~IFF_BONDING; 231162306a36Sopenharmony_ci dev_close(slave_dev); 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_cierr_restore_mac: 231462306a36Sopenharmony_ci slave_dev->priv_flags &= ~IFF_NO_ADDRCONF; 231562306a36Sopenharmony_ci if (!bond->params.fail_over_mac || 231662306a36Sopenharmony_ci BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { 231762306a36Sopenharmony_ci /* XXX TODO - fom follow mode needs to change master's 231862306a36Sopenharmony_ci * MAC if this slave's MAC is in use by the bond, or at 231962306a36Sopenharmony_ci * least print a warning. 232062306a36Sopenharmony_ci */ 232162306a36Sopenharmony_ci bond_hw_addr_copy(ss.__data, new_slave->perm_hwaddr, 232262306a36Sopenharmony_ci new_slave->dev->addr_len); 232362306a36Sopenharmony_ci ss.ss_family = slave_dev->type; 232462306a36Sopenharmony_ci dev_set_mac_address(slave_dev, (struct sockaddr *)&ss, NULL); 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_cierr_restore_mtu: 232862306a36Sopenharmony_ci dev_set_mtu(slave_dev, new_slave->original_mtu); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_cierr_free: 233162306a36Sopenharmony_ci kobject_put(&new_slave->kobj); 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_cierr_undo_flags: 233462306a36Sopenharmony_ci /* Enslave of first slave has failed and we need to fix master's mac */ 233562306a36Sopenharmony_ci if (!bond_has_slaves(bond)) { 233662306a36Sopenharmony_ci if (ether_addr_equal_64bits(bond_dev->dev_addr, 233762306a36Sopenharmony_ci slave_dev->dev_addr)) 233862306a36Sopenharmony_ci eth_hw_addr_random(bond_dev); 233962306a36Sopenharmony_ci if (bond_dev->type != ARPHRD_ETHER) { 234062306a36Sopenharmony_ci dev_close(bond_dev); 234162306a36Sopenharmony_ci bond_ether_setup(bond_dev); 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci return res; 234662306a36Sopenharmony_ci} 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci/* Try to release the slave device <slave> from the bond device <master> 234962306a36Sopenharmony_ci * It is legal to access curr_active_slave without a lock because all the function 235062306a36Sopenharmony_ci * is RTNL-locked. If "all" is true it means that the function is being called 235162306a36Sopenharmony_ci * while destroying a bond interface and all slaves are being released. 235262306a36Sopenharmony_ci * 235362306a36Sopenharmony_ci * The rules for slave state should be: 235462306a36Sopenharmony_ci * for Active/Backup: 235562306a36Sopenharmony_ci * Active stays on all backups go down 235662306a36Sopenharmony_ci * for Bonded connections: 235762306a36Sopenharmony_ci * The first up interface should be left on and all others downed. 235862306a36Sopenharmony_ci */ 235962306a36Sopenharmony_cistatic int __bond_release_one(struct net_device *bond_dev, 236062306a36Sopenharmony_ci struct net_device *slave_dev, 236162306a36Sopenharmony_ci bool all, bool unregister) 236262306a36Sopenharmony_ci{ 236362306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 236462306a36Sopenharmony_ci struct slave *slave, *oldcurrent; 236562306a36Sopenharmony_ci struct sockaddr_storage ss; 236662306a36Sopenharmony_ci int old_flags = bond_dev->flags; 236762306a36Sopenharmony_ci netdev_features_t old_features = bond_dev->features; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci /* slave is not a slave or master is not master of this slave */ 237062306a36Sopenharmony_ci if (!(slave_dev->flags & IFF_SLAVE) || 237162306a36Sopenharmony_ci !netdev_has_upper_dev(slave_dev, bond_dev)) { 237262306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "cannot release slave\n"); 237362306a36Sopenharmony_ci return -EINVAL; 237462306a36Sopenharmony_ci } 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci block_netpoll_tx(); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci slave = bond_get_slave_by_dev(bond, slave_dev); 237962306a36Sopenharmony_ci if (!slave) { 238062306a36Sopenharmony_ci /* not a slave of this bond */ 238162306a36Sopenharmony_ci slave_info(bond_dev, slave_dev, "interface not enslaved\n"); 238262306a36Sopenharmony_ci unblock_netpoll_tx(); 238362306a36Sopenharmony_ci return -EINVAL; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci bond_set_slave_inactive_flags(slave, BOND_SLAVE_NOTIFY_NOW); 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci bond_sysfs_slave_del(slave); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci /* recompute stats just before removing the slave */ 239162306a36Sopenharmony_ci bond_get_stats(bond->dev, &bond->bond_stats); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if (bond->xdp_prog) { 239462306a36Sopenharmony_ci struct netdev_bpf xdp = { 239562306a36Sopenharmony_ci .command = XDP_SETUP_PROG, 239662306a36Sopenharmony_ci .flags = 0, 239762306a36Sopenharmony_ci .prog = NULL, 239862306a36Sopenharmony_ci .extack = NULL, 239962306a36Sopenharmony_ci }; 240062306a36Sopenharmony_ci if (slave_dev->netdev_ops->ndo_bpf(slave_dev, &xdp)) 240162306a36Sopenharmony_ci slave_warn(bond_dev, slave_dev, "failed to unload XDP program\n"); 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci /* unregister rx_handler early so bond_handle_frame wouldn't be called 240562306a36Sopenharmony_ci * for this slave anymore. 240662306a36Sopenharmony_ci */ 240762306a36Sopenharmony_ci netdev_rx_handler_unregister(slave_dev); 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 241062306a36Sopenharmony_ci bond_3ad_unbind_slave(slave); 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci bond_upper_dev_unlink(bond, slave); 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci if (bond_mode_can_use_xmit_hash(bond)) 241562306a36Sopenharmony_ci bond_update_slave_arr(bond, slave); 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci slave_info(bond_dev, slave_dev, "Releasing %s interface\n", 241862306a36Sopenharmony_ci bond_is_active_slave(slave) ? "active" : "backup"); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci oldcurrent = rcu_access_pointer(bond->curr_active_slave); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci RCU_INIT_POINTER(bond->current_arp_slave, NULL); 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci if (!all && (!bond->params.fail_over_mac || 242562306a36Sopenharmony_ci BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP)) { 242662306a36Sopenharmony_ci if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) && 242762306a36Sopenharmony_ci bond_has_slaves(bond)) 242862306a36Sopenharmony_ci slave_warn(bond_dev, slave_dev, "the permanent HWaddr of slave - %pM - is still in use by bond - set the HWaddr of slave to a different address to avoid conflicts\n", 242962306a36Sopenharmony_ci slave->perm_hwaddr); 243062306a36Sopenharmony_ci } 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci if (rtnl_dereference(bond->primary_slave) == slave) 243362306a36Sopenharmony_ci RCU_INIT_POINTER(bond->primary_slave, NULL); 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci if (oldcurrent == slave) 243662306a36Sopenharmony_ci bond_change_active_slave(bond, NULL); 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci if (bond_is_lb(bond)) { 243962306a36Sopenharmony_ci /* Must be called only after the slave has been 244062306a36Sopenharmony_ci * detached from the list and the curr_active_slave 244162306a36Sopenharmony_ci * has been cleared (if our_slave == old_current), 244262306a36Sopenharmony_ci * but before a new active slave is selected. 244362306a36Sopenharmony_ci */ 244462306a36Sopenharmony_ci bond_alb_deinit_slave(bond, slave); 244562306a36Sopenharmony_ci } 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci if (all) { 244862306a36Sopenharmony_ci RCU_INIT_POINTER(bond->curr_active_slave, NULL); 244962306a36Sopenharmony_ci } else if (oldcurrent == slave) { 245062306a36Sopenharmony_ci /* Note that we hold RTNL over this sequence, so there 245162306a36Sopenharmony_ci * is no concern that another slave add/remove event 245262306a36Sopenharmony_ci * will interfere. 245362306a36Sopenharmony_ci */ 245462306a36Sopenharmony_ci bond_select_active_slave(bond); 245562306a36Sopenharmony_ci } 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ci bond_set_carrier(bond); 245862306a36Sopenharmony_ci if (!bond_has_slaves(bond)) 245962306a36Sopenharmony_ci eth_hw_addr_random(bond_dev); 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci unblock_netpoll_tx(); 246262306a36Sopenharmony_ci synchronize_rcu(); 246362306a36Sopenharmony_ci bond->slave_cnt--; 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci if (!bond_has_slaves(bond)) { 246662306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev); 246762306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_RELEASE, bond->dev); 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci bond_compute_features(bond); 247162306a36Sopenharmony_ci if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) && 247262306a36Sopenharmony_ci (old_features & NETIF_F_VLAN_CHALLENGED)) 247362306a36Sopenharmony_ci slave_info(bond_dev, slave_dev, "last VLAN challenged slave left bond - VLAN blocking is removed\n"); 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci vlan_vids_del_by_dev(slave_dev, bond_dev); 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci /* If the mode uses primary, then this case was handled above by 247862306a36Sopenharmony_ci * bond_change_active_slave(..., NULL) 247962306a36Sopenharmony_ci */ 248062306a36Sopenharmony_ci if (!bond_uses_primary(bond)) { 248162306a36Sopenharmony_ci /* unset promiscuity level from slave 248262306a36Sopenharmony_ci * NOTE: The NETDEV_CHANGEADDR call above may change the value 248362306a36Sopenharmony_ci * of the IFF_PROMISC flag in the bond_dev, but we need the 248462306a36Sopenharmony_ci * value of that flag before that change, as that was the value 248562306a36Sopenharmony_ci * when this slave was attached, so we cache at the start of the 248662306a36Sopenharmony_ci * function and use it here. Same goes for ALLMULTI below 248762306a36Sopenharmony_ci */ 248862306a36Sopenharmony_ci if (old_flags & IFF_PROMISC) 248962306a36Sopenharmony_ci dev_set_promiscuity(slave_dev, -1); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci /* unset allmulti level from slave */ 249262306a36Sopenharmony_ci if (old_flags & IFF_ALLMULTI) 249362306a36Sopenharmony_ci dev_set_allmulti(slave_dev, -1); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci if (old_flags & IFF_UP) 249662306a36Sopenharmony_ci bond_hw_addr_flush(bond_dev, slave_dev); 249762306a36Sopenharmony_ci } 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci slave_disable_netpoll(slave); 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci /* close slave before restoring its mac address */ 250262306a36Sopenharmony_ci dev_close(slave_dev); 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci slave_dev->priv_flags &= ~IFF_NO_ADDRCONF; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (bond->params.fail_over_mac != BOND_FOM_ACTIVE || 250762306a36Sopenharmony_ci BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { 250862306a36Sopenharmony_ci /* restore original ("permanent") mac address */ 250962306a36Sopenharmony_ci bond_hw_addr_copy(ss.__data, slave->perm_hwaddr, 251062306a36Sopenharmony_ci slave->dev->addr_len); 251162306a36Sopenharmony_ci ss.ss_family = slave_dev->type; 251262306a36Sopenharmony_ci dev_set_mac_address(slave_dev, (struct sockaddr *)&ss, NULL); 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci if (unregister) 251662306a36Sopenharmony_ci __dev_set_mtu(slave_dev, slave->original_mtu); 251762306a36Sopenharmony_ci else 251862306a36Sopenharmony_ci dev_set_mtu(slave_dev, slave->original_mtu); 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci if (!netif_is_bond_master(slave_dev)) 252162306a36Sopenharmony_ci slave_dev->priv_flags &= ~IFF_BONDING; 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci bond_xdp_set_features(bond_dev); 252462306a36Sopenharmony_ci kobject_put(&slave->kobj); 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci return 0; 252762306a36Sopenharmony_ci} 252862306a36Sopenharmony_ci 252962306a36Sopenharmony_ci/* A wrapper used because of ndo_del_link */ 253062306a36Sopenharmony_ciint bond_release(struct net_device *bond_dev, struct net_device *slave_dev) 253162306a36Sopenharmony_ci{ 253262306a36Sopenharmony_ci return __bond_release_one(bond_dev, slave_dev, false, false); 253362306a36Sopenharmony_ci} 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci/* First release a slave and then destroy the bond if no more slaves are left. 253662306a36Sopenharmony_ci * Must be under rtnl_lock when this function is called. 253762306a36Sopenharmony_ci */ 253862306a36Sopenharmony_cistatic int bond_release_and_destroy(struct net_device *bond_dev, 253962306a36Sopenharmony_ci struct net_device *slave_dev) 254062306a36Sopenharmony_ci{ 254162306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 254262306a36Sopenharmony_ci int ret; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_ci ret = __bond_release_one(bond_dev, slave_dev, false, true); 254562306a36Sopenharmony_ci if (ret == 0 && !bond_has_slaves(bond) && 254662306a36Sopenharmony_ci bond_dev->reg_state != NETREG_UNREGISTERING) { 254762306a36Sopenharmony_ci bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; 254862306a36Sopenharmony_ci netdev_info(bond_dev, "Destroying bond\n"); 254962306a36Sopenharmony_ci bond_remove_proc_entry(bond); 255062306a36Sopenharmony_ci unregister_netdevice(bond_dev); 255162306a36Sopenharmony_ci } 255262306a36Sopenharmony_ci return ret; 255362306a36Sopenharmony_ci} 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_cistatic void bond_info_query(struct net_device *bond_dev, struct ifbond *info) 255662306a36Sopenharmony_ci{ 255762306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci bond_fill_ifbond(bond, info); 256062306a36Sopenharmony_ci} 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_cistatic int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) 256362306a36Sopenharmony_ci{ 256462306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 256562306a36Sopenharmony_ci struct list_head *iter; 256662306a36Sopenharmony_ci int i = 0, res = -ENODEV; 256762306a36Sopenharmony_ci struct slave *slave; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 257062306a36Sopenharmony_ci if (i++ == (int)info->slave_id) { 257162306a36Sopenharmony_ci res = 0; 257262306a36Sopenharmony_ci bond_fill_ifslave(slave, info); 257362306a36Sopenharmony_ci break; 257462306a36Sopenharmony_ci } 257562306a36Sopenharmony_ci } 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci return res; 257862306a36Sopenharmony_ci} 257962306a36Sopenharmony_ci 258062306a36Sopenharmony_ci/*-------------------------------- Monitoring -------------------------------*/ 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci/* called with rcu_read_lock() */ 258362306a36Sopenharmony_cistatic int bond_miimon_inspect(struct bonding *bond) 258462306a36Sopenharmony_ci{ 258562306a36Sopenharmony_ci bool ignore_updelay = false; 258662306a36Sopenharmony_ci int link_state, commit = 0; 258762306a36Sopenharmony_ci struct list_head *iter; 258862306a36Sopenharmony_ci struct slave *slave; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) { 259162306a36Sopenharmony_ci ignore_updelay = !rcu_dereference(bond->curr_active_slave); 259262306a36Sopenharmony_ci } else { 259362306a36Sopenharmony_ci struct bond_up_slave *usable_slaves; 259462306a36Sopenharmony_ci 259562306a36Sopenharmony_ci usable_slaves = rcu_dereference(bond->usable_slaves); 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci if (usable_slaves && usable_slaves->count == 0) 259862306a36Sopenharmony_ci ignore_updelay = true; 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 260262306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_NOCHANGE); 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci link_state = bond_check_dev_link(bond, slave->dev, 0); 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_ci switch (slave->link) { 260762306a36Sopenharmony_ci case BOND_LINK_UP: 260862306a36Sopenharmony_ci if (link_state) 260962306a36Sopenharmony_ci continue; 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_FAIL); 261262306a36Sopenharmony_ci commit++; 261362306a36Sopenharmony_ci slave->delay = bond->params.downdelay; 261462306a36Sopenharmony_ci if (slave->delay) { 261562306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status down for %sinterface, disabling it in %d ms\n", 261662306a36Sopenharmony_ci (BOND_MODE(bond) == 261762306a36Sopenharmony_ci BOND_MODE_ACTIVEBACKUP) ? 261862306a36Sopenharmony_ci (bond_is_active_slave(slave) ? 261962306a36Sopenharmony_ci "active " : "backup ") : "", 262062306a36Sopenharmony_ci bond->params.downdelay * bond->params.miimon); 262162306a36Sopenharmony_ci } 262262306a36Sopenharmony_ci fallthrough; 262362306a36Sopenharmony_ci case BOND_LINK_FAIL: 262462306a36Sopenharmony_ci if (link_state) { 262562306a36Sopenharmony_ci /* recovered before downdelay expired */ 262662306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_UP); 262762306a36Sopenharmony_ci slave->last_link_up = jiffies; 262862306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status up again after %d ms\n", 262962306a36Sopenharmony_ci (bond->params.downdelay - slave->delay) * 263062306a36Sopenharmony_ci bond->params.miimon); 263162306a36Sopenharmony_ci commit++; 263262306a36Sopenharmony_ci continue; 263362306a36Sopenharmony_ci } 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci if (slave->delay <= 0) { 263662306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_DOWN); 263762306a36Sopenharmony_ci commit++; 263862306a36Sopenharmony_ci continue; 263962306a36Sopenharmony_ci } 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci slave->delay--; 264262306a36Sopenharmony_ci break; 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_ci case BOND_LINK_DOWN: 264562306a36Sopenharmony_ci if (!link_state) 264662306a36Sopenharmony_ci continue; 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_BACK); 264962306a36Sopenharmony_ci commit++; 265062306a36Sopenharmony_ci slave->delay = bond->params.updelay; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci if (slave->delay) { 265362306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status up, enabling it in %d ms\n", 265462306a36Sopenharmony_ci ignore_updelay ? 0 : 265562306a36Sopenharmony_ci bond->params.updelay * 265662306a36Sopenharmony_ci bond->params.miimon); 265762306a36Sopenharmony_ci } 265862306a36Sopenharmony_ci fallthrough; 265962306a36Sopenharmony_ci case BOND_LINK_BACK: 266062306a36Sopenharmony_ci if (!link_state) { 266162306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_DOWN); 266262306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status down again after %d ms\n", 266362306a36Sopenharmony_ci (bond->params.updelay - slave->delay) * 266462306a36Sopenharmony_ci bond->params.miimon); 266562306a36Sopenharmony_ci commit++; 266662306a36Sopenharmony_ci continue; 266762306a36Sopenharmony_ci } 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci if (ignore_updelay) 267062306a36Sopenharmony_ci slave->delay = 0; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci if (slave->delay <= 0) { 267362306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_UP); 267462306a36Sopenharmony_ci commit++; 267562306a36Sopenharmony_ci ignore_updelay = false; 267662306a36Sopenharmony_ci continue; 267762306a36Sopenharmony_ci } 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci slave->delay--; 268062306a36Sopenharmony_ci break; 268162306a36Sopenharmony_ci } 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci return commit; 268562306a36Sopenharmony_ci} 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_cistatic void bond_miimon_link_change(struct bonding *bond, 268862306a36Sopenharmony_ci struct slave *slave, 268962306a36Sopenharmony_ci char link) 269062306a36Sopenharmony_ci{ 269162306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 269262306a36Sopenharmony_ci case BOND_MODE_8023AD: 269362306a36Sopenharmony_ci bond_3ad_handle_link_change(slave, link); 269462306a36Sopenharmony_ci break; 269562306a36Sopenharmony_ci case BOND_MODE_TLB: 269662306a36Sopenharmony_ci case BOND_MODE_ALB: 269762306a36Sopenharmony_ci bond_alb_handle_link_change(bond, slave, link); 269862306a36Sopenharmony_ci break; 269962306a36Sopenharmony_ci case BOND_MODE_XOR: 270062306a36Sopenharmony_ci bond_update_slave_arr(bond, NULL); 270162306a36Sopenharmony_ci break; 270262306a36Sopenharmony_ci } 270362306a36Sopenharmony_ci} 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_cistatic void bond_miimon_commit(struct bonding *bond) 270662306a36Sopenharmony_ci{ 270762306a36Sopenharmony_ci struct slave *slave, *primary, *active; 270862306a36Sopenharmony_ci bool do_failover = false; 270962306a36Sopenharmony_ci struct list_head *iter; 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci ASSERT_RTNL(); 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 271462306a36Sopenharmony_ci switch (slave->link_new_state) { 271562306a36Sopenharmony_ci case BOND_LINK_NOCHANGE: 271662306a36Sopenharmony_ci /* For 802.3ad mode, check current slave speed and 271762306a36Sopenharmony_ci * duplex again in case its port was disabled after 271862306a36Sopenharmony_ci * invalid speed/duplex reporting but recovered before 271962306a36Sopenharmony_ci * link monitoring could make a decision on the actual 272062306a36Sopenharmony_ci * link status 272162306a36Sopenharmony_ci */ 272262306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD && 272362306a36Sopenharmony_ci slave->link == BOND_LINK_UP) 272462306a36Sopenharmony_ci bond_3ad_adapter_speed_duplex_changed(slave); 272562306a36Sopenharmony_ci continue; 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci case BOND_LINK_UP: 272862306a36Sopenharmony_ci if (bond_update_speed_duplex(slave) && 272962306a36Sopenharmony_ci bond_needs_speed_duplex(bond)) { 273062306a36Sopenharmony_ci slave->link = BOND_LINK_DOWN; 273162306a36Sopenharmony_ci if (net_ratelimit()) 273262306a36Sopenharmony_ci slave_warn(bond->dev, slave->dev, 273362306a36Sopenharmony_ci "failed to get link speed/duplex\n"); 273462306a36Sopenharmony_ci continue; 273562306a36Sopenharmony_ci } 273662306a36Sopenharmony_ci bond_set_slave_link_state(slave, BOND_LINK_UP, 273762306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 273862306a36Sopenharmony_ci slave->last_link_up = jiffies; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci primary = rtnl_dereference(bond->primary_slave); 274162306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 274262306a36Sopenharmony_ci /* prevent it from being the active one */ 274362306a36Sopenharmony_ci bond_set_backup_slave(slave); 274462306a36Sopenharmony_ci } else if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) { 274562306a36Sopenharmony_ci /* make it immediately active */ 274662306a36Sopenharmony_ci bond_set_active_slave(slave); 274762306a36Sopenharmony_ci } 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status definitely up, %u Mbps %s duplex\n", 275062306a36Sopenharmony_ci slave->speed == SPEED_UNKNOWN ? 0 : slave->speed, 275162306a36Sopenharmony_ci slave->duplex ? "full" : "half"); 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci bond_miimon_link_change(bond, slave, BOND_LINK_UP); 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci active = rtnl_dereference(bond->curr_active_slave); 275662306a36Sopenharmony_ci if (!active || slave == primary || slave->prio > active->prio) 275762306a36Sopenharmony_ci do_failover = true; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci continue; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci case BOND_LINK_DOWN: 276262306a36Sopenharmony_ci if (slave->link_failure_count < UINT_MAX) 276362306a36Sopenharmony_ci slave->link_failure_count++; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci bond_set_slave_link_state(slave, BOND_LINK_DOWN, 276662306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 276762306a36Sopenharmony_ci 276862306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP || 276962306a36Sopenharmony_ci BOND_MODE(bond) == BOND_MODE_8023AD) 277062306a36Sopenharmony_ci bond_set_slave_inactive_flags(slave, 277162306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n"); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci bond_miimon_link_change(bond, slave, BOND_LINK_DOWN); 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci if (slave == rcu_access_pointer(bond->curr_active_slave)) 277862306a36Sopenharmony_ci do_failover = true; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci continue; 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci default: 278362306a36Sopenharmony_ci slave_err(bond->dev, slave->dev, "invalid new link %d on slave\n", 278462306a36Sopenharmony_ci slave->link_new_state); 278562306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_NOCHANGE); 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci continue; 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci } 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci if (do_failover) { 279262306a36Sopenharmony_ci block_netpoll_tx(); 279362306a36Sopenharmony_ci bond_select_active_slave(bond); 279462306a36Sopenharmony_ci unblock_netpoll_tx(); 279562306a36Sopenharmony_ci } 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci bond_set_carrier(bond); 279862306a36Sopenharmony_ci} 279962306a36Sopenharmony_ci 280062306a36Sopenharmony_ci/* bond_mii_monitor 280162306a36Sopenharmony_ci * 280262306a36Sopenharmony_ci * Really a wrapper that splits the mii monitor into two phases: an 280362306a36Sopenharmony_ci * inspection, then (if inspection indicates something needs to be done) 280462306a36Sopenharmony_ci * an acquisition of appropriate locks followed by a commit phase to 280562306a36Sopenharmony_ci * implement whatever link state changes are indicated. 280662306a36Sopenharmony_ci */ 280762306a36Sopenharmony_cistatic void bond_mii_monitor(struct work_struct *work) 280862306a36Sopenharmony_ci{ 280962306a36Sopenharmony_ci struct bonding *bond = container_of(work, struct bonding, 281062306a36Sopenharmony_ci mii_work.work); 281162306a36Sopenharmony_ci bool should_notify_peers = false; 281262306a36Sopenharmony_ci bool commit; 281362306a36Sopenharmony_ci unsigned long delay; 281462306a36Sopenharmony_ci struct slave *slave; 281562306a36Sopenharmony_ci struct list_head *iter; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci delay = msecs_to_jiffies(bond->params.miimon); 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci if (!bond_has_slaves(bond)) 282062306a36Sopenharmony_ci goto re_arm; 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci rcu_read_lock(); 282362306a36Sopenharmony_ci should_notify_peers = bond_should_notify_peers(bond); 282462306a36Sopenharmony_ci commit = !!bond_miimon_inspect(bond); 282562306a36Sopenharmony_ci if (bond->send_peer_notif) { 282662306a36Sopenharmony_ci rcu_read_unlock(); 282762306a36Sopenharmony_ci if (rtnl_trylock()) { 282862306a36Sopenharmony_ci bond->send_peer_notif--; 282962306a36Sopenharmony_ci rtnl_unlock(); 283062306a36Sopenharmony_ci } 283162306a36Sopenharmony_ci } else { 283262306a36Sopenharmony_ci rcu_read_unlock(); 283362306a36Sopenharmony_ci } 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci if (commit) { 283662306a36Sopenharmony_ci /* Race avoidance with bond_close cancel of workqueue */ 283762306a36Sopenharmony_ci if (!rtnl_trylock()) { 283862306a36Sopenharmony_ci delay = 1; 283962306a36Sopenharmony_ci should_notify_peers = false; 284062306a36Sopenharmony_ci goto re_arm; 284162306a36Sopenharmony_ci } 284262306a36Sopenharmony_ci 284362306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 284462306a36Sopenharmony_ci bond_commit_link_state(slave, BOND_SLAVE_NOTIFY_LATER); 284562306a36Sopenharmony_ci } 284662306a36Sopenharmony_ci bond_miimon_commit(bond); 284762306a36Sopenharmony_ci 284862306a36Sopenharmony_ci rtnl_unlock(); /* might sleep, hold no other locks */ 284962306a36Sopenharmony_ci } 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_cire_arm: 285262306a36Sopenharmony_ci if (bond->params.miimon) 285362306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->mii_work, delay); 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_ci if (should_notify_peers) { 285662306a36Sopenharmony_ci if (!rtnl_trylock()) 285762306a36Sopenharmony_ci return; 285862306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev); 285962306a36Sopenharmony_ci rtnl_unlock(); 286062306a36Sopenharmony_ci } 286162306a36Sopenharmony_ci} 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_cistatic int bond_upper_dev_walk(struct net_device *upper, 286462306a36Sopenharmony_ci struct netdev_nested_priv *priv) 286562306a36Sopenharmony_ci{ 286662306a36Sopenharmony_ci __be32 ip = *(__be32 *)priv->data; 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci return ip == bond_confirm_addr(upper, 0, ip); 286962306a36Sopenharmony_ci} 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_cistatic bool bond_has_this_ip(struct bonding *bond, __be32 ip) 287262306a36Sopenharmony_ci{ 287362306a36Sopenharmony_ci struct netdev_nested_priv priv = { 287462306a36Sopenharmony_ci .data = (void *)&ip, 287562306a36Sopenharmony_ci }; 287662306a36Sopenharmony_ci bool ret = false; 287762306a36Sopenharmony_ci 287862306a36Sopenharmony_ci if (ip == bond_confirm_addr(bond->dev, 0, ip)) 287962306a36Sopenharmony_ci return true; 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_ci rcu_read_lock(); 288262306a36Sopenharmony_ci if (netdev_walk_all_upper_dev_rcu(bond->dev, bond_upper_dev_walk, &priv)) 288362306a36Sopenharmony_ci ret = true; 288462306a36Sopenharmony_ci rcu_read_unlock(); 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci return ret; 288762306a36Sopenharmony_ci} 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci#define BOND_VLAN_PROTO_NONE cpu_to_be16(0xffff) 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_cistatic bool bond_handle_vlan(struct slave *slave, struct bond_vlan_tag *tags, 289262306a36Sopenharmony_ci struct sk_buff *skb) 289362306a36Sopenharmony_ci{ 289462306a36Sopenharmony_ci struct net_device *bond_dev = slave->bond->dev; 289562306a36Sopenharmony_ci struct net_device *slave_dev = slave->dev; 289662306a36Sopenharmony_ci struct bond_vlan_tag *outer_tag = tags; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci if (!tags || tags->vlan_proto == BOND_VLAN_PROTO_NONE) 289962306a36Sopenharmony_ci return true; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci tags++; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci /* Go through all the tags backwards and add them to the packet */ 290462306a36Sopenharmony_ci while (tags->vlan_proto != BOND_VLAN_PROTO_NONE) { 290562306a36Sopenharmony_ci if (!tags->vlan_id) { 290662306a36Sopenharmony_ci tags++; 290762306a36Sopenharmony_ci continue; 290862306a36Sopenharmony_ci } 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "inner tag: proto %X vid %X\n", 291162306a36Sopenharmony_ci ntohs(outer_tag->vlan_proto), tags->vlan_id); 291262306a36Sopenharmony_ci skb = vlan_insert_tag_set_proto(skb, tags->vlan_proto, 291362306a36Sopenharmony_ci tags->vlan_id); 291462306a36Sopenharmony_ci if (!skb) { 291562306a36Sopenharmony_ci net_err_ratelimited("failed to insert inner VLAN tag\n"); 291662306a36Sopenharmony_ci return false; 291762306a36Sopenharmony_ci } 291862306a36Sopenharmony_ci 291962306a36Sopenharmony_ci tags++; 292062306a36Sopenharmony_ci } 292162306a36Sopenharmony_ci /* Set the outer tag */ 292262306a36Sopenharmony_ci if (outer_tag->vlan_id) { 292362306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "outer tag: proto %X vid %X\n", 292462306a36Sopenharmony_ci ntohs(outer_tag->vlan_proto), outer_tag->vlan_id); 292562306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, outer_tag->vlan_proto, 292662306a36Sopenharmony_ci outer_tag->vlan_id); 292762306a36Sopenharmony_ci } 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci return true; 293062306a36Sopenharmony_ci} 293162306a36Sopenharmony_ci 293262306a36Sopenharmony_ci/* We go to the (large) trouble of VLAN tagging ARP frames because 293362306a36Sopenharmony_ci * switches in VLAN mode (especially if ports are configured as 293462306a36Sopenharmony_ci * "native" to a VLAN) might not pass non-tagged frames. 293562306a36Sopenharmony_ci */ 293662306a36Sopenharmony_cistatic void bond_arp_send(struct slave *slave, int arp_op, __be32 dest_ip, 293762306a36Sopenharmony_ci __be32 src_ip, struct bond_vlan_tag *tags) 293862306a36Sopenharmony_ci{ 293962306a36Sopenharmony_ci struct net_device *bond_dev = slave->bond->dev; 294062306a36Sopenharmony_ci struct net_device *slave_dev = slave->dev; 294162306a36Sopenharmony_ci struct sk_buff *skb; 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "arp %d on slave: dst %pI4 src %pI4\n", 294462306a36Sopenharmony_ci arp_op, &dest_ip, &src_ip); 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, 294762306a36Sopenharmony_ci NULL, slave_dev->dev_addr, NULL); 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci if (!skb) { 295062306a36Sopenharmony_ci net_err_ratelimited("ARP packet allocation failed\n"); 295162306a36Sopenharmony_ci return; 295262306a36Sopenharmony_ci } 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci if (bond_handle_vlan(slave, tags, skb)) { 295562306a36Sopenharmony_ci slave_update_last_tx(slave); 295662306a36Sopenharmony_ci arp_xmit(skb); 295762306a36Sopenharmony_ci } 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci return; 296062306a36Sopenharmony_ci} 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci/* Validate the device path between the @start_dev and the @end_dev. 296362306a36Sopenharmony_ci * The path is valid if the @end_dev is reachable through device 296462306a36Sopenharmony_ci * stacking. 296562306a36Sopenharmony_ci * When the path is validated, collect any vlan information in the 296662306a36Sopenharmony_ci * path. 296762306a36Sopenharmony_ci */ 296862306a36Sopenharmony_cistruct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, 296962306a36Sopenharmony_ci struct net_device *end_dev, 297062306a36Sopenharmony_ci int level) 297162306a36Sopenharmony_ci{ 297262306a36Sopenharmony_ci struct bond_vlan_tag *tags; 297362306a36Sopenharmony_ci struct net_device *upper; 297462306a36Sopenharmony_ci struct list_head *iter; 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci if (start_dev == end_dev) { 297762306a36Sopenharmony_ci tags = kcalloc(level + 1, sizeof(*tags), GFP_ATOMIC); 297862306a36Sopenharmony_ci if (!tags) 297962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 298062306a36Sopenharmony_ci tags[level].vlan_proto = BOND_VLAN_PROTO_NONE; 298162306a36Sopenharmony_ci return tags; 298262306a36Sopenharmony_ci } 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci netdev_for_each_upper_dev_rcu(start_dev, upper, iter) { 298562306a36Sopenharmony_ci tags = bond_verify_device_path(upper, end_dev, level + 1); 298662306a36Sopenharmony_ci if (IS_ERR_OR_NULL(tags)) { 298762306a36Sopenharmony_ci if (IS_ERR(tags)) 298862306a36Sopenharmony_ci return tags; 298962306a36Sopenharmony_ci continue; 299062306a36Sopenharmony_ci } 299162306a36Sopenharmony_ci if (is_vlan_dev(upper)) { 299262306a36Sopenharmony_ci tags[level].vlan_proto = vlan_dev_vlan_proto(upper); 299362306a36Sopenharmony_ci tags[level].vlan_id = vlan_dev_vlan_id(upper); 299462306a36Sopenharmony_ci } 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci return tags; 299762306a36Sopenharmony_ci } 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ci return NULL; 300062306a36Sopenharmony_ci} 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_cistatic void bond_arp_send_all(struct bonding *bond, struct slave *slave) 300362306a36Sopenharmony_ci{ 300462306a36Sopenharmony_ci struct rtable *rt; 300562306a36Sopenharmony_ci struct bond_vlan_tag *tags; 300662306a36Sopenharmony_ci __be32 *targets = bond->params.arp_targets, addr; 300762306a36Sopenharmony_ci int i; 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_ci for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) { 301062306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: target %pI4\n", 301162306a36Sopenharmony_ci __func__, &targets[i]); 301262306a36Sopenharmony_ci tags = NULL; 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci /* Find out through which dev should the packet go */ 301562306a36Sopenharmony_ci rt = ip_route_output(dev_net(bond->dev), targets[i], 0, 301662306a36Sopenharmony_ci RTO_ONLINK, 0); 301762306a36Sopenharmony_ci if (IS_ERR(rt)) { 301862306a36Sopenharmony_ci /* there's no route to target - try to send arp 301962306a36Sopenharmony_ci * probe to generate any traffic (arp_validate=0) 302062306a36Sopenharmony_ci */ 302162306a36Sopenharmony_ci if (bond->params.arp_validate) 302262306a36Sopenharmony_ci pr_warn_once("%s: no route to arp_ip_target %pI4 and arp_validate is set\n", 302362306a36Sopenharmony_ci bond->dev->name, 302462306a36Sopenharmony_ci &targets[i]); 302562306a36Sopenharmony_ci bond_arp_send(slave, ARPOP_REQUEST, targets[i], 302662306a36Sopenharmony_ci 0, tags); 302762306a36Sopenharmony_ci continue; 302862306a36Sopenharmony_ci } 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci /* bond device itself */ 303162306a36Sopenharmony_ci if (rt->dst.dev == bond->dev) 303262306a36Sopenharmony_ci goto found; 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci rcu_read_lock(); 303562306a36Sopenharmony_ci tags = bond_verify_device_path(bond->dev, rt->dst.dev, 0); 303662306a36Sopenharmony_ci rcu_read_unlock(); 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(tags)) 303962306a36Sopenharmony_ci goto found; 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci /* Not our device - skip */ 304262306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "no path to arp_ip_target %pI4 via rt.dev %s\n", 304362306a36Sopenharmony_ci &targets[i], rt->dst.dev ? rt->dst.dev->name : "NULL"); 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci ip_rt_put(rt); 304662306a36Sopenharmony_ci continue; 304762306a36Sopenharmony_ci 304862306a36Sopenharmony_cifound: 304962306a36Sopenharmony_ci addr = bond_confirm_addr(rt->dst.dev, targets[i], 0); 305062306a36Sopenharmony_ci ip_rt_put(rt); 305162306a36Sopenharmony_ci bond_arp_send(slave, ARPOP_REQUEST, targets[i], addr, tags); 305262306a36Sopenharmony_ci kfree(tags); 305362306a36Sopenharmony_ci } 305462306a36Sopenharmony_ci} 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_cistatic void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip) 305762306a36Sopenharmony_ci{ 305862306a36Sopenharmony_ci int i; 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci if (!sip || !bond_has_this_ip(bond, tip)) { 306162306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: sip %pI4 tip %pI4 not found\n", 306262306a36Sopenharmony_ci __func__, &sip, &tip); 306362306a36Sopenharmony_ci return; 306462306a36Sopenharmony_ci } 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci i = bond_get_targets_ip(bond->params.arp_targets, sip); 306762306a36Sopenharmony_ci if (i == -1) { 306862306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: sip %pI4 not found in targets\n", 306962306a36Sopenharmony_ci __func__, &sip); 307062306a36Sopenharmony_ci return; 307162306a36Sopenharmony_ci } 307262306a36Sopenharmony_ci slave->last_rx = jiffies; 307362306a36Sopenharmony_ci slave->target_last_arp_rx[i] = jiffies; 307462306a36Sopenharmony_ci} 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_cistatic int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, 307762306a36Sopenharmony_ci struct slave *slave) 307862306a36Sopenharmony_ci{ 307962306a36Sopenharmony_ci struct arphdr *arp = (struct arphdr *)skb->data; 308062306a36Sopenharmony_ci struct slave *curr_active_slave, *curr_arp_slave; 308162306a36Sopenharmony_ci unsigned char *arp_ptr; 308262306a36Sopenharmony_ci __be32 sip, tip; 308362306a36Sopenharmony_ci unsigned int alen; 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci alen = arp_hdr_len(bond->dev); 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci if (alen > skb_headlen(skb)) { 308862306a36Sopenharmony_ci arp = kmalloc(alen, GFP_ATOMIC); 308962306a36Sopenharmony_ci if (!arp) 309062306a36Sopenharmony_ci goto out_unlock; 309162306a36Sopenharmony_ci if (skb_copy_bits(skb, 0, arp, alen) < 0) 309262306a36Sopenharmony_ci goto out_unlock; 309362306a36Sopenharmony_ci } 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci if (arp->ar_hln != bond->dev->addr_len || 309662306a36Sopenharmony_ci skb->pkt_type == PACKET_OTHERHOST || 309762306a36Sopenharmony_ci skb->pkt_type == PACKET_LOOPBACK || 309862306a36Sopenharmony_ci arp->ar_hrd != htons(ARPHRD_ETHER) || 309962306a36Sopenharmony_ci arp->ar_pro != htons(ETH_P_IP) || 310062306a36Sopenharmony_ci arp->ar_pln != 4) 310162306a36Sopenharmony_ci goto out_unlock; 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci arp_ptr = (unsigned char *)(arp + 1); 310462306a36Sopenharmony_ci arp_ptr += bond->dev->addr_len; 310562306a36Sopenharmony_ci memcpy(&sip, arp_ptr, 4); 310662306a36Sopenharmony_ci arp_ptr += 4 + bond->dev->addr_len; 310762306a36Sopenharmony_ci memcpy(&tip, arp_ptr, 4); 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: %s/%d av %d sv %d sip %pI4 tip %pI4\n", 311062306a36Sopenharmony_ci __func__, slave->dev->name, bond_slave_state(slave), 311162306a36Sopenharmony_ci bond->params.arp_validate, slave_do_arp_validate(bond, slave), 311262306a36Sopenharmony_ci &sip, &tip); 311362306a36Sopenharmony_ci 311462306a36Sopenharmony_ci curr_active_slave = rcu_dereference(bond->curr_active_slave); 311562306a36Sopenharmony_ci curr_arp_slave = rcu_dereference(bond->current_arp_slave); 311662306a36Sopenharmony_ci 311762306a36Sopenharmony_ci /* We 'trust' the received ARP enough to validate it if: 311862306a36Sopenharmony_ci * 311962306a36Sopenharmony_ci * (a) the slave receiving the ARP is active (which includes the 312062306a36Sopenharmony_ci * current ARP slave, if any), or 312162306a36Sopenharmony_ci * 312262306a36Sopenharmony_ci * (b) the receiving slave isn't active, but there is a currently 312362306a36Sopenharmony_ci * active slave and it received valid arp reply(s) after it became 312462306a36Sopenharmony_ci * the currently active slave, or 312562306a36Sopenharmony_ci * 312662306a36Sopenharmony_ci * (c) there is an ARP slave that sent an ARP during the prior ARP 312762306a36Sopenharmony_ci * interval, and we receive an ARP reply on any slave. We accept 312862306a36Sopenharmony_ci * these because switch FDB update delays may deliver the ARP 312962306a36Sopenharmony_ci * reply to a slave other than the sender of the ARP request. 313062306a36Sopenharmony_ci * 313162306a36Sopenharmony_ci * Note: for (b), backup slaves are receiving the broadcast ARP 313262306a36Sopenharmony_ci * request, not a reply. This request passes from the sending 313362306a36Sopenharmony_ci * slave through the L2 switch(es) to the receiving slave. Since 313462306a36Sopenharmony_ci * this is checking the request, sip/tip are swapped for 313562306a36Sopenharmony_ci * validation. 313662306a36Sopenharmony_ci * 313762306a36Sopenharmony_ci * This is done to avoid endless looping when we can't reach the 313862306a36Sopenharmony_ci * arp_ip_target and fool ourselves with our own arp requests. 313962306a36Sopenharmony_ci */ 314062306a36Sopenharmony_ci if (bond_is_active_slave(slave)) 314162306a36Sopenharmony_ci bond_validate_arp(bond, slave, sip, tip); 314262306a36Sopenharmony_ci else if (curr_active_slave && 314362306a36Sopenharmony_ci time_after(slave_last_rx(bond, curr_active_slave), 314462306a36Sopenharmony_ci curr_active_slave->last_link_up)) 314562306a36Sopenharmony_ci bond_validate_arp(bond, slave, tip, sip); 314662306a36Sopenharmony_ci else if (curr_arp_slave && (arp->ar_op == htons(ARPOP_REPLY)) && 314762306a36Sopenharmony_ci bond_time_in_interval(bond, slave_last_tx(curr_arp_slave), 1)) 314862306a36Sopenharmony_ci bond_validate_arp(bond, slave, sip, tip); 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ciout_unlock: 315162306a36Sopenharmony_ci if (arp != (struct arphdr *)skb->data) 315262306a36Sopenharmony_ci kfree(arp); 315362306a36Sopenharmony_ci return RX_HANDLER_ANOTHER; 315462306a36Sopenharmony_ci} 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 315762306a36Sopenharmony_cistatic void bond_ns_send(struct slave *slave, const struct in6_addr *daddr, 315862306a36Sopenharmony_ci const struct in6_addr *saddr, struct bond_vlan_tag *tags) 315962306a36Sopenharmony_ci{ 316062306a36Sopenharmony_ci struct net_device *bond_dev = slave->bond->dev; 316162306a36Sopenharmony_ci struct net_device *slave_dev = slave->dev; 316262306a36Sopenharmony_ci struct in6_addr mcaddr; 316362306a36Sopenharmony_ci struct sk_buff *skb; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "NS on slave: dst %pI6c src %pI6c\n", 316662306a36Sopenharmony_ci daddr, saddr); 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci skb = ndisc_ns_create(slave_dev, daddr, saddr, 0); 316962306a36Sopenharmony_ci if (!skb) { 317062306a36Sopenharmony_ci net_err_ratelimited("NS packet allocation failed\n"); 317162306a36Sopenharmony_ci return; 317262306a36Sopenharmony_ci } 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci addrconf_addr_solict_mult(daddr, &mcaddr); 317562306a36Sopenharmony_ci if (bond_handle_vlan(slave, tags, skb)) { 317662306a36Sopenharmony_ci slave_update_last_tx(slave); 317762306a36Sopenharmony_ci ndisc_send_skb(skb, &mcaddr, saddr); 317862306a36Sopenharmony_ci } 317962306a36Sopenharmony_ci} 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_cistatic void bond_ns_send_all(struct bonding *bond, struct slave *slave) 318262306a36Sopenharmony_ci{ 318362306a36Sopenharmony_ci struct in6_addr *targets = bond->params.ns_targets; 318462306a36Sopenharmony_ci struct bond_vlan_tag *tags; 318562306a36Sopenharmony_ci struct dst_entry *dst; 318662306a36Sopenharmony_ci struct in6_addr saddr; 318762306a36Sopenharmony_ci struct flowi6 fl6; 318862306a36Sopenharmony_ci int i; 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci for (i = 0; i < BOND_MAX_NS_TARGETS && !ipv6_addr_any(&targets[i]); i++) { 319162306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: target %pI6c\n", 319262306a36Sopenharmony_ci __func__, &targets[i]); 319362306a36Sopenharmony_ci tags = NULL; 319462306a36Sopenharmony_ci 319562306a36Sopenharmony_ci /* Find out through which dev should the packet go */ 319662306a36Sopenharmony_ci memset(&fl6, 0, sizeof(struct flowi6)); 319762306a36Sopenharmony_ci fl6.daddr = targets[i]; 319862306a36Sopenharmony_ci fl6.flowi6_oif = bond->dev->ifindex; 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci dst = ip6_route_output(dev_net(bond->dev), NULL, &fl6); 320162306a36Sopenharmony_ci if (dst->error) { 320262306a36Sopenharmony_ci dst_release(dst); 320362306a36Sopenharmony_ci /* there's no route to target - try to send arp 320462306a36Sopenharmony_ci * probe to generate any traffic (arp_validate=0) 320562306a36Sopenharmony_ci */ 320662306a36Sopenharmony_ci if (bond->params.arp_validate) 320762306a36Sopenharmony_ci pr_warn_once("%s: no route to ns_ip6_target %pI6c and arp_validate is set\n", 320862306a36Sopenharmony_ci bond->dev->name, 320962306a36Sopenharmony_ci &targets[i]); 321062306a36Sopenharmony_ci bond_ns_send(slave, &targets[i], &in6addr_any, tags); 321162306a36Sopenharmony_ci continue; 321262306a36Sopenharmony_ci } 321362306a36Sopenharmony_ci 321462306a36Sopenharmony_ci /* bond device itself */ 321562306a36Sopenharmony_ci if (dst->dev == bond->dev) 321662306a36Sopenharmony_ci goto found; 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci rcu_read_lock(); 321962306a36Sopenharmony_ci tags = bond_verify_device_path(bond->dev, dst->dev, 0); 322062306a36Sopenharmony_ci rcu_read_unlock(); 322162306a36Sopenharmony_ci 322262306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(tags)) 322362306a36Sopenharmony_ci goto found; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci /* Not our device - skip */ 322662306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "no path to ns_ip6_target %pI6c via dst->dev %s\n", 322762306a36Sopenharmony_ci &targets[i], dst->dev ? dst->dev->name : "NULL"); 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ci dst_release(dst); 323062306a36Sopenharmony_ci continue; 323162306a36Sopenharmony_ci 323262306a36Sopenharmony_cifound: 323362306a36Sopenharmony_ci if (!ipv6_dev_get_saddr(dev_net(dst->dev), dst->dev, &targets[i], 0, &saddr)) 323462306a36Sopenharmony_ci bond_ns_send(slave, &targets[i], &saddr, tags); 323562306a36Sopenharmony_ci else 323662306a36Sopenharmony_ci bond_ns_send(slave, &targets[i], &in6addr_any, tags); 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci dst_release(dst); 323962306a36Sopenharmony_ci kfree(tags); 324062306a36Sopenharmony_ci } 324162306a36Sopenharmony_ci} 324262306a36Sopenharmony_ci 324362306a36Sopenharmony_cistatic int bond_confirm_addr6(struct net_device *dev, 324462306a36Sopenharmony_ci struct netdev_nested_priv *priv) 324562306a36Sopenharmony_ci{ 324662306a36Sopenharmony_ci struct in6_addr *addr = (struct in6_addr *)priv->data; 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci return ipv6_chk_addr(dev_net(dev), addr, dev, 0); 324962306a36Sopenharmony_ci} 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_cistatic bool bond_has_this_ip6(struct bonding *bond, struct in6_addr *addr) 325262306a36Sopenharmony_ci{ 325362306a36Sopenharmony_ci struct netdev_nested_priv priv = { 325462306a36Sopenharmony_ci .data = addr, 325562306a36Sopenharmony_ci }; 325662306a36Sopenharmony_ci int ret = false; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci if (bond_confirm_addr6(bond->dev, &priv)) 325962306a36Sopenharmony_ci return true; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci rcu_read_lock(); 326262306a36Sopenharmony_ci if (netdev_walk_all_upper_dev_rcu(bond->dev, bond_confirm_addr6, &priv)) 326362306a36Sopenharmony_ci ret = true; 326462306a36Sopenharmony_ci rcu_read_unlock(); 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci return ret; 326762306a36Sopenharmony_ci} 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_cistatic void bond_validate_na(struct bonding *bond, struct slave *slave, 327062306a36Sopenharmony_ci struct in6_addr *saddr, struct in6_addr *daddr) 327162306a36Sopenharmony_ci{ 327262306a36Sopenharmony_ci int i; 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci /* Ignore NAs that: 327562306a36Sopenharmony_ci * 1. Source address is unspecified address. 327662306a36Sopenharmony_ci * 2. Dest address is neither all-nodes multicast address nor 327762306a36Sopenharmony_ci * exist on bond interface. 327862306a36Sopenharmony_ci */ 327962306a36Sopenharmony_ci if (ipv6_addr_any(saddr) || 328062306a36Sopenharmony_ci (!ipv6_addr_equal(daddr, &in6addr_linklocal_allnodes) && 328162306a36Sopenharmony_ci !bond_has_this_ip6(bond, daddr))) { 328262306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: sip %pI6c tip %pI6c not found\n", 328362306a36Sopenharmony_ci __func__, saddr, daddr); 328462306a36Sopenharmony_ci return; 328562306a36Sopenharmony_ci } 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_ci i = bond_get_targets_ip6(bond->params.ns_targets, saddr); 328862306a36Sopenharmony_ci if (i == -1) { 328962306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: sip %pI6c not found in targets\n", 329062306a36Sopenharmony_ci __func__, saddr); 329162306a36Sopenharmony_ci return; 329262306a36Sopenharmony_ci } 329362306a36Sopenharmony_ci slave->last_rx = jiffies; 329462306a36Sopenharmony_ci slave->target_last_arp_rx[i] = jiffies; 329562306a36Sopenharmony_ci} 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_cistatic int bond_na_rcv(const struct sk_buff *skb, struct bonding *bond, 329862306a36Sopenharmony_ci struct slave *slave) 329962306a36Sopenharmony_ci{ 330062306a36Sopenharmony_ci struct slave *curr_active_slave, *curr_arp_slave; 330162306a36Sopenharmony_ci struct in6_addr *saddr, *daddr; 330262306a36Sopenharmony_ci struct { 330362306a36Sopenharmony_ci struct ipv6hdr ip6; 330462306a36Sopenharmony_ci struct icmp6hdr icmp6; 330562306a36Sopenharmony_ci } *combined, _combined; 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci if (skb->pkt_type == PACKET_OTHERHOST || 330862306a36Sopenharmony_ci skb->pkt_type == PACKET_LOOPBACK) 330962306a36Sopenharmony_ci goto out; 331062306a36Sopenharmony_ci 331162306a36Sopenharmony_ci combined = skb_header_pointer(skb, 0, sizeof(_combined), &_combined); 331262306a36Sopenharmony_ci if (!combined || combined->ip6.nexthdr != NEXTHDR_ICMP || 331362306a36Sopenharmony_ci (combined->icmp6.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION && 331462306a36Sopenharmony_ci combined->icmp6.icmp6_type != NDISC_NEIGHBOUR_ADVERTISEMENT)) 331562306a36Sopenharmony_ci goto out; 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci saddr = &combined->ip6.saddr; 331862306a36Sopenharmony_ci daddr = &combined->ip6.daddr; 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: %s/%d av %d sv %d sip %pI6c tip %pI6c\n", 332162306a36Sopenharmony_ci __func__, slave->dev->name, bond_slave_state(slave), 332262306a36Sopenharmony_ci bond->params.arp_validate, slave_do_arp_validate(bond, slave), 332362306a36Sopenharmony_ci saddr, daddr); 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci curr_active_slave = rcu_dereference(bond->curr_active_slave); 332662306a36Sopenharmony_ci curr_arp_slave = rcu_dereference(bond->current_arp_slave); 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_ci /* We 'trust' the received ARP enough to validate it if: 332962306a36Sopenharmony_ci * see bond_arp_rcv(). 333062306a36Sopenharmony_ci */ 333162306a36Sopenharmony_ci if (bond_is_active_slave(slave)) 333262306a36Sopenharmony_ci bond_validate_na(bond, slave, saddr, daddr); 333362306a36Sopenharmony_ci else if (curr_active_slave && 333462306a36Sopenharmony_ci time_after(slave_last_rx(bond, curr_active_slave), 333562306a36Sopenharmony_ci curr_active_slave->last_link_up)) 333662306a36Sopenharmony_ci bond_validate_na(bond, slave, daddr, saddr); 333762306a36Sopenharmony_ci else if (curr_arp_slave && 333862306a36Sopenharmony_ci bond_time_in_interval(bond, slave_last_tx(curr_arp_slave), 1)) 333962306a36Sopenharmony_ci bond_validate_na(bond, slave, saddr, daddr); 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ciout: 334262306a36Sopenharmony_ci return RX_HANDLER_ANOTHER; 334362306a36Sopenharmony_ci} 334462306a36Sopenharmony_ci#endif 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ciint bond_rcv_validate(const struct sk_buff *skb, struct bonding *bond, 334762306a36Sopenharmony_ci struct slave *slave) 334862306a36Sopenharmony_ci{ 334962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 335062306a36Sopenharmony_ci bool is_ipv6 = skb->protocol == __cpu_to_be16(ETH_P_IPV6); 335162306a36Sopenharmony_ci#endif 335262306a36Sopenharmony_ci bool is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP); 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "%s: skb->dev %s\n", 335562306a36Sopenharmony_ci __func__, skb->dev->name); 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci /* Use arp validate logic for both ARP and NS */ 335862306a36Sopenharmony_ci if (!slave_do_arp_validate(bond, slave)) { 335962306a36Sopenharmony_ci if ((slave_do_arp_validate_only(bond) && is_arp) || 336062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 336162306a36Sopenharmony_ci (slave_do_arp_validate_only(bond) && is_ipv6) || 336262306a36Sopenharmony_ci#endif 336362306a36Sopenharmony_ci !slave_do_arp_validate_only(bond)) 336462306a36Sopenharmony_ci slave->last_rx = jiffies; 336562306a36Sopenharmony_ci return RX_HANDLER_ANOTHER; 336662306a36Sopenharmony_ci } else if (is_arp) { 336762306a36Sopenharmony_ci return bond_arp_rcv(skb, bond, slave); 336862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 336962306a36Sopenharmony_ci } else if (is_ipv6) { 337062306a36Sopenharmony_ci return bond_na_rcv(skb, bond, slave); 337162306a36Sopenharmony_ci#endif 337262306a36Sopenharmony_ci } else { 337362306a36Sopenharmony_ci return RX_HANDLER_ANOTHER; 337462306a36Sopenharmony_ci } 337562306a36Sopenharmony_ci} 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_cistatic void bond_send_validate(struct bonding *bond, struct slave *slave) 337862306a36Sopenharmony_ci{ 337962306a36Sopenharmony_ci bond_arp_send_all(bond, slave); 338062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 338162306a36Sopenharmony_ci bond_ns_send_all(bond, slave); 338262306a36Sopenharmony_ci#endif 338362306a36Sopenharmony_ci} 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci/* function to verify if we're in the arp_interval timeslice, returns true if 338662306a36Sopenharmony_ci * (last_act - arp_interval) <= jiffies <= (last_act + mod * arp_interval + 338762306a36Sopenharmony_ci * arp_interval/2) . the arp_interval/2 is needed for really fast networks. 338862306a36Sopenharmony_ci */ 338962306a36Sopenharmony_cistatic bool bond_time_in_interval(struct bonding *bond, unsigned long last_act, 339062306a36Sopenharmony_ci int mod) 339162306a36Sopenharmony_ci{ 339262306a36Sopenharmony_ci int delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci return time_in_range(jiffies, 339562306a36Sopenharmony_ci last_act - delta_in_ticks, 339662306a36Sopenharmony_ci last_act + mod * delta_in_ticks + delta_in_ticks/2); 339762306a36Sopenharmony_ci} 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci/* This function is called regularly to monitor each slave's link 340062306a36Sopenharmony_ci * ensuring that traffic is being sent and received when arp monitoring 340162306a36Sopenharmony_ci * is used in load-balancing mode. if the adapter has been dormant, then an 340262306a36Sopenharmony_ci * arp is transmitted to generate traffic. see activebackup_arp_monitor for 340362306a36Sopenharmony_ci * arp monitoring in active backup mode. 340462306a36Sopenharmony_ci */ 340562306a36Sopenharmony_cistatic void bond_loadbalance_arp_mon(struct bonding *bond) 340662306a36Sopenharmony_ci{ 340762306a36Sopenharmony_ci struct slave *slave, *oldcurrent; 340862306a36Sopenharmony_ci struct list_head *iter; 340962306a36Sopenharmony_ci int do_failover = 0, slave_state_changed = 0; 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_ci if (!bond_has_slaves(bond)) 341262306a36Sopenharmony_ci goto re_arm; 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci rcu_read_lock(); 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ci oldcurrent = rcu_dereference(bond->curr_active_slave); 341762306a36Sopenharmony_ci /* see if any of the previous devices are up now (i.e. they have 341862306a36Sopenharmony_ci * xmt and rcv traffic). the curr_active_slave does not come into 341962306a36Sopenharmony_ci * the picture unless it is null. also, slave->last_link_up is not 342062306a36Sopenharmony_ci * needed here because we send an arp on each slave and give a slave 342162306a36Sopenharmony_ci * as long as it needs to get the tx/rx within the delta. 342262306a36Sopenharmony_ci * TODO: what about up/down delay in arp mode? it wasn't here before 342362306a36Sopenharmony_ci * so it can wait 342462306a36Sopenharmony_ci */ 342562306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 342662306a36Sopenharmony_ci unsigned long last_tx = slave_last_tx(slave); 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_NOCHANGE); 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci if (slave->link != BOND_LINK_UP) { 343162306a36Sopenharmony_ci if (bond_time_in_interval(bond, last_tx, 1) && 343262306a36Sopenharmony_ci bond_time_in_interval(bond, slave->last_rx, 1)) { 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_UP); 343562306a36Sopenharmony_ci slave_state_changed = 1; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci /* primary_slave has no meaning in round-robin 343862306a36Sopenharmony_ci * mode. the window of a slave being up and 343962306a36Sopenharmony_ci * curr_active_slave being null after enslaving 344062306a36Sopenharmony_ci * is closed. 344162306a36Sopenharmony_ci */ 344262306a36Sopenharmony_ci if (!oldcurrent) { 344362306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status definitely up\n"); 344462306a36Sopenharmony_ci do_failover = 1; 344562306a36Sopenharmony_ci } else { 344662306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "interface is now up\n"); 344762306a36Sopenharmony_ci } 344862306a36Sopenharmony_ci } 344962306a36Sopenharmony_ci } else { 345062306a36Sopenharmony_ci /* slave->link == BOND_LINK_UP */ 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci /* not all switches will respond to an arp request 345362306a36Sopenharmony_ci * when the source ip is 0, so don't take the link down 345462306a36Sopenharmony_ci * if we don't know our ip yet 345562306a36Sopenharmony_ci */ 345662306a36Sopenharmony_ci if (!bond_time_in_interval(bond, last_tx, bond->params.missed_max) || 345762306a36Sopenharmony_ci !bond_time_in_interval(bond, slave->last_rx, bond->params.missed_max)) { 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_DOWN); 346062306a36Sopenharmony_ci slave_state_changed = 1; 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci if (slave->link_failure_count < UINT_MAX) 346362306a36Sopenharmony_ci slave->link_failure_count++; 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "interface is now down\n"); 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci if (slave == oldcurrent) 346862306a36Sopenharmony_ci do_failover = 1; 346962306a36Sopenharmony_ci } 347062306a36Sopenharmony_ci } 347162306a36Sopenharmony_ci 347262306a36Sopenharmony_ci /* note: if switch is in round-robin mode, all links 347362306a36Sopenharmony_ci * must tx arp to ensure all links rx an arp - otherwise 347462306a36Sopenharmony_ci * links may oscillate or not come up at all; if switch is 347562306a36Sopenharmony_ci * in something like xor mode, there is nothing we can 347662306a36Sopenharmony_ci * do - all replies will be rx'ed on same link causing slaves 347762306a36Sopenharmony_ci * to be unstable during low/no traffic periods 347862306a36Sopenharmony_ci */ 347962306a36Sopenharmony_ci if (bond_slave_is_up(slave)) 348062306a36Sopenharmony_ci bond_send_validate(bond, slave); 348162306a36Sopenharmony_ci } 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci rcu_read_unlock(); 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci if (do_failover || slave_state_changed) { 348662306a36Sopenharmony_ci if (!rtnl_trylock()) 348762306a36Sopenharmony_ci goto re_arm; 348862306a36Sopenharmony_ci 348962306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 349062306a36Sopenharmony_ci if (slave->link_new_state != BOND_LINK_NOCHANGE) 349162306a36Sopenharmony_ci slave->link = slave->link_new_state; 349262306a36Sopenharmony_ci } 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci if (slave_state_changed) { 349562306a36Sopenharmony_ci bond_slave_state_change(bond); 349662306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_XOR) 349762306a36Sopenharmony_ci bond_update_slave_arr(bond, NULL); 349862306a36Sopenharmony_ci } 349962306a36Sopenharmony_ci if (do_failover) { 350062306a36Sopenharmony_ci block_netpoll_tx(); 350162306a36Sopenharmony_ci bond_select_active_slave(bond); 350262306a36Sopenharmony_ci unblock_netpoll_tx(); 350362306a36Sopenharmony_ci } 350462306a36Sopenharmony_ci rtnl_unlock(); 350562306a36Sopenharmony_ci } 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_cire_arm: 350862306a36Sopenharmony_ci if (bond->params.arp_interval) 350962306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->arp_work, 351062306a36Sopenharmony_ci msecs_to_jiffies(bond->params.arp_interval)); 351162306a36Sopenharmony_ci} 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_ci/* Called to inspect slaves for active-backup mode ARP monitor link state 351462306a36Sopenharmony_ci * changes. Sets proposed link state in slaves to specify what action 351562306a36Sopenharmony_ci * should take place for the slave. Returns 0 if no changes are found, >0 351662306a36Sopenharmony_ci * if changes to link states must be committed. 351762306a36Sopenharmony_ci * 351862306a36Sopenharmony_ci * Called with rcu_read_lock held. 351962306a36Sopenharmony_ci */ 352062306a36Sopenharmony_cistatic int bond_ab_arp_inspect(struct bonding *bond) 352162306a36Sopenharmony_ci{ 352262306a36Sopenharmony_ci unsigned long last_tx, last_rx; 352362306a36Sopenharmony_ci struct list_head *iter; 352462306a36Sopenharmony_ci struct slave *slave; 352562306a36Sopenharmony_ci int commit = 0; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 352862306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_NOCHANGE); 352962306a36Sopenharmony_ci last_rx = slave_last_rx(bond, slave); 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci if (slave->link != BOND_LINK_UP) { 353262306a36Sopenharmony_ci if (bond_time_in_interval(bond, last_rx, 1)) { 353362306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_UP); 353462306a36Sopenharmony_ci commit++; 353562306a36Sopenharmony_ci } else if (slave->link == BOND_LINK_BACK) { 353662306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_FAIL); 353762306a36Sopenharmony_ci commit++; 353862306a36Sopenharmony_ci } 353962306a36Sopenharmony_ci continue; 354062306a36Sopenharmony_ci } 354162306a36Sopenharmony_ci 354262306a36Sopenharmony_ci /* Give slaves 2*delta after being enslaved or made 354362306a36Sopenharmony_ci * active. This avoids bouncing, as the last receive 354462306a36Sopenharmony_ci * times need a full ARP monitor cycle to be updated. 354562306a36Sopenharmony_ci */ 354662306a36Sopenharmony_ci if (bond_time_in_interval(bond, slave->last_link_up, 2)) 354762306a36Sopenharmony_ci continue; 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci /* Backup slave is down if: 355062306a36Sopenharmony_ci * - No current_arp_slave AND 355162306a36Sopenharmony_ci * - more than (missed_max+1)*delta since last receive AND 355262306a36Sopenharmony_ci * - the bond has an IP address 355362306a36Sopenharmony_ci * 355462306a36Sopenharmony_ci * Note: a non-null current_arp_slave indicates 355562306a36Sopenharmony_ci * the curr_active_slave went down and we are 355662306a36Sopenharmony_ci * searching for a new one; under this condition 355762306a36Sopenharmony_ci * we only take the curr_active_slave down - this 355862306a36Sopenharmony_ci * gives each slave a chance to tx/rx traffic 355962306a36Sopenharmony_ci * before being taken out 356062306a36Sopenharmony_ci */ 356162306a36Sopenharmony_ci if (!bond_is_active_slave(slave) && 356262306a36Sopenharmony_ci !rcu_access_pointer(bond->current_arp_slave) && 356362306a36Sopenharmony_ci !bond_time_in_interval(bond, last_rx, bond->params.missed_max + 1)) { 356462306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_DOWN); 356562306a36Sopenharmony_ci commit++; 356662306a36Sopenharmony_ci } 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci /* Active slave is down if: 356962306a36Sopenharmony_ci * - more than missed_max*delta since transmitting OR 357062306a36Sopenharmony_ci * - (more than missed_max*delta since receive AND 357162306a36Sopenharmony_ci * the bond has an IP address) 357262306a36Sopenharmony_ci */ 357362306a36Sopenharmony_ci last_tx = slave_last_tx(slave); 357462306a36Sopenharmony_ci if (bond_is_active_slave(slave) && 357562306a36Sopenharmony_ci (!bond_time_in_interval(bond, last_tx, bond->params.missed_max) || 357662306a36Sopenharmony_ci !bond_time_in_interval(bond, last_rx, bond->params.missed_max))) { 357762306a36Sopenharmony_ci bond_propose_link_state(slave, BOND_LINK_DOWN); 357862306a36Sopenharmony_ci commit++; 357962306a36Sopenharmony_ci } 358062306a36Sopenharmony_ci } 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci return commit; 358362306a36Sopenharmony_ci} 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_ci/* Called to commit link state changes noted by inspection step of 358662306a36Sopenharmony_ci * active-backup mode ARP monitor. 358762306a36Sopenharmony_ci * 358862306a36Sopenharmony_ci * Called with RTNL hold. 358962306a36Sopenharmony_ci */ 359062306a36Sopenharmony_cistatic void bond_ab_arp_commit(struct bonding *bond) 359162306a36Sopenharmony_ci{ 359262306a36Sopenharmony_ci bool do_failover = false; 359362306a36Sopenharmony_ci struct list_head *iter; 359462306a36Sopenharmony_ci unsigned long last_tx; 359562306a36Sopenharmony_ci struct slave *slave; 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 359862306a36Sopenharmony_ci switch (slave->link_new_state) { 359962306a36Sopenharmony_ci case BOND_LINK_NOCHANGE: 360062306a36Sopenharmony_ci continue; 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci case BOND_LINK_UP: 360362306a36Sopenharmony_ci last_tx = slave_last_tx(slave); 360462306a36Sopenharmony_ci if (rtnl_dereference(bond->curr_active_slave) != slave || 360562306a36Sopenharmony_ci (!rtnl_dereference(bond->curr_active_slave) && 360662306a36Sopenharmony_ci bond_time_in_interval(bond, last_tx, 1))) { 360762306a36Sopenharmony_ci struct slave *current_arp_slave; 360862306a36Sopenharmony_ci 360962306a36Sopenharmony_ci current_arp_slave = rtnl_dereference(bond->current_arp_slave); 361062306a36Sopenharmony_ci bond_set_slave_link_state(slave, BOND_LINK_UP, 361162306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 361262306a36Sopenharmony_ci if (current_arp_slave) { 361362306a36Sopenharmony_ci bond_set_slave_inactive_flags( 361462306a36Sopenharmony_ci current_arp_slave, 361562306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 361662306a36Sopenharmony_ci RCU_INIT_POINTER(bond->current_arp_slave, NULL); 361762306a36Sopenharmony_ci } 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status definitely up\n"); 362062306a36Sopenharmony_ci 362162306a36Sopenharmony_ci if (!rtnl_dereference(bond->curr_active_slave) || 362262306a36Sopenharmony_ci slave == rtnl_dereference(bond->primary_slave) || 362362306a36Sopenharmony_ci slave->prio > rtnl_dereference(bond->curr_active_slave)->prio) 362462306a36Sopenharmony_ci do_failover = true; 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci } 362762306a36Sopenharmony_ci 362862306a36Sopenharmony_ci continue; 362962306a36Sopenharmony_ci 363062306a36Sopenharmony_ci case BOND_LINK_DOWN: 363162306a36Sopenharmony_ci if (slave->link_failure_count < UINT_MAX) 363262306a36Sopenharmony_ci slave->link_failure_count++; 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_ci bond_set_slave_link_state(slave, BOND_LINK_DOWN, 363562306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 363662306a36Sopenharmony_ci bond_set_slave_inactive_flags(slave, 363762306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "link status definitely down, disabling slave\n"); 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci if (slave == rtnl_dereference(bond->curr_active_slave)) { 364262306a36Sopenharmony_ci RCU_INIT_POINTER(bond->current_arp_slave, NULL); 364362306a36Sopenharmony_ci do_failover = true; 364462306a36Sopenharmony_ci } 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci continue; 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci case BOND_LINK_FAIL: 364962306a36Sopenharmony_ci bond_set_slave_link_state(slave, BOND_LINK_FAIL, 365062306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 365162306a36Sopenharmony_ci bond_set_slave_inactive_flags(slave, 365262306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_ci /* A slave has just been enslaved and has become 365562306a36Sopenharmony_ci * the current active slave. 365662306a36Sopenharmony_ci */ 365762306a36Sopenharmony_ci if (rtnl_dereference(bond->curr_active_slave)) 365862306a36Sopenharmony_ci RCU_INIT_POINTER(bond->current_arp_slave, NULL); 365962306a36Sopenharmony_ci continue; 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci default: 366262306a36Sopenharmony_ci slave_err(bond->dev, slave->dev, 366362306a36Sopenharmony_ci "impossible: link_new_state %d on slave\n", 366462306a36Sopenharmony_ci slave->link_new_state); 366562306a36Sopenharmony_ci continue; 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci } 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci if (do_failover) { 367062306a36Sopenharmony_ci block_netpoll_tx(); 367162306a36Sopenharmony_ci bond_select_active_slave(bond); 367262306a36Sopenharmony_ci unblock_netpoll_tx(); 367362306a36Sopenharmony_ci } 367462306a36Sopenharmony_ci 367562306a36Sopenharmony_ci bond_set_carrier(bond); 367662306a36Sopenharmony_ci} 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_ci/* Send ARP probes for active-backup mode ARP monitor. 367962306a36Sopenharmony_ci * 368062306a36Sopenharmony_ci * Called with rcu_read_lock held. 368162306a36Sopenharmony_ci */ 368262306a36Sopenharmony_cistatic bool bond_ab_arp_probe(struct bonding *bond) 368362306a36Sopenharmony_ci{ 368462306a36Sopenharmony_ci struct slave *slave, *before = NULL, *new_slave = NULL, 368562306a36Sopenharmony_ci *curr_arp_slave = rcu_dereference(bond->current_arp_slave), 368662306a36Sopenharmony_ci *curr_active_slave = rcu_dereference(bond->curr_active_slave); 368762306a36Sopenharmony_ci struct list_head *iter; 368862306a36Sopenharmony_ci bool found = false; 368962306a36Sopenharmony_ci bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER; 369062306a36Sopenharmony_ci 369162306a36Sopenharmony_ci if (curr_arp_slave && curr_active_slave) 369262306a36Sopenharmony_ci netdev_info(bond->dev, "PROBE: c_arp %s && cas %s BAD\n", 369362306a36Sopenharmony_ci curr_arp_slave->dev->name, 369462306a36Sopenharmony_ci curr_active_slave->dev->name); 369562306a36Sopenharmony_ci 369662306a36Sopenharmony_ci if (curr_active_slave) { 369762306a36Sopenharmony_ci bond_send_validate(bond, curr_active_slave); 369862306a36Sopenharmony_ci return should_notify_rtnl; 369962306a36Sopenharmony_ci } 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci /* if we don't have a curr_active_slave, search for the next available 370262306a36Sopenharmony_ci * backup slave from the current_arp_slave and make it the candidate 370362306a36Sopenharmony_ci * for becoming the curr_active_slave 370462306a36Sopenharmony_ci */ 370562306a36Sopenharmony_ci 370662306a36Sopenharmony_ci if (!curr_arp_slave) { 370762306a36Sopenharmony_ci curr_arp_slave = bond_first_slave_rcu(bond); 370862306a36Sopenharmony_ci if (!curr_arp_slave) 370962306a36Sopenharmony_ci return should_notify_rtnl; 371062306a36Sopenharmony_ci } 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 371362306a36Sopenharmony_ci if (!found && !before && bond_slave_is_up(slave)) 371462306a36Sopenharmony_ci before = slave; 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci if (found && !new_slave && bond_slave_is_up(slave)) 371762306a36Sopenharmony_ci new_slave = slave; 371862306a36Sopenharmony_ci /* if the link state is up at this point, we 371962306a36Sopenharmony_ci * mark it down - this can happen if we have 372062306a36Sopenharmony_ci * simultaneous link failures and 372162306a36Sopenharmony_ci * reselect_active_interface doesn't make this 372262306a36Sopenharmony_ci * one the current slave so it is still marked 372362306a36Sopenharmony_ci * up when it is actually down 372462306a36Sopenharmony_ci */ 372562306a36Sopenharmony_ci if (!bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) { 372662306a36Sopenharmony_ci bond_set_slave_link_state(slave, BOND_LINK_DOWN, 372762306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_LATER); 372862306a36Sopenharmony_ci if (slave->link_failure_count < UINT_MAX) 372962306a36Sopenharmony_ci slave->link_failure_count++; 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci bond_set_slave_inactive_flags(slave, 373262306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_LATER); 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci slave_info(bond->dev, slave->dev, "backup interface is now down\n"); 373562306a36Sopenharmony_ci } 373662306a36Sopenharmony_ci if (slave == curr_arp_slave) 373762306a36Sopenharmony_ci found = true; 373862306a36Sopenharmony_ci } 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci if (!new_slave && before) 374162306a36Sopenharmony_ci new_slave = before; 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci if (!new_slave) 374462306a36Sopenharmony_ci goto check_state; 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_ci bond_set_slave_link_state(new_slave, BOND_LINK_BACK, 374762306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_LATER); 374862306a36Sopenharmony_ci bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER); 374962306a36Sopenharmony_ci bond_send_validate(bond, new_slave); 375062306a36Sopenharmony_ci new_slave->last_link_up = jiffies; 375162306a36Sopenharmony_ci rcu_assign_pointer(bond->current_arp_slave, new_slave); 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_cicheck_state: 375462306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 375562306a36Sopenharmony_ci if (slave->should_notify || slave->should_notify_link) { 375662306a36Sopenharmony_ci should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW; 375762306a36Sopenharmony_ci break; 375862306a36Sopenharmony_ci } 375962306a36Sopenharmony_ci } 376062306a36Sopenharmony_ci return should_notify_rtnl; 376162306a36Sopenharmony_ci} 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_cistatic void bond_activebackup_arp_mon(struct bonding *bond) 376462306a36Sopenharmony_ci{ 376562306a36Sopenharmony_ci bool should_notify_peers = false; 376662306a36Sopenharmony_ci bool should_notify_rtnl = false; 376762306a36Sopenharmony_ci int delta_in_ticks; 376862306a36Sopenharmony_ci 376962306a36Sopenharmony_ci delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_ci if (!bond_has_slaves(bond)) 377262306a36Sopenharmony_ci goto re_arm; 377362306a36Sopenharmony_ci 377462306a36Sopenharmony_ci rcu_read_lock(); 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_ci should_notify_peers = bond_should_notify_peers(bond); 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci if (bond_ab_arp_inspect(bond)) { 377962306a36Sopenharmony_ci rcu_read_unlock(); 378062306a36Sopenharmony_ci 378162306a36Sopenharmony_ci /* Race avoidance with bond_close flush of workqueue */ 378262306a36Sopenharmony_ci if (!rtnl_trylock()) { 378362306a36Sopenharmony_ci delta_in_ticks = 1; 378462306a36Sopenharmony_ci should_notify_peers = false; 378562306a36Sopenharmony_ci goto re_arm; 378662306a36Sopenharmony_ci } 378762306a36Sopenharmony_ci 378862306a36Sopenharmony_ci bond_ab_arp_commit(bond); 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci rtnl_unlock(); 379162306a36Sopenharmony_ci rcu_read_lock(); 379262306a36Sopenharmony_ci } 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_ci should_notify_rtnl = bond_ab_arp_probe(bond); 379562306a36Sopenharmony_ci rcu_read_unlock(); 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_cire_arm: 379862306a36Sopenharmony_ci if (bond->params.arp_interval) 379962306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); 380062306a36Sopenharmony_ci 380162306a36Sopenharmony_ci if (should_notify_peers || should_notify_rtnl) { 380262306a36Sopenharmony_ci if (!rtnl_trylock()) 380362306a36Sopenharmony_ci return; 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_ci if (should_notify_peers) { 380662306a36Sopenharmony_ci bond->send_peer_notif--; 380762306a36Sopenharmony_ci call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, 380862306a36Sopenharmony_ci bond->dev); 380962306a36Sopenharmony_ci } 381062306a36Sopenharmony_ci if (should_notify_rtnl) { 381162306a36Sopenharmony_ci bond_slave_state_notify(bond); 381262306a36Sopenharmony_ci bond_slave_link_notify(bond); 381362306a36Sopenharmony_ci } 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci rtnl_unlock(); 381662306a36Sopenharmony_ci } 381762306a36Sopenharmony_ci} 381862306a36Sopenharmony_ci 381962306a36Sopenharmony_cistatic void bond_arp_monitor(struct work_struct *work) 382062306a36Sopenharmony_ci{ 382162306a36Sopenharmony_ci struct bonding *bond = container_of(work, struct bonding, 382262306a36Sopenharmony_ci arp_work.work); 382362306a36Sopenharmony_ci 382462306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) 382562306a36Sopenharmony_ci bond_activebackup_arp_mon(bond); 382662306a36Sopenharmony_ci else 382762306a36Sopenharmony_ci bond_loadbalance_arp_mon(bond); 382862306a36Sopenharmony_ci} 382962306a36Sopenharmony_ci 383062306a36Sopenharmony_ci/*-------------------------- netdev event handling --------------------------*/ 383162306a36Sopenharmony_ci 383262306a36Sopenharmony_ci/* Change device name */ 383362306a36Sopenharmony_cistatic int bond_event_changename(struct bonding *bond) 383462306a36Sopenharmony_ci{ 383562306a36Sopenharmony_ci bond_remove_proc_entry(bond); 383662306a36Sopenharmony_ci bond_create_proc_entry(bond); 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci bond_debug_reregister(bond); 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_ci return NOTIFY_DONE; 384162306a36Sopenharmony_ci} 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_cistatic int bond_master_netdev_event(unsigned long event, 384462306a36Sopenharmony_ci struct net_device *bond_dev) 384562306a36Sopenharmony_ci{ 384662306a36Sopenharmony_ci struct bonding *event_bond = netdev_priv(bond_dev); 384762306a36Sopenharmony_ci 384862306a36Sopenharmony_ci netdev_dbg(bond_dev, "%s called\n", __func__); 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci switch (event) { 385162306a36Sopenharmony_ci case NETDEV_CHANGENAME: 385262306a36Sopenharmony_ci return bond_event_changename(event_bond); 385362306a36Sopenharmony_ci case NETDEV_UNREGISTER: 385462306a36Sopenharmony_ci bond_remove_proc_entry(event_bond); 385562306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 385662306a36Sopenharmony_ci xfrm_dev_state_flush(dev_net(bond_dev), bond_dev, true); 385762306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 385862306a36Sopenharmony_ci break; 385962306a36Sopenharmony_ci case NETDEV_REGISTER: 386062306a36Sopenharmony_ci bond_create_proc_entry(event_bond); 386162306a36Sopenharmony_ci break; 386262306a36Sopenharmony_ci default: 386362306a36Sopenharmony_ci break; 386462306a36Sopenharmony_ci } 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_ci return NOTIFY_DONE; 386762306a36Sopenharmony_ci} 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_cistatic int bond_slave_netdev_event(unsigned long event, 387062306a36Sopenharmony_ci struct net_device *slave_dev) 387162306a36Sopenharmony_ci{ 387262306a36Sopenharmony_ci struct slave *slave = bond_slave_get_rtnl(slave_dev), *primary; 387362306a36Sopenharmony_ci struct bonding *bond; 387462306a36Sopenharmony_ci struct net_device *bond_dev; 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci /* A netdev event can be generated while enslaving a device 387762306a36Sopenharmony_ci * before netdev_rx_handler_register is called in which case 387862306a36Sopenharmony_ci * slave will be NULL 387962306a36Sopenharmony_ci */ 388062306a36Sopenharmony_ci if (!slave) { 388162306a36Sopenharmony_ci netdev_dbg(slave_dev, "%s called on NULL slave\n", __func__); 388262306a36Sopenharmony_ci return NOTIFY_DONE; 388362306a36Sopenharmony_ci } 388462306a36Sopenharmony_ci 388562306a36Sopenharmony_ci bond_dev = slave->bond->dev; 388662306a36Sopenharmony_ci bond = slave->bond; 388762306a36Sopenharmony_ci primary = rtnl_dereference(bond->primary_slave); 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "%s called\n", __func__); 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci switch (event) { 389262306a36Sopenharmony_ci case NETDEV_UNREGISTER: 389362306a36Sopenharmony_ci if (bond_dev->type != ARPHRD_ETHER) 389462306a36Sopenharmony_ci bond_release_and_destroy(bond_dev, slave_dev); 389562306a36Sopenharmony_ci else 389662306a36Sopenharmony_ci __bond_release_one(bond_dev, slave_dev, false, true); 389762306a36Sopenharmony_ci break; 389862306a36Sopenharmony_ci case NETDEV_UP: 389962306a36Sopenharmony_ci case NETDEV_CHANGE: 390062306a36Sopenharmony_ci /* For 802.3ad mode only: 390162306a36Sopenharmony_ci * Getting invalid Speed/Duplex values here will put slave 390262306a36Sopenharmony_ci * in weird state. Mark it as link-fail if the link was 390362306a36Sopenharmony_ci * previously up or link-down if it hasn't yet come up, and 390462306a36Sopenharmony_ci * let link-monitoring (miimon) set it right when correct 390562306a36Sopenharmony_ci * speeds/duplex are available. 390662306a36Sopenharmony_ci */ 390762306a36Sopenharmony_ci if (bond_update_speed_duplex(slave) && 390862306a36Sopenharmony_ci BOND_MODE(bond) == BOND_MODE_8023AD) { 390962306a36Sopenharmony_ci if (slave->last_link_up) 391062306a36Sopenharmony_ci slave->link = BOND_LINK_FAIL; 391162306a36Sopenharmony_ci else 391262306a36Sopenharmony_ci slave->link = BOND_LINK_DOWN; 391362306a36Sopenharmony_ci } 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) 391662306a36Sopenharmony_ci bond_3ad_adapter_speed_duplex_changed(slave); 391762306a36Sopenharmony_ci fallthrough; 391862306a36Sopenharmony_ci case NETDEV_DOWN: 391962306a36Sopenharmony_ci /* Refresh slave-array if applicable! 392062306a36Sopenharmony_ci * If the setup does not use miimon or arpmon (mode-specific!), 392162306a36Sopenharmony_ci * then these events will not cause the slave-array to be 392262306a36Sopenharmony_ci * refreshed. This will cause xmit to use a slave that is not 392362306a36Sopenharmony_ci * usable. Avoid such situation by refeshing the array at these 392462306a36Sopenharmony_ci * events. If these (miimon/arpmon) parameters are configured 392562306a36Sopenharmony_ci * then array gets refreshed twice and that should be fine! 392662306a36Sopenharmony_ci */ 392762306a36Sopenharmony_ci if (bond_mode_can_use_xmit_hash(bond)) 392862306a36Sopenharmony_ci bond_update_slave_arr(bond, NULL); 392962306a36Sopenharmony_ci break; 393062306a36Sopenharmony_ci case NETDEV_CHANGEMTU: 393162306a36Sopenharmony_ci /* TODO: Should slaves be allowed to 393262306a36Sopenharmony_ci * independently alter their MTU? For 393362306a36Sopenharmony_ci * an active-backup bond, slaves need 393462306a36Sopenharmony_ci * not be the same type of device, so 393562306a36Sopenharmony_ci * MTUs may vary. For other modes, 393662306a36Sopenharmony_ci * slaves arguably should have the 393762306a36Sopenharmony_ci * same MTUs. To do this, we'd need to 393862306a36Sopenharmony_ci * take over the slave's change_mtu 393962306a36Sopenharmony_ci * function for the duration of their 394062306a36Sopenharmony_ci * servitude. 394162306a36Sopenharmony_ci */ 394262306a36Sopenharmony_ci break; 394362306a36Sopenharmony_ci case NETDEV_CHANGENAME: 394462306a36Sopenharmony_ci /* we don't care if we don't have primary set */ 394562306a36Sopenharmony_ci if (!bond_uses_primary(bond) || 394662306a36Sopenharmony_ci !bond->params.primary[0]) 394762306a36Sopenharmony_ci break; 394862306a36Sopenharmony_ci 394962306a36Sopenharmony_ci if (slave == primary) { 395062306a36Sopenharmony_ci /* slave's name changed - he's no longer primary */ 395162306a36Sopenharmony_ci RCU_INIT_POINTER(bond->primary_slave, NULL); 395262306a36Sopenharmony_ci } else if (!strcmp(slave_dev->name, bond->params.primary)) { 395362306a36Sopenharmony_ci /* we have a new primary slave */ 395462306a36Sopenharmony_ci rcu_assign_pointer(bond->primary_slave, slave); 395562306a36Sopenharmony_ci } else { /* we didn't change primary - exit */ 395662306a36Sopenharmony_ci break; 395762306a36Sopenharmony_ci } 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci netdev_info(bond->dev, "Primary slave changed to %s, reselecting active slave\n", 396062306a36Sopenharmony_ci primary ? slave_dev->name : "none"); 396162306a36Sopenharmony_ci 396262306a36Sopenharmony_ci block_netpoll_tx(); 396362306a36Sopenharmony_ci bond_select_active_slave(bond); 396462306a36Sopenharmony_ci unblock_netpoll_tx(); 396562306a36Sopenharmony_ci break; 396662306a36Sopenharmony_ci case NETDEV_FEAT_CHANGE: 396762306a36Sopenharmony_ci if (!bond->notifier_ctx) { 396862306a36Sopenharmony_ci bond->notifier_ctx = true; 396962306a36Sopenharmony_ci bond_compute_features(bond); 397062306a36Sopenharmony_ci bond->notifier_ctx = false; 397162306a36Sopenharmony_ci } 397262306a36Sopenharmony_ci break; 397362306a36Sopenharmony_ci case NETDEV_RESEND_IGMP: 397462306a36Sopenharmony_ci /* Propagate to master device */ 397562306a36Sopenharmony_ci call_netdevice_notifiers(event, slave->bond->dev); 397662306a36Sopenharmony_ci break; 397762306a36Sopenharmony_ci case NETDEV_XDP_FEAT_CHANGE: 397862306a36Sopenharmony_ci bond_xdp_set_features(bond_dev); 397962306a36Sopenharmony_ci break; 398062306a36Sopenharmony_ci default: 398162306a36Sopenharmony_ci break; 398262306a36Sopenharmony_ci } 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci return NOTIFY_DONE; 398562306a36Sopenharmony_ci} 398662306a36Sopenharmony_ci 398762306a36Sopenharmony_ci/* bond_netdev_event: handle netdev notifier chain events. 398862306a36Sopenharmony_ci * 398962306a36Sopenharmony_ci * This function receives events for the netdev chain. The caller (an 399062306a36Sopenharmony_ci * ioctl handler calling blocking_notifier_call_chain) holds the necessary 399162306a36Sopenharmony_ci * locks for us to safely manipulate the slave devices (RTNL lock, 399262306a36Sopenharmony_ci * dev_probe_lock). 399362306a36Sopenharmony_ci */ 399462306a36Sopenharmony_cistatic int bond_netdev_event(struct notifier_block *this, 399562306a36Sopenharmony_ci unsigned long event, void *ptr) 399662306a36Sopenharmony_ci{ 399762306a36Sopenharmony_ci struct net_device *event_dev = netdev_notifier_info_to_dev(ptr); 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_ci netdev_dbg(event_dev, "%s received %s\n", 400062306a36Sopenharmony_ci __func__, netdev_cmd_to_name(event)); 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci if (!(event_dev->priv_flags & IFF_BONDING)) 400362306a36Sopenharmony_ci return NOTIFY_DONE; 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci if (event_dev->flags & IFF_MASTER) { 400662306a36Sopenharmony_ci int ret; 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci ret = bond_master_netdev_event(event, event_dev); 400962306a36Sopenharmony_ci if (ret != NOTIFY_DONE) 401062306a36Sopenharmony_ci return ret; 401162306a36Sopenharmony_ci } 401262306a36Sopenharmony_ci 401362306a36Sopenharmony_ci if (event_dev->flags & IFF_SLAVE) 401462306a36Sopenharmony_ci return bond_slave_netdev_event(event, event_dev); 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ci return NOTIFY_DONE; 401762306a36Sopenharmony_ci} 401862306a36Sopenharmony_ci 401962306a36Sopenharmony_cistatic struct notifier_block bond_netdev_notifier = { 402062306a36Sopenharmony_ci .notifier_call = bond_netdev_event, 402162306a36Sopenharmony_ci}; 402262306a36Sopenharmony_ci 402362306a36Sopenharmony_ci/*---------------------------- Hashing Policies -----------------------------*/ 402462306a36Sopenharmony_ci 402562306a36Sopenharmony_ci/* Helper to access data in a packet, with or without a backing skb. 402662306a36Sopenharmony_ci * If skb is given the data is linearized if necessary via pskb_may_pull. 402762306a36Sopenharmony_ci */ 402862306a36Sopenharmony_cistatic inline const void *bond_pull_data(struct sk_buff *skb, 402962306a36Sopenharmony_ci const void *data, int hlen, int n) 403062306a36Sopenharmony_ci{ 403162306a36Sopenharmony_ci if (likely(n <= hlen)) 403262306a36Sopenharmony_ci return data; 403362306a36Sopenharmony_ci else if (skb && likely(pskb_may_pull(skb, n))) 403462306a36Sopenharmony_ci return skb->data; 403562306a36Sopenharmony_ci 403662306a36Sopenharmony_ci return NULL; 403762306a36Sopenharmony_ci} 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_ci/* L2 hash helper */ 404062306a36Sopenharmony_cistatic inline u32 bond_eth_hash(struct sk_buff *skb, const void *data, int mhoff, int hlen) 404162306a36Sopenharmony_ci{ 404262306a36Sopenharmony_ci struct ethhdr *ep; 404362306a36Sopenharmony_ci 404462306a36Sopenharmony_ci data = bond_pull_data(skb, data, hlen, mhoff + sizeof(struct ethhdr)); 404562306a36Sopenharmony_ci if (!data) 404662306a36Sopenharmony_ci return 0; 404762306a36Sopenharmony_ci 404862306a36Sopenharmony_ci ep = (struct ethhdr *)(data + mhoff); 404962306a36Sopenharmony_ci return ep->h_dest[5] ^ ep->h_source[5] ^ be16_to_cpu(ep->h_proto); 405062306a36Sopenharmony_ci} 405162306a36Sopenharmony_ci 405262306a36Sopenharmony_cistatic bool bond_flow_ip(struct sk_buff *skb, struct flow_keys *fk, const void *data, 405362306a36Sopenharmony_ci int hlen, __be16 l2_proto, int *nhoff, int *ip_proto, bool l34) 405462306a36Sopenharmony_ci{ 405562306a36Sopenharmony_ci const struct ipv6hdr *iph6; 405662306a36Sopenharmony_ci const struct iphdr *iph; 405762306a36Sopenharmony_ci 405862306a36Sopenharmony_ci if (l2_proto == htons(ETH_P_IP)) { 405962306a36Sopenharmony_ci data = bond_pull_data(skb, data, hlen, *nhoff + sizeof(*iph)); 406062306a36Sopenharmony_ci if (!data) 406162306a36Sopenharmony_ci return false; 406262306a36Sopenharmony_ci 406362306a36Sopenharmony_ci iph = (const struct iphdr *)(data + *nhoff); 406462306a36Sopenharmony_ci iph_to_flow_copy_v4addrs(fk, iph); 406562306a36Sopenharmony_ci *nhoff += iph->ihl << 2; 406662306a36Sopenharmony_ci if (!ip_is_fragment(iph)) 406762306a36Sopenharmony_ci *ip_proto = iph->protocol; 406862306a36Sopenharmony_ci } else if (l2_proto == htons(ETH_P_IPV6)) { 406962306a36Sopenharmony_ci data = bond_pull_data(skb, data, hlen, *nhoff + sizeof(*iph6)); 407062306a36Sopenharmony_ci if (!data) 407162306a36Sopenharmony_ci return false; 407262306a36Sopenharmony_ci 407362306a36Sopenharmony_ci iph6 = (const struct ipv6hdr *)(data + *nhoff); 407462306a36Sopenharmony_ci iph_to_flow_copy_v6addrs(fk, iph6); 407562306a36Sopenharmony_ci *nhoff += sizeof(*iph6); 407662306a36Sopenharmony_ci *ip_proto = iph6->nexthdr; 407762306a36Sopenharmony_ci } else { 407862306a36Sopenharmony_ci return false; 407962306a36Sopenharmony_ci } 408062306a36Sopenharmony_ci 408162306a36Sopenharmony_ci if (l34 && *ip_proto >= 0) 408262306a36Sopenharmony_ci fk->ports.ports = __skb_flow_get_ports(skb, *nhoff, *ip_proto, data, hlen); 408362306a36Sopenharmony_ci 408462306a36Sopenharmony_ci return true; 408562306a36Sopenharmony_ci} 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_cistatic u32 bond_vlan_srcmac_hash(struct sk_buff *skb, const void *data, int mhoff, int hlen) 408862306a36Sopenharmony_ci{ 408962306a36Sopenharmony_ci u32 srcmac_vendor = 0, srcmac_dev = 0; 409062306a36Sopenharmony_ci struct ethhdr *mac_hdr; 409162306a36Sopenharmony_ci u16 vlan = 0; 409262306a36Sopenharmony_ci int i; 409362306a36Sopenharmony_ci 409462306a36Sopenharmony_ci data = bond_pull_data(skb, data, hlen, mhoff + sizeof(struct ethhdr)); 409562306a36Sopenharmony_ci if (!data) 409662306a36Sopenharmony_ci return 0; 409762306a36Sopenharmony_ci mac_hdr = (struct ethhdr *)(data + mhoff); 409862306a36Sopenharmony_ci 409962306a36Sopenharmony_ci for (i = 0; i < 3; i++) 410062306a36Sopenharmony_ci srcmac_vendor = (srcmac_vendor << 8) | mac_hdr->h_source[i]; 410162306a36Sopenharmony_ci 410262306a36Sopenharmony_ci for (i = 3; i < ETH_ALEN; i++) 410362306a36Sopenharmony_ci srcmac_dev = (srcmac_dev << 8) | mac_hdr->h_source[i]; 410462306a36Sopenharmony_ci 410562306a36Sopenharmony_ci if (skb && skb_vlan_tag_present(skb)) 410662306a36Sopenharmony_ci vlan = skb_vlan_tag_get(skb); 410762306a36Sopenharmony_ci 410862306a36Sopenharmony_ci return vlan ^ srcmac_vendor ^ srcmac_dev; 410962306a36Sopenharmony_ci} 411062306a36Sopenharmony_ci 411162306a36Sopenharmony_ci/* Extract the appropriate headers based on bond's xmit policy */ 411262306a36Sopenharmony_cistatic bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, const void *data, 411362306a36Sopenharmony_ci __be16 l2_proto, int nhoff, int hlen, struct flow_keys *fk) 411462306a36Sopenharmony_ci{ 411562306a36Sopenharmony_ci bool l34 = bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34; 411662306a36Sopenharmony_ci int ip_proto = -1; 411762306a36Sopenharmony_ci 411862306a36Sopenharmony_ci switch (bond->params.xmit_policy) { 411962306a36Sopenharmony_ci case BOND_XMIT_POLICY_ENCAP23: 412062306a36Sopenharmony_ci case BOND_XMIT_POLICY_ENCAP34: 412162306a36Sopenharmony_ci memset(fk, 0, sizeof(*fk)); 412262306a36Sopenharmony_ci return __skb_flow_dissect(NULL, skb, &flow_keys_bonding, 412362306a36Sopenharmony_ci fk, data, l2_proto, nhoff, hlen, 0); 412462306a36Sopenharmony_ci default: 412562306a36Sopenharmony_ci break; 412662306a36Sopenharmony_ci } 412762306a36Sopenharmony_ci 412862306a36Sopenharmony_ci fk->ports.ports = 0; 412962306a36Sopenharmony_ci memset(&fk->icmp, 0, sizeof(fk->icmp)); 413062306a36Sopenharmony_ci if (!bond_flow_ip(skb, fk, data, hlen, l2_proto, &nhoff, &ip_proto, l34)) 413162306a36Sopenharmony_ci return false; 413262306a36Sopenharmony_ci 413362306a36Sopenharmony_ci /* ICMP error packets contains at least 8 bytes of the header 413462306a36Sopenharmony_ci * of the packet which generated the error. Use this information 413562306a36Sopenharmony_ci * to correlate ICMP error packets within the same flow which 413662306a36Sopenharmony_ci * generated the error. 413762306a36Sopenharmony_ci */ 413862306a36Sopenharmony_ci if (ip_proto == IPPROTO_ICMP || ip_proto == IPPROTO_ICMPV6) { 413962306a36Sopenharmony_ci skb_flow_get_icmp_tci(skb, &fk->icmp, data, nhoff, hlen); 414062306a36Sopenharmony_ci if (ip_proto == IPPROTO_ICMP) { 414162306a36Sopenharmony_ci if (!icmp_is_err(fk->icmp.type)) 414262306a36Sopenharmony_ci return true; 414362306a36Sopenharmony_ci 414462306a36Sopenharmony_ci nhoff += sizeof(struct icmphdr); 414562306a36Sopenharmony_ci } else if (ip_proto == IPPROTO_ICMPV6) { 414662306a36Sopenharmony_ci if (!icmpv6_is_err(fk->icmp.type)) 414762306a36Sopenharmony_ci return true; 414862306a36Sopenharmony_ci 414962306a36Sopenharmony_ci nhoff += sizeof(struct icmp6hdr); 415062306a36Sopenharmony_ci } 415162306a36Sopenharmony_ci return bond_flow_ip(skb, fk, data, hlen, l2_proto, &nhoff, &ip_proto, l34); 415262306a36Sopenharmony_ci } 415362306a36Sopenharmony_ci 415462306a36Sopenharmony_ci return true; 415562306a36Sopenharmony_ci} 415662306a36Sopenharmony_ci 415762306a36Sopenharmony_cistatic u32 bond_ip_hash(u32 hash, struct flow_keys *flow, int xmit_policy) 415862306a36Sopenharmony_ci{ 415962306a36Sopenharmony_ci hash ^= (__force u32)flow_get_u32_dst(flow) ^ 416062306a36Sopenharmony_ci (__force u32)flow_get_u32_src(flow); 416162306a36Sopenharmony_ci hash ^= (hash >> 16); 416262306a36Sopenharmony_ci hash ^= (hash >> 8); 416362306a36Sopenharmony_ci 416462306a36Sopenharmony_ci /* discard lowest hash bit to deal with the common even ports pattern */ 416562306a36Sopenharmony_ci if (xmit_policy == BOND_XMIT_POLICY_LAYER34 || 416662306a36Sopenharmony_ci xmit_policy == BOND_XMIT_POLICY_ENCAP34) 416762306a36Sopenharmony_ci return hash >> 1; 416862306a36Sopenharmony_ci 416962306a36Sopenharmony_ci return hash; 417062306a36Sopenharmony_ci} 417162306a36Sopenharmony_ci 417262306a36Sopenharmony_ci/* Generate hash based on xmit policy. If @skb is given it is used to linearize 417362306a36Sopenharmony_ci * the data as required, but this function can be used without it if the data is 417462306a36Sopenharmony_ci * known to be linear (e.g. with xdp_buff). 417562306a36Sopenharmony_ci */ 417662306a36Sopenharmony_cistatic u32 __bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, const void *data, 417762306a36Sopenharmony_ci __be16 l2_proto, int mhoff, int nhoff, int hlen) 417862306a36Sopenharmony_ci{ 417962306a36Sopenharmony_ci struct flow_keys flow; 418062306a36Sopenharmony_ci u32 hash; 418162306a36Sopenharmony_ci 418262306a36Sopenharmony_ci if (bond->params.xmit_policy == BOND_XMIT_POLICY_VLAN_SRCMAC) 418362306a36Sopenharmony_ci return bond_vlan_srcmac_hash(skb, data, mhoff, hlen); 418462306a36Sopenharmony_ci 418562306a36Sopenharmony_ci if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER2 || 418662306a36Sopenharmony_ci !bond_flow_dissect(bond, skb, data, l2_proto, nhoff, hlen, &flow)) 418762306a36Sopenharmony_ci return bond_eth_hash(skb, data, mhoff, hlen); 418862306a36Sopenharmony_ci 418962306a36Sopenharmony_ci if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER23 || 419062306a36Sopenharmony_ci bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP23) { 419162306a36Sopenharmony_ci hash = bond_eth_hash(skb, data, mhoff, hlen); 419262306a36Sopenharmony_ci } else { 419362306a36Sopenharmony_ci if (flow.icmp.id) 419462306a36Sopenharmony_ci memcpy(&hash, &flow.icmp, sizeof(hash)); 419562306a36Sopenharmony_ci else 419662306a36Sopenharmony_ci memcpy(&hash, &flow.ports.ports, sizeof(hash)); 419762306a36Sopenharmony_ci } 419862306a36Sopenharmony_ci 419962306a36Sopenharmony_ci return bond_ip_hash(hash, &flow, bond->params.xmit_policy); 420062306a36Sopenharmony_ci} 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_ci/** 420362306a36Sopenharmony_ci * bond_xmit_hash - generate a hash value based on the xmit policy 420462306a36Sopenharmony_ci * @bond: bonding device 420562306a36Sopenharmony_ci * @skb: buffer to use for headers 420662306a36Sopenharmony_ci * 420762306a36Sopenharmony_ci * This function will extract the necessary headers from the skb buffer and use 420862306a36Sopenharmony_ci * them to generate a hash based on the xmit_policy set in the bonding device 420962306a36Sopenharmony_ci */ 421062306a36Sopenharmony_ciu32 bond_xmit_hash(struct bonding *bond, struct sk_buff *skb) 421162306a36Sopenharmony_ci{ 421262306a36Sopenharmony_ci if (bond->params.xmit_policy == BOND_XMIT_POLICY_ENCAP34 && 421362306a36Sopenharmony_ci skb->l4_hash) 421462306a36Sopenharmony_ci return skb->hash; 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ci return __bond_xmit_hash(bond, skb, skb->data, skb->protocol, 421762306a36Sopenharmony_ci 0, skb_network_offset(skb), 421862306a36Sopenharmony_ci skb_headlen(skb)); 421962306a36Sopenharmony_ci} 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci/** 422262306a36Sopenharmony_ci * bond_xmit_hash_xdp - generate a hash value based on the xmit policy 422362306a36Sopenharmony_ci * @bond: bonding device 422462306a36Sopenharmony_ci * @xdp: buffer to use for headers 422562306a36Sopenharmony_ci * 422662306a36Sopenharmony_ci * The XDP variant of bond_xmit_hash. 422762306a36Sopenharmony_ci */ 422862306a36Sopenharmony_cistatic u32 bond_xmit_hash_xdp(struct bonding *bond, struct xdp_buff *xdp) 422962306a36Sopenharmony_ci{ 423062306a36Sopenharmony_ci struct ethhdr *eth; 423162306a36Sopenharmony_ci 423262306a36Sopenharmony_ci if (xdp->data + sizeof(struct ethhdr) > xdp->data_end) 423362306a36Sopenharmony_ci return 0; 423462306a36Sopenharmony_ci 423562306a36Sopenharmony_ci eth = (struct ethhdr *)xdp->data; 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ci return __bond_xmit_hash(bond, NULL, xdp->data, eth->h_proto, 0, 423862306a36Sopenharmony_ci sizeof(struct ethhdr), xdp->data_end - xdp->data); 423962306a36Sopenharmony_ci} 424062306a36Sopenharmony_ci 424162306a36Sopenharmony_ci/*-------------------------- Device entry points ----------------------------*/ 424262306a36Sopenharmony_ci 424362306a36Sopenharmony_civoid bond_work_init_all(struct bonding *bond) 424462306a36Sopenharmony_ci{ 424562306a36Sopenharmony_ci INIT_DELAYED_WORK(&bond->mcast_work, 424662306a36Sopenharmony_ci bond_resend_igmp_join_requests_delayed); 424762306a36Sopenharmony_ci INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor); 424862306a36Sopenharmony_ci INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor); 424962306a36Sopenharmony_ci INIT_DELAYED_WORK(&bond->arp_work, bond_arp_monitor); 425062306a36Sopenharmony_ci INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler); 425162306a36Sopenharmony_ci INIT_DELAYED_WORK(&bond->slave_arr_work, bond_slave_arr_handler); 425262306a36Sopenharmony_ci} 425362306a36Sopenharmony_ci 425462306a36Sopenharmony_cistatic void bond_work_cancel_all(struct bonding *bond) 425562306a36Sopenharmony_ci{ 425662306a36Sopenharmony_ci cancel_delayed_work_sync(&bond->mii_work); 425762306a36Sopenharmony_ci cancel_delayed_work_sync(&bond->arp_work); 425862306a36Sopenharmony_ci cancel_delayed_work_sync(&bond->alb_work); 425962306a36Sopenharmony_ci cancel_delayed_work_sync(&bond->ad_work); 426062306a36Sopenharmony_ci cancel_delayed_work_sync(&bond->mcast_work); 426162306a36Sopenharmony_ci cancel_delayed_work_sync(&bond->slave_arr_work); 426262306a36Sopenharmony_ci} 426362306a36Sopenharmony_ci 426462306a36Sopenharmony_cistatic int bond_open(struct net_device *bond_dev) 426562306a36Sopenharmony_ci{ 426662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 426762306a36Sopenharmony_ci struct list_head *iter; 426862306a36Sopenharmony_ci struct slave *slave; 426962306a36Sopenharmony_ci 427062306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ROUNDROBIN && !bond->rr_tx_counter) { 427162306a36Sopenharmony_ci bond->rr_tx_counter = alloc_percpu(u32); 427262306a36Sopenharmony_ci if (!bond->rr_tx_counter) 427362306a36Sopenharmony_ci return -ENOMEM; 427462306a36Sopenharmony_ci } 427562306a36Sopenharmony_ci 427662306a36Sopenharmony_ci /* reset slave->backup and slave->inactive */ 427762306a36Sopenharmony_ci if (bond_has_slaves(bond)) { 427862306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 427962306a36Sopenharmony_ci if (bond_uses_primary(bond) && 428062306a36Sopenharmony_ci slave != rcu_access_pointer(bond->curr_active_slave)) { 428162306a36Sopenharmony_ci bond_set_slave_inactive_flags(slave, 428262306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 428362306a36Sopenharmony_ci } else if (BOND_MODE(bond) != BOND_MODE_8023AD) { 428462306a36Sopenharmony_ci bond_set_slave_active_flags(slave, 428562306a36Sopenharmony_ci BOND_SLAVE_NOTIFY_NOW); 428662306a36Sopenharmony_ci } 428762306a36Sopenharmony_ci } 428862306a36Sopenharmony_ci } 428962306a36Sopenharmony_ci 429062306a36Sopenharmony_ci if (bond_is_lb(bond)) { 429162306a36Sopenharmony_ci /* bond_alb_initialize must be called before the timer 429262306a36Sopenharmony_ci * is started. 429362306a36Sopenharmony_ci */ 429462306a36Sopenharmony_ci if (bond_alb_initialize(bond, (BOND_MODE(bond) == BOND_MODE_ALB))) 429562306a36Sopenharmony_ci return -ENOMEM; 429662306a36Sopenharmony_ci if (bond->params.tlb_dynamic_lb || BOND_MODE(bond) == BOND_MODE_ALB) 429762306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->alb_work, 0); 429862306a36Sopenharmony_ci } 429962306a36Sopenharmony_ci 430062306a36Sopenharmony_ci if (bond->params.miimon) /* link check interval, in milliseconds. */ 430162306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->mii_work, 0); 430262306a36Sopenharmony_ci 430362306a36Sopenharmony_ci if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ 430462306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->arp_work, 0); 430562306a36Sopenharmony_ci bond->recv_probe = bond_rcv_validate; 430662306a36Sopenharmony_ci } 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 430962306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->ad_work, 0); 431062306a36Sopenharmony_ci /* register to receive LACPDUs */ 431162306a36Sopenharmony_ci bond->recv_probe = bond_3ad_lacpdu_recv; 431262306a36Sopenharmony_ci bond_3ad_initiate_agg_selection(bond, 1); 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) 431562306a36Sopenharmony_ci dev_mc_add(slave->dev, lacpdu_mcast_addr); 431662306a36Sopenharmony_ci } 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci if (bond_mode_can_use_xmit_hash(bond)) 431962306a36Sopenharmony_ci bond_update_slave_arr(bond, NULL); 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ci return 0; 432262306a36Sopenharmony_ci} 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_cistatic int bond_close(struct net_device *bond_dev) 432562306a36Sopenharmony_ci{ 432662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 432762306a36Sopenharmony_ci struct slave *slave; 432862306a36Sopenharmony_ci 432962306a36Sopenharmony_ci bond_work_cancel_all(bond); 433062306a36Sopenharmony_ci bond->send_peer_notif = 0; 433162306a36Sopenharmony_ci if (bond_is_lb(bond)) 433262306a36Sopenharmony_ci bond_alb_deinitialize(bond); 433362306a36Sopenharmony_ci bond->recv_probe = NULL; 433462306a36Sopenharmony_ci 433562306a36Sopenharmony_ci if (bond_uses_primary(bond)) { 433662306a36Sopenharmony_ci rcu_read_lock(); 433762306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 433862306a36Sopenharmony_ci if (slave) 433962306a36Sopenharmony_ci bond_hw_addr_flush(bond_dev, slave->dev); 434062306a36Sopenharmony_ci rcu_read_unlock(); 434162306a36Sopenharmony_ci } else { 434262306a36Sopenharmony_ci struct list_head *iter; 434362306a36Sopenharmony_ci 434462306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) 434562306a36Sopenharmony_ci bond_hw_addr_flush(bond_dev, slave->dev); 434662306a36Sopenharmony_ci } 434762306a36Sopenharmony_ci 434862306a36Sopenharmony_ci return 0; 434962306a36Sopenharmony_ci} 435062306a36Sopenharmony_ci 435162306a36Sopenharmony_ci/* fold stats, assuming all rtnl_link_stats64 fields are u64, but 435262306a36Sopenharmony_ci * that some drivers can provide 32bit values only. 435362306a36Sopenharmony_ci */ 435462306a36Sopenharmony_cistatic void bond_fold_stats(struct rtnl_link_stats64 *_res, 435562306a36Sopenharmony_ci const struct rtnl_link_stats64 *_new, 435662306a36Sopenharmony_ci const struct rtnl_link_stats64 *_old) 435762306a36Sopenharmony_ci{ 435862306a36Sopenharmony_ci const u64 *new = (const u64 *)_new; 435962306a36Sopenharmony_ci const u64 *old = (const u64 *)_old; 436062306a36Sopenharmony_ci u64 *res = (u64 *)_res; 436162306a36Sopenharmony_ci int i; 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_ci for (i = 0; i < sizeof(*_res) / sizeof(u64); i++) { 436462306a36Sopenharmony_ci u64 nv = new[i]; 436562306a36Sopenharmony_ci u64 ov = old[i]; 436662306a36Sopenharmony_ci s64 delta = nv - ov; 436762306a36Sopenharmony_ci 436862306a36Sopenharmony_ci /* detects if this particular field is 32bit only */ 436962306a36Sopenharmony_ci if (((nv | ov) >> 32) == 0) 437062306a36Sopenharmony_ci delta = (s64)(s32)((u32)nv - (u32)ov); 437162306a36Sopenharmony_ci 437262306a36Sopenharmony_ci /* filter anomalies, some drivers reset their stats 437362306a36Sopenharmony_ci * at down/up events. 437462306a36Sopenharmony_ci */ 437562306a36Sopenharmony_ci if (delta > 0) 437662306a36Sopenharmony_ci res[i] += delta; 437762306a36Sopenharmony_ci } 437862306a36Sopenharmony_ci} 437962306a36Sopenharmony_ci 438062306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP 438162306a36Sopenharmony_cistatic int bond_get_lowest_level_rcu(struct net_device *dev) 438262306a36Sopenharmony_ci{ 438362306a36Sopenharmony_ci struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; 438462306a36Sopenharmony_ci struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; 438562306a36Sopenharmony_ci int cur = 0, max = 0; 438662306a36Sopenharmony_ci 438762306a36Sopenharmony_ci now = dev; 438862306a36Sopenharmony_ci iter = &dev->adj_list.lower; 438962306a36Sopenharmony_ci 439062306a36Sopenharmony_ci while (1) { 439162306a36Sopenharmony_ci next = NULL; 439262306a36Sopenharmony_ci while (1) { 439362306a36Sopenharmony_ci ldev = netdev_next_lower_dev_rcu(now, &iter); 439462306a36Sopenharmony_ci if (!ldev) 439562306a36Sopenharmony_ci break; 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci next = ldev; 439862306a36Sopenharmony_ci niter = &ldev->adj_list.lower; 439962306a36Sopenharmony_ci dev_stack[cur] = now; 440062306a36Sopenharmony_ci iter_stack[cur++] = iter; 440162306a36Sopenharmony_ci if (max <= cur) 440262306a36Sopenharmony_ci max = cur; 440362306a36Sopenharmony_ci break; 440462306a36Sopenharmony_ci } 440562306a36Sopenharmony_ci 440662306a36Sopenharmony_ci if (!next) { 440762306a36Sopenharmony_ci if (!cur) 440862306a36Sopenharmony_ci return max; 440962306a36Sopenharmony_ci next = dev_stack[--cur]; 441062306a36Sopenharmony_ci niter = iter_stack[cur]; 441162306a36Sopenharmony_ci } 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_ci now = next; 441462306a36Sopenharmony_ci iter = niter; 441562306a36Sopenharmony_ci } 441662306a36Sopenharmony_ci 441762306a36Sopenharmony_ci return max; 441862306a36Sopenharmony_ci} 441962306a36Sopenharmony_ci#endif 442062306a36Sopenharmony_ci 442162306a36Sopenharmony_cistatic void bond_get_stats(struct net_device *bond_dev, 442262306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 442362306a36Sopenharmony_ci{ 442462306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 442562306a36Sopenharmony_ci struct rtnl_link_stats64 temp; 442662306a36Sopenharmony_ci struct list_head *iter; 442762306a36Sopenharmony_ci struct slave *slave; 442862306a36Sopenharmony_ci int nest_level = 0; 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci 443162306a36Sopenharmony_ci rcu_read_lock(); 443262306a36Sopenharmony_ci#ifdef CONFIG_LOCKDEP 443362306a36Sopenharmony_ci nest_level = bond_get_lowest_level_rcu(bond_dev); 443462306a36Sopenharmony_ci#endif 443562306a36Sopenharmony_ci 443662306a36Sopenharmony_ci spin_lock_nested(&bond->stats_lock, nest_level); 443762306a36Sopenharmony_ci memcpy(stats, &bond->bond_stats, sizeof(*stats)); 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 444062306a36Sopenharmony_ci const struct rtnl_link_stats64 *new = 444162306a36Sopenharmony_ci dev_get_stats(slave->dev, &temp); 444262306a36Sopenharmony_ci 444362306a36Sopenharmony_ci bond_fold_stats(stats, new, &slave->slave_stats); 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_ci /* save off the slave stats for the next run */ 444662306a36Sopenharmony_ci memcpy(&slave->slave_stats, new, sizeof(*new)); 444762306a36Sopenharmony_ci } 444862306a36Sopenharmony_ci 444962306a36Sopenharmony_ci memcpy(&bond->bond_stats, stats, sizeof(*stats)); 445062306a36Sopenharmony_ci spin_unlock(&bond->stats_lock); 445162306a36Sopenharmony_ci rcu_read_unlock(); 445262306a36Sopenharmony_ci} 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_cistatic int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) 445562306a36Sopenharmony_ci{ 445662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 445762306a36Sopenharmony_ci struct mii_ioctl_data *mii = NULL; 445862306a36Sopenharmony_ci 445962306a36Sopenharmony_ci netdev_dbg(bond_dev, "bond_eth_ioctl: cmd=%d\n", cmd); 446062306a36Sopenharmony_ci 446162306a36Sopenharmony_ci switch (cmd) { 446262306a36Sopenharmony_ci case SIOCGMIIPHY: 446362306a36Sopenharmony_ci mii = if_mii(ifr); 446462306a36Sopenharmony_ci if (!mii) 446562306a36Sopenharmony_ci return -EINVAL; 446662306a36Sopenharmony_ci 446762306a36Sopenharmony_ci mii->phy_id = 0; 446862306a36Sopenharmony_ci fallthrough; 446962306a36Sopenharmony_ci case SIOCGMIIREG: 447062306a36Sopenharmony_ci /* We do this again just in case we were called by SIOCGMIIREG 447162306a36Sopenharmony_ci * instead of SIOCGMIIPHY. 447262306a36Sopenharmony_ci */ 447362306a36Sopenharmony_ci mii = if_mii(ifr); 447462306a36Sopenharmony_ci if (!mii) 447562306a36Sopenharmony_ci return -EINVAL; 447662306a36Sopenharmony_ci 447762306a36Sopenharmony_ci if (mii->reg_num == 1) { 447862306a36Sopenharmony_ci mii->val_out = 0; 447962306a36Sopenharmony_ci if (netif_carrier_ok(bond->dev)) 448062306a36Sopenharmony_ci mii->val_out = BMSR_LSTATUS; 448162306a36Sopenharmony_ci } 448262306a36Sopenharmony_ci 448362306a36Sopenharmony_ci break; 448462306a36Sopenharmony_ci default: 448562306a36Sopenharmony_ci return -EOPNOTSUPP; 448662306a36Sopenharmony_ci } 448762306a36Sopenharmony_ci 448862306a36Sopenharmony_ci return 0; 448962306a36Sopenharmony_ci} 449062306a36Sopenharmony_ci 449162306a36Sopenharmony_cistatic int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd) 449262306a36Sopenharmony_ci{ 449362306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 449462306a36Sopenharmony_ci struct net_device *slave_dev = NULL; 449562306a36Sopenharmony_ci struct ifbond k_binfo; 449662306a36Sopenharmony_ci struct ifbond __user *u_binfo = NULL; 449762306a36Sopenharmony_ci struct ifslave k_sinfo; 449862306a36Sopenharmony_ci struct ifslave __user *u_sinfo = NULL; 449962306a36Sopenharmony_ci struct bond_opt_value newval; 450062306a36Sopenharmony_ci struct net *net; 450162306a36Sopenharmony_ci int res = 0; 450262306a36Sopenharmony_ci 450362306a36Sopenharmony_ci netdev_dbg(bond_dev, "bond_ioctl: cmd=%d\n", cmd); 450462306a36Sopenharmony_ci 450562306a36Sopenharmony_ci switch (cmd) { 450662306a36Sopenharmony_ci case SIOCBONDINFOQUERY: 450762306a36Sopenharmony_ci u_binfo = (struct ifbond __user *)ifr->ifr_data; 450862306a36Sopenharmony_ci 450962306a36Sopenharmony_ci if (copy_from_user(&k_binfo, u_binfo, sizeof(ifbond))) 451062306a36Sopenharmony_ci return -EFAULT; 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci bond_info_query(bond_dev, &k_binfo); 451362306a36Sopenharmony_ci if (copy_to_user(u_binfo, &k_binfo, sizeof(ifbond))) 451462306a36Sopenharmony_ci return -EFAULT; 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_ci return 0; 451762306a36Sopenharmony_ci case SIOCBONDSLAVEINFOQUERY: 451862306a36Sopenharmony_ci u_sinfo = (struct ifslave __user *)ifr->ifr_data; 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ci if (copy_from_user(&k_sinfo, u_sinfo, sizeof(ifslave))) 452162306a36Sopenharmony_ci return -EFAULT; 452262306a36Sopenharmony_ci 452362306a36Sopenharmony_ci res = bond_slave_info_query(bond_dev, &k_sinfo); 452462306a36Sopenharmony_ci if (res == 0 && 452562306a36Sopenharmony_ci copy_to_user(u_sinfo, &k_sinfo, sizeof(ifslave))) 452662306a36Sopenharmony_ci return -EFAULT; 452762306a36Sopenharmony_ci 452862306a36Sopenharmony_ci return res; 452962306a36Sopenharmony_ci default: 453062306a36Sopenharmony_ci break; 453162306a36Sopenharmony_ci } 453262306a36Sopenharmony_ci 453362306a36Sopenharmony_ci net = dev_net(bond_dev); 453462306a36Sopenharmony_ci 453562306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) 453662306a36Sopenharmony_ci return -EPERM; 453762306a36Sopenharmony_ci 453862306a36Sopenharmony_ci slave_dev = __dev_get_by_name(net, ifr->ifr_slave); 453962306a36Sopenharmony_ci 454062306a36Sopenharmony_ci slave_dbg(bond_dev, slave_dev, "slave_dev=%p:\n", slave_dev); 454162306a36Sopenharmony_ci 454262306a36Sopenharmony_ci if (!slave_dev) 454362306a36Sopenharmony_ci return -ENODEV; 454462306a36Sopenharmony_ci 454562306a36Sopenharmony_ci switch (cmd) { 454662306a36Sopenharmony_ci case SIOCBONDENSLAVE: 454762306a36Sopenharmony_ci res = bond_enslave(bond_dev, slave_dev, NULL); 454862306a36Sopenharmony_ci break; 454962306a36Sopenharmony_ci case SIOCBONDRELEASE: 455062306a36Sopenharmony_ci res = bond_release(bond_dev, slave_dev); 455162306a36Sopenharmony_ci break; 455262306a36Sopenharmony_ci case SIOCBONDSETHWADDR: 455362306a36Sopenharmony_ci res = bond_set_dev_addr(bond_dev, slave_dev); 455462306a36Sopenharmony_ci break; 455562306a36Sopenharmony_ci case SIOCBONDCHANGEACTIVE: 455662306a36Sopenharmony_ci bond_opt_initstr(&newval, slave_dev->name); 455762306a36Sopenharmony_ci res = __bond_opt_set_notify(bond, BOND_OPT_ACTIVE_SLAVE, 455862306a36Sopenharmony_ci &newval); 455962306a36Sopenharmony_ci break; 456062306a36Sopenharmony_ci default: 456162306a36Sopenharmony_ci res = -EOPNOTSUPP; 456262306a36Sopenharmony_ci } 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ci return res; 456562306a36Sopenharmony_ci} 456662306a36Sopenharmony_ci 456762306a36Sopenharmony_cistatic int bond_siocdevprivate(struct net_device *bond_dev, struct ifreq *ifr, 456862306a36Sopenharmony_ci void __user *data, int cmd) 456962306a36Sopenharmony_ci{ 457062306a36Sopenharmony_ci struct ifreq ifrdata = { .ifr_data = data }; 457162306a36Sopenharmony_ci 457262306a36Sopenharmony_ci switch (cmd) { 457362306a36Sopenharmony_ci case BOND_INFO_QUERY_OLD: 457462306a36Sopenharmony_ci return bond_do_ioctl(bond_dev, &ifrdata, SIOCBONDINFOQUERY); 457562306a36Sopenharmony_ci case BOND_SLAVE_INFO_QUERY_OLD: 457662306a36Sopenharmony_ci return bond_do_ioctl(bond_dev, &ifrdata, SIOCBONDSLAVEINFOQUERY); 457762306a36Sopenharmony_ci case BOND_ENSLAVE_OLD: 457862306a36Sopenharmony_ci return bond_do_ioctl(bond_dev, ifr, SIOCBONDENSLAVE); 457962306a36Sopenharmony_ci case BOND_RELEASE_OLD: 458062306a36Sopenharmony_ci return bond_do_ioctl(bond_dev, ifr, SIOCBONDRELEASE); 458162306a36Sopenharmony_ci case BOND_SETHWADDR_OLD: 458262306a36Sopenharmony_ci return bond_do_ioctl(bond_dev, ifr, SIOCBONDSETHWADDR); 458362306a36Sopenharmony_ci case BOND_CHANGE_ACTIVE_OLD: 458462306a36Sopenharmony_ci return bond_do_ioctl(bond_dev, ifr, SIOCBONDCHANGEACTIVE); 458562306a36Sopenharmony_ci } 458662306a36Sopenharmony_ci 458762306a36Sopenharmony_ci return -EOPNOTSUPP; 458862306a36Sopenharmony_ci} 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_cistatic void bond_change_rx_flags(struct net_device *bond_dev, int change) 459162306a36Sopenharmony_ci{ 459262306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 459362306a36Sopenharmony_ci 459462306a36Sopenharmony_ci if (change & IFF_PROMISC) 459562306a36Sopenharmony_ci bond_set_promiscuity(bond, 459662306a36Sopenharmony_ci bond_dev->flags & IFF_PROMISC ? 1 : -1); 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ci if (change & IFF_ALLMULTI) 459962306a36Sopenharmony_ci bond_set_allmulti(bond, 460062306a36Sopenharmony_ci bond_dev->flags & IFF_ALLMULTI ? 1 : -1); 460162306a36Sopenharmony_ci} 460262306a36Sopenharmony_ci 460362306a36Sopenharmony_cistatic void bond_set_rx_mode(struct net_device *bond_dev) 460462306a36Sopenharmony_ci{ 460562306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 460662306a36Sopenharmony_ci struct list_head *iter; 460762306a36Sopenharmony_ci struct slave *slave; 460862306a36Sopenharmony_ci 460962306a36Sopenharmony_ci rcu_read_lock(); 461062306a36Sopenharmony_ci if (bond_uses_primary(bond)) { 461162306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 461262306a36Sopenharmony_ci if (slave) { 461362306a36Sopenharmony_ci dev_uc_sync(slave->dev, bond_dev); 461462306a36Sopenharmony_ci dev_mc_sync(slave->dev, bond_dev); 461562306a36Sopenharmony_ci } 461662306a36Sopenharmony_ci } else { 461762306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 461862306a36Sopenharmony_ci dev_uc_sync_multiple(slave->dev, bond_dev); 461962306a36Sopenharmony_ci dev_mc_sync_multiple(slave->dev, bond_dev); 462062306a36Sopenharmony_ci } 462162306a36Sopenharmony_ci } 462262306a36Sopenharmony_ci rcu_read_unlock(); 462362306a36Sopenharmony_ci} 462462306a36Sopenharmony_ci 462562306a36Sopenharmony_cistatic int bond_neigh_init(struct neighbour *n) 462662306a36Sopenharmony_ci{ 462762306a36Sopenharmony_ci struct bonding *bond = netdev_priv(n->dev); 462862306a36Sopenharmony_ci const struct net_device_ops *slave_ops; 462962306a36Sopenharmony_ci struct neigh_parms parms; 463062306a36Sopenharmony_ci struct slave *slave; 463162306a36Sopenharmony_ci int ret = 0; 463262306a36Sopenharmony_ci 463362306a36Sopenharmony_ci rcu_read_lock(); 463462306a36Sopenharmony_ci slave = bond_first_slave_rcu(bond); 463562306a36Sopenharmony_ci if (!slave) 463662306a36Sopenharmony_ci goto out; 463762306a36Sopenharmony_ci slave_ops = slave->dev->netdev_ops; 463862306a36Sopenharmony_ci if (!slave_ops->ndo_neigh_setup) 463962306a36Sopenharmony_ci goto out; 464062306a36Sopenharmony_ci 464162306a36Sopenharmony_ci /* TODO: find another way [1] to implement this. 464262306a36Sopenharmony_ci * Passing a zeroed structure is fragile, 464362306a36Sopenharmony_ci * but at least we do not pass garbage. 464462306a36Sopenharmony_ci * 464562306a36Sopenharmony_ci * [1] One way would be that ndo_neigh_setup() never touch 464662306a36Sopenharmony_ci * struct neigh_parms, but propagate the new neigh_setup() 464762306a36Sopenharmony_ci * back to ___neigh_create() / neigh_parms_alloc() 464862306a36Sopenharmony_ci */ 464962306a36Sopenharmony_ci memset(&parms, 0, sizeof(parms)); 465062306a36Sopenharmony_ci ret = slave_ops->ndo_neigh_setup(slave->dev, &parms); 465162306a36Sopenharmony_ci 465262306a36Sopenharmony_ci if (ret) 465362306a36Sopenharmony_ci goto out; 465462306a36Sopenharmony_ci 465562306a36Sopenharmony_ci if (parms.neigh_setup) 465662306a36Sopenharmony_ci ret = parms.neigh_setup(n); 465762306a36Sopenharmony_ciout: 465862306a36Sopenharmony_ci rcu_read_unlock(); 465962306a36Sopenharmony_ci return ret; 466062306a36Sopenharmony_ci} 466162306a36Sopenharmony_ci 466262306a36Sopenharmony_ci/* The bonding ndo_neigh_setup is called at init time beofre any 466362306a36Sopenharmony_ci * slave exists. So we must declare proxy setup function which will 466462306a36Sopenharmony_ci * be used at run time to resolve the actual slave neigh param setup. 466562306a36Sopenharmony_ci * 466662306a36Sopenharmony_ci * It's also called by master devices (such as vlans) to setup their 466762306a36Sopenharmony_ci * underlying devices. In that case - do nothing, we're already set up from 466862306a36Sopenharmony_ci * our init. 466962306a36Sopenharmony_ci */ 467062306a36Sopenharmony_cistatic int bond_neigh_setup(struct net_device *dev, 467162306a36Sopenharmony_ci struct neigh_parms *parms) 467262306a36Sopenharmony_ci{ 467362306a36Sopenharmony_ci /* modify only our neigh_parms */ 467462306a36Sopenharmony_ci if (parms->dev == dev) 467562306a36Sopenharmony_ci parms->neigh_setup = bond_neigh_init; 467662306a36Sopenharmony_ci 467762306a36Sopenharmony_ci return 0; 467862306a36Sopenharmony_ci} 467962306a36Sopenharmony_ci 468062306a36Sopenharmony_ci/* Change the MTU of all of a master's slaves to match the master */ 468162306a36Sopenharmony_cistatic int bond_change_mtu(struct net_device *bond_dev, int new_mtu) 468262306a36Sopenharmony_ci{ 468362306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 468462306a36Sopenharmony_ci struct slave *slave, *rollback_slave; 468562306a36Sopenharmony_ci struct list_head *iter; 468662306a36Sopenharmony_ci int res = 0; 468762306a36Sopenharmony_ci 468862306a36Sopenharmony_ci netdev_dbg(bond_dev, "bond=%p, new_mtu=%d\n", bond, new_mtu); 468962306a36Sopenharmony_ci 469062306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 469162306a36Sopenharmony_ci slave_dbg(bond_dev, slave->dev, "s %p c_m %p\n", 469262306a36Sopenharmony_ci slave, slave->dev->netdev_ops->ndo_change_mtu); 469362306a36Sopenharmony_ci 469462306a36Sopenharmony_ci res = dev_set_mtu(slave->dev, new_mtu); 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci if (res) { 469762306a36Sopenharmony_ci /* If we failed to set the slave's mtu to the new value 469862306a36Sopenharmony_ci * we must abort the operation even in ACTIVE_BACKUP 469962306a36Sopenharmony_ci * mode, because if we allow the backup slaves to have 470062306a36Sopenharmony_ci * different mtu values than the active slave we'll 470162306a36Sopenharmony_ci * need to change their mtu when doing a failover. That 470262306a36Sopenharmony_ci * means changing their mtu from timer context, which 470362306a36Sopenharmony_ci * is probably not a good idea. 470462306a36Sopenharmony_ci */ 470562306a36Sopenharmony_ci slave_dbg(bond_dev, slave->dev, "err %d setting mtu to %d\n", 470662306a36Sopenharmony_ci res, new_mtu); 470762306a36Sopenharmony_ci goto unwind; 470862306a36Sopenharmony_ci } 470962306a36Sopenharmony_ci } 471062306a36Sopenharmony_ci 471162306a36Sopenharmony_ci bond_dev->mtu = new_mtu; 471262306a36Sopenharmony_ci 471362306a36Sopenharmony_ci return 0; 471462306a36Sopenharmony_ci 471562306a36Sopenharmony_ciunwind: 471662306a36Sopenharmony_ci /* unwind from head to the slave that failed */ 471762306a36Sopenharmony_ci bond_for_each_slave(bond, rollback_slave, iter) { 471862306a36Sopenharmony_ci int tmp_res; 471962306a36Sopenharmony_ci 472062306a36Sopenharmony_ci if (rollback_slave == slave) 472162306a36Sopenharmony_ci break; 472262306a36Sopenharmony_ci 472362306a36Sopenharmony_ci tmp_res = dev_set_mtu(rollback_slave->dev, bond_dev->mtu); 472462306a36Sopenharmony_ci if (tmp_res) 472562306a36Sopenharmony_ci slave_dbg(bond_dev, rollback_slave->dev, "unwind err %d\n", 472662306a36Sopenharmony_ci tmp_res); 472762306a36Sopenharmony_ci } 472862306a36Sopenharmony_ci 472962306a36Sopenharmony_ci return res; 473062306a36Sopenharmony_ci} 473162306a36Sopenharmony_ci 473262306a36Sopenharmony_ci/* Change HW address 473362306a36Sopenharmony_ci * 473462306a36Sopenharmony_ci * Note that many devices must be down to change the HW address, and 473562306a36Sopenharmony_ci * downing the master releases all slaves. We can make bonds full of 473662306a36Sopenharmony_ci * bonding devices to test this, however. 473762306a36Sopenharmony_ci */ 473862306a36Sopenharmony_cistatic int bond_set_mac_address(struct net_device *bond_dev, void *addr) 473962306a36Sopenharmony_ci{ 474062306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 474162306a36Sopenharmony_ci struct slave *slave, *rollback_slave; 474262306a36Sopenharmony_ci struct sockaddr_storage *ss = addr, tmp_ss; 474362306a36Sopenharmony_ci struct list_head *iter; 474462306a36Sopenharmony_ci int res = 0; 474562306a36Sopenharmony_ci 474662306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ALB) 474762306a36Sopenharmony_ci return bond_alb_set_mac_address(bond_dev, addr); 474862306a36Sopenharmony_ci 474962306a36Sopenharmony_ci 475062306a36Sopenharmony_ci netdev_dbg(bond_dev, "%s: bond=%p\n", __func__, bond); 475162306a36Sopenharmony_ci 475262306a36Sopenharmony_ci /* If fail_over_mac is enabled, do nothing and return success. 475362306a36Sopenharmony_ci * Returning an error causes ifenslave to fail. 475462306a36Sopenharmony_ci */ 475562306a36Sopenharmony_ci if (bond->params.fail_over_mac && 475662306a36Sopenharmony_ci BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) 475762306a36Sopenharmony_ci return 0; 475862306a36Sopenharmony_ci 475962306a36Sopenharmony_ci if (!is_valid_ether_addr(ss->__data)) 476062306a36Sopenharmony_ci return -EADDRNOTAVAIL; 476162306a36Sopenharmony_ci 476262306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 476362306a36Sopenharmony_ci slave_dbg(bond_dev, slave->dev, "%s: slave=%p\n", 476462306a36Sopenharmony_ci __func__, slave); 476562306a36Sopenharmony_ci res = dev_set_mac_address(slave->dev, addr, NULL); 476662306a36Sopenharmony_ci if (res) { 476762306a36Sopenharmony_ci /* TODO: consider downing the slave 476862306a36Sopenharmony_ci * and retry ? 476962306a36Sopenharmony_ci * User should expect communications 477062306a36Sopenharmony_ci * breakage anyway until ARP finish 477162306a36Sopenharmony_ci * updating, so... 477262306a36Sopenharmony_ci */ 477362306a36Sopenharmony_ci slave_dbg(bond_dev, slave->dev, "%s: err %d\n", 477462306a36Sopenharmony_ci __func__, res); 477562306a36Sopenharmony_ci goto unwind; 477662306a36Sopenharmony_ci } 477762306a36Sopenharmony_ci } 477862306a36Sopenharmony_ci 477962306a36Sopenharmony_ci /* success */ 478062306a36Sopenharmony_ci dev_addr_set(bond_dev, ss->__data); 478162306a36Sopenharmony_ci return 0; 478262306a36Sopenharmony_ci 478362306a36Sopenharmony_ciunwind: 478462306a36Sopenharmony_ci memcpy(tmp_ss.__data, bond_dev->dev_addr, bond_dev->addr_len); 478562306a36Sopenharmony_ci tmp_ss.ss_family = bond_dev->type; 478662306a36Sopenharmony_ci 478762306a36Sopenharmony_ci /* unwind from head to the slave that failed */ 478862306a36Sopenharmony_ci bond_for_each_slave(bond, rollback_slave, iter) { 478962306a36Sopenharmony_ci int tmp_res; 479062306a36Sopenharmony_ci 479162306a36Sopenharmony_ci if (rollback_slave == slave) 479262306a36Sopenharmony_ci break; 479362306a36Sopenharmony_ci 479462306a36Sopenharmony_ci tmp_res = dev_set_mac_address(rollback_slave->dev, 479562306a36Sopenharmony_ci (struct sockaddr *)&tmp_ss, NULL); 479662306a36Sopenharmony_ci if (tmp_res) { 479762306a36Sopenharmony_ci slave_dbg(bond_dev, rollback_slave->dev, "%s: unwind err %d\n", 479862306a36Sopenharmony_ci __func__, tmp_res); 479962306a36Sopenharmony_ci } 480062306a36Sopenharmony_ci } 480162306a36Sopenharmony_ci 480262306a36Sopenharmony_ci return res; 480362306a36Sopenharmony_ci} 480462306a36Sopenharmony_ci 480562306a36Sopenharmony_ci/** 480662306a36Sopenharmony_ci * bond_get_slave_by_id - get xmit slave with slave_id 480762306a36Sopenharmony_ci * @bond: bonding device that is transmitting 480862306a36Sopenharmony_ci * @slave_id: slave id up to slave_cnt-1 through which to transmit 480962306a36Sopenharmony_ci * 481062306a36Sopenharmony_ci * This function tries to get slave with slave_id but in case 481162306a36Sopenharmony_ci * it fails, it tries to find the first available slave for transmission. 481262306a36Sopenharmony_ci */ 481362306a36Sopenharmony_cistatic struct slave *bond_get_slave_by_id(struct bonding *bond, 481462306a36Sopenharmony_ci int slave_id) 481562306a36Sopenharmony_ci{ 481662306a36Sopenharmony_ci struct list_head *iter; 481762306a36Sopenharmony_ci struct slave *slave; 481862306a36Sopenharmony_ci int i = slave_id; 481962306a36Sopenharmony_ci 482062306a36Sopenharmony_ci /* Here we start from the slave with slave_id */ 482162306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 482262306a36Sopenharmony_ci if (--i < 0) { 482362306a36Sopenharmony_ci if (bond_slave_can_tx(slave)) 482462306a36Sopenharmony_ci return slave; 482562306a36Sopenharmony_ci } 482662306a36Sopenharmony_ci } 482762306a36Sopenharmony_ci 482862306a36Sopenharmony_ci /* Here we start from the first slave up to slave_id */ 482962306a36Sopenharmony_ci i = slave_id; 483062306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 483162306a36Sopenharmony_ci if (--i < 0) 483262306a36Sopenharmony_ci break; 483362306a36Sopenharmony_ci if (bond_slave_can_tx(slave)) 483462306a36Sopenharmony_ci return slave; 483562306a36Sopenharmony_ci } 483662306a36Sopenharmony_ci /* no slave that can tx has been found */ 483762306a36Sopenharmony_ci return NULL; 483862306a36Sopenharmony_ci} 483962306a36Sopenharmony_ci 484062306a36Sopenharmony_ci/** 484162306a36Sopenharmony_ci * bond_rr_gen_slave_id - generate slave id based on packets_per_slave 484262306a36Sopenharmony_ci * @bond: bonding device to use 484362306a36Sopenharmony_ci * 484462306a36Sopenharmony_ci * Based on the value of the bonding device's packets_per_slave parameter 484562306a36Sopenharmony_ci * this function generates a slave id, which is usually used as the next 484662306a36Sopenharmony_ci * slave to transmit through. 484762306a36Sopenharmony_ci */ 484862306a36Sopenharmony_cistatic u32 bond_rr_gen_slave_id(struct bonding *bond) 484962306a36Sopenharmony_ci{ 485062306a36Sopenharmony_ci u32 slave_id; 485162306a36Sopenharmony_ci struct reciprocal_value reciprocal_packets_per_slave; 485262306a36Sopenharmony_ci int packets_per_slave = bond->params.packets_per_slave; 485362306a36Sopenharmony_ci 485462306a36Sopenharmony_ci switch (packets_per_slave) { 485562306a36Sopenharmony_ci case 0: 485662306a36Sopenharmony_ci slave_id = get_random_u32(); 485762306a36Sopenharmony_ci break; 485862306a36Sopenharmony_ci case 1: 485962306a36Sopenharmony_ci slave_id = this_cpu_inc_return(*bond->rr_tx_counter); 486062306a36Sopenharmony_ci break; 486162306a36Sopenharmony_ci default: 486262306a36Sopenharmony_ci reciprocal_packets_per_slave = 486362306a36Sopenharmony_ci bond->params.reciprocal_packets_per_slave; 486462306a36Sopenharmony_ci slave_id = this_cpu_inc_return(*bond->rr_tx_counter); 486562306a36Sopenharmony_ci slave_id = reciprocal_divide(slave_id, 486662306a36Sopenharmony_ci reciprocal_packets_per_slave); 486762306a36Sopenharmony_ci break; 486862306a36Sopenharmony_ci } 486962306a36Sopenharmony_ci 487062306a36Sopenharmony_ci return slave_id; 487162306a36Sopenharmony_ci} 487262306a36Sopenharmony_ci 487362306a36Sopenharmony_cistatic struct slave *bond_xmit_roundrobin_slave_get(struct bonding *bond, 487462306a36Sopenharmony_ci struct sk_buff *skb) 487562306a36Sopenharmony_ci{ 487662306a36Sopenharmony_ci struct slave *slave; 487762306a36Sopenharmony_ci int slave_cnt; 487862306a36Sopenharmony_ci u32 slave_id; 487962306a36Sopenharmony_ci 488062306a36Sopenharmony_ci /* Start with the curr_active_slave that joined the bond as the 488162306a36Sopenharmony_ci * default for sending IGMP traffic. For failover purposes one 488262306a36Sopenharmony_ci * needs to maintain some consistency for the interface that will 488362306a36Sopenharmony_ci * send the join/membership reports. The curr_active_slave found 488462306a36Sopenharmony_ci * will send all of this type of traffic. 488562306a36Sopenharmony_ci */ 488662306a36Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) { 488762306a36Sopenharmony_ci int noff = skb_network_offset(skb); 488862306a36Sopenharmony_ci struct iphdr *iph; 488962306a36Sopenharmony_ci 489062306a36Sopenharmony_ci if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph)))) 489162306a36Sopenharmony_ci goto non_igmp; 489262306a36Sopenharmony_ci 489362306a36Sopenharmony_ci iph = ip_hdr(skb); 489462306a36Sopenharmony_ci if (iph->protocol == IPPROTO_IGMP) { 489562306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 489662306a36Sopenharmony_ci if (slave) 489762306a36Sopenharmony_ci return slave; 489862306a36Sopenharmony_ci return bond_get_slave_by_id(bond, 0); 489962306a36Sopenharmony_ci } 490062306a36Sopenharmony_ci } 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_cinon_igmp: 490362306a36Sopenharmony_ci slave_cnt = READ_ONCE(bond->slave_cnt); 490462306a36Sopenharmony_ci if (likely(slave_cnt)) { 490562306a36Sopenharmony_ci slave_id = bond_rr_gen_slave_id(bond) % slave_cnt; 490662306a36Sopenharmony_ci return bond_get_slave_by_id(bond, slave_id); 490762306a36Sopenharmony_ci } 490862306a36Sopenharmony_ci return NULL; 490962306a36Sopenharmony_ci} 491062306a36Sopenharmony_ci 491162306a36Sopenharmony_cistatic struct slave *bond_xdp_xmit_roundrobin_slave_get(struct bonding *bond, 491262306a36Sopenharmony_ci struct xdp_buff *xdp) 491362306a36Sopenharmony_ci{ 491462306a36Sopenharmony_ci struct slave *slave; 491562306a36Sopenharmony_ci int slave_cnt; 491662306a36Sopenharmony_ci u32 slave_id; 491762306a36Sopenharmony_ci const struct ethhdr *eth; 491862306a36Sopenharmony_ci void *data = xdp->data; 491962306a36Sopenharmony_ci 492062306a36Sopenharmony_ci if (data + sizeof(struct ethhdr) > xdp->data_end) 492162306a36Sopenharmony_ci goto non_igmp; 492262306a36Sopenharmony_ci 492362306a36Sopenharmony_ci eth = (struct ethhdr *)data; 492462306a36Sopenharmony_ci data += sizeof(struct ethhdr); 492562306a36Sopenharmony_ci 492662306a36Sopenharmony_ci /* See comment on IGMP in bond_xmit_roundrobin_slave_get() */ 492762306a36Sopenharmony_ci if (eth->h_proto == htons(ETH_P_IP)) { 492862306a36Sopenharmony_ci const struct iphdr *iph; 492962306a36Sopenharmony_ci 493062306a36Sopenharmony_ci if (data + sizeof(struct iphdr) > xdp->data_end) 493162306a36Sopenharmony_ci goto non_igmp; 493262306a36Sopenharmony_ci 493362306a36Sopenharmony_ci iph = (struct iphdr *)data; 493462306a36Sopenharmony_ci 493562306a36Sopenharmony_ci if (iph->protocol == IPPROTO_IGMP) { 493662306a36Sopenharmony_ci slave = rcu_dereference(bond->curr_active_slave); 493762306a36Sopenharmony_ci if (slave) 493862306a36Sopenharmony_ci return slave; 493962306a36Sopenharmony_ci return bond_get_slave_by_id(bond, 0); 494062306a36Sopenharmony_ci } 494162306a36Sopenharmony_ci } 494262306a36Sopenharmony_ci 494362306a36Sopenharmony_cinon_igmp: 494462306a36Sopenharmony_ci slave_cnt = READ_ONCE(bond->slave_cnt); 494562306a36Sopenharmony_ci if (likely(slave_cnt)) { 494662306a36Sopenharmony_ci slave_id = bond_rr_gen_slave_id(bond) % slave_cnt; 494762306a36Sopenharmony_ci return bond_get_slave_by_id(bond, slave_id); 494862306a36Sopenharmony_ci } 494962306a36Sopenharmony_ci return NULL; 495062306a36Sopenharmony_ci} 495162306a36Sopenharmony_ci 495262306a36Sopenharmony_cistatic netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb, 495362306a36Sopenharmony_ci struct net_device *bond_dev) 495462306a36Sopenharmony_ci{ 495562306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 495662306a36Sopenharmony_ci struct slave *slave; 495762306a36Sopenharmony_ci 495862306a36Sopenharmony_ci slave = bond_xmit_roundrobin_slave_get(bond, skb); 495962306a36Sopenharmony_ci if (likely(slave)) 496062306a36Sopenharmony_ci return bond_dev_queue_xmit(bond, skb, slave->dev); 496162306a36Sopenharmony_ci 496262306a36Sopenharmony_ci return bond_tx_drop(bond_dev, skb); 496362306a36Sopenharmony_ci} 496462306a36Sopenharmony_ci 496562306a36Sopenharmony_cistatic struct slave *bond_xmit_activebackup_slave_get(struct bonding *bond) 496662306a36Sopenharmony_ci{ 496762306a36Sopenharmony_ci return rcu_dereference(bond->curr_active_slave); 496862306a36Sopenharmony_ci} 496962306a36Sopenharmony_ci 497062306a36Sopenharmony_ci/* In active-backup mode, we know that bond->curr_active_slave is always valid if 497162306a36Sopenharmony_ci * the bond has a usable interface. 497262306a36Sopenharmony_ci */ 497362306a36Sopenharmony_cistatic netdev_tx_t bond_xmit_activebackup(struct sk_buff *skb, 497462306a36Sopenharmony_ci struct net_device *bond_dev) 497562306a36Sopenharmony_ci{ 497662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 497762306a36Sopenharmony_ci struct slave *slave; 497862306a36Sopenharmony_ci 497962306a36Sopenharmony_ci slave = bond_xmit_activebackup_slave_get(bond); 498062306a36Sopenharmony_ci if (slave) 498162306a36Sopenharmony_ci return bond_dev_queue_xmit(bond, skb, slave->dev); 498262306a36Sopenharmony_ci 498362306a36Sopenharmony_ci return bond_tx_drop(bond_dev, skb); 498462306a36Sopenharmony_ci} 498562306a36Sopenharmony_ci 498662306a36Sopenharmony_ci/* Use this to update slave_array when (a) it's not appropriate to update 498762306a36Sopenharmony_ci * slave_array right away (note that update_slave_array() may sleep) 498862306a36Sopenharmony_ci * and / or (b) RTNL is not held. 498962306a36Sopenharmony_ci */ 499062306a36Sopenharmony_civoid bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay) 499162306a36Sopenharmony_ci{ 499262306a36Sopenharmony_ci queue_delayed_work(bond->wq, &bond->slave_arr_work, delay); 499362306a36Sopenharmony_ci} 499462306a36Sopenharmony_ci 499562306a36Sopenharmony_ci/* Slave array work handler. Holds only RTNL */ 499662306a36Sopenharmony_cistatic void bond_slave_arr_handler(struct work_struct *work) 499762306a36Sopenharmony_ci{ 499862306a36Sopenharmony_ci struct bonding *bond = container_of(work, struct bonding, 499962306a36Sopenharmony_ci slave_arr_work.work); 500062306a36Sopenharmony_ci int ret; 500162306a36Sopenharmony_ci 500262306a36Sopenharmony_ci if (!rtnl_trylock()) 500362306a36Sopenharmony_ci goto err; 500462306a36Sopenharmony_ci 500562306a36Sopenharmony_ci ret = bond_update_slave_arr(bond, NULL); 500662306a36Sopenharmony_ci rtnl_unlock(); 500762306a36Sopenharmony_ci if (ret) { 500862306a36Sopenharmony_ci pr_warn_ratelimited("Failed to update slave array from WT\n"); 500962306a36Sopenharmony_ci goto err; 501062306a36Sopenharmony_ci } 501162306a36Sopenharmony_ci return; 501262306a36Sopenharmony_ci 501362306a36Sopenharmony_cierr: 501462306a36Sopenharmony_ci bond_slave_arr_work_rearm(bond, 1); 501562306a36Sopenharmony_ci} 501662306a36Sopenharmony_ci 501762306a36Sopenharmony_cistatic void bond_skip_slave(struct bond_up_slave *slaves, 501862306a36Sopenharmony_ci struct slave *skipslave) 501962306a36Sopenharmony_ci{ 502062306a36Sopenharmony_ci int idx; 502162306a36Sopenharmony_ci 502262306a36Sopenharmony_ci /* Rare situation where caller has asked to skip a specific 502362306a36Sopenharmony_ci * slave but allocation failed (most likely!). BTW this is 502462306a36Sopenharmony_ci * only possible when the call is initiated from 502562306a36Sopenharmony_ci * __bond_release_one(). In this situation; overwrite the 502662306a36Sopenharmony_ci * skipslave entry in the array with the last entry from the 502762306a36Sopenharmony_ci * array to avoid a situation where the xmit path may choose 502862306a36Sopenharmony_ci * this to-be-skipped slave to send a packet out. 502962306a36Sopenharmony_ci */ 503062306a36Sopenharmony_ci for (idx = 0; slaves && idx < slaves->count; idx++) { 503162306a36Sopenharmony_ci if (skipslave == slaves->arr[idx]) { 503262306a36Sopenharmony_ci slaves->arr[idx] = 503362306a36Sopenharmony_ci slaves->arr[slaves->count - 1]; 503462306a36Sopenharmony_ci slaves->count--; 503562306a36Sopenharmony_ci break; 503662306a36Sopenharmony_ci } 503762306a36Sopenharmony_ci } 503862306a36Sopenharmony_ci} 503962306a36Sopenharmony_ci 504062306a36Sopenharmony_cistatic void bond_set_slave_arr(struct bonding *bond, 504162306a36Sopenharmony_ci struct bond_up_slave *usable_slaves, 504262306a36Sopenharmony_ci struct bond_up_slave *all_slaves) 504362306a36Sopenharmony_ci{ 504462306a36Sopenharmony_ci struct bond_up_slave *usable, *all; 504562306a36Sopenharmony_ci 504662306a36Sopenharmony_ci usable = rtnl_dereference(bond->usable_slaves); 504762306a36Sopenharmony_ci rcu_assign_pointer(bond->usable_slaves, usable_slaves); 504862306a36Sopenharmony_ci kfree_rcu(usable, rcu); 504962306a36Sopenharmony_ci 505062306a36Sopenharmony_ci all = rtnl_dereference(bond->all_slaves); 505162306a36Sopenharmony_ci rcu_assign_pointer(bond->all_slaves, all_slaves); 505262306a36Sopenharmony_ci kfree_rcu(all, rcu); 505362306a36Sopenharmony_ci} 505462306a36Sopenharmony_ci 505562306a36Sopenharmony_cistatic void bond_reset_slave_arr(struct bonding *bond) 505662306a36Sopenharmony_ci{ 505762306a36Sopenharmony_ci bond_set_slave_arr(bond, NULL, NULL); 505862306a36Sopenharmony_ci} 505962306a36Sopenharmony_ci 506062306a36Sopenharmony_ci/* Build the usable slaves array in control path for modes that use xmit-hash 506162306a36Sopenharmony_ci * to determine the slave interface - 506262306a36Sopenharmony_ci * (a) BOND_MODE_8023AD 506362306a36Sopenharmony_ci * (b) BOND_MODE_XOR 506462306a36Sopenharmony_ci * (c) (BOND_MODE_TLB || BOND_MODE_ALB) && tlb_dynamic_lb == 0 506562306a36Sopenharmony_ci * 506662306a36Sopenharmony_ci * The caller is expected to hold RTNL only and NO other lock! 506762306a36Sopenharmony_ci */ 506862306a36Sopenharmony_ciint bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) 506962306a36Sopenharmony_ci{ 507062306a36Sopenharmony_ci struct bond_up_slave *usable_slaves = NULL, *all_slaves = NULL; 507162306a36Sopenharmony_ci struct slave *slave; 507262306a36Sopenharmony_ci struct list_head *iter; 507362306a36Sopenharmony_ci int agg_id = 0; 507462306a36Sopenharmony_ci int ret = 0; 507562306a36Sopenharmony_ci 507662306a36Sopenharmony_ci might_sleep(); 507762306a36Sopenharmony_ci 507862306a36Sopenharmony_ci usable_slaves = kzalloc(struct_size(usable_slaves, arr, 507962306a36Sopenharmony_ci bond->slave_cnt), GFP_KERNEL); 508062306a36Sopenharmony_ci all_slaves = kzalloc(struct_size(all_slaves, arr, 508162306a36Sopenharmony_ci bond->slave_cnt), GFP_KERNEL); 508262306a36Sopenharmony_ci if (!usable_slaves || !all_slaves) { 508362306a36Sopenharmony_ci ret = -ENOMEM; 508462306a36Sopenharmony_ci goto out; 508562306a36Sopenharmony_ci } 508662306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 508762306a36Sopenharmony_ci struct ad_info ad_info; 508862306a36Sopenharmony_ci 508962306a36Sopenharmony_ci spin_lock_bh(&bond->mode_lock); 509062306a36Sopenharmony_ci if (bond_3ad_get_active_agg_info(bond, &ad_info)) { 509162306a36Sopenharmony_ci spin_unlock_bh(&bond->mode_lock); 509262306a36Sopenharmony_ci pr_debug("bond_3ad_get_active_agg_info failed\n"); 509362306a36Sopenharmony_ci /* No active aggragator means it's not safe to use 509462306a36Sopenharmony_ci * the previous array. 509562306a36Sopenharmony_ci */ 509662306a36Sopenharmony_ci bond_reset_slave_arr(bond); 509762306a36Sopenharmony_ci goto out; 509862306a36Sopenharmony_ci } 509962306a36Sopenharmony_ci spin_unlock_bh(&bond->mode_lock); 510062306a36Sopenharmony_ci agg_id = ad_info.aggregator_id; 510162306a36Sopenharmony_ci } 510262306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 510362306a36Sopenharmony_ci if (skipslave == slave) 510462306a36Sopenharmony_ci continue; 510562306a36Sopenharmony_ci 510662306a36Sopenharmony_ci all_slaves->arr[all_slaves->count++] = slave; 510762306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_8023AD) { 510862306a36Sopenharmony_ci struct aggregator *agg; 510962306a36Sopenharmony_ci 511062306a36Sopenharmony_ci agg = SLAVE_AD_INFO(slave)->port.aggregator; 511162306a36Sopenharmony_ci if (!agg || agg->aggregator_identifier != agg_id) 511262306a36Sopenharmony_ci continue; 511362306a36Sopenharmony_ci } 511462306a36Sopenharmony_ci if (!bond_slave_can_tx(slave)) 511562306a36Sopenharmony_ci continue; 511662306a36Sopenharmony_ci 511762306a36Sopenharmony_ci slave_dbg(bond->dev, slave->dev, "Adding slave to tx hash array[%d]\n", 511862306a36Sopenharmony_ci usable_slaves->count); 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci usable_slaves->arr[usable_slaves->count++] = slave; 512162306a36Sopenharmony_ci } 512262306a36Sopenharmony_ci 512362306a36Sopenharmony_ci bond_set_slave_arr(bond, usable_slaves, all_slaves); 512462306a36Sopenharmony_ci return ret; 512562306a36Sopenharmony_ciout: 512662306a36Sopenharmony_ci if (ret != 0 && skipslave) { 512762306a36Sopenharmony_ci bond_skip_slave(rtnl_dereference(bond->all_slaves), 512862306a36Sopenharmony_ci skipslave); 512962306a36Sopenharmony_ci bond_skip_slave(rtnl_dereference(bond->usable_slaves), 513062306a36Sopenharmony_ci skipslave); 513162306a36Sopenharmony_ci } 513262306a36Sopenharmony_ci kfree_rcu(all_slaves, rcu); 513362306a36Sopenharmony_ci kfree_rcu(usable_slaves, rcu); 513462306a36Sopenharmony_ci 513562306a36Sopenharmony_ci return ret; 513662306a36Sopenharmony_ci} 513762306a36Sopenharmony_ci 513862306a36Sopenharmony_cistatic struct slave *bond_xmit_3ad_xor_slave_get(struct bonding *bond, 513962306a36Sopenharmony_ci struct sk_buff *skb, 514062306a36Sopenharmony_ci struct bond_up_slave *slaves) 514162306a36Sopenharmony_ci{ 514262306a36Sopenharmony_ci struct slave *slave; 514362306a36Sopenharmony_ci unsigned int count; 514462306a36Sopenharmony_ci u32 hash; 514562306a36Sopenharmony_ci 514662306a36Sopenharmony_ci hash = bond_xmit_hash(bond, skb); 514762306a36Sopenharmony_ci count = slaves ? READ_ONCE(slaves->count) : 0; 514862306a36Sopenharmony_ci if (unlikely(!count)) 514962306a36Sopenharmony_ci return NULL; 515062306a36Sopenharmony_ci 515162306a36Sopenharmony_ci slave = slaves->arr[hash % count]; 515262306a36Sopenharmony_ci return slave; 515362306a36Sopenharmony_ci} 515462306a36Sopenharmony_ci 515562306a36Sopenharmony_cistatic struct slave *bond_xdp_xmit_3ad_xor_slave_get(struct bonding *bond, 515662306a36Sopenharmony_ci struct xdp_buff *xdp) 515762306a36Sopenharmony_ci{ 515862306a36Sopenharmony_ci struct bond_up_slave *slaves; 515962306a36Sopenharmony_ci unsigned int count; 516062306a36Sopenharmony_ci u32 hash; 516162306a36Sopenharmony_ci 516262306a36Sopenharmony_ci hash = bond_xmit_hash_xdp(bond, xdp); 516362306a36Sopenharmony_ci slaves = rcu_dereference(bond->usable_slaves); 516462306a36Sopenharmony_ci count = slaves ? READ_ONCE(slaves->count) : 0; 516562306a36Sopenharmony_ci if (unlikely(!count)) 516662306a36Sopenharmony_ci return NULL; 516762306a36Sopenharmony_ci 516862306a36Sopenharmony_ci return slaves->arr[hash % count]; 516962306a36Sopenharmony_ci} 517062306a36Sopenharmony_ci 517162306a36Sopenharmony_ci/* Use this Xmit function for 3AD as well as XOR modes. The current 517262306a36Sopenharmony_ci * usable slave array is formed in the control path. The xmit function 517362306a36Sopenharmony_ci * just calculates hash and sends the packet out. 517462306a36Sopenharmony_ci */ 517562306a36Sopenharmony_cistatic netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb, 517662306a36Sopenharmony_ci struct net_device *dev) 517762306a36Sopenharmony_ci{ 517862306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 517962306a36Sopenharmony_ci struct bond_up_slave *slaves; 518062306a36Sopenharmony_ci struct slave *slave; 518162306a36Sopenharmony_ci 518262306a36Sopenharmony_ci slaves = rcu_dereference(bond->usable_slaves); 518362306a36Sopenharmony_ci slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves); 518462306a36Sopenharmony_ci if (likely(slave)) 518562306a36Sopenharmony_ci return bond_dev_queue_xmit(bond, skb, slave->dev); 518662306a36Sopenharmony_ci 518762306a36Sopenharmony_ci return bond_tx_drop(dev, skb); 518862306a36Sopenharmony_ci} 518962306a36Sopenharmony_ci 519062306a36Sopenharmony_ci/* in broadcast mode, we send everything to all usable interfaces. */ 519162306a36Sopenharmony_cistatic netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, 519262306a36Sopenharmony_ci struct net_device *bond_dev) 519362306a36Sopenharmony_ci{ 519462306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 519562306a36Sopenharmony_ci struct slave *slave = NULL; 519662306a36Sopenharmony_ci struct list_head *iter; 519762306a36Sopenharmony_ci bool xmit_suc = false; 519862306a36Sopenharmony_ci bool skb_used = false; 519962306a36Sopenharmony_ci 520062306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 520162306a36Sopenharmony_ci struct sk_buff *skb2; 520262306a36Sopenharmony_ci 520362306a36Sopenharmony_ci if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)) 520462306a36Sopenharmony_ci continue; 520562306a36Sopenharmony_ci 520662306a36Sopenharmony_ci if (bond_is_last_slave(bond, slave)) { 520762306a36Sopenharmony_ci skb2 = skb; 520862306a36Sopenharmony_ci skb_used = true; 520962306a36Sopenharmony_ci } else { 521062306a36Sopenharmony_ci skb2 = skb_clone(skb, GFP_ATOMIC); 521162306a36Sopenharmony_ci if (!skb2) { 521262306a36Sopenharmony_ci net_err_ratelimited("%s: Error: %s: skb_clone() failed\n", 521362306a36Sopenharmony_ci bond_dev->name, __func__); 521462306a36Sopenharmony_ci continue; 521562306a36Sopenharmony_ci } 521662306a36Sopenharmony_ci } 521762306a36Sopenharmony_ci 521862306a36Sopenharmony_ci if (bond_dev_queue_xmit(bond, skb2, slave->dev) == NETDEV_TX_OK) 521962306a36Sopenharmony_ci xmit_suc = true; 522062306a36Sopenharmony_ci } 522162306a36Sopenharmony_ci 522262306a36Sopenharmony_ci if (!skb_used) 522362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 522462306a36Sopenharmony_ci 522562306a36Sopenharmony_ci if (xmit_suc) 522662306a36Sopenharmony_ci return NETDEV_TX_OK; 522762306a36Sopenharmony_ci 522862306a36Sopenharmony_ci dev_core_stats_tx_dropped_inc(bond_dev); 522962306a36Sopenharmony_ci return NET_XMIT_DROP; 523062306a36Sopenharmony_ci} 523162306a36Sopenharmony_ci 523262306a36Sopenharmony_ci/*------------------------- Device initialization ---------------------------*/ 523362306a36Sopenharmony_ci 523462306a36Sopenharmony_ci/* Lookup the slave that corresponds to a qid */ 523562306a36Sopenharmony_cistatic inline int bond_slave_override(struct bonding *bond, 523662306a36Sopenharmony_ci struct sk_buff *skb) 523762306a36Sopenharmony_ci{ 523862306a36Sopenharmony_ci struct slave *slave = NULL; 523962306a36Sopenharmony_ci struct list_head *iter; 524062306a36Sopenharmony_ci 524162306a36Sopenharmony_ci if (!skb_rx_queue_recorded(skb)) 524262306a36Sopenharmony_ci return 1; 524362306a36Sopenharmony_ci 524462306a36Sopenharmony_ci /* Find out if any slaves have the same mapping as this skb. */ 524562306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 524662306a36Sopenharmony_ci if (slave->queue_id == skb_get_queue_mapping(skb)) { 524762306a36Sopenharmony_ci if (bond_slave_is_up(slave) && 524862306a36Sopenharmony_ci slave->link == BOND_LINK_UP) { 524962306a36Sopenharmony_ci bond_dev_queue_xmit(bond, skb, slave->dev); 525062306a36Sopenharmony_ci return 0; 525162306a36Sopenharmony_ci } 525262306a36Sopenharmony_ci /* If the slave isn't UP, use default transmit policy. */ 525362306a36Sopenharmony_ci break; 525462306a36Sopenharmony_ci } 525562306a36Sopenharmony_ci } 525662306a36Sopenharmony_ci 525762306a36Sopenharmony_ci return 1; 525862306a36Sopenharmony_ci} 525962306a36Sopenharmony_ci 526062306a36Sopenharmony_ci 526162306a36Sopenharmony_cistatic u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb, 526262306a36Sopenharmony_ci struct net_device *sb_dev) 526362306a36Sopenharmony_ci{ 526462306a36Sopenharmony_ci /* This helper function exists to help dev_pick_tx get the correct 526562306a36Sopenharmony_ci * destination queue. Using a helper function skips a call to 526662306a36Sopenharmony_ci * skb_tx_hash and will put the skbs in the queue we expect on their 526762306a36Sopenharmony_ci * way down to the bonding driver. 526862306a36Sopenharmony_ci */ 526962306a36Sopenharmony_ci u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0; 527062306a36Sopenharmony_ci 527162306a36Sopenharmony_ci /* Save the original txq to restore before passing to the driver */ 527262306a36Sopenharmony_ci qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb_get_queue_mapping(skb); 527362306a36Sopenharmony_ci 527462306a36Sopenharmony_ci if (unlikely(txq >= dev->real_num_tx_queues)) { 527562306a36Sopenharmony_ci do { 527662306a36Sopenharmony_ci txq -= dev->real_num_tx_queues; 527762306a36Sopenharmony_ci } while (txq >= dev->real_num_tx_queues); 527862306a36Sopenharmony_ci } 527962306a36Sopenharmony_ci return txq; 528062306a36Sopenharmony_ci} 528162306a36Sopenharmony_ci 528262306a36Sopenharmony_cistatic struct net_device *bond_xmit_get_slave(struct net_device *master_dev, 528362306a36Sopenharmony_ci struct sk_buff *skb, 528462306a36Sopenharmony_ci bool all_slaves) 528562306a36Sopenharmony_ci{ 528662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(master_dev); 528762306a36Sopenharmony_ci struct bond_up_slave *slaves; 528862306a36Sopenharmony_ci struct slave *slave = NULL; 528962306a36Sopenharmony_ci 529062306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 529162306a36Sopenharmony_ci case BOND_MODE_ROUNDROBIN: 529262306a36Sopenharmony_ci slave = bond_xmit_roundrobin_slave_get(bond, skb); 529362306a36Sopenharmony_ci break; 529462306a36Sopenharmony_ci case BOND_MODE_ACTIVEBACKUP: 529562306a36Sopenharmony_ci slave = bond_xmit_activebackup_slave_get(bond); 529662306a36Sopenharmony_ci break; 529762306a36Sopenharmony_ci case BOND_MODE_8023AD: 529862306a36Sopenharmony_ci case BOND_MODE_XOR: 529962306a36Sopenharmony_ci if (all_slaves) 530062306a36Sopenharmony_ci slaves = rcu_dereference(bond->all_slaves); 530162306a36Sopenharmony_ci else 530262306a36Sopenharmony_ci slaves = rcu_dereference(bond->usable_slaves); 530362306a36Sopenharmony_ci slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves); 530462306a36Sopenharmony_ci break; 530562306a36Sopenharmony_ci case BOND_MODE_BROADCAST: 530662306a36Sopenharmony_ci break; 530762306a36Sopenharmony_ci case BOND_MODE_ALB: 530862306a36Sopenharmony_ci slave = bond_xmit_alb_slave_get(bond, skb); 530962306a36Sopenharmony_ci break; 531062306a36Sopenharmony_ci case BOND_MODE_TLB: 531162306a36Sopenharmony_ci slave = bond_xmit_tlb_slave_get(bond, skb); 531262306a36Sopenharmony_ci break; 531362306a36Sopenharmony_ci default: 531462306a36Sopenharmony_ci /* Should never happen, mode already checked */ 531562306a36Sopenharmony_ci WARN_ONCE(true, "Unknown bonding mode"); 531662306a36Sopenharmony_ci break; 531762306a36Sopenharmony_ci } 531862306a36Sopenharmony_ci 531962306a36Sopenharmony_ci if (slave) 532062306a36Sopenharmony_ci return slave->dev; 532162306a36Sopenharmony_ci return NULL; 532262306a36Sopenharmony_ci} 532362306a36Sopenharmony_ci 532462306a36Sopenharmony_cistatic void bond_sk_to_flow(struct sock *sk, struct flow_keys *flow) 532562306a36Sopenharmony_ci{ 532662306a36Sopenharmony_ci switch (sk->sk_family) { 532762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 532862306a36Sopenharmony_ci case AF_INET6: 532962306a36Sopenharmony_ci if (ipv6_only_sock(sk) || 533062306a36Sopenharmony_ci ipv6_addr_type(&sk->sk_v6_daddr) != IPV6_ADDR_MAPPED) { 533162306a36Sopenharmony_ci flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; 533262306a36Sopenharmony_ci flow->addrs.v6addrs.src = inet6_sk(sk)->saddr; 533362306a36Sopenharmony_ci flow->addrs.v6addrs.dst = sk->sk_v6_daddr; 533462306a36Sopenharmony_ci break; 533562306a36Sopenharmony_ci } 533662306a36Sopenharmony_ci fallthrough; 533762306a36Sopenharmony_ci#endif 533862306a36Sopenharmony_ci default: /* AF_INET */ 533962306a36Sopenharmony_ci flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; 534062306a36Sopenharmony_ci flow->addrs.v4addrs.src = inet_sk(sk)->inet_rcv_saddr; 534162306a36Sopenharmony_ci flow->addrs.v4addrs.dst = inet_sk(sk)->inet_daddr; 534262306a36Sopenharmony_ci break; 534362306a36Sopenharmony_ci } 534462306a36Sopenharmony_ci 534562306a36Sopenharmony_ci flow->ports.src = inet_sk(sk)->inet_sport; 534662306a36Sopenharmony_ci flow->ports.dst = inet_sk(sk)->inet_dport; 534762306a36Sopenharmony_ci} 534862306a36Sopenharmony_ci 534962306a36Sopenharmony_ci/** 535062306a36Sopenharmony_ci * bond_sk_hash_l34 - generate a hash value based on the socket's L3 and L4 fields 535162306a36Sopenharmony_ci * @sk: socket to use for headers 535262306a36Sopenharmony_ci * 535362306a36Sopenharmony_ci * This function will extract the necessary field from the socket and use 535462306a36Sopenharmony_ci * them to generate a hash based on the LAYER34 xmit_policy. 535562306a36Sopenharmony_ci * Assumes that sk is a TCP or UDP socket. 535662306a36Sopenharmony_ci */ 535762306a36Sopenharmony_cistatic u32 bond_sk_hash_l34(struct sock *sk) 535862306a36Sopenharmony_ci{ 535962306a36Sopenharmony_ci struct flow_keys flow; 536062306a36Sopenharmony_ci u32 hash; 536162306a36Sopenharmony_ci 536262306a36Sopenharmony_ci bond_sk_to_flow(sk, &flow); 536362306a36Sopenharmony_ci 536462306a36Sopenharmony_ci /* L4 */ 536562306a36Sopenharmony_ci memcpy(&hash, &flow.ports.ports, sizeof(hash)); 536662306a36Sopenharmony_ci /* L3 */ 536762306a36Sopenharmony_ci return bond_ip_hash(hash, &flow, BOND_XMIT_POLICY_LAYER34); 536862306a36Sopenharmony_ci} 536962306a36Sopenharmony_ci 537062306a36Sopenharmony_cistatic struct net_device *__bond_sk_get_lower_dev(struct bonding *bond, 537162306a36Sopenharmony_ci struct sock *sk) 537262306a36Sopenharmony_ci{ 537362306a36Sopenharmony_ci struct bond_up_slave *slaves; 537462306a36Sopenharmony_ci struct slave *slave; 537562306a36Sopenharmony_ci unsigned int count; 537662306a36Sopenharmony_ci u32 hash; 537762306a36Sopenharmony_ci 537862306a36Sopenharmony_ci slaves = rcu_dereference(bond->usable_slaves); 537962306a36Sopenharmony_ci count = slaves ? READ_ONCE(slaves->count) : 0; 538062306a36Sopenharmony_ci if (unlikely(!count)) 538162306a36Sopenharmony_ci return NULL; 538262306a36Sopenharmony_ci 538362306a36Sopenharmony_ci hash = bond_sk_hash_l34(sk); 538462306a36Sopenharmony_ci slave = slaves->arr[hash % count]; 538562306a36Sopenharmony_ci 538662306a36Sopenharmony_ci return slave->dev; 538762306a36Sopenharmony_ci} 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_cistatic struct net_device *bond_sk_get_lower_dev(struct net_device *dev, 539062306a36Sopenharmony_ci struct sock *sk) 539162306a36Sopenharmony_ci{ 539262306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 539362306a36Sopenharmony_ci struct net_device *lower = NULL; 539462306a36Sopenharmony_ci 539562306a36Sopenharmony_ci rcu_read_lock(); 539662306a36Sopenharmony_ci if (bond_sk_check(bond)) 539762306a36Sopenharmony_ci lower = __bond_sk_get_lower_dev(bond, sk); 539862306a36Sopenharmony_ci rcu_read_unlock(); 539962306a36Sopenharmony_ci 540062306a36Sopenharmony_ci return lower; 540162306a36Sopenharmony_ci} 540262306a36Sopenharmony_ci 540362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_TLS_DEVICE) 540462306a36Sopenharmony_cistatic netdev_tx_t bond_tls_device_xmit(struct bonding *bond, struct sk_buff *skb, 540562306a36Sopenharmony_ci struct net_device *dev) 540662306a36Sopenharmony_ci{ 540762306a36Sopenharmony_ci struct net_device *tls_netdev = rcu_dereference(tls_get_ctx(skb->sk)->netdev); 540862306a36Sopenharmony_ci 540962306a36Sopenharmony_ci /* tls_netdev might become NULL, even if tls_is_skb_tx_device_offloaded 541062306a36Sopenharmony_ci * was true, if tls_device_down is running in parallel, but it's OK, 541162306a36Sopenharmony_ci * because bond_get_slave_by_dev has a NULL check. 541262306a36Sopenharmony_ci */ 541362306a36Sopenharmony_ci if (likely(bond_get_slave_by_dev(bond, tls_netdev))) 541462306a36Sopenharmony_ci return bond_dev_queue_xmit(bond, skb, tls_netdev); 541562306a36Sopenharmony_ci return bond_tx_drop(dev, skb); 541662306a36Sopenharmony_ci} 541762306a36Sopenharmony_ci#endif 541862306a36Sopenharmony_ci 541962306a36Sopenharmony_cistatic netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev) 542062306a36Sopenharmony_ci{ 542162306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 542262306a36Sopenharmony_ci 542362306a36Sopenharmony_ci if (bond_should_override_tx_queue(bond) && 542462306a36Sopenharmony_ci !bond_slave_override(bond, skb)) 542562306a36Sopenharmony_ci return NETDEV_TX_OK; 542662306a36Sopenharmony_ci 542762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_TLS_DEVICE) 542862306a36Sopenharmony_ci if (tls_is_skb_tx_device_offloaded(skb)) 542962306a36Sopenharmony_ci return bond_tls_device_xmit(bond, skb, dev); 543062306a36Sopenharmony_ci#endif 543162306a36Sopenharmony_ci 543262306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 543362306a36Sopenharmony_ci case BOND_MODE_ROUNDROBIN: 543462306a36Sopenharmony_ci return bond_xmit_roundrobin(skb, dev); 543562306a36Sopenharmony_ci case BOND_MODE_ACTIVEBACKUP: 543662306a36Sopenharmony_ci return bond_xmit_activebackup(skb, dev); 543762306a36Sopenharmony_ci case BOND_MODE_8023AD: 543862306a36Sopenharmony_ci case BOND_MODE_XOR: 543962306a36Sopenharmony_ci return bond_3ad_xor_xmit(skb, dev); 544062306a36Sopenharmony_ci case BOND_MODE_BROADCAST: 544162306a36Sopenharmony_ci return bond_xmit_broadcast(skb, dev); 544262306a36Sopenharmony_ci case BOND_MODE_ALB: 544362306a36Sopenharmony_ci return bond_alb_xmit(skb, dev); 544462306a36Sopenharmony_ci case BOND_MODE_TLB: 544562306a36Sopenharmony_ci return bond_tlb_xmit(skb, dev); 544662306a36Sopenharmony_ci default: 544762306a36Sopenharmony_ci /* Should never happen, mode already checked */ 544862306a36Sopenharmony_ci netdev_err(dev, "Unknown bonding mode %d\n", BOND_MODE(bond)); 544962306a36Sopenharmony_ci WARN_ON_ONCE(1); 545062306a36Sopenharmony_ci return bond_tx_drop(dev, skb); 545162306a36Sopenharmony_ci } 545262306a36Sopenharmony_ci} 545362306a36Sopenharmony_ci 545462306a36Sopenharmony_cistatic netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) 545562306a36Sopenharmony_ci{ 545662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 545762306a36Sopenharmony_ci netdev_tx_t ret = NETDEV_TX_OK; 545862306a36Sopenharmony_ci 545962306a36Sopenharmony_ci /* If we risk deadlock from transmitting this in the 546062306a36Sopenharmony_ci * netpoll path, tell netpoll to queue the frame for later tx 546162306a36Sopenharmony_ci */ 546262306a36Sopenharmony_ci if (unlikely(is_netpoll_tx_blocked(dev))) 546362306a36Sopenharmony_ci return NETDEV_TX_BUSY; 546462306a36Sopenharmony_ci 546562306a36Sopenharmony_ci rcu_read_lock(); 546662306a36Sopenharmony_ci if (bond_has_slaves(bond)) 546762306a36Sopenharmony_ci ret = __bond_start_xmit(skb, dev); 546862306a36Sopenharmony_ci else 546962306a36Sopenharmony_ci ret = bond_tx_drop(dev, skb); 547062306a36Sopenharmony_ci rcu_read_unlock(); 547162306a36Sopenharmony_ci 547262306a36Sopenharmony_ci return ret; 547362306a36Sopenharmony_ci} 547462306a36Sopenharmony_ci 547562306a36Sopenharmony_cistatic struct net_device * 547662306a36Sopenharmony_cibond_xdp_get_xmit_slave(struct net_device *bond_dev, struct xdp_buff *xdp) 547762306a36Sopenharmony_ci{ 547862306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 547962306a36Sopenharmony_ci struct slave *slave; 548062306a36Sopenharmony_ci 548162306a36Sopenharmony_ci /* Caller needs to hold rcu_read_lock() */ 548262306a36Sopenharmony_ci 548362306a36Sopenharmony_ci switch (BOND_MODE(bond)) { 548462306a36Sopenharmony_ci case BOND_MODE_ROUNDROBIN: 548562306a36Sopenharmony_ci slave = bond_xdp_xmit_roundrobin_slave_get(bond, xdp); 548662306a36Sopenharmony_ci break; 548762306a36Sopenharmony_ci 548862306a36Sopenharmony_ci case BOND_MODE_ACTIVEBACKUP: 548962306a36Sopenharmony_ci slave = bond_xmit_activebackup_slave_get(bond); 549062306a36Sopenharmony_ci break; 549162306a36Sopenharmony_ci 549262306a36Sopenharmony_ci case BOND_MODE_8023AD: 549362306a36Sopenharmony_ci case BOND_MODE_XOR: 549462306a36Sopenharmony_ci slave = bond_xdp_xmit_3ad_xor_slave_get(bond, xdp); 549562306a36Sopenharmony_ci break; 549662306a36Sopenharmony_ci 549762306a36Sopenharmony_ci default: 549862306a36Sopenharmony_ci /* Should never happen. Mode guarded by bond_xdp_check() */ 549962306a36Sopenharmony_ci netdev_err(bond_dev, "Unknown bonding mode %d for xdp xmit\n", BOND_MODE(bond)); 550062306a36Sopenharmony_ci WARN_ON_ONCE(1); 550162306a36Sopenharmony_ci return NULL; 550262306a36Sopenharmony_ci } 550362306a36Sopenharmony_ci 550462306a36Sopenharmony_ci if (slave) 550562306a36Sopenharmony_ci return slave->dev; 550662306a36Sopenharmony_ci 550762306a36Sopenharmony_ci return NULL; 550862306a36Sopenharmony_ci} 550962306a36Sopenharmony_ci 551062306a36Sopenharmony_cistatic int bond_xdp_xmit(struct net_device *bond_dev, 551162306a36Sopenharmony_ci int n, struct xdp_frame **frames, u32 flags) 551262306a36Sopenharmony_ci{ 551362306a36Sopenharmony_ci int nxmit, err = -ENXIO; 551462306a36Sopenharmony_ci 551562306a36Sopenharmony_ci rcu_read_lock(); 551662306a36Sopenharmony_ci 551762306a36Sopenharmony_ci for (nxmit = 0; nxmit < n; nxmit++) { 551862306a36Sopenharmony_ci struct xdp_frame *frame = frames[nxmit]; 551962306a36Sopenharmony_ci struct xdp_frame *frames1[] = {frame}; 552062306a36Sopenharmony_ci struct net_device *slave_dev; 552162306a36Sopenharmony_ci struct xdp_buff xdp; 552262306a36Sopenharmony_ci 552362306a36Sopenharmony_ci xdp_convert_frame_to_buff(frame, &xdp); 552462306a36Sopenharmony_ci 552562306a36Sopenharmony_ci slave_dev = bond_xdp_get_xmit_slave(bond_dev, &xdp); 552662306a36Sopenharmony_ci if (!slave_dev) { 552762306a36Sopenharmony_ci err = -ENXIO; 552862306a36Sopenharmony_ci break; 552962306a36Sopenharmony_ci } 553062306a36Sopenharmony_ci 553162306a36Sopenharmony_ci err = slave_dev->netdev_ops->ndo_xdp_xmit(slave_dev, 1, frames1, flags); 553262306a36Sopenharmony_ci if (err < 1) 553362306a36Sopenharmony_ci break; 553462306a36Sopenharmony_ci } 553562306a36Sopenharmony_ci 553662306a36Sopenharmony_ci rcu_read_unlock(); 553762306a36Sopenharmony_ci 553862306a36Sopenharmony_ci /* If error happened on the first frame then we can pass the error up, otherwise 553962306a36Sopenharmony_ci * report the number of frames that were xmitted. 554062306a36Sopenharmony_ci */ 554162306a36Sopenharmony_ci if (err < 0) 554262306a36Sopenharmony_ci return (nxmit == 0 ? err : nxmit); 554362306a36Sopenharmony_ci 554462306a36Sopenharmony_ci return nxmit; 554562306a36Sopenharmony_ci} 554662306a36Sopenharmony_ci 554762306a36Sopenharmony_cistatic int bond_xdp_set(struct net_device *dev, struct bpf_prog *prog, 554862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 554962306a36Sopenharmony_ci{ 555062306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 555162306a36Sopenharmony_ci struct list_head *iter; 555262306a36Sopenharmony_ci struct slave *slave, *rollback_slave; 555362306a36Sopenharmony_ci struct bpf_prog *old_prog; 555462306a36Sopenharmony_ci struct netdev_bpf xdp = { 555562306a36Sopenharmony_ci .command = XDP_SETUP_PROG, 555662306a36Sopenharmony_ci .flags = 0, 555762306a36Sopenharmony_ci .prog = prog, 555862306a36Sopenharmony_ci .extack = extack, 555962306a36Sopenharmony_ci }; 556062306a36Sopenharmony_ci int err; 556162306a36Sopenharmony_ci 556262306a36Sopenharmony_ci ASSERT_RTNL(); 556362306a36Sopenharmony_ci 556462306a36Sopenharmony_ci if (!bond_xdp_check(bond)) 556562306a36Sopenharmony_ci return -EOPNOTSUPP; 556662306a36Sopenharmony_ci 556762306a36Sopenharmony_ci old_prog = bond->xdp_prog; 556862306a36Sopenharmony_ci bond->xdp_prog = prog; 556962306a36Sopenharmony_ci 557062306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 557162306a36Sopenharmony_ci struct net_device *slave_dev = slave->dev; 557262306a36Sopenharmony_ci 557362306a36Sopenharmony_ci if (!slave_dev->netdev_ops->ndo_bpf || 557462306a36Sopenharmony_ci !slave_dev->netdev_ops->ndo_xdp_xmit) { 557562306a36Sopenharmony_ci SLAVE_NL_ERR(dev, slave_dev, extack, 557662306a36Sopenharmony_ci "Slave device does not support XDP"); 557762306a36Sopenharmony_ci err = -EOPNOTSUPP; 557862306a36Sopenharmony_ci goto err; 557962306a36Sopenharmony_ci } 558062306a36Sopenharmony_ci 558162306a36Sopenharmony_ci if (dev_xdp_prog_count(slave_dev) > 0) { 558262306a36Sopenharmony_ci SLAVE_NL_ERR(dev, slave_dev, extack, 558362306a36Sopenharmony_ci "Slave has XDP program loaded, please unload before enslaving"); 558462306a36Sopenharmony_ci err = -EOPNOTSUPP; 558562306a36Sopenharmony_ci goto err; 558662306a36Sopenharmony_ci } 558762306a36Sopenharmony_ci 558862306a36Sopenharmony_ci err = slave_dev->netdev_ops->ndo_bpf(slave_dev, &xdp); 558962306a36Sopenharmony_ci if (err < 0) { 559062306a36Sopenharmony_ci /* ndo_bpf() sets extack error message */ 559162306a36Sopenharmony_ci slave_err(dev, slave_dev, "Error %d calling ndo_bpf\n", err); 559262306a36Sopenharmony_ci goto err; 559362306a36Sopenharmony_ci } 559462306a36Sopenharmony_ci if (prog) 559562306a36Sopenharmony_ci bpf_prog_inc(prog); 559662306a36Sopenharmony_ci } 559762306a36Sopenharmony_ci 559862306a36Sopenharmony_ci if (prog) { 559962306a36Sopenharmony_ci static_branch_inc(&bpf_master_redirect_enabled_key); 560062306a36Sopenharmony_ci } else if (old_prog) { 560162306a36Sopenharmony_ci bpf_prog_put(old_prog); 560262306a36Sopenharmony_ci static_branch_dec(&bpf_master_redirect_enabled_key); 560362306a36Sopenharmony_ci } 560462306a36Sopenharmony_ci 560562306a36Sopenharmony_ci return 0; 560662306a36Sopenharmony_ci 560762306a36Sopenharmony_cierr: 560862306a36Sopenharmony_ci /* unwind the program changes */ 560962306a36Sopenharmony_ci bond->xdp_prog = old_prog; 561062306a36Sopenharmony_ci xdp.prog = old_prog; 561162306a36Sopenharmony_ci xdp.extack = NULL; /* do not overwrite original error */ 561262306a36Sopenharmony_ci 561362306a36Sopenharmony_ci bond_for_each_slave(bond, rollback_slave, iter) { 561462306a36Sopenharmony_ci struct net_device *slave_dev = rollback_slave->dev; 561562306a36Sopenharmony_ci int err_unwind; 561662306a36Sopenharmony_ci 561762306a36Sopenharmony_ci if (slave == rollback_slave) 561862306a36Sopenharmony_ci break; 561962306a36Sopenharmony_ci 562062306a36Sopenharmony_ci err_unwind = slave_dev->netdev_ops->ndo_bpf(slave_dev, &xdp); 562162306a36Sopenharmony_ci if (err_unwind < 0) 562262306a36Sopenharmony_ci slave_err(dev, slave_dev, 562362306a36Sopenharmony_ci "Error %d when unwinding XDP program change\n", err_unwind); 562462306a36Sopenharmony_ci else if (xdp.prog) 562562306a36Sopenharmony_ci bpf_prog_inc(xdp.prog); 562662306a36Sopenharmony_ci } 562762306a36Sopenharmony_ci return err; 562862306a36Sopenharmony_ci} 562962306a36Sopenharmony_ci 563062306a36Sopenharmony_cistatic int bond_xdp(struct net_device *dev, struct netdev_bpf *xdp) 563162306a36Sopenharmony_ci{ 563262306a36Sopenharmony_ci switch (xdp->command) { 563362306a36Sopenharmony_ci case XDP_SETUP_PROG: 563462306a36Sopenharmony_ci return bond_xdp_set(dev, xdp->prog, xdp->extack); 563562306a36Sopenharmony_ci default: 563662306a36Sopenharmony_ci return -EINVAL; 563762306a36Sopenharmony_ci } 563862306a36Sopenharmony_ci} 563962306a36Sopenharmony_ci 564062306a36Sopenharmony_cistatic u32 bond_mode_bcast_speed(struct slave *slave, u32 speed) 564162306a36Sopenharmony_ci{ 564262306a36Sopenharmony_ci if (speed == 0 || speed == SPEED_UNKNOWN) 564362306a36Sopenharmony_ci speed = slave->speed; 564462306a36Sopenharmony_ci else 564562306a36Sopenharmony_ci speed = min(speed, slave->speed); 564662306a36Sopenharmony_ci 564762306a36Sopenharmony_ci return speed; 564862306a36Sopenharmony_ci} 564962306a36Sopenharmony_ci 565062306a36Sopenharmony_ci/* Set the BOND_PHC_INDEX flag to notify user space */ 565162306a36Sopenharmony_cistatic int bond_set_phc_index_flag(struct kernel_hwtstamp_config *kernel_cfg) 565262306a36Sopenharmony_ci{ 565362306a36Sopenharmony_ci struct ifreq *ifr = kernel_cfg->ifr; 565462306a36Sopenharmony_ci struct hwtstamp_config cfg; 565562306a36Sopenharmony_ci 565662306a36Sopenharmony_ci if (kernel_cfg->copied_to_user) { 565762306a36Sopenharmony_ci /* Lower device has a legacy implementation */ 565862306a36Sopenharmony_ci if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) 565962306a36Sopenharmony_ci return -EFAULT; 566062306a36Sopenharmony_ci 566162306a36Sopenharmony_ci cfg.flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX; 566262306a36Sopenharmony_ci if (copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg))) 566362306a36Sopenharmony_ci return -EFAULT; 566462306a36Sopenharmony_ci } else { 566562306a36Sopenharmony_ci kernel_cfg->flags |= HWTSTAMP_FLAG_BONDED_PHC_INDEX; 566662306a36Sopenharmony_ci } 566762306a36Sopenharmony_ci 566862306a36Sopenharmony_ci return 0; 566962306a36Sopenharmony_ci} 567062306a36Sopenharmony_ci 567162306a36Sopenharmony_cistatic int bond_hwtstamp_get(struct net_device *dev, 567262306a36Sopenharmony_ci struct kernel_hwtstamp_config *cfg) 567362306a36Sopenharmony_ci{ 567462306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 567562306a36Sopenharmony_ci struct net_device *real_dev; 567662306a36Sopenharmony_ci int err; 567762306a36Sopenharmony_ci 567862306a36Sopenharmony_ci real_dev = bond_option_active_slave_get_rcu(bond); 567962306a36Sopenharmony_ci if (!real_dev) 568062306a36Sopenharmony_ci return -EOPNOTSUPP; 568162306a36Sopenharmony_ci 568262306a36Sopenharmony_ci err = generic_hwtstamp_get_lower(real_dev, cfg); 568362306a36Sopenharmony_ci if (err) 568462306a36Sopenharmony_ci return err; 568562306a36Sopenharmony_ci 568662306a36Sopenharmony_ci return bond_set_phc_index_flag(cfg); 568762306a36Sopenharmony_ci} 568862306a36Sopenharmony_ci 568962306a36Sopenharmony_cistatic int bond_hwtstamp_set(struct net_device *dev, 569062306a36Sopenharmony_ci struct kernel_hwtstamp_config *cfg, 569162306a36Sopenharmony_ci struct netlink_ext_ack *extack) 569262306a36Sopenharmony_ci{ 569362306a36Sopenharmony_ci struct bonding *bond = netdev_priv(dev); 569462306a36Sopenharmony_ci struct net_device *real_dev; 569562306a36Sopenharmony_ci int err; 569662306a36Sopenharmony_ci 569762306a36Sopenharmony_ci if (!(cfg->flags & HWTSTAMP_FLAG_BONDED_PHC_INDEX)) 569862306a36Sopenharmony_ci return -EOPNOTSUPP; 569962306a36Sopenharmony_ci 570062306a36Sopenharmony_ci real_dev = bond_option_active_slave_get_rcu(bond); 570162306a36Sopenharmony_ci if (!real_dev) 570262306a36Sopenharmony_ci return -EOPNOTSUPP; 570362306a36Sopenharmony_ci 570462306a36Sopenharmony_ci err = generic_hwtstamp_set_lower(real_dev, cfg, extack); 570562306a36Sopenharmony_ci if (err) 570662306a36Sopenharmony_ci return err; 570762306a36Sopenharmony_ci 570862306a36Sopenharmony_ci return bond_set_phc_index_flag(cfg); 570962306a36Sopenharmony_ci} 571062306a36Sopenharmony_ci 571162306a36Sopenharmony_cistatic int bond_ethtool_get_link_ksettings(struct net_device *bond_dev, 571262306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 571362306a36Sopenharmony_ci{ 571462306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 571562306a36Sopenharmony_ci struct list_head *iter; 571662306a36Sopenharmony_ci struct slave *slave; 571762306a36Sopenharmony_ci u32 speed = 0; 571862306a36Sopenharmony_ci 571962306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 572062306a36Sopenharmony_ci cmd->base.port = PORT_OTHER; 572162306a36Sopenharmony_ci 572262306a36Sopenharmony_ci /* Since bond_slave_can_tx returns false for all inactive or down slaves, we 572362306a36Sopenharmony_ci * do not need to check mode. Though link speed might not represent 572462306a36Sopenharmony_ci * the true receive or transmit bandwidth (not all modes are symmetric) 572562306a36Sopenharmony_ci * this is an accurate maximum. 572662306a36Sopenharmony_ci */ 572762306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) { 572862306a36Sopenharmony_ci if (bond_slave_can_tx(slave)) { 572962306a36Sopenharmony_ci bond_update_speed_duplex(slave); 573062306a36Sopenharmony_ci if (slave->speed != SPEED_UNKNOWN) { 573162306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_BROADCAST) 573262306a36Sopenharmony_ci speed = bond_mode_bcast_speed(slave, 573362306a36Sopenharmony_ci speed); 573462306a36Sopenharmony_ci else 573562306a36Sopenharmony_ci speed += slave->speed; 573662306a36Sopenharmony_ci } 573762306a36Sopenharmony_ci if (cmd->base.duplex == DUPLEX_UNKNOWN && 573862306a36Sopenharmony_ci slave->duplex != DUPLEX_UNKNOWN) 573962306a36Sopenharmony_ci cmd->base.duplex = slave->duplex; 574062306a36Sopenharmony_ci } 574162306a36Sopenharmony_ci } 574262306a36Sopenharmony_ci cmd->base.speed = speed ? : SPEED_UNKNOWN; 574362306a36Sopenharmony_ci 574462306a36Sopenharmony_ci return 0; 574562306a36Sopenharmony_ci} 574662306a36Sopenharmony_ci 574762306a36Sopenharmony_cistatic void bond_ethtool_get_drvinfo(struct net_device *bond_dev, 574862306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 574962306a36Sopenharmony_ci{ 575062306a36Sopenharmony_ci strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver)); 575162306a36Sopenharmony_ci snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), "%d", 575262306a36Sopenharmony_ci BOND_ABI_VERSION); 575362306a36Sopenharmony_ci} 575462306a36Sopenharmony_ci 575562306a36Sopenharmony_cistatic int bond_ethtool_get_ts_info(struct net_device *bond_dev, 575662306a36Sopenharmony_ci struct ethtool_ts_info *info) 575762306a36Sopenharmony_ci{ 575862306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 575962306a36Sopenharmony_ci struct ethtool_ts_info ts_info; 576062306a36Sopenharmony_ci const struct ethtool_ops *ops; 576162306a36Sopenharmony_ci struct net_device *real_dev; 576262306a36Sopenharmony_ci bool sw_tx_support = false; 576362306a36Sopenharmony_ci struct phy_device *phydev; 576462306a36Sopenharmony_ci struct list_head *iter; 576562306a36Sopenharmony_ci struct slave *slave; 576662306a36Sopenharmony_ci int ret = 0; 576762306a36Sopenharmony_ci 576862306a36Sopenharmony_ci rcu_read_lock(); 576962306a36Sopenharmony_ci real_dev = bond_option_active_slave_get_rcu(bond); 577062306a36Sopenharmony_ci dev_hold(real_dev); 577162306a36Sopenharmony_ci rcu_read_unlock(); 577262306a36Sopenharmony_ci 577362306a36Sopenharmony_ci if (real_dev) { 577462306a36Sopenharmony_ci ops = real_dev->ethtool_ops; 577562306a36Sopenharmony_ci phydev = real_dev->phydev; 577662306a36Sopenharmony_ci 577762306a36Sopenharmony_ci if (phy_has_tsinfo(phydev)) { 577862306a36Sopenharmony_ci ret = phy_ts_info(phydev, info); 577962306a36Sopenharmony_ci goto out; 578062306a36Sopenharmony_ci } else if (ops->get_ts_info) { 578162306a36Sopenharmony_ci ret = ops->get_ts_info(real_dev, info); 578262306a36Sopenharmony_ci goto out; 578362306a36Sopenharmony_ci } 578462306a36Sopenharmony_ci } else { 578562306a36Sopenharmony_ci /* Check if all slaves support software tx timestamping */ 578662306a36Sopenharmony_ci rcu_read_lock(); 578762306a36Sopenharmony_ci bond_for_each_slave_rcu(bond, slave, iter) { 578862306a36Sopenharmony_ci ret = -1; 578962306a36Sopenharmony_ci ops = slave->dev->ethtool_ops; 579062306a36Sopenharmony_ci phydev = slave->dev->phydev; 579162306a36Sopenharmony_ci 579262306a36Sopenharmony_ci if (phy_has_tsinfo(phydev)) 579362306a36Sopenharmony_ci ret = phy_ts_info(phydev, &ts_info); 579462306a36Sopenharmony_ci else if (ops->get_ts_info) 579562306a36Sopenharmony_ci ret = ops->get_ts_info(slave->dev, &ts_info); 579662306a36Sopenharmony_ci 579762306a36Sopenharmony_ci if (!ret && (ts_info.so_timestamping & SOF_TIMESTAMPING_TX_SOFTWARE)) { 579862306a36Sopenharmony_ci sw_tx_support = true; 579962306a36Sopenharmony_ci continue; 580062306a36Sopenharmony_ci } 580162306a36Sopenharmony_ci 580262306a36Sopenharmony_ci sw_tx_support = false; 580362306a36Sopenharmony_ci break; 580462306a36Sopenharmony_ci } 580562306a36Sopenharmony_ci rcu_read_unlock(); 580662306a36Sopenharmony_ci } 580762306a36Sopenharmony_ci 580862306a36Sopenharmony_ci ret = 0; 580962306a36Sopenharmony_ci info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | 581062306a36Sopenharmony_ci SOF_TIMESTAMPING_SOFTWARE; 581162306a36Sopenharmony_ci if (sw_tx_support) 581262306a36Sopenharmony_ci info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE; 581362306a36Sopenharmony_ci 581462306a36Sopenharmony_ci info->phc_index = -1; 581562306a36Sopenharmony_ci 581662306a36Sopenharmony_ciout: 581762306a36Sopenharmony_ci dev_put(real_dev); 581862306a36Sopenharmony_ci return ret; 581962306a36Sopenharmony_ci} 582062306a36Sopenharmony_ci 582162306a36Sopenharmony_cistatic const struct ethtool_ops bond_ethtool_ops = { 582262306a36Sopenharmony_ci .get_drvinfo = bond_ethtool_get_drvinfo, 582362306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 582462306a36Sopenharmony_ci .get_link_ksettings = bond_ethtool_get_link_ksettings, 582562306a36Sopenharmony_ci .get_ts_info = bond_ethtool_get_ts_info, 582662306a36Sopenharmony_ci}; 582762306a36Sopenharmony_ci 582862306a36Sopenharmony_cistatic const struct net_device_ops bond_netdev_ops = { 582962306a36Sopenharmony_ci .ndo_init = bond_init, 583062306a36Sopenharmony_ci .ndo_uninit = bond_uninit, 583162306a36Sopenharmony_ci .ndo_open = bond_open, 583262306a36Sopenharmony_ci .ndo_stop = bond_close, 583362306a36Sopenharmony_ci .ndo_start_xmit = bond_start_xmit, 583462306a36Sopenharmony_ci .ndo_select_queue = bond_select_queue, 583562306a36Sopenharmony_ci .ndo_get_stats64 = bond_get_stats, 583662306a36Sopenharmony_ci .ndo_eth_ioctl = bond_eth_ioctl, 583762306a36Sopenharmony_ci .ndo_siocbond = bond_do_ioctl, 583862306a36Sopenharmony_ci .ndo_siocdevprivate = bond_siocdevprivate, 583962306a36Sopenharmony_ci .ndo_change_rx_flags = bond_change_rx_flags, 584062306a36Sopenharmony_ci .ndo_set_rx_mode = bond_set_rx_mode, 584162306a36Sopenharmony_ci .ndo_change_mtu = bond_change_mtu, 584262306a36Sopenharmony_ci .ndo_set_mac_address = bond_set_mac_address, 584362306a36Sopenharmony_ci .ndo_neigh_setup = bond_neigh_setup, 584462306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, 584562306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, 584662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 584762306a36Sopenharmony_ci .ndo_netpoll_setup = bond_netpoll_setup, 584862306a36Sopenharmony_ci .ndo_netpoll_cleanup = bond_netpoll_cleanup, 584962306a36Sopenharmony_ci .ndo_poll_controller = bond_poll_controller, 585062306a36Sopenharmony_ci#endif 585162306a36Sopenharmony_ci .ndo_add_slave = bond_enslave, 585262306a36Sopenharmony_ci .ndo_del_slave = bond_release, 585362306a36Sopenharmony_ci .ndo_fix_features = bond_fix_features, 585462306a36Sopenharmony_ci .ndo_features_check = passthru_features_check, 585562306a36Sopenharmony_ci .ndo_get_xmit_slave = bond_xmit_get_slave, 585662306a36Sopenharmony_ci .ndo_sk_get_lower_dev = bond_sk_get_lower_dev, 585762306a36Sopenharmony_ci .ndo_bpf = bond_xdp, 585862306a36Sopenharmony_ci .ndo_xdp_xmit = bond_xdp_xmit, 585962306a36Sopenharmony_ci .ndo_xdp_get_xmit_slave = bond_xdp_get_xmit_slave, 586062306a36Sopenharmony_ci .ndo_hwtstamp_get = bond_hwtstamp_get, 586162306a36Sopenharmony_ci .ndo_hwtstamp_set = bond_hwtstamp_set, 586262306a36Sopenharmony_ci}; 586362306a36Sopenharmony_ci 586462306a36Sopenharmony_cistatic const struct device_type bond_type = { 586562306a36Sopenharmony_ci .name = "bond", 586662306a36Sopenharmony_ci}; 586762306a36Sopenharmony_ci 586862306a36Sopenharmony_cistatic void bond_destructor(struct net_device *bond_dev) 586962306a36Sopenharmony_ci{ 587062306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 587162306a36Sopenharmony_ci 587262306a36Sopenharmony_ci if (bond->wq) 587362306a36Sopenharmony_ci destroy_workqueue(bond->wq); 587462306a36Sopenharmony_ci 587562306a36Sopenharmony_ci free_percpu(bond->rr_tx_counter); 587662306a36Sopenharmony_ci} 587762306a36Sopenharmony_ci 587862306a36Sopenharmony_civoid bond_setup(struct net_device *bond_dev) 587962306a36Sopenharmony_ci{ 588062306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 588162306a36Sopenharmony_ci 588262306a36Sopenharmony_ci spin_lock_init(&bond->mode_lock); 588362306a36Sopenharmony_ci bond->params = bonding_defaults; 588462306a36Sopenharmony_ci 588562306a36Sopenharmony_ci /* Initialize pointers */ 588662306a36Sopenharmony_ci bond->dev = bond_dev; 588762306a36Sopenharmony_ci 588862306a36Sopenharmony_ci /* Initialize the device entry points */ 588962306a36Sopenharmony_ci ether_setup(bond_dev); 589062306a36Sopenharmony_ci bond_dev->max_mtu = ETH_MAX_MTU; 589162306a36Sopenharmony_ci bond_dev->netdev_ops = &bond_netdev_ops; 589262306a36Sopenharmony_ci bond_dev->ethtool_ops = &bond_ethtool_ops; 589362306a36Sopenharmony_ci 589462306a36Sopenharmony_ci bond_dev->needs_free_netdev = true; 589562306a36Sopenharmony_ci bond_dev->priv_destructor = bond_destructor; 589662306a36Sopenharmony_ci 589762306a36Sopenharmony_ci SET_NETDEV_DEVTYPE(bond_dev, &bond_type); 589862306a36Sopenharmony_ci 589962306a36Sopenharmony_ci /* Initialize the device options */ 590062306a36Sopenharmony_ci bond_dev->flags |= IFF_MASTER; 590162306a36Sopenharmony_ci bond_dev->priv_flags |= IFF_BONDING | IFF_UNICAST_FLT | IFF_NO_QUEUE; 590262306a36Sopenharmony_ci bond_dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_TX_SKB_SHARING); 590362306a36Sopenharmony_ci 590462306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 590562306a36Sopenharmony_ci /* set up xfrm device ops (only supported in active-backup right now) */ 590662306a36Sopenharmony_ci bond_dev->xfrmdev_ops = &bond_xfrmdev_ops; 590762306a36Sopenharmony_ci INIT_LIST_HEAD(&bond->ipsec_list); 590862306a36Sopenharmony_ci spin_lock_init(&bond->ipsec_lock); 590962306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 591062306a36Sopenharmony_ci 591162306a36Sopenharmony_ci /* don't acquire bond device's netif_tx_lock when transmitting */ 591262306a36Sopenharmony_ci bond_dev->features |= NETIF_F_LLTX; 591362306a36Sopenharmony_ci 591462306a36Sopenharmony_ci /* By default, we declare the bond to be fully 591562306a36Sopenharmony_ci * VLAN hardware accelerated capable. Special 591662306a36Sopenharmony_ci * care is taken in the various xmit functions 591762306a36Sopenharmony_ci * when there are slaves that are not hw accel 591862306a36Sopenharmony_ci * capable 591962306a36Sopenharmony_ci */ 592062306a36Sopenharmony_ci 592162306a36Sopenharmony_ci /* Don't allow bond devices to change network namespaces. */ 592262306a36Sopenharmony_ci bond_dev->features |= NETIF_F_NETNS_LOCAL; 592362306a36Sopenharmony_ci 592462306a36Sopenharmony_ci bond_dev->hw_features = BOND_VLAN_FEATURES | 592562306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX | 592662306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_FILTER | 592762306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_RX | 592862306a36Sopenharmony_ci NETIF_F_HW_VLAN_STAG_FILTER; 592962306a36Sopenharmony_ci 593062306a36Sopenharmony_ci bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL; 593162306a36Sopenharmony_ci bond_dev->features |= bond_dev->hw_features; 593262306a36Sopenharmony_ci bond_dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; 593362306a36Sopenharmony_ci#ifdef CONFIG_XFRM_OFFLOAD 593462306a36Sopenharmony_ci bond_dev->hw_features |= BOND_XFRM_FEATURES; 593562306a36Sopenharmony_ci /* Only enable XFRM features if this is an active-backup config */ 593662306a36Sopenharmony_ci if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP) 593762306a36Sopenharmony_ci bond_dev->features |= BOND_XFRM_FEATURES; 593862306a36Sopenharmony_ci#endif /* CONFIG_XFRM_OFFLOAD */ 593962306a36Sopenharmony_ci} 594062306a36Sopenharmony_ci 594162306a36Sopenharmony_ci/* Destroy a bonding device. 594262306a36Sopenharmony_ci * Must be under rtnl_lock when this function is called. 594362306a36Sopenharmony_ci */ 594462306a36Sopenharmony_cistatic void bond_uninit(struct net_device *bond_dev) 594562306a36Sopenharmony_ci{ 594662306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 594762306a36Sopenharmony_ci struct list_head *iter; 594862306a36Sopenharmony_ci struct slave *slave; 594962306a36Sopenharmony_ci 595062306a36Sopenharmony_ci bond_netpoll_cleanup(bond_dev); 595162306a36Sopenharmony_ci 595262306a36Sopenharmony_ci /* Release the bonded slaves */ 595362306a36Sopenharmony_ci bond_for_each_slave(bond, slave, iter) 595462306a36Sopenharmony_ci __bond_release_one(bond_dev, slave->dev, true, true); 595562306a36Sopenharmony_ci netdev_info(bond_dev, "Released all slaves\n"); 595662306a36Sopenharmony_ci 595762306a36Sopenharmony_ci bond_set_slave_arr(bond, NULL, NULL); 595862306a36Sopenharmony_ci 595962306a36Sopenharmony_ci list_del(&bond->bond_list); 596062306a36Sopenharmony_ci 596162306a36Sopenharmony_ci bond_debug_unregister(bond); 596262306a36Sopenharmony_ci} 596362306a36Sopenharmony_ci 596462306a36Sopenharmony_ci/*------------------------- Module initialization ---------------------------*/ 596562306a36Sopenharmony_ci 596662306a36Sopenharmony_cistatic int __init bond_check_params(struct bond_params *params) 596762306a36Sopenharmony_ci{ 596862306a36Sopenharmony_ci int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; 596962306a36Sopenharmony_ci struct bond_opt_value newval; 597062306a36Sopenharmony_ci const struct bond_opt_value *valptr; 597162306a36Sopenharmony_ci int arp_all_targets_value = 0; 597262306a36Sopenharmony_ci u16 ad_actor_sys_prio = 0; 597362306a36Sopenharmony_ci u16 ad_user_port_key = 0; 597462306a36Sopenharmony_ci __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0 }; 597562306a36Sopenharmony_ci int arp_ip_count; 597662306a36Sopenharmony_ci int bond_mode = BOND_MODE_ROUNDROBIN; 597762306a36Sopenharmony_ci int xmit_hashtype = BOND_XMIT_POLICY_LAYER2; 597862306a36Sopenharmony_ci int lacp_fast = 0; 597962306a36Sopenharmony_ci int tlb_dynamic_lb; 598062306a36Sopenharmony_ci 598162306a36Sopenharmony_ci /* Convert string parameters. */ 598262306a36Sopenharmony_ci if (mode) { 598362306a36Sopenharmony_ci bond_opt_initstr(&newval, mode); 598462306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_MODE), &newval); 598562306a36Sopenharmony_ci if (!valptr) { 598662306a36Sopenharmony_ci pr_err("Error: Invalid bonding mode \"%s\"\n", mode); 598762306a36Sopenharmony_ci return -EINVAL; 598862306a36Sopenharmony_ci } 598962306a36Sopenharmony_ci bond_mode = valptr->value; 599062306a36Sopenharmony_ci } 599162306a36Sopenharmony_ci 599262306a36Sopenharmony_ci if (xmit_hash_policy) { 599362306a36Sopenharmony_ci if (bond_mode == BOND_MODE_ROUNDROBIN || 599462306a36Sopenharmony_ci bond_mode == BOND_MODE_ACTIVEBACKUP || 599562306a36Sopenharmony_ci bond_mode == BOND_MODE_BROADCAST) { 599662306a36Sopenharmony_ci pr_info("xmit_hash_policy param is irrelevant in mode %s\n", 599762306a36Sopenharmony_ci bond_mode_name(bond_mode)); 599862306a36Sopenharmony_ci } else { 599962306a36Sopenharmony_ci bond_opt_initstr(&newval, xmit_hash_policy); 600062306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_XMIT_HASH), 600162306a36Sopenharmony_ci &newval); 600262306a36Sopenharmony_ci if (!valptr) { 600362306a36Sopenharmony_ci pr_err("Error: Invalid xmit_hash_policy \"%s\"\n", 600462306a36Sopenharmony_ci xmit_hash_policy); 600562306a36Sopenharmony_ci return -EINVAL; 600662306a36Sopenharmony_ci } 600762306a36Sopenharmony_ci xmit_hashtype = valptr->value; 600862306a36Sopenharmony_ci } 600962306a36Sopenharmony_ci } 601062306a36Sopenharmony_ci 601162306a36Sopenharmony_ci if (lacp_rate) { 601262306a36Sopenharmony_ci if (bond_mode != BOND_MODE_8023AD) { 601362306a36Sopenharmony_ci pr_info("lacp_rate param is irrelevant in mode %s\n", 601462306a36Sopenharmony_ci bond_mode_name(bond_mode)); 601562306a36Sopenharmony_ci } else { 601662306a36Sopenharmony_ci bond_opt_initstr(&newval, lacp_rate); 601762306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_LACP_RATE), 601862306a36Sopenharmony_ci &newval); 601962306a36Sopenharmony_ci if (!valptr) { 602062306a36Sopenharmony_ci pr_err("Error: Invalid lacp rate \"%s\"\n", 602162306a36Sopenharmony_ci lacp_rate); 602262306a36Sopenharmony_ci return -EINVAL; 602362306a36Sopenharmony_ci } 602462306a36Sopenharmony_ci lacp_fast = valptr->value; 602562306a36Sopenharmony_ci } 602662306a36Sopenharmony_ci } 602762306a36Sopenharmony_ci 602862306a36Sopenharmony_ci if (ad_select) { 602962306a36Sopenharmony_ci bond_opt_initstr(&newval, ad_select); 603062306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_SELECT), 603162306a36Sopenharmony_ci &newval); 603262306a36Sopenharmony_ci if (!valptr) { 603362306a36Sopenharmony_ci pr_err("Error: Invalid ad_select \"%s\"\n", ad_select); 603462306a36Sopenharmony_ci return -EINVAL; 603562306a36Sopenharmony_ci } 603662306a36Sopenharmony_ci params->ad_select = valptr->value; 603762306a36Sopenharmony_ci if (bond_mode != BOND_MODE_8023AD) 603862306a36Sopenharmony_ci pr_warn("ad_select param only affects 802.3ad mode\n"); 603962306a36Sopenharmony_ci } else { 604062306a36Sopenharmony_ci params->ad_select = BOND_AD_STABLE; 604162306a36Sopenharmony_ci } 604262306a36Sopenharmony_ci 604362306a36Sopenharmony_ci if (max_bonds < 0) { 604462306a36Sopenharmony_ci pr_warn("Warning: max_bonds (%d) not in range %d-%d, so it was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", 604562306a36Sopenharmony_ci max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS); 604662306a36Sopenharmony_ci max_bonds = BOND_DEFAULT_MAX_BONDS; 604762306a36Sopenharmony_ci } 604862306a36Sopenharmony_ci 604962306a36Sopenharmony_ci if (miimon < 0) { 605062306a36Sopenharmony_ci pr_warn("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n", 605162306a36Sopenharmony_ci miimon, INT_MAX); 605262306a36Sopenharmony_ci miimon = 0; 605362306a36Sopenharmony_ci } 605462306a36Sopenharmony_ci 605562306a36Sopenharmony_ci if (updelay < 0) { 605662306a36Sopenharmony_ci pr_warn("Warning: updelay module parameter (%d), not in range 0-%d, so it was reset to 0\n", 605762306a36Sopenharmony_ci updelay, INT_MAX); 605862306a36Sopenharmony_ci updelay = 0; 605962306a36Sopenharmony_ci } 606062306a36Sopenharmony_ci 606162306a36Sopenharmony_ci if (downdelay < 0) { 606262306a36Sopenharmony_ci pr_warn("Warning: downdelay module parameter (%d), not in range 0-%d, so it was reset to 0\n", 606362306a36Sopenharmony_ci downdelay, INT_MAX); 606462306a36Sopenharmony_ci downdelay = 0; 606562306a36Sopenharmony_ci } 606662306a36Sopenharmony_ci 606762306a36Sopenharmony_ci if ((use_carrier != 0) && (use_carrier != 1)) { 606862306a36Sopenharmony_ci pr_warn("Warning: use_carrier module parameter (%d), not of valid value (0/1), so it was set to 1\n", 606962306a36Sopenharmony_ci use_carrier); 607062306a36Sopenharmony_ci use_carrier = 1; 607162306a36Sopenharmony_ci } 607262306a36Sopenharmony_ci 607362306a36Sopenharmony_ci if (num_peer_notif < 0 || num_peer_notif > 255) { 607462306a36Sopenharmony_ci pr_warn("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", 607562306a36Sopenharmony_ci num_peer_notif); 607662306a36Sopenharmony_ci num_peer_notif = 1; 607762306a36Sopenharmony_ci } 607862306a36Sopenharmony_ci 607962306a36Sopenharmony_ci /* reset values for 802.3ad/TLB/ALB */ 608062306a36Sopenharmony_ci if (!bond_mode_uses_arp(bond_mode)) { 608162306a36Sopenharmony_ci if (!miimon) { 608262306a36Sopenharmony_ci pr_warn("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n"); 608362306a36Sopenharmony_ci pr_warn("Forcing miimon to 100msec\n"); 608462306a36Sopenharmony_ci miimon = BOND_DEFAULT_MIIMON; 608562306a36Sopenharmony_ci } 608662306a36Sopenharmony_ci } 608762306a36Sopenharmony_ci 608862306a36Sopenharmony_ci if (tx_queues < 1 || tx_queues > 255) { 608962306a36Sopenharmony_ci pr_warn("Warning: tx_queues (%d) should be between 1 and 255, resetting to %d\n", 609062306a36Sopenharmony_ci tx_queues, BOND_DEFAULT_TX_QUEUES); 609162306a36Sopenharmony_ci tx_queues = BOND_DEFAULT_TX_QUEUES; 609262306a36Sopenharmony_ci } 609362306a36Sopenharmony_ci 609462306a36Sopenharmony_ci if ((all_slaves_active != 0) && (all_slaves_active != 1)) { 609562306a36Sopenharmony_ci pr_warn("Warning: all_slaves_active module parameter (%d), not of valid value (0/1), so it was set to 0\n", 609662306a36Sopenharmony_ci all_slaves_active); 609762306a36Sopenharmony_ci all_slaves_active = 0; 609862306a36Sopenharmony_ci } 609962306a36Sopenharmony_ci 610062306a36Sopenharmony_ci if (resend_igmp < 0 || resend_igmp > 255) { 610162306a36Sopenharmony_ci pr_warn("Warning: resend_igmp (%d) should be between 0 and 255, resetting to %d\n", 610262306a36Sopenharmony_ci resend_igmp, BOND_DEFAULT_RESEND_IGMP); 610362306a36Sopenharmony_ci resend_igmp = BOND_DEFAULT_RESEND_IGMP; 610462306a36Sopenharmony_ci } 610562306a36Sopenharmony_ci 610662306a36Sopenharmony_ci bond_opt_initval(&newval, packets_per_slave); 610762306a36Sopenharmony_ci if (!bond_opt_parse(bond_opt_get(BOND_OPT_PACKETS_PER_SLAVE), &newval)) { 610862306a36Sopenharmony_ci pr_warn("Warning: packets_per_slave (%d) should be between 0 and %u resetting to 1\n", 610962306a36Sopenharmony_ci packets_per_slave, USHRT_MAX); 611062306a36Sopenharmony_ci packets_per_slave = 1; 611162306a36Sopenharmony_ci } 611262306a36Sopenharmony_ci 611362306a36Sopenharmony_ci if (bond_mode == BOND_MODE_ALB) { 611462306a36Sopenharmony_ci pr_notice("In ALB mode you might experience client disconnections upon reconnection of a link if the bonding module updelay parameter (%d msec) is incompatible with the forwarding delay time of the switch\n", 611562306a36Sopenharmony_ci updelay); 611662306a36Sopenharmony_ci } 611762306a36Sopenharmony_ci 611862306a36Sopenharmony_ci if (!miimon) { 611962306a36Sopenharmony_ci if (updelay || downdelay) { 612062306a36Sopenharmony_ci /* just warn the user the up/down delay will have 612162306a36Sopenharmony_ci * no effect since miimon is zero... 612262306a36Sopenharmony_ci */ 612362306a36Sopenharmony_ci pr_warn("Warning: miimon module parameter not set and updelay (%d) or downdelay (%d) module parameter is set; updelay and downdelay have no effect unless miimon is set\n", 612462306a36Sopenharmony_ci updelay, downdelay); 612562306a36Sopenharmony_ci } 612662306a36Sopenharmony_ci } else { 612762306a36Sopenharmony_ci /* don't allow arp monitoring */ 612862306a36Sopenharmony_ci if (arp_interval) { 612962306a36Sopenharmony_ci pr_warn("Warning: miimon (%d) and arp_interval (%d) can't be used simultaneously, disabling ARP monitoring\n", 613062306a36Sopenharmony_ci miimon, arp_interval); 613162306a36Sopenharmony_ci arp_interval = 0; 613262306a36Sopenharmony_ci } 613362306a36Sopenharmony_ci 613462306a36Sopenharmony_ci if ((updelay % miimon) != 0) { 613562306a36Sopenharmony_ci pr_warn("Warning: updelay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n", 613662306a36Sopenharmony_ci updelay, miimon, (updelay / miimon) * miimon); 613762306a36Sopenharmony_ci } 613862306a36Sopenharmony_ci 613962306a36Sopenharmony_ci updelay /= miimon; 614062306a36Sopenharmony_ci 614162306a36Sopenharmony_ci if ((downdelay % miimon) != 0) { 614262306a36Sopenharmony_ci pr_warn("Warning: downdelay (%d) is not a multiple of miimon (%d), downdelay rounded to %d ms\n", 614362306a36Sopenharmony_ci downdelay, miimon, 614462306a36Sopenharmony_ci (downdelay / miimon) * miimon); 614562306a36Sopenharmony_ci } 614662306a36Sopenharmony_ci 614762306a36Sopenharmony_ci downdelay /= miimon; 614862306a36Sopenharmony_ci } 614962306a36Sopenharmony_ci 615062306a36Sopenharmony_ci if (arp_interval < 0) { 615162306a36Sopenharmony_ci pr_warn("Warning: arp_interval module parameter (%d), not in range 0-%d, so it was reset to 0\n", 615262306a36Sopenharmony_ci arp_interval, INT_MAX); 615362306a36Sopenharmony_ci arp_interval = 0; 615462306a36Sopenharmony_ci } 615562306a36Sopenharmony_ci 615662306a36Sopenharmony_ci for (arp_ip_count = 0, i = 0; 615762306a36Sopenharmony_ci (arp_ip_count < BOND_MAX_ARP_TARGETS) && arp_ip_target[i]; i++) { 615862306a36Sopenharmony_ci __be32 ip; 615962306a36Sopenharmony_ci 616062306a36Sopenharmony_ci /* not a complete check, but good enough to catch mistakes */ 616162306a36Sopenharmony_ci if (!in4_pton(arp_ip_target[i], -1, (u8 *)&ip, -1, NULL) || 616262306a36Sopenharmony_ci !bond_is_ip_target_ok(ip)) { 616362306a36Sopenharmony_ci pr_warn("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n", 616462306a36Sopenharmony_ci arp_ip_target[i]); 616562306a36Sopenharmony_ci arp_interval = 0; 616662306a36Sopenharmony_ci } else { 616762306a36Sopenharmony_ci if (bond_get_targets_ip(arp_target, ip) == -1) 616862306a36Sopenharmony_ci arp_target[arp_ip_count++] = ip; 616962306a36Sopenharmony_ci else 617062306a36Sopenharmony_ci pr_warn("Warning: duplicate address %pI4 in arp_ip_target, skipping\n", 617162306a36Sopenharmony_ci &ip); 617262306a36Sopenharmony_ci } 617362306a36Sopenharmony_ci } 617462306a36Sopenharmony_ci 617562306a36Sopenharmony_ci if (arp_interval && !arp_ip_count) { 617662306a36Sopenharmony_ci /* don't allow arping if no arp_ip_target given... */ 617762306a36Sopenharmony_ci pr_warn("Warning: arp_interval module parameter (%d) specified without providing an arp_ip_target parameter, arp_interval was reset to 0\n", 617862306a36Sopenharmony_ci arp_interval); 617962306a36Sopenharmony_ci arp_interval = 0; 618062306a36Sopenharmony_ci } 618162306a36Sopenharmony_ci 618262306a36Sopenharmony_ci if (arp_validate) { 618362306a36Sopenharmony_ci if (!arp_interval) { 618462306a36Sopenharmony_ci pr_err("arp_validate requires arp_interval\n"); 618562306a36Sopenharmony_ci return -EINVAL; 618662306a36Sopenharmony_ci } 618762306a36Sopenharmony_ci 618862306a36Sopenharmony_ci bond_opt_initstr(&newval, arp_validate); 618962306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_ARP_VALIDATE), 619062306a36Sopenharmony_ci &newval); 619162306a36Sopenharmony_ci if (!valptr) { 619262306a36Sopenharmony_ci pr_err("Error: invalid arp_validate \"%s\"\n", 619362306a36Sopenharmony_ci arp_validate); 619462306a36Sopenharmony_ci return -EINVAL; 619562306a36Sopenharmony_ci } 619662306a36Sopenharmony_ci arp_validate_value = valptr->value; 619762306a36Sopenharmony_ci } else { 619862306a36Sopenharmony_ci arp_validate_value = 0; 619962306a36Sopenharmony_ci } 620062306a36Sopenharmony_ci 620162306a36Sopenharmony_ci if (arp_all_targets) { 620262306a36Sopenharmony_ci bond_opt_initstr(&newval, arp_all_targets); 620362306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_ARP_ALL_TARGETS), 620462306a36Sopenharmony_ci &newval); 620562306a36Sopenharmony_ci if (!valptr) { 620662306a36Sopenharmony_ci pr_err("Error: invalid arp_all_targets_value \"%s\"\n", 620762306a36Sopenharmony_ci arp_all_targets); 620862306a36Sopenharmony_ci arp_all_targets_value = 0; 620962306a36Sopenharmony_ci } else { 621062306a36Sopenharmony_ci arp_all_targets_value = valptr->value; 621162306a36Sopenharmony_ci } 621262306a36Sopenharmony_ci } 621362306a36Sopenharmony_ci 621462306a36Sopenharmony_ci if (miimon) { 621562306a36Sopenharmony_ci pr_info("MII link monitoring set to %d ms\n", miimon); 621662306a36Sopenharmony_ci } else if (arp_interval) { 621762306a36Sopenharmony_ci valptr = bond_opt_get_val(BOND_OPT_ARP_VALIDATE, 621862306a36Sopenharmony_ci arp_validate_value); 621962306a36Sopenharmony_ci pr_info("ARP monitoring set to %d ms, validate %s, with %d target(s):", 622062306a36Sopenharmony_ci arp_interval, valptr->string, arp_ip_count); 622162306a36Sopenharmony_ci 622262306a36Sopenharmony_ci for (i = 0; i < arp_ip_count; i++) 622362306a36Sopenharmony_ci pr_cont(" %s", arp_ip_target[i]); 622462306a36Sopenharmony_ci 622562306a36Sopenharmony_ci pr_cont("\n"); 622662306a36Sopenharmony_ci 622762306a36Sopenharmony_ci } else if (max_bonds) { 622862306a36Sopenharmony_ci /* miimon and arp_interval not set, we need one so things 622962306a36Sopenharmony_ci * work as expected, see bonding.txt for details 623062306a36Sopenharmony_ci */ 623162306a36Sopenharmony_ci pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details\n"); 623262306a36Sopenharmony_ci } 623362306a36Sopenharmony_ci 623462306a36Sopenharmony_ci if (primary && !bond_mode_uses_primary(bond_mode)) { 623562306a36Sopenharmony_ci /* currently, using a primary only makes sense 623662306a36Sopenharmony_ci * in active backup, TLB or ALB modes 623762306a36Sopenharmony_ci */ 623862306a36Sopenharmony_ci pr_warn("Warning: %s primary device specified but has no effect in %s mode\n", 623962306a36Sopenharmony_ci primary, bond_mode_name(bond_mode)); 624062306a36Sopenharmony_ci primary = NULL; 624162306a36Sopenharmony_ci } 624262306a36Sopenharmony_ci 624362306a36Sopenharmony_ci if (primary && primary_reselect) { 624462306a36Sopenharmony_ci bond_opt_initstr(&newval, primary_reselect); 624562306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_PRIMARY_RESELECT), 624662306a36Sopenharmony_ci &newval); 624762306a36Sopenharmony_ci if (!valptr) { 624862306a36Sopenharmony_ci pr_err("Error: Invalid primary_reselect \"%s\"\n", 624962306a36Sopenharmony_ci primary_reselect); 625062306a36Sopenharmony_ci return -EINVAL; 625162306a36Sopenharmony_ci } 625262306a36Sopenharmony_ci primary_reselect_value = valptr->value; 625362306a36Sopenharmony_ci } else { 625462306a36Sopenharmony_ci primary_reselect_value = BOND_PRI_RESELECT_ALWAYS; 625562306a36Sopenharmony_ci } 625662306a36Sopenharmony_ci 625762306a36Sopenharmony_ci if (fail_over_mac) { 625862306a36Sopenharmony_ci bond_opt_initstr(&newval, fail_over_mac); 625962306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_FAIL_OVER_MAC), 626062306a36Sopenharmony_ci &newval); 626162306a36Sopenharmony_ci if (!valptr) { 626262306a36Sopenharmony_ci pr_err("Error: invalid fail_over_mac \"%s\"\n", 626362306a36Sopenharmony_ci fail_over_mac); 626462306a36Sopenharmony_ci return -EINVAL; 626562306a36Sopenharmony_ci } 626662306a36Sopenharmony_ci fail_over_mac_value = valptr->value; 626762306a36Sopenharmony_ci if (bond_mode != BOND_MODE_ACTIVEBACKUP) 626862306a36Sopenharmony_ci pr_warn("Warning: fail_over_mac only affects active-backup mode\n"); 626962306a36Sopenharmony_ci } else { 627062306a36Sopenharmony_ci fail_over_mac_value = BOND_FOM_NONE; 627162306a36Sopenharmony_ci } 627262306a36Sopenharmony_ci 627362306a36Sopenharmony_ci bond_opt_initstr(&newval, "default"); 627462306a36Sopenharmony_ci valptr = bond_opt_parse( 627562306a36Sopenharmony_ci bond_opt_get(BOND_OPT_AD_ACTOR_SYS_PRIO), 627662306a36Sopenharmony_ci &newval); 627762306a36Sopenharmony_ci if (!valptr) { 627862306a36Sopenharmony_ci pr_err("Error: No ad_actor_sys_prio default value"); 627962306a36Sopenharmony_ci return -EINVAL; 628062306a36Sopenharmony_ci } 628162306a36Sopenharmony_ci ad_actor_sys_prio = valptr->value; 628262306a36Sopenharmony_ci 628362306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_AD_USER_PORT_KEY), 628462306a36Sopenharmony_ci &newval); 628562306a36Sopenharmony_ci if (!valptr) { 628662306a36Sopenharmony_ci pr_err("Error: No ad_user_port_key default value"); 628762306a36Sopenharmony_ci return -EINVAL; 628862306a36Sopenharmony_ci } 628962306a36Sopenharmony_ci ad_user_port_key = valptr->value; 629062306a36Sopenharmony_ci 629162306a36Sopenharmony_ci bond_opt_initstr(&newval, "default"); 629262306a36Sopenharmony_ci valptr = bond_opt_parse(bond_opt_get(BOND_OPT_TLB_DYNAMIC_LB), &newval); 629362306a36Sopenharmony_ci if (!valptr) { 629462306a36Sopenharmony_ci pr_err("Error: No tlb_dynamic_lb default value"); 629562306a36Sopenharmony_ci return -EINVAL; 629662306a36Sopenharmony_ci } 629762306a36Sopenharmony_ci tlb_dynamic_lb = valptr->value; 629862306a36Sopenharmony_ci 629962306a36Sopenharmony_ci if (lp_interval == 0) { 630062306a36Sopenharmony_ci pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n", 630162306a36Sopenharmony_ci INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL); 630262306a36Sopenharmony_ci lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL; 630362306a36Sopenharmony_ci } 630462306a36Sopenharmony_ci 630562306a36Sopenharmony_ci /* fill params struct with the proper values */ 630662306a36Sopenharmony_ci params->mode = bond_mode; 630762306a36Sopenharmony_ci params->xmit_policy = xmit_hashtype; 630862306a36Sopenharmony_ci params->miimon = miimon; 630962306a36Sopenharmony_ci params->num_peer_notif = num_peer_notif; 631062306a36Sopenharmony_ci params->arp_interval = arp_interval; 631162306a36Sopenharmony_ci params->arp_validate = arp_validate_value; 631262306a36Sopenharmony_ci params->arp_all_targets = arp_all_targets_value; 631362306a36Sopenharmony_ci params->missed_max = 2; 631462306a36Sopenharmony_ci params->updelay = updelay; 631562306a36Sopenharmony_ci params->downdelay = downdelay; 631662306a36Sopenharmony_ci params->peer_notif_delay = 0; 631762306a36Sopenharmony_ci params->use_carrier = use_carrier; 631862306a36Sopenharmony_ci params->lacp_active = 1; 631962306a36Sopenharmony_ci params->lacp_fast = lacp_fast; 632062306a36Sopenharmony_ci params->primary[0] = 0; 632162306a36Sopenharmony_ci params->primary_reselect = primary_reselect_value; 632262306a36Sopenharmony_ci params->fail_over_mac = fail_over_mac_value; 632362306a36Sopenharmony_ci params->tx_queues = tx_queues; 632462306a36Sopenharmony_ci params->all_slaves_active = all_slaves_active; 632562306a36Sopenharmony_ci params->resend_igmp = resend_igmp; 632662306a36Sopenharmony_ci params->min_links = min_links; 632762306a36Sopenharmony_ci params->lp_interval = lp_interval; 632862306a36Sopenharmony_ci params->packets_per_slave = packets_per_slave; 632962306a36Sopenharmony_ci params->tlb_dynamic_lb = tlb_dynamic_lb; 633062306a36Sopenharmony_ci params->ad_actor_sys_prio = ad_actor_sys_prio; 633162306a36Sopenharmony_ci eth_zero_addr(params->ad_actor_system); 633262306a36Sopenharmony_ci params->ad_user_port_key = ad_user_port_key; 633362306a36Sopenharmony_ci if (packets_per_slave > 0) { 633462306a36Sopenharmony_ci params->reciprocal_packets_per_slave = 633562306a36Sopenharmony_ci reciprocal_value(packets_per_slave); 633662306a36Sopenharmony_ci } else { 633762306a36Sopenharmony_ci /* reciprocal_packets_per_slave is unused if 633862306a36Sopenharmony_ci * packets_per_slave is 0 or 1, just initialize it 633962306a36Sopenharmony_ci */ 634062306a36Sopenharmony_ci params->reciprocal_packets_per_slave = 634162306a36Sopenharmony_ci (struct reciprocal_value) { 0 }; 634262306a36Sopenharmony_ci } 634362306a36Sopenharmony_ci 634462306a36Sopenharmony_ci if (primary) 634562306a36Sopenharmony_ci strscpy_pad(params->primary, primary, sizeof(params->primary)); 634662306a36Sopenharmony_ci 634762306a36Sopenharmony_ci memcpy(params->arp_targets, arp_target, sizeof(arp_target)); 634862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 634962306a36Sopenharmony_ci memset(params->ns_targets, 0, sizeof(struct in6_addr) * BOND_MAX_NS_TARGETS); 635062306a36Sopenharmony_ci#endif 635162306a36Sopenharmony_ci 635262306a36Sopenharmony_ci return 0; 635362306a36Sopenharmony_ci} 635462306a36Sopenharmony_ci 635562306a36Sopenharmony_ci/* Called from registration process */ 635662306a36Sopenharmony_cistatic int bond_init(struct net_device *bond_dev) 635762306a36Sopenharmony_ci{ 635862306a36Sopenharmony_ci struct bonding *bond = netdev_priv(bond_dev); 635962306a36Sopenharmony_ci struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id); 636062306a36Sopenharmony_ci 636162306a36Sopenharmony_ci netdev_dbg(bond_dev, "Begin bond_init\n"); 636262306a36Sopenharmony_ci 636362306a36Sopenharmony_ci bond->wq = alloc_ordered_workqueue(bond_dev->name, WQ_MEM_RECLAIM); 636462306a36Sopenharmony_ci if (!bond->wq) 636562306a36Sopenharmony_ci return -ENOMEM; 636662306a36Sopenharmony_ci 636762306a36Sopenharmony_ci bond->notifier_ctx = false; 636862306a36Sopenharmony_ci 636962306a36Sopenharmony_ci spin_lock_init(&bond->stats_lock); 637062306a36Sopenharmony_ci netdev_lockdep_set_classes(bond_dev); 637162306a36Sopenharmony_ci 637262306a36Sopenharmony_ci list_add_tail(&bond->bond_list, &bn->dev_list); 637362306a36Sopenharmony_ci 637462306a36Sopenharmony_ci bond_prepare_sysfs_group(bond); 637562306a36Sopenharmony_ci 637662306a36Sopenharmony_ci bond_debug_register(bond); 637762306a36Sopenharmony_ci 637862306a36Sopenharmony_ci /* Ensure valid dev_addr */ 637962306a36Sopenharmony_ci if (is_zero_ether_addr(bond_dev->dev_addr) && 638062306a36Sopenharmony_ci bond_dev->addr_assign_type == NET_ADDR_PERM) 638162306a36Sopenharmony_ci eth_hw_addr_random(bond_dev); 638262306a36Sopenharmony_ci 638362306a36Sopenharmony_ci return 0; 638462306a36Sopenharmony_ci} 638562306a36Sopenharmony_ci 638662306a36Sopenharmony_ciunsigned int bond_get_num_tx_queues(void) 638762306a36Sopenharmony_ci{ 638862306a36Sopenharmony_ci return tx_queues; 638962306a36Sopenharmony_ci} 639062306a36Sopenharmony_ci 639162306a36Sopenharmony_ci/* Create a new bond based on the specified name and bonding parameters. 639262306a36Sopenharmony_ci * If name is NULL, obtain a suitable "bond%d" name for us. 639362306a36Sopenharmony_ci * Caller must NOT hold rtnl_lock; we need to release it here before we 639462306a36Sopenharmony_ci * set up our sysfs entries. 639562306a36Sopenharmony_ci */ 639662306a36Sopenharmony_ciint bond_create(struct net *net, const char *name) 639762306a36Sopenharmony_ci{ 639862306a36Sopenharmony_ci struct net_device *bond_dev; 639962306a36Sopenharmony_ci struct bonding *bond; 640062306a36Sopenharmony_ci int res = -ENOMEM; 640162306a36Sopenharmony_ci 640262306a36Sopenharmony_ci rtnl_lock(); 640362306a36Sopenharmony_ci 640462306a36Sopenharmony_ci bond_dev = alloc_netdev_mq(sizeof(struct bonding), 640562306a36Sopenharmony_ci name ? name : "bond%d", NET_NAME_UNKNOWN, 640662306a36Sopenharmony_ci bond_setup, tx_queues); 640762306a36Sopenharmony_ci if (!bond_dev) 640862306a36Sopenharmony_ci goto out; 640962306a36Sopenharmony_ci 641062306a36Sopenharmony_ci bond = netdev_priv(bond_dev); 641162306a36Sopenharmony_ci dev_net_set(bond_dev, net); 641262306a36Sopenharmony_ci bond_dev->rtnl_link_ops = &bond_link_ops; 641362306a36Sopenharmony_ci 641462306a36Sopenharmony_ci res = register_netdevice(bond_dev); 641562306a36Sopenharmony_ci if (res < 0) { 641662306a36Sopenharmony_ci free_netdev(bond_dev); 641762306a36Sopenharmony_ci goto out; 641862306a36Sopenharmony_ci } 641962306a36Sopenharmony_ci 642062306a36Sopenharmony_ci netif_carrier_off(bond_dev); 642162306a36Sopenharmony_ci 642262306a36Sopenharmony_ci bond_work_init_all(bond); 642362306a36Sopenharmony_ci 642462306a36Sopenharmony_ciout: 642562306a36Sopenharmony_ci rtnl_unlock(); 642662306a36Sopenharmony_ci return res; 642762306a36Sopenharmony_ci} 642862306a36Sopenharmony_ci 642962306a36Sopenharmony_cistatic int __net_init bond_net_init(struct net *net) 643062306a36Sopenharmony_ci{ 643162306a36Sopenharmony_ci struct bond_net *bn = net_generic(net, bond_net_id); 643262306a36Sopenharmony_ci 643362306a36Sopenharmony_ci bn->net = net; 643462306a36Sopenharmony_ci INIT_LIST_HEAD(&bn->dev_list); 643562306a36Sopenharmony_ci 643662306a36Sopenharmony_ci bond_create_proc_dir(bn); 643762306a36Sopenharmony_ci bond_create_sysfs(bn); 643862306a36Sopenharmony_ci 643962306a36Sopenharmony_ci return 0; 644062306a36Sopenharmony_ci} 644162306a36Sopenharmony_ci 644262306a36Sopenharmony_cistatic void __net_exit bond_net_exit_batch(struct list_head *net_list) 644362306a36Sopenharmony_ci{ 644462306a36Sopenharmony_ci struct bond_net *bn; 644562306a36Sopenharmony_ci struct net *net; 644662306a36Sopenharmony_ci LIST_HEAD(list); 644762306a36Sopenharmony_ci 644862306a36Sopenharmony_ci list_for_each_entry(net, net_list, exit_list) { 644962306a36Sopenharmony_ci bn = net_generic(net, bond_net_id); 645062306a36Sopenharmony_ci bond_destroy_sysfs(bn); 645162306a36Sopenharmony_ci } 645262306a36Sopenharmony_ci 645362306a36Sopenharmony_ci /* Kill off any bonds created after unregistering bond rtnl ops */ 645462306a36Sopenharmony_ci rtnl_lock(); 645562306a36Sopenharmony_ci list_for_each_entry(net, net_list, exit_list) { 645662306a36Sopenharmony_ci struct bonding *bond, *tmp_bond; 645762306a36Sopenharmony_ci 645862306a36Sopenharmony_ci bn = net_generic(net, bond_net_id); 645962306a36Sopenharmony_ci list_for_each_entry_safe(bond, tmp_bond, &bn->dev_list, bond_list) 646062306a36Sopenharmony_ci unregister_netdevice_queue(bond->dev, &list); 646162306a36Sopenharmony_ci } 646262306a36Sopenharmony_ci unregister_netdevice_many(&list); 646362306a36Sopenharmony_ci rtnl_unlock(); 646462306a36Sopenharmony_ci 646562306a36Sopenharmony_ci list_for_each_entry(net, net_list, exit_list) { 646662306a36Sopenharmony_ci bn = net_generic(net, bond_net_id); 646762306a36Sopenharmony_ci bond_destroy_proc_dir(bn); 646862306a36Sopenharmony_ci } 646962306a36Sopenharmony_ci} 647062306a36Sopenharmony_ci 647162306a36Sopenharmony_cistatic struct pernet_operations bond_net_ops = { 647262306a36Sopenharmony_ci .init = bond_net_init, 647362306a36Sopenharmony_ci .exit_batch = bond_net_exit_batch, 647462306a36Sopenharmony_ci .id = &bond_net_id, 647562306a36Sopenharmony_ci .size = sizeof(struct bond_net), 647662306a36Sopenharmony_ci}; 647762306a36Sopenharmony_ci 647862306a36Sopenharmony_cistatic int __init bonding_init(void) 647962306a36Sopenharmony_ci{ 648062306a36Sopenharmony_ci int i; 648162306a36Sopenharmony_ci int res; 648262306a36Sopenharmony_ci 648362306a36Sopenharmony_ci res = bond_check_params(&bonding_defaults); 648462306a36Sopenharmony_ci if (res) 648562306a36Sopenharmony_ci goto out; 648662306a36Sopenharmony_ci 648762306a36Sopenharmony_ci res = register_pernet_subsys(&bond_net_ops); 648862306a36Sopenharmony_ci if (res) 648962306a36Sopenharmony_ci goto out; 649062306a36Sopenharmony_ci 649162306a36Sopenharmony_ci res = bond_netlink_init(); 649262306a36Sopenharmony_ci if (res) 649362306a36Sopenharmony_ci goto err_link; 649462306a36Sopenharmony_ci 649562306a36Sopenharmony_ci bond_create_debugfs(); 649662306a36Sopenharmony_ci 649762306a36Sopenharmony_ci for (i = 0; i < max_bonds; i++) { 649862306a36Sopenharmony_ci res = bond_create(&init_net, NULL); 649962306a36Sopenharmony_ci if (res) 650062306a36Sopenharmony_ci goto err; 650162306a36Sopenharmony_ci } 650262306a36Sopenharmony_ci 650362306a36Sopenharmony_ci skb_flow_dissector_init(&flow_keys_bonding, 650462306a36Sopenharmony_ci flow_keys_bonding_keys, 650562306a36Sopenharmony_ci ARRAY_SIZE(flow_keys_bonding_keys)); 650662306a36Sopenharmony_ci 650762306a36Sopenharmony_ci register_netdevice_notifier(&bond_netdev_notifier); 650862306a36Sopenharmony_ciout: 650962306a36Sopenharmony_ci return res; 651062306a36Sopenharmony_cierr: 651162306a36Sopenharmony_ci bond_destroy_debugfs(); 651262306a36Sopenharmony_ci bond_netlink_fini(); 651362306a36Sopenharmony_cierr_link: 651462306a36Sopenharmony_ci unregister_pernet_subsys(&bond_net_ops); 651562306a36Sopenharmony_ci goto out; 651662306a36Sopenharmony_ci 651762306a36Sopenharmony_ci} 651862306a36Sopenharmony_ci 651962306a36Sopenharmony_cistatic void __exit bonding_exit(void) 652062306a36Sopenharmony_ci{ 652162306a36Sopenharmony_ci unregister_netdevice_notifier(&bond_netdev_notifier); 652262306a36Sopenharmony_ci 652362306a36Sopenharmony_ci bond_destroy_debugfs(); 652462306a36Sopenharmony_ci 652562306a36Sopenharmony_ci bond_netlink_fini(); 652662306a36Sopenharmony_ci unregister_pernet_subsys(&bond_net_ops); 652762306a36Sopenharmony_ci 652862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 652962306a36Sopenharmony_ci /* Make sure we don't have an imbalance on our netpoll blocking */ 653062306a36Sopenharmony_ci WARN_ON(atomic_read(&netpoll_block_tx)); 653162306a36Sopenharmony_ci#endif 653262306a36Sopenharmony_ci} 653362306a36Sopenharmony_ci 653462306a36Sopenharmony_cimodule_init(bonding_init); 653562306a36Sopenharmony_cimodule_exit(bonding_exit); 653662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 653762306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESCRIPTION); 653862306a36Sopenharmony_ciMODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others"); 6539