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