162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/net/bond/bond_options.c - bonding options
462306a36Sopenharmony_ci * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
562306a36Sopenharmony_ci * Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/errno.h>
962306a36Sopenharmony_ci#include <linux/if.h>
1062306a36Sopenharmony_ci#include <linux/netdevice.h>
1162306a36Sopenharmony_ci#include <linux/spinlock.h>
1262306a36Sopenharmony_ci#include <linux/rcupdate.h>
1362306a36Sopenharmony_ci#include <linux/ctype.h>
1462306a36Sopenharmony_ci#include <linux/inet.h>
1562306a36Sopenharmony_ci#include <linux/sched/signal.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <net/bonding.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int bond_option_active_slave_set(struct bonding *bond,
2062306a36Sopenharmony_ci					const struct bond_opt_value *newval);
2162306a36Sopenharmony_cistatic int bond_option_miimon_set(struct bonding *bond,
2262306a36Sopenharmony_ci				  const struct bond_opt_value *newval);
2362306a36Sopenharmony_cistatic int bond_option_updelay_set(struct bonding *bond,
2462306a36Sopenharmony_ci				   const struct bond_opt_value *newval);
2562306a36Sopenharmony_cistatic int bond_option_downdelay_set(struct bonding *bond,
2662306a36Sopenharmony_ci				     const struct bond_opt_value *newval);
2762306a36Sopenharmony_cistatic int bond_option_peer_notif_delay_set(struct bonding *bond,
2862306a36Sopenharmony_ci					    const struct bond_opt_value *newval);
2962306a36Sopenharmony_cistatic int bond_option_use_carrier_set(struct bonding *bond,
3062306a36Sopenharmony_ci				       const struct bond_opt_value *newval);
3162306a36Sopenharmony_cistatic int bond_option_arp_interval_set(struct bonding *bond,
3262306a36Sopenharmony_ci					const struct bond_opt_value *newval);
3362306a36Sopenharmony_cistatic int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
3462306a36Sopenharmony_cistatic int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
3562306a36Sopenharmony_cistatic int bond_option_arp_ip_targets_set(struct bonding *bond,
3662306a36Sopenharmony_ci					  const struct bond_opt_value *newval);
3762306a36Sopenharmony_cistatic int bond_option_ns_ip6_targets_set(struct bonding *bond,
3862306a36Sopenharmony_ci					  const struct bond_opt_value *newval);
3962306a36Sopenharmony_cistatic int bond_option_arp_validate_set(struct bonding *bond,
4062306a36Sopenharmony_ci					const struct bond_opt_value *newval);
4162306a36Sopenharmony_cistatic int bond_option_arp_all_targets_set(struct bonding *bond,
4262306a36Sopenharmony_ci					   const struct bond_opt_value *newval);
4362306a36Sopenharmony_cistatic int bond_option_prio_set(struct bonding *bond,
4462306a36Sopenharmony_ci				const struct bond_opt_value *newval);
4562306a36Sopenharmony_cistatic int bond_option_primary_set(struct bonding *bond,
4662306a36Sopenharmony_ci				   const struct bond_opt_value *newval);
4762306a36Sopenharmony_cistatic int bond_option_primary_reselect_set(struct bonding *bond,
4862306a36Sopenharmony_ci					    const struct bond_opt_value *newval);
4962306a36Sopenharmony_cistatic int bond_option_fail_over_mac_set(struct bonding *bond,
5062306a36Sopenharmony_ci					 const struct bond_opt_value *newval);
5162306a36Sopenharmony_cistatic int bond_option_xmit_hash_policy_set(struct bonding *bond,
5262306a36Sopenharmony_ci					    const struct bond_opt_value *newval);
5362306a36Sopenharmony_cistatic int bond_option_resend_igmp_set(struct bonding *bond,
5462306a36Sopenharmony_ci				       const struct bond_opt_value *newval);
5562306a36Sopenharmony_cistatic int bond_option_num_peer_notif_set(struct bonding *bond,
5662306a36Sopenharmony_ci					  const struct bond_opt_value *newval);
5762306a36Sopenharmony_cistatic int bond_option_all_slaves_active_set(struct bonding *bond,
5862306a36Sopenharmony_ci					     const struct bond_opt_value *newval);
5962306a36Sopenharmony_cistatic int bond_option_min_links_set(struct bonding *bond,
6062306a36Sopenharmony_ci				     const struct bond_opt_value *newval);
6162306a36Sopenharmony_cistatic int bond_option_lp_interval_set(struct bonding *bond,
6262306a36Sopenharmony_ci				       const struct bond_opt_value *newval);
6362306a36Sopenharmony_cistatic int bond_option_pps_set(struct bonding *bond,
6462306a36Sopenharmony_ci			       const struct bond_opt_value *newval);
6562306a36Sopenharmony_cistatic int bond_option_lacp_active_set(struct bonding *bond,
6662306a36Sopenharmony_ci				       const struct bond_opt_value *newval);
6762306a36Sopenharmony_cistatic int bond_option_lacp_rate_set(struct bonding *bond,
6862306a36Sopenharmony_ci				     const struct bond_opt_value *newval);
6962306a36Sopenharmony_cistatic int bond_option_ad_select_set(struct bonding *bond,
7062306a36Sopenharmony_ci				     const struct bond_opt_value *newval);
7162306a36Sopenharmony_cistatic int bond_option_queue_id_set(struct bonding *bond,
7262306a36Sopenharmony_ci				    const struct bond_opt_value *newval);
7362306a36Sopenharmony_cistatic int bond_option_mode_set(struct bonding *bond,
7462306a36Sopenharmony_ci				const struct bond_opt_value *newval);
7562306a36Sopenharmony_cistatic int bond_option_slaves_set(struct bonding *bond,
7662306a36Sopenharmony_ci				  const struct bond_opt_value *newval);
7762306a36Sopenharmony_cistatic int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
7862306a36Sopenharmony_ci				  const struct bond_opt_value *newval);
7962306a36Sopenharmony_cistatic int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
8062306a36Sopenharmony_ci					     const struct bond_opt_value *newval);
8162306a36Sopenharmony_cistatic int bond_option_ad_actor_system_set(struct bonding *bond,
8262306a36Sopenharmony_ci					   const struct bond_opt_value *newval);
8362306a36Sopenharmony_cistatic int bond_option_ad_user_port_key_set(struct bonding *bond,
8462306a36Sopenharmony_ci					    const struct bond_opt_value *newval);
8562306a36Sopenharmony_cistatic int bond_option_missed_max_set(struct bonding *bond,
8662306a36Sopenharmony_ci				      const struct bond_opt_value *newval);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic const struct bond_opt_value bond_mode_tbl[] = {
9062306a36Sopenharmony_ci	{ "balance-rr",    BOND_MODE_ROUNDROBIN,   BOND_VALFLAG_DEFAULT},
9162306a36Sopenharmony_ci	{ "active-backup", BOND_MODE_ACTIVEBACKUP, 0},
9262306a36Sopenharmony_ci	{ "balance-xor",   BOND_MODE_XOR,          0},
9362306a36Sopenharmony_ci	{ "broadcast",     BOND_MODE_BROADCAST,    0},
9462306a36Sopenharmony_ci	{ "802.3ad",       BOND_MODE_8023AD,       0},
9562306a36Sopenharmony_ci	{ "balance-tlb",   BOND_MODE_TLB,          0},
9662306a36Sopenharmony_ci	{ "balance-alb",   BOND_MODE_ALB,          0},
9762306a36Sopenharmony_ci	{ NULL,            -1,                     0},
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic const struct bond_opt_value bond_pps_tbl[] = {
10162306a36Sopenharmony_ci	{ "default", 1,         BOND_VALFLAG_DEFAULT},
10262306a36Sopenharmony_ci	{ "maxval",  USHRT_MAX, BOND_VALFLAG_MAX},
10362306a36Sopenharmony_ci	{ NULL,      -1,        0},
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic const struct bond_opt_value bond_xmit_hashtype_tbl[] = {
10762306a36Sopenharmony_ci	{ "layer2",      BOND_XMIT_POLICY_LAYER2,      BOND_VALFLAG_DEFAULT},
10862306a36Sopenharmony_ci	{ "layer3+4",    BOND_XMIT_POLICY_LAYER34,     0},
10962306a36Sopenharmony_ci	{ "layer2+3",    BOND_XMIT_POLICY_LAYER23,     0},
11062306a36Sopenharmony_ci	{ "encap2+3",    BOND_XMIT_POLICY_ENCAP23,     0},
11162306a36Sopenharmony_ci	{ "encap3+4",    BOND_XMIT_POLICY_ENCAP34,     0},
11262306a36Sopenharmony_ci	{ "vlan+srcmac", BOND_XMIT_POLICY_VLAN_SRCMAC, 0},
11362306a36Sopenharmony_ci	{ NULL,          -1,                           0},
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic const struct bond_opt_value bond_arp_validate_tbl[] = {
11762306a36Sopenharmony_ci	{ "none",		BOND_ARP_VALIDATE_NONE,		BOND_VALFLAG_DEFAULT},
11862306a36Sopenharmony_ci	{ "active",		BOND_ARP_VALIDATE_ACTIVE,	0},
11962306a36Sopenharmony_ci	{ "backup",		BOND_ARP_VALIDATE_BACKUP,	0},
12062306a36Sopenharmony_ci	{ "all",		BOND_ARP_VALIDATE_ALL,		0},
12162306a36Sopenharmony_ci	{ "filter",		BOND_ARP_FILTER,		0},
12262306a36Sopenharmony_ci	{ "filter_active",	BOND_ARP_FILTER_ACTIVE,		0},
12362306a36Sopenharmony_ci	{ "filter_backup",	BOND_ARP_FILTER_BACKUP,		0},
12462306a36Sopenharmony_ci	{ NULL,			-1,				0},
12562306a36Sopenharmony_ci};
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct bond_opt_value bond_arp_all_targets_tbl[] = {
12862306a36Sopenharmony_ci	{ "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT},
12962306a36Sopenharmony_ci	{ "all", BOND_ARP_TARGETS_ALL, 0},
13062306a36Sopenharmony_ci	{ NULL,  -1,                   0},
13162306a36Sopenharmony_ci};
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic const struct bond_opt_value bond_fail_over_mac_tbl[] = {
13462306a36Sopenharmony_ci	{ "none",   BOND_FOM_NONE,   BOND_VALFLAG_DEFAULT},
13562306a36Sopenharmony_ci	{ "active", BOND_FOM_ACTIVE, 0},
13662306a36Sopenharmony_ci	{ "follow", BOND_FOM_FOLLOW, 0},
13762306a36Sopenharmony_ci	{ NULL,     -1,              0},
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic const struct bond_opt_value bond_intmax_tbl[] = {
14162306a36Sopenharmony_ci	{ "off",     0,       BOND_VALFLAG_DEFAULT},
14262306a36Sopenharmony_ci	{ "maxval",  INT_MAX, BOND_VALFLAG_MAX},
14362306a36Sopenharmony_ci	{ NULL,      -1,      0}
14462306a36Sopenharmony_ci};
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic const struct bond_opt_value bond_lacp_active[] = {
14762306a36Sopenharmony_ci	{ "off", 0,  0},
14862306a36Sopenharmony_ci	{ "on",  1,  BOND_VALFLAG_DEFAULT},
14962306a36Sopenharmony_ci	{ NULL,  -1, 0}
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const struct bond_opt_value bond_lacp_rate_tbl[] = {
15362306a36Sopenharmony_ci	{ "slow", AD_LACP_SLOW, 0},
15462306a36Sopenharmony_ci	{ "fast", AD_LACP_FAST, 0},
15562306a36Sopenharmony_ci	{ NULL,   -1,           0},
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic const struct bond_opt_value bond_ad_select_tbl[] = {
15962306a36Sopenharmony_ci	{ "stable",    BOND_AD_STABLE,    BOND_VALFLAG_DEFAULT},
16062306a36Sopenharmony_ci	{ "bandwidth", BOND_AD_BANDWIDTH, 0},
16162306a36Sopenharmony_ci	{ "count",     BOND_AD_COUNT,     0},
16262306a36Sopenharmony_ci	{ NULL,        -1,                0},
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic const struct bond_opt_value bond_num_peer_notif_tbl[] = {
16662306a36Sopenharmony_ci	{ "off",     0,   0},
16762306a36Sopenharmony_ci	{ "maxval",  255, BOND_VALFLAG_MAX},
16862306a36Sopenharmony_ci	{ "default", 1,   BOND_VALFLAG_DEFAULT},
16962306a36Sopenharmony_ci	{ NULL,      -1,  0}
17062306a36Sopenharmony_ci};
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic const struct bond_opt_value bond_peer_notif_delay_tbl[] = {
17362306a36Sopenharmony_ci	{ "off",     0,   0},
17462306a36Sopenharmony_ci	{ "maxval",  300000, BOND_VALFLAG_MAX},
17562306a36Sopenharmony_ci	{ NULL,      -1,  0}
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic const struct bond_opt_value bond_primary_reselect_tbl[] = {
17962306a36Sopenharmony_ci	{ "always",  BOND_PRI_RESELECT_ALWAYS,  BOND_VALFLAG_DEFAULT},
18062306a36Sopenharmony_ci	{ "better",  BOND_PRI_RESELECT_BETTER,  0},
18162306a36Sopenharmony_ci	{ "failure", BOND_PRI_RESELECT_FAILURE, 0},
18262306a36Sopenharmony_ci	{ NULL,      -1},
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic const struct bond_opt_value bond_use_carrier_tbl[] = {
18662306a36Sopenharmony_ci	{ "off", 0,  0},
18762306a36Sopenharmony_ci	{ "on",  1,  BOND_VALFLAG_DEFAULT},
18862306a36Sopenharmony_ci	{ NULL,  -1, 0}
18962306a36Sopenharmony_ci};
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic const struct bond_opt_value bond_all_slaves_active_tbl[] = {
19262306a36Sopenharmony_ci	{ "off", 0,  BOND_VALFLAG_DEFAULT},
19362306a36Sopenharmony_ci	{ "on",  1,  0},
19462306a36Sopenharmony_ci	{ NULL,  -1, 0}
19562306a36Sopenharmony_ci};
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic const struct bond_opt_value bond_resend_igmp_tbl[] = {
19862306a36Sopenharmony_ci	{ "off",     0,   0},
19962306a36Sopenharmony_ci	{ "maxval",  255, BOND_VALFLAG_MAX},
20062306a36Sopenharmony_ci	{ "default", 1,   BOND_VALFLAG_DEFAULT},
20162306a36Sopenharmony_ci	{ NULL,      -1,  0}
20262306a36Sopenharmony_ci};
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic const struct bond_opt_value bond_lp_interval_tbl[] = {
20562306a36Sopenharmony_ci	{ "minval",  1,       BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
20662306a36Sopenharmony_ci	{ "maxval",  INT_MAX, BOND_VALFLAG_MAX},
20762306a36Sopenharmony_ci	{ NULL,      -1,      0},
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
21162306a36Sopenharmony_ci	{ "off", 0,  0},
21262306a36Sopenharmony_ci	{ "on",  1,  BOND_VALFLAG_DEFAULT},
21362306a36Sopenharmony_ci	{ NULL,  -1, 0}
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
21762306a36Sopenharmony_ci	{ "minval",  1,     BOND_VALFLAG_MIN},
21862306a36Sopenharmony_ci	{ "maxval",  65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT},
21962306a36Sopenharmony_ci	{ NULL,      -1,    0},
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic const struct bond_opt_value bond_ad_user_port_key_tbl[] = {
22362306a36Sopenharmony_ci	{ "minval",  0,     BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
22462306a36Sopenharmony_ci	{ "maxval",  1023,  BOND_VALFLAG_MAX},
22562306a36Sopenharmony_ci	{ NULL,      -1,    0},
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic const struct bond_opt_value bond_missed_max_tbl[] = {
22962306a36Sopenharmony_ci	{ "minval",	1,	BOND_VALFLAG_MIN},
23062306a36Sopenharmony_ci	{ "maxval",	255,	BOND_VALFLAG_MAX},
23162306a36Sopenharmony_ci	{ "default",	2,	BOND_VALFLAG_DEFAULT},
23262306a36Sopenharmony_ci	{ NULL,		-1,	0},
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic const struct bond_option bond_opts[BOND_OPT_LAST] = {
23662306a36Sopenharmony_ci	[BOND_OPT_MODE] = {
23762306a36Sopenharmony_ci		.id = BOND_OPT_MODE,
23862306a36Sopenharmony_ci		.name = "mode",
23962306a36Sopenharmony_ci		.desc = "bond device mode",
24062306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_NOSLAVES | BOND_OPTFLAG_IFDOWN,
24162306a36Sopenharmony_ci		.values = bond_mode_tbl,
24262306a36Sopenharmony_ci		.set = bond_option_mode_set
24362306a36Sopenharmony_ci	},
24462306a36Sopenharmony_ci	[BOND_OPT_PACKETS_PER_SLAVE] = {
24562306a36Sopenharmony_ci		.id = BOND_OPT_PACKETS_PER_SLAVE,
24662306a36Sopenharmony_ci		.name = "packets_per_slave",
24762306a36Sopenharmony_ci		.desc = "Packets to send per slave in RR mode",
24862306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ROUNDROBIN)),
24962306a36Sopenharmony_ci		.values = bond_pps_tbl,
25062306a36Sopenharmony_ci		.set = bond_option_pps_set
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci	[BOND_OPT_XMIT_HASH] = {
25362306a36Sopenharmony_ci		.id = BOND_OPT_XMIT_HASH,
25462306a36Sopenharmony_ci		.name = "xmit_hash_policy",
25562306a36Sopenharmony_ci		.desc = "balance-xor, 802.3ad, and tlb hashing method",
25662306a36Sopenharmony_ci		.values = bond_xmit_hashtype_tbl,
25762306a36Sopenharmony_ci		.set = bond_option_xmit_hash_policy_set
25862306a36Sopenharmony_ci	},
25962306a36Sopenharmony_ci	[BOND_OPT_ARP_VALIDATE] = {
26062306a36Sopenharmony_ci		.id = BOND_OPT_ARP_VALIDATE,
26162306a36Sopenharmony_ci		.name = "arp_validate",
26262306a36Sopenharmony_ci		.desc = "validate src/dst of ARP probes",
26362306a36Sopenharmony_ci		.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
26462306a36Sopenharmony_ci			       BIT(BOND_MODE_ALB),
26562306a36Sopenharmony_ci		.values = bond_arp_validate_tbl,
26662306a36Sopenharmony_ci		.set = bond_option_arp_validate_set
26762306a36Sopenharmony_ci	},
26862306a36Sopenharmony_ci	[BOND_OPT_ARP_ALL_TARGETS] = {
26962306a36Sopenharmony_ci		.id = BOND_OPT_ARP_ALL_TARGETS,
27062306a36Sopenharmony_ci		.name = "arp_all_targets",
27162306a36Sopenharmony_ci		.desc = "fail on any/all arp targets timeout",
27262306a36Sopenharmony_ci		.values = bond_arp_all_targets_tbl,
27362306a36Sopenharmony_ci		.set = bond_option_arp_all_targets_set
27462306a36Sopenharmony_ci	},
27562306a36Sopenharmony_ci	[BOND_OPT_FAIL_OVER_MAC] = {
27662306a36Sopenharmony_ci		.id = BOND_OPT_FAIL_OVER_MAC,
27762306a36Sopenharmony_ci		.name = "fail_over_mac",
27862306a36Sopenharmony_ci		.desc = "For active-backup, do not set all slaves to the same MAC",
27962306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_NOSLAVES,
28062306a36Sopenharmony_ci		.values = bond_fail_over_mac_tbl,
28162306a36Sopenharmony_ci		.set = bond_option_fail_over_mac_set
28262306a36Sopenharmony_ci	},
28362306a36Sopenharmony_ci	[BOND_OPT_ARP_INTERVAL] = {
28462306a36Sopenharmony_ci		.id = BOND_OPT_ARP_INTERVAL,
28562306a36Sopenharmony_ci		.name = "arp_interval",
28662306a36Sopenharmony_ci		.desc = "arp interval in milliseconds",
28762306a36Sopenharmony_ci		.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
28862306a36Sopenharmony_ci			       BIT(BOND_MODE_ALB),
28962306a36Sopenharmony_ci		.values = bond_intmax_tbl,
29062306a36Sopenharmony_ci		.set = bond_option_arp_interval_set
29162306a36Sopenharmony_ci	},
29262306a36Sopenharmony_ci	[BOND_OPT_MISSED_MAX] = {
29362306a36Sopenharmony_ci		.id = BOND_OPT_MISSED_MAX,
29462306a36Sopenharmony_ci		.name = "arp_missed_max",
29562306a36Sopenharmony_ci		.desc = "Maximum number of missed ARP interval",
29662306a36Sopenharmony_ci		.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
29762306a36Sopenharmony_ci			       BIT(BOND_MODE_ALB),
29862306a36Sopenharmony_ci		.values = bond_missed_max_tbl,
29962306a36Sopenharmony_ci		.set = bond_option_missed_max_set
30062306a36Sopenharmony_ci	},
30162306a36Sopenharmony_ci	[BOND_OPT_ARP_TARGETS] = {
30262306a36Sopenharmony_ci		.id = BOND_OPT_ARP_TARGETS,
30362306a36Sopenharmony_ci		.name = "arp_ip_target",
30462306a36Sopenharmony_ci		.desc = "arp targets in n.n.n.n form",
30562306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
30662306a36Sopenharmony_ci		.set = bond_option_arp_ip_targets_set
30762306a36Sopenharmony_ci	},
30862306a36Sopenharmony_ci	[BOND_OPT_NS_TARGETS] = {
30962306a36Sopenharmony_ci		.id = BOND_OPT_NS_TARGETS,
31062306a36Sopenharmony_ci		.name = "ns_ip6_target",
31162306a36Sopenharmony_ci		.desc = "NS targets in ffff:ffff::ffff:ffff form",
31262306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
31362306a36Sopenharmony_ci		.set = bond_option_ns_ip6_targets_set
31462306a36Sopenharmony_ci	},
31562306a36Sopenharmony_ci	[BOND_OPT_DOWNDELAY] = {
31662306a36Sopenharmony_ci		.id = BOND_OPT_DOWNDELAY,
31762306a36Sopenharmony_ci		.name = "downdelay",
31862306a36Sopenharmony_ci		.desc = "Delay before considering link down, in milliseconds",
31962306a36Sopenharmony_ci		.values = bond_intmax_tbl,
32062306a36Sopenharmony_ci		.set = bond_option_downdelay_set
32162306a36Sopenharmony_ci	},
32262306a36Sopenharmony_ci	[BOND_OPT_UPDELAY] = {
32362306a36Sopenharmony_ci		.id = BOND_OPT_UPDELAY,
32462306a36Sopenharmony_ci		.name = "updelay",
32562306a36Sopenharmony_ci		.desc = "Delay before considering link up, in milliseconds",
32662306a36Sopenharmony_ci		.values = bond_intmax_tbl,
32762306a36Sopenharmony_ci		.set = bond_option_updelay_set
32862306a36Sopenharmony_ci	},
32962306a36Sopenharmony_ci	[BOND_OPT_LACP_ACTIVE] = {
33062306a36Sopenharmony_ci		.id = BOND_OPT_LACP_ACTIVE,
33162306a36Sopenharmony_ci		.name = "lacp_active",
33262306a36Sopenharmony_ci		.desc = "Send LACPDU frames with configured lacp rate or acts as speak when spoken to",
33362306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_IFDOWN,
33462306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
33562306a36Sopenharmony_ci		.values = bond_lacp_active,
33662306a36Sopenharmony_ci		.set = bond_option_lacp_active_set
33762306a36Sopenharmony_ci	},
33862306a36Sopenharmony_ci	[BOND_OPT_LACP_RATE] = {
33962306a36Sopenharmony_ci		.id = BOND_OPT_LACP_RATE,
34062306a36Sopenharmony_ci		.name = "lacp_rate",
34162306a36Sopenharmony_ci		.desc = "LACPDU tx rate to request from 802.3ad partner",
34262306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_IFDOWN,
34362306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
34462306a36Sopenharmony_ci		.values = bond_lacp_rate_tbl,
34562306a36Sopenharmony_ci		.set = bond_option_lacp_rate_set
34662306a36Sopenharmony_ci	},
34762306a36Sopenharmony_ci	[BOND_OPT_MINLINKS] = {
34862306a36Sopenharmony_ci		.id = BOND_OPT_MINLINKS,
34962306a36Sopenharmony_ci		.name = "min_links",
35062306a36Sopenharmony_ci		.desc = "Minimum number of available links before turning on carrier",
35162306a36Sopenharmony_ci		.values = bond_intmax_tbl,
35262306a36Sopenharmony_ci		.set = bond_option_min_links_set
35362306a36Sopenharmony_ci	},
35462306a36Sopenharmony_ci	[BOND_OPT_AD_SELECT] = {
35562306a36Sopenharmony_ci		.id = BOND_OPT_AD_SELECT,
35662306a36Sopenharmony_ci		.name = "ad_select",
35762306a36Sopenharmony_ci		.desc = "803.ad aggregation selection logic",
35862306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_IFDOWN,
35962306a36Sopenharmony_ci		.values = bond_ad_select_tbl,
36062306a36Sopenharmony_ci		.set = bond_option_ad_select_set
36162306a36Sopenharmony_ci	},
36262306a36Sopenharmony_ci	[BOND_OPT_NUM_PEER_NOTIF] = {
36362306a36Sopenharmony_ci		.id = BOND_OPT_NUM_PEER_NOTIF,
36462306a36Sopenharmony_ci		.name = "num_unsol_na",
36562306a36Sopenharmony_ci		.desc = "Number of peer notifications to send on failover event",
36662306a36Sopenharmony_ci		.values = bond_num_peer_notif_tbl,
36762306a36Sopenharmony_ci		.set = bond_option_num_peer_notif_set
36862306a36Sopenharmony_ci	},
36962306a36Sopenharmony_ci	[BOND_OPT_MIIMON] = {
37062306a36Sopenharmony_ci		.id = BOND_OPT_MIIMON,
37162306a36Sopenharmony_ci		.name = "miimon",
37262306a36Sopenharmony_ci		.desc = "Link check interval in milliseconds",
37362306a36Sopenharmony_ci		.values = bond_intmax_tbl,
37462306a36Sopenharmony_ci		.set = bond_option_miimon_set
37562306a36Sopenharmony_ci	},
37662306a36Sopenharmony_ci	[BOND_OPT_PRIO] = {
37762306a36Sopenharmony_ci		.id = BOND_OPT_PRIO,
37862306a36Sopenharmony_ci		.name = "prio",
37962306a36Sopenharmony_ci		.desc = "Link priority for failover re-selection",
38062306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
38162306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
38262306a36Sopenharmony_ci						BIT(BOND_MODE_TLB) |
38362306a36Sopenharmony_ci						BIT(BOND_MODE_ALB)),
38462306a36Sopenharmony_ci		.set = bond_option_prio_set
38562306a36Sopenharmony_ci	},
38662306a36Sopenharmony_ci	[BOND_OPT_PRIMARY] = {
38762306a36Sopenharmony_ci		.id = BOND_OPT_PRIMARY,
38862306a36Sopenharmony_ci		.name = "primary",
38962306a36Sopenharmony_ci		.desc = "Primary network device to use",
39062306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
39162306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
39262306a36Sopenharmony_ci						BIT(BOND_MODE_TLB) |
39362306a36Sopenharmony_ci						BIT(BOND_MODE_ALB)),
39462306a36Sopenharmony_ci		.set = bond_option_primary_set
39562306a36Sopenharmony_ci	},
39662306a36Sopenharmony_ci	[BOND_OPT_PRIMARY_RESELECT] = {
39762306a36Sopenharmony_ci		.id = BOND_OPT_PRIMARY_RESELECT,
39862306a36Sopenharmony_ci		.name = "primary_reselect",
39962306a36Sopenharmony_ci		.desc = "Reselect primary slave once it comes up",
40062306a36Sopenharmony_ci		.values = bond_primary_reselect_tbl,
40162306a36Sopenharmony_ci		.set = bond_option_primary_reselect_set
40262306a36Sopenharmony_ci	},
40362306a36Sopenharmony_ci	[BOND_OPT_USE_CARRIER] = {
40462306a36Sopenharmony_ci		.id = BOND_OPT_USE_CARRIER,
40562306a36Sopenharmony_ci		.name = "use_carrier",
40662306a36Sopenharmony_ci		.desc = "Use netif_carrier_ok (vs MII ioctls) in miimon",
40762306a36Sopenharmony_ci		.values = bond_use_carrier_tbl,
40862306a36Sopenharmony_ci		.set = bond_option_use_carrier_set
40962306a36Sopenharmony_ci	},
41062306a36Sopenharmony_ci	[BOND_OPT_ACTIVE_SLAVE] = {
41162306a36Sopenharmony_ci		.id = BOND_OPT_ACTIVE_SLAVE,
41262306a36Sopenharmony_ci		.name = "active_slave",
41362306a36Sopenharmony_ci		.desc = "Currently active slave",
41462306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
41562306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
41662306a36Sopenharmony_ci						BIT(BOND_MODE_TLB) |
41762306a36Sopenharmony_ci						BIT(BOND_MODE_ALB)),
41862306a36Sopenharmony_ci		.set = bond_option_active_slave_set
41962306a36Sopenharmony_ci	},
42062306a36Sopenharmony_ci	[BOND_OPT_QUEUE_ID] = {
42162306a36Sopenharmony_ci		.id = BOND_OPT_QUEUE_ID,
42262306a36Sopenharmony_ci		.name = "queue_id",
42362306a36Sopenharmony_ci		.desc = "Set queue id of a slave",
42462306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
42562306a36Sopenharmony_ci		.set = bond_option_queue_id_set
42662306a36Sopenharmony_ci	},
42762306a36Sopenharmony_ci	[BOND_OPT_ALL_SLAVES_ACTIVE] = {
42862306a36Sopenharmony_ci		.id = BOND_OPT_ALL_SLAVES_ACTIVE,
42962306a36Sopenharmony_ci		.name = "all_slaves_active",
43062306a36Sopenharmony_ci		.desc = "Keep all frames received on an interface by setting active flag for all slaves",
43162306a36Sopenharmony_ci		.values = bond_all_slaves_active_tbl,
43262306a36Sopenharmony_ci		.set = bond_option_all_slaves_active_set
43362306a36Sopenharmony_ci	},
43462306a36Sopenharmony_ci	[BOND_OPT_RESEND_IGMP] = {
43562306a36Sopenharmony_ci		.id = BOND_OPT_RESEND_IGMP,
43662306a36Sopenharmony_ci		.name = "resend_igmp",
43762306a36Sopenharmony_ci		.desc = "Number of IGMP membership reports to send on link failure",
43862306a36Sopenharmony_ci		.values = bond_resend_igmp_tbl,
43962306a36Sopenharmony_ci		.set = bond_option_resend_igmp_set
44062306a36Sopenharmony_ci	},
44162306a36Sopenharmony_ci	[BOND_OPT_LP_INTERVAL] = {
44262306a36Sopenharmony_ci		.id = BOND_OPT_LP_INTERVAL,
44362306a36Sopenharmony_ci		.name = "lp_interval",
44462306a36Sopenharmony_ci		.desc = "The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch",
44562306a36Sopenharmony_ci		.values = bond_lp_interval_tbl,
44662306a36Sopenharmony_ci		.set = bond_option_lp_interval_set
44762306a36Sopenharmony_ci	},
44862306a36Sopenharmony_ci	[BOND_OPT_SLAVES] = {
44962306a36Sopenharmony_ci		.id = BOND_OPT_SLAVES,
45062306a36Sopenharmony_ci		.name = "slaves",
45162306a36Sopenharmony_ci		.desc = "Slave membership management",
45262306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
45362306a36Sopenharmony_ci		.set = bond_option_slaves_set
45462306a36Sopenharmony_ci	},
45562306a36Sopenharmony_ci	[BOND_OPT_TLB_DYNAMIC_LB] = {
45662306a36Sopenharmony_ci		.id = BOND_OPT_TLB_DYNAMIC_LB,
45762306a36Sopenharmony_ci		.name = "tlb_dynamic_lb",
45862306a36Sopenharmony_ci		.desc = "Enable dynamic flow shuffling",
45962306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_TLB) | BIT(BOND_MODE_ALB)),
46062306a36Sopenharmony_ci		.values = bond_tlb_dynamic_lb_tbl,
46162306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_IFDOWN,
46262306a36Sopenharmony_ci		.set = bond_option_tlb_dynamic_lb_set,
46362306a36Sopenharmony_ci	},
46462306a36Sopenharmony_ci	[BOND_OPT_AD_ACTOR_SYS_PRIO] = {
46562306a36Sopenharmony_ci		.id = BOND_OPT_AD_ACTOR_SYS_PRIO,
46662306a36Sopenharmony_ci		.name = "ad_actor_sys_prio",
46762306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
46862306a36Sopenharmony_ci		.values = bond_ad_actor_sys_prio_tbl,
46962306a36Sopenharmony_ci		.set = bond_option_ad_actor_sys_prio_set,
47062306a36Sopenharmony_ci	},
47162306a36Sopenharmony_ci	[BOND_OPT_AD_ACTOR_SYSTEM] = {
47262306a36Sopenharmony_ci		.id = BOND_OPT_AD_ACTOR_SYSTEM,
47362306a36Sopenharmony_ci		.name = "ad_actor_system",
47462306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
47562306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_RAWVAL,
47662306a36Sopenharmony_ci		.set = bond_option_ad_actor_system_set,
47762306a36Sopenharmony_ci	},
47862306a36Sopenharmony_ci	[BOND_OPT_AD_USER_PORT_KEY] = {
47962306a36Sopenharmony_ci		.id = BOND_OPT_AD_USER_PORT_KEY,
48062306a36Sopenharmony_ci		.name = "ad_user_port_key",
48162306a36Sopenharmony_ci		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
48262306a36Sopenharmony_ci		.flags = BOND_OPTFLAG_IFDOWN,
48362306a36Sopenharmony_ci		.values = bond_ad_user_port_key_tbl,
48462306a36Sopenharmony_ci		.set = bond_option_ad_user_port_key_set,
48562306a36Sopenharmony_ci	},
48662306a36Sopenharmony_ci	[BOND_OPT_NUM_PEER_NOTIF_ALIAS] = {
48762306a36Sopenharmony_ci		.id = BOND_OPT_NUM_PEER_NOTIF_ALIAS,
48862306a36Sopenharmony_ci		.name = "num_grat_arp",
48962306a36Sopenharmony_ci		.desc = "Number of peer notifications to send on failover event",
49062306a36Sopenharmony_ci		.values = bond_num_peer_notif_tbl,
49162306a36Sopenharmony_ci		.set = bond_option_num_peer_notif_set
49262306a36Sopenharmony_ci	},
49362306a36Sopenharmony_ci	[BOND_OPT_PEER_NOTIF_DELAY] = {
49462306a36Sopenharmony_ci		.id = BOND_OPT_PEER_NOTIF_DELAY,
49562306a36Sopenharmony_ci		.name = "peer_notif_delay",
49662306a36Sopenharmony_ci		.desc = "Delay between each peer notification on failover event, in milliseconds",
49762306a36Sopenharmony_ci		.values = bond_peer_notif_delay_tbl,
49862306a36Sopenharmony_ci		.set = bond_option_peer_notif_delay_set
49962306a36Sopenharmony_ci	}
50062306a36Sopenharmony_ci};
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/* Searches for an option by name */
50362306a36Sopenharmony_ciconst struct bond_option *bond_opt_get_by_name(const char *name)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	const struct bond_option *opt;
50662306a36Sopenharmony_ci	int option;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	for (option = 0; option < BOND_OPT_LAST; option++) {
50962306a36Sopenharmony_ci		opt = bond_opt_get(option);
51062306a36Sopenharmony_ci		if (opt && !strcmp(opt->name, name))
51162306a36Sopenharmony_ci			return opt;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return NULL;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci/* Searches for a value in opt's values[] table */
51862306a36Sopenharmony_ciconst struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	const struct bond_option *opt;
52162306a36Sopenharmony_ci	int i;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	opt = bond_opt_get(option);
52462306a36Sopenharmony_ci	if (WARN_ON(!opt))
52562306a36Sopenharmony_ci		return NULL;
52662306a36Sopenharmony_ci	for (i = 0; opt->values && opt->values[i].string; i++)
52762306a36Sopenharmony_ci		if (opt->values[i].value == val)
52862306a36Sopenharmony_ci			return &opt->values[i];
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	return NULL;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci/* Searches for a value in opt's values[] table which matches the flagmask */
53462306a36Sopenharmony_cistatic const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
53562306a36Sopenharmony_ci						       u32 flagmask)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	int i;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	for (i = 0; opt->values && opt->values[i].string; i++)
54062306a36Sopenharmony_ci		if (opt->values[i].flags & flagmask)
54162306a36Sopenharmony_ci			return &opt->values[i];
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	return NULL;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/* If maxval is missing then there's no range to check. In case minval is
54762306a36Sopenharmony_ci * missing then it's considered to be 0.
54862306a36Sopenharmony_ci */
54962306a36Sopenharmony_cistatic bool bond_opt_check_range(const struct bond_option *opt, u64 val)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	const struct bond_opt_value *minval, *maxval;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
55462306a36Sopenharmony_ci	maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
55562306a36Sopenharmony_ci	if (!maxval || (minval && val < minval->value) || val > maxval->value)
55662306a36Sopenharmony_ci		return false;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	return true;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci/**
56262306a36Sopenharmony_ci * bond_opt_parse - parse option value
56362306a36Sopenharmony_ci * @opt: the option to parse against
56462306a36Sopenharmony_ci * @val: value to parse
56562306a36Sopenharmony_ci *
56662306a36Sopenharmony_ci * This function tries to extract the value from @val and check if it's
56762306a36Sopenharmony_ci * a possible match for the option and returns NULL if a match isn't found,
56862306a36Sopenharmony_ci * or the struct_opt_value that matched. It also strips the new line from
56962306a36Sopenharmony_ci * @val->string if it's present.
57062306a36Sopenharmony_ci */
57162306a36Sopenharmony_ciconst struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
57262306a36Sopenharmony_ci					    struct bond_opt_value *val)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, };
57562306a36Sopenharmony_ci	const struct bond_opt_value *tbl;
57662306a36Sopenharmony_ci	const struct bond_opt_value *ret = NULL;
57762306a36Sopenharmony_ci	bool checkval;
57862306a36Sopenharmony_ci	int i, rv;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	/* No parsing if the option wants a raw val */
58162306a36Sopenharmony_ci	if (opt->flags & BOND_OPTFLAG_RAWVAL)
58262306a36Sopenharmony_ci		return val;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	tbl = opt->values;
58562306a36Sopenharmony_ci	if (!tbl)
58662306a36Sopenharmony_ci		goto out;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	/* ULLONG_MAX is used to bypass string processing */
58962306a36Sopenharmony_ci	checkval = val->value != ULLONG_MAX;
59062306a36Sopenharmony_ci	if (!checkval) {
59162306a36Sopenharmony_ci		if (!val->string)
59262306a36Sopenharmony_ci			goto out;
59362306a36Sopenharmony_ci		p = strchr(val->string, '\n');
59462306a36Sopenharmony_ci		if (p)
59562306a36Sopenharmony_ci			*p = '\0';
59662306a36Sopenharmony_ci		for (p = val->string; *p; p++)
59762306a36Sopenharmony_ci			if (!(isdigit(*p) || isspace(*p)))
59862306a36Sopenharmony_ci				break;
59962306a36Sopenharmony_ci		/* The following code extracts the string to match or the value
60062306a36Sopenharmony_ci		 * and sets checkval appropriately
60162306a36Sopenharmony_ci		 */
60262306a36Sopenharmony_ci		if (*p) {
60362306a36Sopenharmony_ci			rv = sscanf(val->string, "%32s", valstr);
60462306a36Sopenharmony_ci		} else {
60562306a36Sopenharmony_ci			rv = sscanf(val->string, "%llu", &val->value);
60662306a36Sopenharmony_ci			checkval = true;
60762306a36Sopenharmony_ci		}
60862306a36Sopenharmony_ci		if (!rv)
60962306a36Sopenharmony_ci			goto out;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	for (i = 0; tbl[i].string; i++) {
61362306a36Sopenharmony_ci		/* Check for exact match */
61462306a36Sopenharmony_ci		if (checkval) {
61562306a36Sopenharmony_ci			if (val->value == tbl[i].value)
61662306a36Sopenharmony_ci				ret = &tbl[i];
61762306a36Sopenharmony_ci		} else {
61862306a36Sopenharmony_ci			if (!strcmp(valstr, "default") &&
61962306a36Sopenharmony_ci			    (tbl[i].flags & BOND_VALFLAG_DEFAULT))
62062306a36Sopenharmony_ci				ret = &tbl[i];
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci			if (!strcmp(valstr, tbl[i].string))
62362306a36Sopenharmony_ci				ret = &tbl[i];
62462306a36Sopenharmony_ci		}
62562306a36Sopenharmony_ci		/* Found an exact match */
62662306a36Sopenharmony_ci		if (ret)
62762306a36Sopenharmony_ci			goto out;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci	/* Possible range match */
63062306a36Sopenharmony_ci	if (checkval && bond_opt_check_range(opt, val->value))
63162306a36Sopenharmony_ci		ret = val;
63262306a36Sopenharmony_ciout:
63362306a36Sopenharmony_ci	return ret;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/* Check opt's dependencies against bond mode and currently set options */
63762306a36Sopenharmony_cistatic int bond_opt_check_deps(struct bonding *bond,
63862306a36Sopenharmony_ci			       const struct bond_option *opt)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct bond_params *params = &bond->params;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (test_bit(params->mode, &opt->unsuppmodes))
64362306a36Sopenharmony_ci		return -EACCES;
64462306a36Sopenharmony_ci	if ((opt->flags & BOND_OPTFLAG_NOSLAVES) && bond_has_slaves(bond))
64562306a36Sopenharmony_ci		return -ENOTEMPTY;
64662306a36Sopenharmony_ci	if ((opt->flags & BOND_OPTFLAG_IFDOWN) && (bond->dev->flags & IFF_UP))
64762306a36Sopenharmony_ci		return -EBUSY;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	return 0;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic void bond_opt_dep_print(struct bonding *bond,
65362306a36Sopenharmony_ci			       const struct bond_option *opt,
65462306a36Sopenharmony_ci			       struct nlattr *bad_attr,
65562306a36Sopenharmony_ci			       struct netlink_ext_ack *extack)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	const struct bond_opt_value *modeval;
65862306a36Sopenharmony_ci	struct bond_params *params;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	params = &bond->params;
66162306a36Sopenharmony_ci	modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode);
66262306a36Sopenharmony_ci	if (test_bit(params->mode, &opt->unsuppmodes)) {
66362306a36Sopenharmony_ci		netdev_err(bond->dev, "option %s: mode dependency failed, not supported in mode %s(%llu)\n",
66462306a36Sopenharmony_ci			   opt->name, modeval->string, modeval->value);
66562306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, bad_attr,
66662306a36Sopenharmony_ci				    "option not supported in mode");
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci}
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_cistatic void bond_opt_error_interpret(struct bonding *bond,
67162306a36Sopenharmony_ci				     const struct bond_option *opt,
67262306a36Sopenharmony_ci				     int error, const struct bond_opt_value *val,
67362306a36Sopenharmony_ci				     struct nlattr *bad_attr,
67462306a36Sopenharmony_ci				     struct netlink_ext_ack *extack)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	const struct bond_opt_value *minval, *maxval;
67762306a36Sopenharmony_ci	char *p;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	switch (error) {
68062306a36Sopenharmony_ci	case -EINVAL:
68162306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, bad_attr, "invalid option value");
68262306a36Sopenharmony_ci		if (val) {
68362306a36Sopenharmony_ci			if (val->string) {
68462306a36Sopenharmony_ci				/* sometimes RAWVAL opts may have new lines */
68562306a36Sopenharmony_ci				p = strchr(val->string, '\n');
68662306a36Sopenharmony_ci				if (p)
68762306a36Sopenharmony_ci					*p = '\0';
68862306a36Sopenharmony_ci				netdev_err(bond->dev, "option %s: invalid value (%s)\n",
68962306a36Sopenharmony_ci					   opt->name, val->string);
69062306a36Sopenharmony_ci			} else {
69162306a36Sopenharmony_ci				netdev_err(bond->dev, "option %s: invalid value (%llu)\n",
69262306a36Sopenharmony_ci					   opt->name, val->value);
69362306a36Sopenharmony_ci			}
69462306a36Sopenharmony_ci		}
69562306a36Sopenharmony_ci		minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
69662306a36Sopenharmony_ci		maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
69762306a36Sopenharmony_ci		if (!maxval)
69862306a36Sopenharmony_ci			break;
69962306a36Sopenharmony_ci		netdev_err(bond->dev, "option %s: allowed values %llu - %llu\n",
70062306a36Sopenharmony_ci			   opt->name, minval ? minval->value : 0, maxval->value);
70162306a36Sopenharmony_ci		break;
70262306a36Sopenharmony_ci	case -EACCES:
70362306a36Sopenharmony_ci		bond_opt_dep_print(bond, opt, bad_attr, extack);
70462306a36Sopenharmony_ci		break;
70562306a36Sopenharmony_ci	case -ENOTEMPTY:
70662306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, bad_attr,
70762306a36Sopenharmony_ci				    "unable to set option because the bond device has slaves");
70862306a36Sopenharmony_ci		netdev_err(bond->dev, "option %s: unable to set because the bond device has slaves\n",
70962306a36Sopenharmony_ci			   opt->name);
71062306a36Sopenharmony_ci		break;
71162306a36Sopenharmony_ci	case -EBUSY:
71262306a36Sopenharmony_ci		NL_SET_ERR_MSG_ATTR(extack, bad_attr,
71362306a36Sopenharmony_ci				    "unable to set option because the bond is up");
71462306a36Sopenharmony_ci		netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n",
71562306a36Sopenharmony_ci			   opt->name);
71662306a36Sopenharmony_ci		break;
71762306a36Sopenharmony_ci	case -ENODEV:
71862306a36Sopenharmony_ci		if (val && val->string) {
71962306a36Sopenharmony_ci			p = strchr(val->string, '\n');
72062306a36Sopenharmony_ci			if (p)
72162306a36Sopenharmony_ci				*p = '\0';
72262306a36Sopenharmony_ci			netdev_err(bond->dev, "option %s: interface %s does not exist!\n",
72362306a36Sopenharmony_ci				   opt->name, val->string);
72462306a36Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(extack, bad_attr,
72562306a36Sopenharmony_ci					    "interface does not exist");
72662306a36Sopenharmony_ci		}
72762306a36Sopenharmony_ci		break;
72862306a36Sopenharmony_ci	default:
72962306a36Sopenharmony_ci		break;
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci}
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci/**
73462306a36Sopenharmony_ci * __bond_opt_set - set a bonding option
73562306a36Sopenharmony_ci * @bond: target bond device
73662306a36Sopenharmony_ci * @option: option to set
73762306a36Sopenharmony_ci * @val: value to set it to
73862306a36Sopenharmony_ci * @bad_attr: netlink attribue that caused the error
73962306a36Sopenharmony_ci * @extack: extended netlink error structure, used when an error message
74062306a36Sopenharmony_ci *          needs to be returned to the caller via netlink
74162306a36Sopenharmony_ci *
74262306a36Sopenharmony_ci * This function is used to change the bond's option value, it can be
74362306a36Sopenharmony_ci * used for both enabling/changing an option and for disabling it. RTNL lock
74462306a36Sopenharmony_ci * must be obtained before calling this function.
74562306a36Sopenharmony_ci */
74662306a36Sopenharmony_ciint __bond_opt_set(struct bonding *bond,
74762306a36Sopenharmony_ci		   unsigned int option, struct bond_opt_value *val,
74862306a36Sopenharmony_ci		   struct nlattr *bad_attr, struct netlink_ext_ack *extack)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	const struct bond_opt_value *retval = NULL;
75162306a36Sopenharmony_ci	const struct bond_option *opt;
75262306a36Sopenharmony_ci	int ret = -ENOENT;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	ASSERT_RTNL();
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	opt = bond_opt_get(option);
75762306a36Sopenharmony_ci	if (WARN_ON(!val) || WARN_ON(!opt))
75862306a36Sopenharmony_ci		goto out;
75962306a36Sopenharmony_ci	ret = bond_opt_check_deps(bond, opt);
76062306a36Sopenharmony_ci	if (ret)
76162306a36Sopenharmony_ci		goto out;
76262306a36Sopenharmony_ci	retval = bond_opt_parse(opt, val);
76362306a36Sopenharmony_ci	if (!retval) {
76462306a36Sopenharmony_ci		ret = -EINVAL;
76562306a36Sopenharmony_ci		goto out;
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci	ret = opt->set(bond, retval);
76862306a36Sopenharmony_ciout:
76962306a36Sopenharmony_ci	if (ret)
77062306a36Sopenharmony_ci		bond_opt_error_interpret(bond, opt, ret, val, bad_attr, extack);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	return ret;
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci/**
77562306a36Sopenharmony_ci * __bond_opt_set_notify - set a bonding option
77662306a36Sopenharmony_ci * @bond: target bond device
77762306a36Sopenharmony_ci * @option: option to set
77862306a36Sopenharmony_ci * @val: value to set it to
77962306a36Sopenharmony_ci *
78062306a36Sopenharmony_ci * This function is used to change the bond's option value and trigger
78162306a36Sopenharmony_ci * a notification to user sapce. It can be used for both enabling/changing
78262306a36Sopenharmony_ci * an option and for disabling it. RTNL lock must be obtained before calling
78362306a36Sopenharmony_ci * this function.
78462306a36Sopenharmony_ci */
78562306a36Sopenharmony_ciint __bond_opt_set_notify(struct bonding *bond,
78662306a36Sopenharmony_ci			  unsigned int option, struct bond_opt_value *val)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	int ret;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	ASSERT_RTNL();
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	ret = __bond_opt_set(bond, option, val, NULL, NULL);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if (!ret && (bond->dev->reg_state == NETREG_REGISTERED))
79562306a36Sopenharmony_ci		call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	return ret;
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci/**
80162306a36Sopenharmony_ci * bond_opt_tryset_rtnl - try to acquire rtnl and call __bond_opt_set
80262306a36Sopenharmony_ci * @bond: target bond device
80362306a36Sopenharmony_ci * @option: option to set
80462306a36Sopenharmony_ci * @buf: value to set it to
80562306a36Sopenharmony_ci *
80662306a36Sopenharmony_ci * This function tries to acquire RTNL without blocking and if successful
80762306a36Sopenharmony_ci * calls __bond_opt_set. It is mainly used for sysfs option manipulation.
80862306a36Sopenharmony_ci */
80962306a36Sopenharmony_ciint bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	struct bond_opt_value optval;
81262306a36Sopenharmony_ci	int ret;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	if (!rtnl_trylock())
81562306a36Sopenharmony_ci		return restart_syscall();
81662306a36Sopenharmony_ci	bond_opt_initstr(&optval, buf);
81762306a36Sopenharmony_ci	ret = __bond_opt_set_notify(bond, option, &optval);
81862306a36Sopenharmony_ci	rtnl_unlock();
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	return ret;
82162306a36Sopenharmony_ci}
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci/**
82462306a36Sopenharmony_ci * bond_opt_get - get a pointer to an option
82562306a36Sopenharmony_ci * @option: option for which to return a pointer
82662306a36Sopenharmony_ci *
82762306a36Sopenharmony_ci * This function checks if option is valid and if so returns a pointer
82862306a36Sopenharmony_ci * to its entry in the bond_opts[] option array.
82962306a36Sopenharmony_ci */
83062306a36Sopenharmony_ciconst struct bond_option *bond_opt_get(unsigned int option)
83162306a36Sopenharmony_ci{
83262306a36Sopenharmony_ci	if (!BOND_OPT_VALID(option))
83362306a36Sopenharmony_ci		return NULL;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	return &bond_opts[option];
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic bool bond_set_xfrm_features(struct bonding *bond)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_XFRM_OFFLOAD))
84162306a36Sopenharmony_ci		return false;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
84462306a36Sopenharmony_ci		bond->dev->wanted_features |= BOND_XFRM_FEATURES;
84562306a36Sopenharmony_ci	else
84662306a36Sopenharmony_ci		bond->dev->wanted_features &= ~BOND_XFRM_FEATURES;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return true;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic int bond_option_mode_set(struct bonding *bond,
85262306a36Sopenharmony_ci				const struct bond_opt_value *newval)
85362306a36Sopenharmony_ci{
85462306a36Sopenharmony_ci	if (!bond_mode_uses_arp(newval->value)) {
85562306a36Sopenharmony_ci		if (bond->params.arp_interval) {
85662306a36Sopenharmony_ci			netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n",
85762306a36Sopenharmony_ci				   newval->string);
85862306a36Sopenharmony_ci			/* disable arp monitoring */
85962306a36Sopenharmony_ci			bond->params.arp_interval = 0;
86062306a36Sopenharmony_ci		}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci		if (!bond->params.miimon) {
86362306a36Sopenharmony_ci			/* set miimon to default value */
86462306a36Sopenharmony_ci			bond->params.miimon = BOND_DEFAULT_MIIMON;
86562306a36Sopenharmony_ci			netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n",
86662306a36Sopenharmony_ci				   bond->params.miimon);
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (newval->value == BOND_MODE_ALB)
87162306a36Sopenharmony_ci		bond->params.tlb_dynamic_lb = 1;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	/* don't cache arp_validate between modes */
87462306a36Sopenharmony_ci	bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
87562306a36Sopenharmony_ci	bond->params.mode = newval->value;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	if (bond->dev->reg_state == NETREG_REGISTERED) {
87862306a36Sopenharmony_ci		bool update = false;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci		update |= bond_set_xfrm_features(bond);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci		if (update)
88362306a36Sopenharmony_ci			netdev_update_features(bond->dev);
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	bond_xdp_set_features(bond->dev);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	return 0;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic int bond_option_active_slave_set(struct bonding *bond,
89262306a36Sopenharmony_ci					const struct bond_opt_value *newval)
89362306a36Sopenharmony_ci{
89462306a36Sopenharmony_ci	char ifname[IFNAMSIZ] = { 0, };
89562306a36Sopenharmony_ci	struct net_device *slave_dev;
89662306a36Sopenharmony_ci	int ret = 0;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	sscanf(newval->string, "%15s", ifname); /* IFNAMSIZ */
89962306a36Sopenharmony_ci	if (!strlen(ifname) || newval->string[0] == '\n') {
90062306a36Sopenharmony_ci		slave_dev = NULL;
90162306a36Sopenharmony_ci	} else {
90262306a36Sopenharmony_ci		slave_dev = __dev_get_by_name(dev_net(bond->dev), ifname);
90362306a36Sopenharmony_ci		if (!slave_dev)
90462306a36Sopenharmony_ci			return -ENODEV;
90562306a36Sopenharmony_ci	}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	if (slave_dev) {
90862306a36Sopenharmony_ci		if (!netif_is_bond_slave(slave_dev)) {
90962306a36Sopenharmony_ci			slave_err(bond->dev, slave_dev, "Device is not bonding slave\n");
91062306a36Sopenharmony_ci			return -EINVAL;
91162306a36Sopenharmony_ci		}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci		if (bond->dev != netdev_master_upper_dev_get(slave_dev)) {
91462306a36Sopenharmony_ci			slave_err(bond->dev, slave_dev, "Device is not our slave\n");
91562306a36Sopenharmony_ci			return -EINVAL;
91662306a36Sopenharmony_ci		}
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	block_netpoll_tx();
92062306a36Sopenharmony_ci	/* check to see if we are clearing active */
92162306a36Sopenharmony_ci	if (!slave_dev) {
92262306a36Sopenharmony_ci		netdev_dbg(bond->dev, "Clearing current active slave\n");
92362306a36Sopenharmony_ci		RCU_INIT_POINTER(bond->curr_active_slave, NULL);
92462306a36Sopenharmony_ci		bond_select_active_slave(bond);
92562306a36Sopenharmony_ci	} else {
92662306a36Sopenharmony_ci		struct slave *old_active = rtnl_dereference(bond->curr_active_slave);
92762306a36Sopenharmony_ci		struct slave *new_active = bond_slave_get_rtnl(slave_dev);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		BUG_ON(!new_active);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		if (new_active == old_active) {
93262306a36Sopenharmony_ci			/* do nothing */
93362306a36Sopenharmony_ci			slave_dbg(bond->dev, new_active->dev, "is already the current active slave\n");
93462306a36Sopenharmony_ci		} else {
93562306a36Sopenharmony_ci			if (old_active && (new_active->link == BOND_LINK_UP) &&
93662306a36Sopenharmony_ci			    bond_slave_is_up(new_active)) {
93762306a36Sopenharmony_ci				slave_dbg(bond->dev, new_active->dev, "Setting as active slave\n");
93862306a36Sopenharmony_ci				bond_change_active_slave(bond, new_active);
93962306a36Sopenharmony_ci			} else {
94062306a36Sopenharmony_ci				slave_err(bond->dev, new_active->dev, "Could not set as active slave; either %s is down or the link is down\n",
94162306a36Sopenharmony_ci					  new_active->dev->name);
94262306a36Sopenharmony_ci				ret = -EINVAL;
94362306a36Sopenharmony_ci			}
94462306a36Sopenharmony_ci		}
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci	unblock_netpoll_tx();
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	return ret;
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci/* There are two tricky bits here.  First, if MII monitoring is activated, then
95262306a36Sopenharmony_ci * we must disable ARP monitoring.  Second, if the timer isn't running, we must
95362306a36Sopenharmony_ci * start it.
95462306a36Sopenharmony_ci */
95562306a36Sopenharmony_cistatic int bond_option_miimon_set(struct bonding *bond,
95662306a36Sopenharmony_ci				  const struct bond_opt_value *newval)
95762306a36Sopenharmony_ci{
95862306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting MII monitoring interval to %llu\n",
95962306a36Sopenharmony_ci		   newval->value);
96062306a36Sopenharmony_ci	bond->params.miimon = newval->value;
96162306a36Sopenharmony_ci	if (bond->params.updelay)
96262306a36Sopenharmony_ci		netdev_dbg(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n",
96362306a36Sopenharmony_ci			   bond->params.updelay * bond->params.miimon);
96462306a36Sopenharmony_ci	if (bond->params.downdelay)
96562306a36Sopenharmony_ci		netdev_dbg(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
96662306a36Sopenharmony_ci			   bond->params.downdelay * bond->params.miimon);
96762306a36Sopenharmony_ci	if (bond->params.peer_notif_delay)
96862306a36Sopenharmony_ci		netdev_dbg(bond->dev, "Note: Updating peer_notif_delay (to %d) since it is a multiple of the miimon value\n",
96962306a36Sopenharmony_ci			   bond->params.peer_notif_delay * bond->params.miimon);
97062306a36Sopenharmony_ci	if (newval->value && bond->params.arp_interval) {
97162306a36Sopenharmony_ci		netdev_dbg(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n");
97262306a36Sopenharmony_ci		bond->params.arp_interval = 0;
97362306a36Sopenharmony_ci		if (bond->params.arp_validate)
97462306a36Sopenharmony_ci			bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
97562306a36Sopenharmony_ci	}
97662306a36Sopenharmony_ci	if (bond->dev->flags & IFF_UP) {
97762306a36Sopenharmony_ci		/* If the interface is up, we may need to fire off
97862306a36Sopenharmony_ci		 * the MII timer. If the interface is down, the
97962306a36Sopenharmony_ci		 * timer will get fired off when the open function
98062306a36Sopenharmony_ci		 * is called.
98162306a36Sopenharmony_ci		 */
98262306a36Sopenharmony_ci		if (!newval->value) {
98362306a36Sopenharmony_ci			cancel_delayed_work_sync(&bond->mii_work);
98462306a36Sopenharmony_ci		} else {
98562306a36Sopenharmony_ci			cancel_delayed_work_sync(&bond->arp_work);
98662306a36Sopenharmony_ci			queue_delayed_work(bond->wq, &bond->mii_work, 0);
98762306a36Sopenharmony_ci		}
98862306a36Sopenharmony_ci	}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	return 0;
99162306a36Sopenharmony_ci}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci/* Set up, down and peer notification delays. These must be multiples
99462306a36Sopenharmony_ci * of the MII monitoring value, and are stored internally as the
99562306a36Sopenharmony_ci * multiplier. Thus, we must translate to MS for the real world.
99662306a36Sopenharmony_ci */
99762306a36Sopenharmony_cistatic int _bond_option_delay_set(struct bonding *bond,
99862306a36Sopenharmony_ci				  const struct bond_opt_value *newval,
99962306a36Sopenharmony_ci				  const char *name,
100062306a36Sopenharmony_ci				  int *target)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	int value = newval->value;
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	if (!bond->params.miimon) {
100562306a36Sopenharmony_ci		netdev_err(bond->dev, "Unable to set %s as MII monitoring is disabled\n",
100662306a36Sopenharmony_ci			   name);
100762306a36Sopenharmony_ci		return -EPERM;
100862306a36Sopenharmony_ci	}
100962306a36Sopenharmony_ci	if ((value % bond->params.miimon) != 0) {
101062306a36Sopenharmony_ci		netdev_warn(bond->dev,
101162306a36Sopenharmony_ci			    "%s (%d) is not a multiple of miimon (%d), value rounded to %d ms\n",
101262306a36Sopenharmony_ci			    name,
101362306a36Sopenharmony_ci			    value, bond->params.miimon,
101462306a36Sopenharmony_ci			    (value / bond->params.miimon) *
101562306a36Sopenharmony_ci			    bond->params.miimon);
101662306a36Sopenharmony_ci	}
101762306a36Sopenharmony_ci	*target = value / bond->params.miimon;
101862306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting %s to %d\n",
101962306a36Sopenharmony_ci		   name,
102062306a36Sopenharmony_ci		   *target * bond->params.miimon);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	return 0;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cistatic int bond_option_updelay_set(struct bonding *bond,
102662306a36Sopenharmony_ci				   const struct bond_opt_value *newval)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	return _bond_option_delay_set(bond, newval, "up delay",
102962306a36Sopenharmony_ci				      &bond->params.updelay);
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_cistatic int bond_option_downdelay_set(struct bonding *bond,
103362306a36Sopenharmony_ci				     const struct bond_opt_value *newval)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	return _bond_option_delay_set(bond, newval, "down delay",
103662306a36Sopenharmony_ci				      &bond->params.downdelay);
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic int bond_option_peer_notif_delay_set(struct bonding *bond,
104062306a36Sopenharmony_ci					    const struct bond_opt_value *newval)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	int ret = _bond_option_delay_set(bond, newval,
104362306a36Sopenharmony_ci					 "peer notification delay",
104462306a36Sopenharmony_ci					 &bond->params.peer_notif_delay);
104562306a36Sopenharmony_ci	return ret;
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic int bond_option_use_carrier_set(struct bonding *bond,
104962306a36Sopenharmony_ci				       const struct bond_opt_value *newval)
105062306a36Sopenharmony_ci{
105162306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting use_carrier to %llu\n",
105262306a36Sopenharmony_ci		   newval->value);
105362306a36Sopenharmony_ci	bond->params.use_carrier = newval->value;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	return 0;
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci/* There are two tricky bits here.  First, if ARP monitoring is activated, then
105962306a36Sopenharmony_ci * we must disable MII monitoring.  Second, if the ARP timer isn't running,
106062306a36Sopenharmony_ci * we must start it.
106162306a36Sopenharmony_ci */
106262306a36Sopenharmony_cistatic int bond_option_arp_interval_set(struct bonding *bond,
106362306a36Sopenharmony_ci					const struct bond_opt_value *newval)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting ARP monitoring interval to %llu\n",
106662306a36Sopenharmony_ci		   newval->value);
106762306a36Sopenharmony_ci	bond->params.arp_interval = newval->value;
106862306a36Sopenharmony_ci	if (newval->value) {
106962306a36Sopenharmony_ci		if (bond->params.miimon) {
107062306a36Sopenharmony_ci			netdev_dbg(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n");
107162306a36Sopenharmony_ci			bond->params.miimon = 0;
107262306a36Sopenharmony_ci		}
107362306a36Sopenharmony_ci		if (!bond->params.arp_targets[0])
107462306a36Sopenharmony_ci			netdev_dbg(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n");
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci	if (bond->dev->flags & IFF_UP) {
107762306a36Sopenharmony_ci		/* If the interface is up, we may need to fire off
107862306a36Sopenharmony_ci		 * the ARP timer.  If the interface is down, the
107962306a36Sopenharmony_ci		 * timer will get fired off when the open function
108062306a36Sopenharmony_ci		 * is called.
108162306a36Sopenharmony_ci		 */
108262306a36Sopenharmony_ci		if (!newval->value) {
108362306a36Sopenharmony_ci			if (bond->params.arp_validate)
108462306a36Sopenharmony_ci				bond->recv_probe = NULL;
108562306a36Sopenharmony_ci			cancel_delayed_work_sync(&bond->arp_work);
108662306a36Sopenharmony_ci		} else {
108762306a36Sopenharmony_ci			/* arp_validate can be set only in active-backup mode */
108862306a36Sopenharmony_ci			bond->recv_probe = bond_rcv_validate;
108962306a36Sopenharmony_ci			cancel_delayed_work_sync(&bond->mii_work);
109062306a36Sopenharmony_ci			queue_delayed_work(bond->wq, &bond->arp_work, 0);
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	return 0;
109562306a36Sopenharmony_ci}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_cistatic void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
109862306a36Sopenharmony_ci					    __be32 target,
109962306a36Sopenharmony_ci					    unsigned long last_rx)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	__be32 *targets = bond->params.arp_targets;
110262306a36Sopenharmony_ci	struct list_head *iter;
110362306a36Sopenharmony_ci	struct slave *slave;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) {
110662306a36Sopenharmony_ci		bond_for_each_slave(bond, slave, iter)
110762306a36Sopenharmony_ci			slave->target_last_arp_rx[slot] = last_rx;
110862306a36Sopenharmony_ci		targets[slot] = target;
110962306a36Sopenharmony_ci	}
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	__be32 *targets = bond->params.arp_targets;
111562306a36Sopenharmony_ci	int ind;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (!bond_is_ip_target_ok(target)) {
111862306a36Sopenharmony_ci		netdev_err(bond->dev, "invalid ARP target %pI4 specified for addition\n",
111962306a36Sopenharmony_ci			   &target);
112062306a36Sopenharmony_ci		return -EINVAL;
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	if (bond_get_targets_ip(targets, target) != -1) { /* dup */
112462306a36Sopenharmony_ci		netdev_err(bond->dev, "ARP target %pI4 is already present\n",
112562306a36Sopenharmony_ci			   &target);
112662306a36Sopenharmony_ci		return -EINVAL;
112762306a36Sopenharmony_ci	}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	ind = bond_get_targets_ip(targets, 0); /* first free slot */
113062306a36Sopenharmony_ci	if (ind == -1) {
113162306a36Sopenharmony_ci		netdev_err(bond->dev, "ARP target table is full!\n");
113262306a36Sopenharmony_ci		return -EINVAL;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Adding ARP target %pI4\n", &target);
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	_bond_options_arp_ip_target_set(bond, ind, target, jiffies);
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	return 0;
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_cistatic int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	return _bond_option_arp_ip_target_add(bond, target);
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
114862306a36Sopenharmony_ci{
114962306a36Sopenharmony_ci	__be32 *targets = bond->params.arp_targets;
115062306a36Sopenharmony_ci	struct list_head *iter;
115162306a36Sopenharmony_ci	struct slave *slave;
115262306a36Sopenharmony_ci	unsigned long *targets_rx;
115362306a36Sopenharmony_ci	int ind, i;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (!bond_is_ip_target_ok(target)) {
115662306a36Sopenharmony_ci		netdev_err(bond->dev, "invalid ARP target %pI4 specified for removal\n",
115762306a36Sopenharmony_ci			   &target);
115862306a36Sopenharmony_ci		return -EINVAL;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	ind = bond_get_targets_ip(targets, target);
116262306a36Sopenharmony_ci	if (ind == -1) {
116362306a36Sopenharmony_ci		netdev_err(bond->dev, "unable to remove nonexistent ARP target %pI4\n",
116462306a36Sopenharmony_ci			   &target);
116562306a36Sopenharmony_ci		return -EINVAL;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (ind == 0 && !targets[1] && bond->params.arp_interval)
116962306a36Sopenharmony_ci		netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	bond_for_each_slave(bond, slave, iter) {
117462306a36Sopenharmony_ci		targets_rx = slave->target_last_arp_rx;
117562306a36Sopenharmony_ci		for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
117662306a36Sopenharmony_ci			targets_rx[i] = targets_rx[i+1];
117762306a36Sopenharmony_ci		targets_rx[i] = 0;
117862306a36Sopenharmony_ci	}
117962306a36Sopenharmony_ci	for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
118062306a36Sopenharmony_ci		targets[i] = targets[i+1];
118162306a36Sopenharmony_ci	targets[i] = 0;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	return 0;
118462306a36Sopenharmony_ci}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_civoid bond_option_arp_ip_targets_clear(struct bonding *bond)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	int i;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
119162306a36Sopenharmony_ci		_bond_options_arp_ip_target_set(bond, i, 0, 0);
119262306a36Sopenharmony_ci}
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_cistatic int bond_option_arp_ip_targets_set(struct bonding *bond,
119562306a36Sopenharmony_ci					  const struct bond_opt_value *newval)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	int ret = -EPERM;
119862306a36Sopenharmony_ci	__be32 target;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	if (newval->string) {
120162306a36Sopenharmony_ci		if (!in4_pton(newval->string+1, -1, (u8 *)&target, -1, NULL)) {
120262306a36Sopenharmony_ci			netdev_err(bond->dev, "invalid ARP target %pI4 specified\n",
120362306a36Sopenharmony_ci				   &target);
120462306a36Sopenharmony_ci			return ret;
120562306a36Sopenharmony_ci		}
120662306a36Sopenharmony_ci		if (newval->string[0] == '+')
120762306a36Sopenharmony_ci			ret = bond_option_arp_ip_target_add(bond, target);
120862306a36Sopenharmony_ci		else if (newval->string[0] == '-')
120962306a36Sopenharmony_ci			ret = bond_option_arp_ip_target_rem(bond, target);
121062306a36Sopenharmony_ci		else
121162306a36Sopenharmony_ci			netdev_err(bond->dev, "no command found in arp_ip_targets file - use +<addr> or -<addr>\n");
121262306a36Sopenharmony_ci	} else {
121362306a36Sopenharmony_ci		target = newval->value;
121462306a36Sopenharmony_ci		ret = bond_option_arp_ip_target_add(bond, target);
121562306a36Sopenharmony_ci	}
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	return ret;
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
122162306a36Sopenharmony_cistatic void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
122262306a36Sopenharmony_ci					    struct in6_addr *target,
122362306a36Sopenharmony_ci					    unsigned long last_rx)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	struct in6_addr *targets = bond->params.ns_targets;
122662306a36Sopenharmony_ci	struct list_head *iter;
122762306a36Sopenharmony_ci	struct slave *slave;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
123062306a36Sopenharmony_ci		bond_for_each_slave(bond, slave, iter)
123162306a36Sopenharmony_ci			slave->target_last_arp_rx[slot] = last_rx;
123262306a36Sopenharmony_ci		targets[slot] = *target;
123362306a36Sopenharmony_ci	}
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_civoid bond_option_ns_ip6_targets_clear(struct bonding *bond)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	struct in6_addr addr_any = in6addr_any;
123962306a36Sopenharmony_ci	int i;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	for (i = 0; i < BOND_MAX_NS_TARGETS; i++)
124262306a36Sopenharmony_ci		_bond_options_ns_ip6_target_set(bond, i, &addr_any, 0);
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_cistatic int bond_option_ns_ip6_targets_set(struct bonding *bond,
124662306a36Sopenharmony_ci					  const struct bond_opt_value *newval)
124762306a36Sopenharmony_ci{
124862306a36Sopenharmony_ci	struct in6_addr *target = (struct in6_addr *)newval->extra;
124962306a36Sopenharmony_ci	struct in6_addr *targets = bond->params.ns_targets;
125062306a36Sopenharmony_ci	struct in6_addr addr_any = in6addr_any;
125162306a36Sopenharmony_ci	int index;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	if (!bond_is_ip6_target_ok(target)) {
125462306a36Sopenharmony_ci		netdev_err(bond->dev, "invalid NS target %pI6c specified for addition\n",
125562306a36Sopenharmony_ci			   target);
125662306a36Sopenharmony_ci		return -EINVAL;
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	if (bond_get_targets_ip6(targets, target) != -1) { /* dup */
126062306a36Sopenharmony_ci		netdev_err(bond->dev, "NS target %pI6c is already present\n",
126162306a36Sopenharmony_ci			   target);
126262306a36Sopenharmony_ci		return -EINVAL;
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	index = bond_get_targets_ip6(targets, &addr_any); /* first free slot */
126662306a36Sopenharmony_ci	if (index == -1) {
126762306a36Sopenharmony_ci		netdev_err(bond->dev, "NS target table is full!\n");
126862306a36Sopenharmony_ci		return -EINVAL;
126962306a36Sopenharmony_ci	}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Adding NS target %pI6c\n", target);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	_bond_options_ns_ip6_target_set(bond, index, target, jiffies);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	return 0;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci#else
127862306a36Sopenharmony_cistatic int bond_option_ns_ip6_targets_set(struct bonding *bond,
127962306a36Sopenharmony_ci					  const struct bond_opt_value *newval)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	return -EPERM;
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci#endif
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_cistatic int bond_option_arp_validate_set(struct bonding *bond,
128662306a36Sopenharmony_ci					const struct bond_opt_value *newval)
128762306a36Sopenharmony_ci{
128862306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
128962306a36Sopenharmony_ci		   newval->string, newval->value);
129062306a36Sopenharmony_ci	bond->params.arp_validate = newval->value;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	return 0;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic int bond_option_arp_all_targets_set(struct bonding *bond,
129662306a36Sopenharmony_ci					   const struct bond_opt_value *newval)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting arp_all_targets to %s (%llu)\n",
129962306a36Sopenharmony_ci		   newval->string, newval->value);
130062306a36Sopenharmony_ci	bond->params.arp_all_targets = newval->value;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return 0;
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic int bond_option_missed_max_set(struct bonding *bond,
130662306a36Sopenharmony_ci				      const struct bond_opt_value *newval)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting missed max to %s (%llu)\n",
130962306a36Sopenharmony_ci		   newval->string, newval->value);
131062306a36Sopenharmony_ci	bond->params.missed_max = newval->value;
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	return 0;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic int bond_option_prio_set(struct bonding *bond,
131662306a36Sopenharmony_ci				const struct bond_opt_value *newval)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	struct slave *slave;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	slave = bond_slave_get_rtnl(newval->slave_dev);
132162306a36Sopenharmony_ci	if (!slave) {
132262306a36Sopenharmony_ci		netdev_dbg(newval->slave_dev, "%s called on NULL slave\n", __func__);
132362306a36Sopenharmony_ci		return -ENODEV;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci	slave->prio = newval->value;
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	if (rtnl_dereference(bond->primary_slave))
132862306a36Sopenharmony_ci		slave_warn(bond->dev, slave->dev,
132962306a36Sopenharmony_ci			   "prio updated, but will not affect failover re-selection as primary slave have been set\n");
133062306a36Sopenharmony_ci	else
133162306a36Sopenharmony_ci		bond_select_active_slave(bond);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	return 0;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_cistatic int bond_option_primary_set(struct bonding *bond,
133762306a36Sopenharmony_ci				   const struct bond_opt_value *newval)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci	char *p, *primary = newval->string;
134062306a36Sopenharmony_ci	struct list_head *iter;
134162306a36Sopenharmony_ci	struct slave *slave;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	block_netpoll_tx();
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	p = strchr(primary, '\n');
134662306a36Sopenharmony_ci	if (p)
134762306a36Sopenharmony_ci		*p = '\0';
134862306a36Sopenharmony_ci	/* check to see if we are clearing primary */
134962306a36Sopenharmony_ci	if (!strlen(primary)) {
135062306a36Sopenharmony_ci		netdev_dbg(bond->dev, "Setting primary slave to None\n");
135162306a36Sopenharmony_ci		RCU_INIT_POINTER(bond->primary_slave, NULL);
135262306a36Sopenharmony_ci		memset(bond->params.primary, 0, sizeof(bond->params.primary));
135362306a36Sopenharmony_ci		bond_select_active_slave(bond);
135462306a36Sopenharmony_ci		goto out;
135562306a36Sopenharmony_ci	}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	bond_for_each_slave(bond, slave, iter) {
135862306a36Sopenharmony_ci		if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
135962306a36Sopenharmony_ci			slave_dbg(bond->dev, slave->dev, "Setting as primary slave\n");
136062306a36Sopenharmony_ci			rcu_assign_pointer(bond->primary_slave, slave);
136162306a36Sopenharmony_ci			strcpy(bond->params.primary, slave->dev->name);
136262306a36Sopenharmony_ci			bond->force_primary = true;
136362306a36Sopenharmony_ci			bond_select_active_slave(bond);
136462306a36Sopenharmony_ci			goto out;
136562306a36Sopenharmony_ci		}
136662306a36Sopenharmony_ci	}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (rtnl_dereference(bond->primary_slave)) {
136962306a36Sopenharmony_ci		netdev_dbg(bond->dev, "Setting primary slave to None\n");
137062306a36Sopenharmony_ci		RCU_INIT_POINTER(bond->primary_slave, NULL);
137162306a36Sopenharmony_ci		bond_select_active_slave(bond);
137262306a36Sopenharmony_ci	}
137362306a36Sopenharmony_ci	strscpy_pad(bond->params.primary, primary, IFNAMSIZ);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved yet\n",
137662306a36Sopenharmony_ci		   primary);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ciout:
137962306a36Sopenharmony_ci	unblock_netpoll_tx();
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	return 0;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic int bond_option_primary_reselect_set(struct bonding *bond,
138562306a36Sopenharmony_ci					    const struct bond_opt_value *newval)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting primary_reselect to %s (%llu)\n",
138862306a36Sopenharmony_ci		   newval->string, newval->value);
138962306a36Sopenharmony_ci	bond->params.primary_reselect = newval->value;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	block_netpoll_tx();
139262306a36Sopenharmony_ci	bond_select_active_slave(bond);
139362306a36Sopenharmony_ci	unblock_netpoll_tx();
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	return 0;
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic int bond_option_fail_over_mac_set(struct bonding *bond,
139962306a36Sopenharmony_ci					 const struct bond_opt_value *newval)
140062306a36Sopenharmony_ci{
140162306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting fail_over_mac to %s (%llu)\n",
140262306a36Sopenharmony_ci		   newval->string, newval->value);
140362306a36Sopenharmony_ci	bond->params.fail_over_mac = newval->value;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	return 0;
140662306a36Sopenharmony_ci}
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_cistatic int bond_option_xmit_hash_policy_set(struct bonding *bond,
140962306a36Sopenharmony_ci					    const struct bond_opt_value *newval)
141062306a36Sopenharmony_ci{
141162306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
141262306a36Sopenharmony_ci		   newval->string, newval->value);
141362306a36Sopenharmony_ci	bond->params.xmit_policy = newval->value;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	return 0;
141662306a36Sopenharmony_ci}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_cistatic int bond_option_resend_igmp_set(struct bonding *bond,
141962306a36Sopenharmony_ci				       const struct bond_opt_value *newval)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting resend_igmp to %llu\n",
142262306a36Sopenharmony_ci		   newval->value);
142362306a36Sopenharmony_ci	bond->params.resend_igmp = newval->value;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	return 0;
142662306a36Sopenharmony_ci}
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_cistatic int bond_option_num_peer_notif_set(struct bonding *bond,
142962306a36Sopenharmony_ci				   const struct bond_opt_value *newval)
143062306a36Sopenharmony_ci{
143162306a36Sopenharmony_ci	bond->params.num_peer_notif = newval->value;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	return 0;
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic int bond_option_all_slaves_active_set(struct bonding *bond,
143762306a36Sopenharmony_ci					     const struct bond_opt_value *newval)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct list_head *iter;
144062306a36Sopenharmony_ci	struct slave *slave;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	if (newval->value == bond->params.all_slaves_active)
144362306a36Sopenharmony_ci		return 0;
144462306a36Sopenharmony_ci	bond->params.all_slaves_active = newval->value;
144562306a36Sopenharmony_ci	bond_for_each_slave(bond, slave, iter) {
144662306a36Sopenharmony_ci		if (!bond_is_active_slave(slave)) {
144762306a36Sopenharmony_ci			if (newval->value)
144862306a36Sopenharmony_ci				slave->inactive = 0;
144962306a36Sopenharmony_ci			else
145062306a36Sopenharmony_ci				slave->inactive = 1;
145162306a36Sopenharmony_ci		}
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	return 0;
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic int bond_option_min_links_set(struct bonding *bond,
145862306a36Sopenharmony_ci				     const struct bond_opt_value *newval)
145962306a36Sopenharmony_ci{
146062306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting min links value to %llu\n",
146162306a36Sopenharmony_ci		   newval->value);
146262306a36Sopenharmony_ci	bond->params.min_links = newval->value;
146362306a36Sopenharmony_ci	bond_set_carrier(bond);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	return 0;
146662306a36Sopenharmony_ci}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_cistatic int bond_option_lp_interval_set(struct bonding *bond,
146962306a36Sopenharmony_ci				       const struct bond_opt_value *newval)
147062306a36Sopenharmony_ci{
147162306a36Sopenharmony_ci	bond->params.lp_interval = newval->value;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	return 0;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_cistatic int bond_option_pps_set(struct bonding *bond,
147762306a36Sopenharmony_ci			       const struct bond_opt_value *newval)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting packets per slave to %llu\n",
148062306a36Sopenharmony_ci		   newval->value);
148162306a36Sopenharmony_ci	bond->params.packets_per_slave = newval->value;
148262306a36Sopenharmony_ci	if (newval->value > 0) {
148362306a36Sopenharmony_ci		bond->params.reciprocal_packets_per_slave =
148462306a36Sopenharmony_ci			reciprocal_value(newval->value);
148562306a36Sopenharmony_ci	} else {
148662306a36Sopenharmony_ci		/* reciprocal_packets_per_slave is unused if
148762306a36Sopenharmony_ci		 * packets_per_slave is 0 or 1, just initialize it
148862306a36Sopenharmony_ci		 */
148962306a36Sopenharmony_ci		bond->params.reciprocal_packets_per_slave =
149062306a36Sopenharmony_ci			(struct reciprocal_value) { 0 };
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	return 0;
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_cistatic int bond_option_lacp_active_set(struct bonding *bond,
149762306a36Sopenharmony_ci				       const struct bond_opt_value *newval)
149862306a36Sopenharmony_ci{
149962306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting LACP active to %s (%llu)\n",
150062306a36Sopenharmony_ci		   newval->string, newval->value);
150162306a36Sopenharmony_ci	bond->params.lacp_active = newval->value;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	return 0;
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic int bond_option_lacp_rate_set(struct bonding *bond,
150762306a36Sopenharmony_ci				     const struct bond_opt_value *newval)
150862306a36Sopenharmony_ci{
150962306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting LACP rate to %s (%llu)\n",
151062306a36Sopenharmony_ci		   newval->string, newval->value);
151162306a36Sopenharmony_ci	bond->params.lacp_fast = newval->value;
151262306a36Sopenharmony_ci	bond_3ad_update_lacp_rate(bond);
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	return 0;
151562306a36Sopenharmony_ci}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_cistatic int bond_option_ad_select_set(struct bonding *bond,
151862306a36Sopenharmony_ci				     const struct bond_opt_value *newval)
151962306a36Sopenharmony_ci{
152062306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting ad_select to %s (%llu)\n",
152162306a36Sopenharmony_ci		   newval->string, newval->value);
152262306a36Sopenharmony_ci	bond->params.ad_select = newval->value;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	return 0;
152562306a36Sopenharmony_ci}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_cistatic int bond_option_queue_id_set(struct bonding *bond,
152862306a36Sopenharmony_ci				    const struct bond_opt_value *newval)
152962306a36Sopenharmony_ci{
153062306a36Sopenharmony_ci	struct slave *slave, *update_slave;
153162306a36Sopenharmony_ci	struct net_device *sdev;
153262306a36Sopenharmony_ci	struct list_head *iter;
153362306a36Sopenharmony_ci	char *delim;
153462306a36Sopenharmony_ci	int ret = 0;
153562306a36Sopenharmony_ci	u16 qid;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	/* delim will point to queue id if successful */
153862306a36Sopenharmony_ci	delim = strchr(newval->string, ':');
153962306a36Sopenharmony_ci	if (!delim)
154062306a36Sopenharmony_ci		goto err_no_cmd;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	/* Terminate string that points to device name and bump it
154362306a36Sopenharmony_ci	 * up one, so we can read the queue id there.
154462306a36Sopenharmony_ci	 */
154562306a36Sopenharmony_ci	*delim = '\0';
154662306a36Sopenharmony_ci	if (sscanf(++delim, "%hd\n", &qid) != 1)
154762306a36Sopenharmony_ci		goto err_no_cmd;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	/* Check buffer length, valid ifname and queue id */
155062306a36Sopenharmony_ci	if (!dev_valid_name(newval->string) ||
155162306a36Sopenharmony_ci	    qid > bond->dev->real_num_tx_queues)
155262306a36Sopenharmony_ci		goto err_no_cmd;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	/* Get the pointer to that interface if it exists */
155562306a36Sopenharmony_ci	sdev = __dev_get_by_name(dev_net(bond->dev), newval->string);
155662306a36Sopenharmony_ci	if (!sdev)
155762306a36Sopenharmony_ci		goto err_no_cmd;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	/* Search for thes slave and check for duplicate qids */
156062306a36Sopenharmony_ci	update_slave = NULL;
156162306a36Sopenharmony_ci	bond_for_each_slave(bond, slave, iter) {
156262306a36Sopenharmony_ci		if (sdev == slave->dev)
156362306a36Sopenharmony_ci			/* We don't need to check the matching
156462306a36Sopenharmony_ci			 * slave for dups, since we're overwriting it
156562306a36Sopenharmony_ci			 */
156662306a36Sopenharmony_ci			update_slave = slave;
156762306a36Sopenharmony_ci		else if (qid && qid == slave->queue_id) {
156862306a36Sopenharmony_ci			goto err_no_cmd;
156962306a36Sopenharmony_ci		}
157062306a36Sopenharmony_ci	}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	if (!update_slave)
157362306a36Sopenharmony_ci		goto err_no_cmd;
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	/* Actually set the qids for the slave */
157662306a36Sopenharmony_ci	update_slave->queue_id = qid;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ciout:
157962306a36Sopenharmony_ci	return ret;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_cierr_no_cmd:
158262306a36Sopenharmony_ci	netdev_dbg(bond->dev, "invalid input for queue_id set\n");
158362306a36Sopenharmony_ci	ret = -EPERM;
158462306a36Sopenharmony_ci	goto out;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci}
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_cistatic int bond_option_slaves_set(struct bonding *bond,
158962306a36Sopenharmony_ci				  const struct bond_opt_value *newval)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	char command[IFNAMSIZ + 1] = { 0, };
159262306a36Sopenharmony_ci	struct net_device *dev;
159362306a36Sopenharmony_ci	char *ifname;
159462306a36Sopenharmony_ci	int ret;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	sscanf(newval->string, "%16s", command); /* IFNAMSIZ*/
159762306a36Sopenharmony_ci	ifname = command + 1;
159862306a36Sopenharmony_ci	if ((strlen(command) <= 1) ||
159962306a36Sopenharmony_ci	    (command[0] != '+' && command[0] != '-') ||
160062306a36Sopenharmony_ci	    !dev_valid_name(ifname))
160162306a36Sopenharmony_ci		goto err_no_cmd;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	dev = __dev_get_by_name(dev_net(bond->dev), ifname);
160462306a36Sopenharmony_ci	if (!dev) {
160562306a36Sopenharmony_ci		netdev_dbg(bond->dev, "interface %s does not exist!\n",
160662306a36Sopenharmony_ci			   ifname);
160762306a36Sopenharmony_ci		ret = -ENODEV;
160862306a36Sopenharmony_ci		goto out;
160962306a36Sopenharmony_ci	}
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	switch (command[0]) {
161262306a36Sopenharmony_ci	case '+':
161362306a36Sopenharmony_ci		slave_dbg(bond->dev, dev, "Enslaving interface\n");
161462306a36Sopenharmony_ci		ret = bond_enslave(bond->dev, dev, NULL);
161562306a36Sopenharmony_ci		break;
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	case '-':
161862306a36Sopenharmony_ci		slave_dbg(bond->dev, dev, "Releasing interface\n");
161962306a36Sopenharmony_ci		ret = bond_release(bond->dev, dev);
162062306a36Sopenharmony_ci		break;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	default:
162362306a36Sopenharmony_ci		/* should not run here. */
162462306a36Sopenharmony_ci		goto err_no_cmd;
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ciout:
162862306a36Sopenharmony_ci	return ret;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_cierr_no_cmd:
163162306a36Sopenharmony_ci	netdev_err(bond->dev, "no command found in slaves file - use +ifname or -ifname\n");
163262306a36Sopenharmony_ci	ret = -EPERM;
163362306a36Sopenharmony_ci	goto out;
163462306a36Sopenharmony_ci}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_cistatic int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
163762306a36Sopenharmony_ci					  const struct bond_opt_value *newval)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting dynamic-lb to %s (%llu)\n",
164062306a36Sopenharmony_ci		   newval->string, newval->value);
164162306a36Sopenharmony_ci	bond->params.tlb_dynamic_lb = newval->value;
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	return 0;
164462306a36Sopenharmony_ci}
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_cistatic int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
164762306a36Sopenharmony_ci					     const struct bond_opt_value *newval)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting ad_actor_sys_prio to %llu\n",
165062306a36Sopenharmony_ci		   newval->value);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	bond->params.ad_actor_sys_prio = newval->value;
165362306a36Sopenharmony_ci	bond_3ad_update_ad_actor_settings(bond);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	return 0;
165662306a36Sopenharmony_ci}
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_cistatic int bond_option_ad_actor_system_set(struct bonding *bond,
165962306a36Sopenharmony_ci					   const struct bond_opt_value *newval)
166062306a36Sopenharmony_ci{
166162306a36Sopenharmony_ci	u8 macaddr[ETH_ALEN];
166262306a36Sopenharmony_ci	u8 *mac;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	if (newval->string) {
166562306a36Sopenharmony_ci		if (!mac_pton(newval->string, macaddr))
166662306a36Sopenharmony_ci			goto err;
166762306a36Sopenharmony_ci		mac = macaddr;
166862306a36Sopenharmony_ci	} else {
166962306a36Sopenharmony_ci		mac = (u8 *)&newval->value;
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	if (is_multicast_ether_addr(mac))
167362306a36Sopenharmony_ci		goto err;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting ad_actor_system to %pM\n", mac);
167662306a36Sopenharmony_ci	ether_addr_copy(bond->params.ad_actor_system, mac);
167762306a36Sopenharmony_ci	bond_3ad_update_ad_actor_settings(bond);
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	return 0;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_cierr:
168262306a36Sopenharmony_ci	netdev_err(bond->dev, "Invalid ad_actor_system MAC address.\n");
168362306a36Sopenharmony_ci	return -EINVAL;
168462306a36Sopenharmony_ci}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_cistatic int bond_option_ad_user_port_key_set(struct bonding *bond,
168762306a36Sopenharmony_ci					    const struct bond_opt_value *newval)
168862306a36Sopenharmony_ci{
168962306a36Sopenharmony_ci	netdev_dbg(bond->dev, "Setting ad_user_port_key to %llu\n",
169062306a36Sopenharmony_ci		   newval->value);
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	bond->params.ad_user_port_key = newval->value;
169362306a36Sopenharmony_ci	return 0;
169462306a36Sopenharmony_ci}
1695