xref: /openbmc/linux/drivers/net/bonding/bond_options.c (revision 36db6e8484ed455bbb320d89a119378897ae991c)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
272be35feSJiri Pirko /*
372be35feSJiri Pirko  * drivers/net/bond/bond_options.c - bonding options
472be35feSJiri Pirko  * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
5eecdaa6eSsfeldma@cumulusnetworks.com  * Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com>
672be35feSJiri Pirko  */
772be35feSJiri Pirko 
872be35feSJiri Pirko #include <linux/errno.h>
972be35feSJiri Pirko #include <linux/if.h>
10d9e32b21SJiri Pirko #include <linux/netdevice.h>
11eb2d4c64SMike Galbraith #include <linux/spinlock.h>
12d9e32b21SJiri Pirko #include <linux/rcupdate.h>
1309117362SNikolay Aleksandrov #include <linux/ctype.h>
144fb0ef58SNikolay Aleksandrov #include <linux/inet.h>
15174cd4b1SIngo Molnar #include <linux/sched/signal.h>
16174cd4b1SIngo Molnar 
171ef8019bSDavid S. Miller #include <net/bonding.h>
189ea6b70fSHangbin Liu #include <net/ndisc.h>
1972be35feSJiri Pirko 
20f3253339Sstephen hemminger static int bond_option_active_slave_set(struct bonding *bond,
2128f084ccSstephen hemminger 					const struct bond_opt_value *newval);
22f3253339Sstephen hemminger static int bond_option_miimon_set(struct bonding *bond,
2328f084ccSstephen hemminger 				  const struct bond_opt_value *newval);
24f3253339Sstephen hemminger static int bond_option_updelay_set(struct bonding *bond,
2528f084ccSstephen hemminger 				   const struct bond_opt_value *newval);
26f3253339Sstephen hemminger static int bond_option_downdelay_set(struct bonding *bond,
2728f084ccSstephen hemminger 				     const struct bond_opt_value *newval);
2807a4ddecSVincent Bernat static int bond_option_peer_notif_delay_set(struct bonding *bond,
2907a4ddecSVincent Bernat 					    const struct bond_opt_value *newval);
30f3253339Sstephen hemminger static int bond_option_use_carrier_set(struct bonding *bond,
3128f084ccSstephen hemminger 				       const struct bond_opt_value *newval);
32f3253339Sstephen hemminger static int bond_option_arp_interval_set(struct bonding *bond,
3328f084ccSstephen hemminger 					const struct bond_opt_value *newval);
34f3253339Sstephen hemminger static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
35f3253339Sstephen hemminger static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
36f3253339Sstephen hemminger static int bond_option_arp_ip_targets_set(struct bonding *bond,
3728f084ccSstephen hemminger 					  const struct bond_opt_value *newval);
38129e3c1bSHangbin Liu static int bond_option_ns_ip6_targets_set(struct bonding *bond,
39129e3c1bSHangbin Liu 					  const struct bond_opt_value *newval);
40f3253339Sstephen hemminger static int bond_option_arp_validate_set(struct bonding *bond,
4128f084ccSstephen hemminger 					const struct bond_opt_value *newval);
42f3253339Sstephen hemminger static int bond_option_arp_all_targets_set(struct bonding *bond,
4328f084ccSstephen hemminger 					   const struct bond_opt_value *newval);
440a2ff7ccSHangbin Liu static int bond_option_prio_set(struct bonding *bond,
450a2ff7ccSHangbin Liu 				const struct bond_opt_value *newval);
46f3253339Sstephen hemminger static int bond_option_primary_set(struct bonding *bond,
4728f084ccSstephen hemminger 				   const struct bond_opt_value *newval);
48f3253339Sstephen hemminger static int bond_option_primary_reselect_set(struct bonding *bond,
4928f084ccSstephen hemminger 					    const struct bond_opt_value *newval);
50f3253339Sstephen hemminger static int bond_option_fail_over_mac_set(struct bonding *bond,
5128f084ccSstephen hemminger 					 const struct bond_opt_value *newval);
52f3253339Sstephen hemminger static int bond_option_xmit_hash_policy_set(struct bonding *bond,
5328f084ccSstephen hemminger 					    const struct bond_opt_value *newval);
54f3253339Sstephen hemminger static int bond_option_resend_igmp_set(struct bonding *bond,
5528f084ccSstephen hemminger 				       const struct bond_opt_value *newval);
56f3253339Sstephen hemminger static int bond_option_num_peer_notif_set(struct bonding *bond,
5728f084ccSstephen hemminger 					  const struct bond_opt_value *newval);
58f3253339Sstephen hemminger static int bond_option_all_slaves_active_set(struct bonding *bond,
5928f084ccSstephen hemminger 					     const struct bond_opt_value *newval);
60f3253339Sstephen hemminger static int bond_option_min_links_set(struct bonding *bond,
6128f084ccSstephen hemminger 				     const struct bond_opt_value *newval);
62f3253339Sstephen hemminger static int bond_option_lp_interval_set(struct bonding *bond,
6328f084ccSstephen hemminger 				       const struct bond_opt_value *newval);
64f3253339Sstephen hemminger static int bond_option_pps_set(struct bonding *bond,
6528f084ccSstephen hemminger 			       const struct bond_opt_value *newval);
663a755cd8SHangbin Liu static int bond_option_lacp_active_set(struct bonding *bond,
673a755cd8SHangbin Liu 				       const struct bond_opt_value *newval);
68f3253339Sstephen hemminger static int bond_option_lacp_rate_set(struct bonding *bond,
6928f084ccSstephen hemminger 				     const struct bond_opt_value *newval);
70f3253339Sstephen hemminger static int bond_option_ad_select_set(struct bonding *bond,
7128f084ccSstephen hemminger 				     const struct bond_opt_value *newval);
72f3253339Sstephen hemminger static int bond_option_queue_id_set(struct bonding *bond,
7328f084ccSstephen hemminger 				    const struct bond_opt_value *newval);
74f3253339Sstephen hemminger static int bond_option_mode_set(struct bonding *bond,
7528f084ccSstephen hemminger 				const struct bond_opt_value *newval);
76f3253339Sstephen hemminger static int bond_option_slaves_set(struct bonding *bond,
7728f084ccSstephen hemminger 				  const struct bond_opt_value *newval);
78e9f0fb88SMahesh Bandewar static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
79e9f0fb88SMahesh Bandewar 				  const struct bond_opt_value *newval);
806791e466SMahesh Bandewar static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
816791e466SMahesh Bandewar 					     const struct bond_opt_value *newval);
8274514957SMahesh Bandewar static int bond_option_ad_actor_system_set(struct bonding *bond,
8374514957SMahesh Bandewar 					   const struct bond_opt_value *newval);
84d22a5fc0SMahesh Bandewar static int bond_option_ad_user_port_key_set(struct bonding *bond,
85d22a5fc0SMahesh Bandewar 					    const struct bond_opt_value *newval);
865944b5abSHangbin Liu static int bond_option_missed_max_set(struct bonding *bond,
875944b5abSHangbin Liu 				      const struct bond_opt_value *newval);
88f3253339Sstephen hemminger 
89f3253339Sstephen hemminger 
90f3253339Sstephen hemminger static const struct bond_opt_value bond_mode_tbl[] = {
912b3798d5SNikolay Aleksandrov 	{ "balance-rr",    BOND_MODE_ROUNDROBIN,   BOND_VALFLAG_DEFAULT},
922b3798d5SNikolay Aleksandrov 	{ "active-backup", BOND_MODE_ACTIVEBACKUP, 0},
932b3798d5SNikolay Aleksandrov 	{ "balance-xor",   BOND_MODE_XOR,          0},
942b3798d5SNikolay Aleksandrov 	{ "broadcast",     BOND_MODE_BROADCAST,    0},
952b3798d5SNikolay Aleksandrov 	{ "802.3ad",       BOND_MODE_8023AD,       0},
962b3798d5SNikolay Aleksandrov 	{ "balance-tlb",   BOND_MODE_TLB,          0},
972b3798d5SNikolay Aleksandrov 	{ "balance-alb",   BOND_MODE_ALB,          0},
982b3798d5SNikolay Aleksandrov 	{ NULL,            -1,                     0},
992b3798d5SNikolay Aleksandrov };
1002b3798d5SNikolay Aleksandrov 
101f3253339Sstephen hemminger static const struct bond_opt_value bond_pps_tbl[] = {
102aa59d851SNikolay Aleksandrov 	{ "default", 1,         BOND_VALFLAG_DEFAULT},
103aa59d851SNikolay Aleksandrov 	{ "maxval",  USHRT_MAX, BOND_VALFLAG_MAX},
104aa59d851SNikolay Aleksandrov 	{ NULL,      -1,        0},
105aa59d851SNikolay Aleksandrov };
106aa59d851SNikolay Aleksandrov 
107f3253339Sstephen hemminger static const struct bond_opt_value bond_xmit_hashtype_tbl[] = {
108a4b32ce7SNikolay Aleksandrov 	{ "layer2",      BOND_XMIT_POLICY_LAYER2,      BOND_VALFLAG_DEFAULT},
109a4b32ce7SNikolay Aleksandrov 	{ "layer3+4",    BOND_XMIT_POLICY_LAYER34,     0},
110a4b32ce7SNikolay Aleksandrov 	{ "layer2+3",    BOND_XMIT_POLICY_LAYER23,     0},
111a4b32ce7SNikolay Aleksandrov 	{ "encap2+3",    BOND_XMIT_POLICY_ENCAP23,     0},
112a4b32ce7SNikolay Aleksandrov 	{ "encap3+4",    BOND_XMIT_POLICY_ENCAP34,     0},
1137b8fc010SJarod Wilson 	{ "vlan+srcmac", BOND_XMIT_POLICY_VLAN_SRCMAC, 0},
114a4b32ce7SNikolay Aleksandrov 	{ NULL,          -1,                           0},
115a4b32ce7SNikolay Aleksandrov };
116a4b32ce7SNikolay Aleksandrov 
117f3253339Sstephen hemminger static const struct bond_opt_value bond_arp_validate_tbl[] = {
11816228881SNikolay Aleksandrov 	{ "none",		BOND_ARP_VALIDATE_NONE,		BOND_VALFLAG_DEFAULT},
11916228881SNikolay Aleksandrov 	{ "active",		BOND_ARP_VALIDATE_ACTIVE,	0},
12016228881SNikolay Aleksandrov 	{ "backup",		BOND_ARP_VALIDATE_BACKUP,	0},
12116228881SNikolay Aleksandrov 	{ "all",		BOND_ARP_VALIDATE_ALL,		0},
122896149ffSVeaceslav Falico 	{ "filter",		BOND_ARP_FILTER,		0},
123896149ffSVeaceslav Falico 	{ "filter_active",	BOND_ARP_FILTER_ACTIVE,		0},
124896149ffSVeaceslav Falico 	{ "filter_backup",	BOND_ARP_FILTER_BACKUP,		0},
12516228881SNikolay Aleksandrov 	{ NULL,			-1,				0},
12616228881SNikolay Aleksandrov };
12716228881SNikolay Aleksandrov 
128f3253339Sstephen hemminger static const struct bond_opt_value bond_arp_all_targets_tbl[] = {
129edf36b24SNikolay Aleksandrov 	{ "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT},
130edf36b24SNikolay Aleksandrov 	{ "all", BOND_ARP_TARGETS_ALL, 0},
131edf36b24SNikolay Aleksandrov 	{ NULL,  -1,                   0},
132edf36b24SNikolay Aleksandrov };
133edf36b24SNikolay Aleksandrov 
134f3253339Sstephen hemminger static const struct bond_opt_value bond_fail_over_mac_tbl[] = {
1351df6b6aaSNikolay Aleksandrov 	{ "none",   BOND_FOM_NONE,   BOND_VALFLAG_DEFAULT},
1361df6b6aaSNikolay Aleksandrov 	{ "active", BOND_FOM_ACTIVE, 0},
1371df6b6aaSNikolay Aleksandrov 	{ "follow", BOND_FOM_FOLLOW, 0},
1381df6b6aaSNikolay Aleksandrov 	{ NULL,     -1,              0},
1391df6b6aaSNikolay Aleksandrov };
1401df6b6aaSNikolay Aleksandrov 
141f3253339Sstephen hemminger static const struct bond_opt_value bond_intmax_tbl[] = {
1427bdb04edSNikolay Aleksandrov 	{ "off",     0,       BOND_VALFLAG_DEFAULT},
1437bdb04edSNikolay Aleksandrov 	{ "maxval",  INT_MAX, BOND_VALFLAG_MAX},
14481c70806SNikolay Aleksandrov 	{ NULL,      -1,      0}
1457bdb04edSNikolay Aleksandrov };
1467bdb04edSNikolay Aleksandrov 
1473a755cd8SHangbin Liu static const struct bond_opt_value bond_lacp_active[] = {
1483a755cd8SHangbin Liu 	{ "off", 0,  0},
1493a755cd8SHangbin Liu 	{ "on",  1,  BOND_VALFLAG_DEFAULT},
1503a755cd8SHangbin Liu 	{ NULL,  -1, 0}
1513a755cd8SHangbin Liu };
1523a755cd8SHangbin Liu 
153f3253339Sstephen hemminger static const struct bond_opt_value bond_lacp_rate_tbl[] = {
154d3131de7SNikolay Aleksandrov 	{ "slow", AD_LACP_SLOW, 0},
155d3131de7SNikolay Aleksandrov 	{ "fast", AD_LACP_FAST, 0},
156d3131de7SNikolay Aleksandrov 	{ NULL,   -1,           0},
157d3131de7SNikolay Aleksandrov };
158d3131de7SNikolay Aleksandrov 
159f3253339Sstephen hemminger static const struct bond_opt_value bond_ad_select_tbl[] = {
1609e5f5eebSNikolay Aleksandrov 	{ "stable",    BOND_AD_STABLE,    BOND_VALFLAG_DEFAULT},
1619e5f5eebSNikolay Aleksandrov 	{ "bandwidth", BOND_AD_BANDWIDTH, 0},
1629e5f5eebSNikolay Aleksandrov 	{ "count",     BOND_AD_COUNT,     0},
1639e5f5eebSNikolay Aleksandrov 	{ NULL,        -1,                0},
1649e5f5eebSNikolay Aleksandrov };
1659e5f5eebSNikolay Aleksandrov 
166f3253339Sstephen hemminger static const struct bond_opt_value bond_num_peer_notif_tbl[] = {
167ef56becbSNikolay Aleksandrov 	{ "off",     0,   0},
168ef56becbSNikolay Aleksandrov 	{ "maxval",  255, BOND_VALFLAG_MAX},
169ef56becbSNikolay Aleksandrov 	{ "default", 1,   BOND_VALFLAG_DEFAULT},
170ef56becbSNikolay Aleksandrov 	{ NULL,      -1,  0}
171ef56becbSNikolay Aleksandrov };
172ef56becbSNikolay Aleksandrov 
1739949e2efSHangbin Liu static const struct bond_opt_value bond_peer_notif_delay_tbl[] = {
1749949e2efSHangbin Liu 	{ "off",     0,   0},
1759949e2efSHangbin Liu 	{ "maxval",  300000, BOND_VALFLAG_MAX},
1769949e2efSHangbin Liu 	{ NULL,      -1,  0}
1779949e2efSHangbin Liu };
1789949e2efSHangbin Liu 
179f3253339Sstephen hemminger static const struct bond_opt_value bond_primary_reselect_tbl[] = {
180388d3a6dSNikolay Aleksandrov 	{ "always",  BOND_PRI_RESELECT_ALWAYS,  BOND_VALFLAG_DEFAULT},
181388d3a6dSNikolay Aleksandrov 	{ "better",  BOND_PRI_RESELECT_BETTER,  0},
182388d3a6dSNikolay Aleksandrov 	{ "failure", BOND_PRI_RESELECT_FAILURE, 0},
183388d3a6dSNikolay Aleksandrov 	{ NULL,      -1},
184388d3a6dSNikolay Aleksandrov };
185388d3a6dSNikolay Aleksandrov 
186f3253339Sstephen hemminger static const struct bond_opt_value bond_use_carrier_tbl[] = {
1870fff0608SNikolay Aleksandrov 	{ "off", 0,  0},
1880fff0608SNikolay Aleksandrov 	{ "on",  1,  BOND_VALFLAG_DEFAULT},
1890fff0608SNikolay Aleksandrov 	{ NULL,  -1, 0}
1900fff0608SNikolay Aleksandrov };
1910fff0608SNikolay Aleksandrov 
192f3253339Sstephen hemminger static const struct bond_opt_value bond_all_slaves_active_tbl[] = {
1933df01162SNikolay Aleksandrov 	{ "off", 0,  BOND_VALFLAG_DEFAULT},
1943df01162SNikolay Aleksandrov 	{ "on",  1,  0},
1953df01162SNikolay Aleksandrov 	{ NULL,  -1, 0}
1963df01162SNikolay Aleksandrov };
1973df01162SNikolay Aleksandrov 
198f3253339Sstephen hemminger static const struct bond_opt_value bond_resend_igmp_tbl[] = {
199105c8fb6SNikolay Aleksandrov 	{ "off",     0,   0},
200105c8fb6SNikolay Aleksandrov 	{ "maxval",  255, BOND_VALFLAG_MAX},
201105c8fb6SNikolay Aleksandrov 	{ "default", 1,   BOND_VALFLAG_DEFAULT},
202105c8fb6SNikolay Aleksandrov 	{ NULL,      -1,  0}
203105c8fb6SNikolay Aleksandrov };
204105c8fb6SNikolay Aleksandrov 
205f3253339Sstephen hemminger static const struct bond_opt_value bond_lp_interval_tbl[] = {
2064325b374SNikolay Aleksandrov 	{ "minval",  1,       BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
2074325b374SNikolay Aleksandrov 	{ "maxval",  INT_MAX, BOND_VALFLAG_MAX},
2085bd4e4c1SSasha Levin 	{ NULL,      -1,      0},
2094325b374SNikolay Aleksandrov };
2104325b374SNikolay Aleksandrov 
211e9f0fb88SMahesh Bandewar static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
212e9f0fb88SMahesh Bandewar 	{ "off", 0,  0},
213e9f0fb88SMahesh Bandewar 	{ "on",  1,  BOND_VALFLAG_DEFAULT},
214e9f0fb88SMahesh Bandewar 	{ NULL,  -1, 0}
215e9f0fb88SMahesh Bandewar };
216e9f0fb88SMahesh Bandewar 
2176791e466SMahesh Bandewar static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
2186791e466SMahesh Bandewar 	{ "minval",  1,     BOND_VALFLAG_MIN},
2196791e466SMahesh Bandewar 	{ "maxval",  65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT},
2206791e466SMahesh Bandewar 	{ NULL,      -1,    0},
2216791e466SMahesh Bandewar };
2226791e466SMahesh Bandewar 
223d22a5fc0SMahesh Bandewar static const struct bond_opt_value bond_ad_user_port_key_tbl[] = {
224d22a5fc0SMahesh Bandewar 	{ "minval",  0,     BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
225d22a5fc0SMahesh Bandewar 	{ "maxval",  1023,  BOND_VALFLAG_MAX},
226d22a5fc0SMahesh Bandewar 	{ NULL,      -1,    0},
227d22a5fc0SMahesh Bandewar };
228d22a5fc0SMahesh Bandewar 
2295944b5abSHangbin Liu static const struct bond_opt_value bond_missed_max_tbl[] = {
2305944b5abSHangbin Liu 	{ "minval",	1,	BOND_VALFLAG_MIN},
2315944b5abSHangbin Liu 	{ "maxval",	255,	BOND_VALFLAG_MAX},
2325944b5abSHangbin Liu 	{ "default",	2,	BOND_VALFLAG_DEFAULT},
2335944b5abSHangbin Liu 	{ NULL,		-1,	0},
2345944b5abSHangbin Liu };
2355944b5abSHangbin Liu 
2367bfa0145SJonathan Toppins static const struct bond_option bond_opts[BOND_OPT_LAST] = {
2372b3798d5SNikolay Aleksandrov 	[BOND_OPT_MODE] = {
2382b3798d5SNikolay Aleksandrov 		.id = BOND_OPT_MODE,
2392b3798d5SNikolay Aleksandrov 		.name = "mode",
2402b3798d5SNikolay Aleksandrov 		.desc = "bond device mode",
2412b3798d5SNikolay Aleksandrov 		.flags = BOND_OPTFLAG_NOSLAVES | BOND_OPTFLAG_IFDOWN,
2422b3798d5SNikolay Aleksandrov 		.values = bond_mode_tbl,
2432b3798d5SNikolay Aleksandrov 		.set = bond_option_mode_set
2442b3798d5SNikolay Aleksandrov 	},
245aa59d851SNikolay Aleksandrov 	[BOND_OPT_PACKETS_PER_SLAVE] = {
246aa59d851SNikolay Aleksandrov 		.id = BOND_OPT_PACKETS_PER_SLAVE,
247aa59d851SNikolay Aleksandrov 		.name = "packets_per_slave",
248aa59d851SNikolay Aleksandrov 		.desc = "Packets to send per slave in RR mode",
249aa59d851SNikolay Aleksandrov 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ROUNDROBIN)),
250aa59d851SNikolay Aleksandrov 		.values = bond_pps_tbl,
251aa59d851SNikolay Aleksandrov 		.set = bond_option_pps_set
252aa59d851SNikolay Aleksandrov 	},
253a4b32ce7SNikolay Aleksandrov 	[BOND_OPT_XMIT_HASH] = {
254a4b32ce7SNikolay Aleksandrov 		.id = BOND_OPT_XMIT_HASH,
255a4b32ce7SNikolay Aleksandrov 		.name = "xmit_hash_policy",
256f05b42eaSMahesh Bandewar 		.desc = "balance-xor, 802.3ad, and tlb hashing method",
257a4b32ce7SNikolay Aleksandrov 		.values = bond_xmit_hashtype_tbl,
258a4b32ce7SNikolay Aleksandrov 		.set = bond_option_xmit_hash_policy_set
259a4b32ce7SNikolay Aleksandrov 	},
26016228881SNikolay Aleksandrov 	[BOND_OPT_ARP_VALIDATE] = {
26116228881SNikolay Aleksandrov 		.id = BOND_OPT_ARP_VALIDATE,
26216228881SNikolay Aleksandrov 		.name = "arp_validate",
26316228881SNikolay Aleksandrov 		.desc = "validate src/dst of ARP probes",
26413ac34a8SVeaceslav Falico 		.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
26513ac34a8SVeaceslav Falico 			       BIT(BOND_MODE_ALB),
26616228881SNikolay Aleksandrov 		.values = bond_arp_validate_tbl,
26716228881SNikolay Aleksandrov 		.set = bond_option_arp_validate_set
26816228881SNikolay Aleksandrov 	},
269edf36b24SNikolay Aleksandrov 	[BOND_OPT_ARP_ALL_TARGETS] = {
270edf36b24SNikolay Aleksandrov 		.id = BOND_OPT_ARP_ALL_TARGETS,
271edf36b24SNikolay Aleksandrov 		.name = "arp_all_targets",
272edf36b24SNikolay Aleksandrov 		.desc = "fail on any/all arp targets timeout",
273edf36b24SNikolay Aleksandrov 		.values = bond_arp_all_targets_tbl,
274edf36b24SNikolay Aleksandrov 		.set = bond_option_arp_all_targets_set
275edf36b24SNikolay Aleksandrov 	},
2761df6b6aaSNikolay Aleksandrov 	[BOND_OPT_FAIL_OVER_MAC] = {
2771df6b6aaSNikolay Aleksandrov 		.id = BOND_OPT_FAIL_OVER_MAC,
2781df6b6aaSNikolay Aleksandrov 		.name = "fail_over_mac",
2791df6b6aaSNikolay Aleksandrov 		.desc = "For active-backup, do not set all slaves to the same MAC",
2801df6b6aaSNikolay Aleksandrov 		.flags = BOND_OPTFLAG_NOSLAVES,
2811df6b6aaSNikolay Aleksandrov 		.values = bond_fail_over_mac_tbl,
2821df6b6aaSNikolay Aleksandrov 		.set = bond_option_fail_over_mac_set
2831df6b6aaSNikolay Aleksandrov 	},
2847bdb04edSNikolay Aleksandrov 	[BOND_OPT_ARP_INTERVAL] = {
2857bdb04edSNikolay Aleksandrov 		.id = BOND_OPT_ARP_INTERVAL,
2867bdb04edSNikolay Aleksandrov 		.name = "arp_interval",
2877bdb04edSNikolay Aleksandrov 		.desc = "arp interval in milliseconds",
2887bdb04edSNikolay Aleksandrov 		.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
2897bdb04edSNikolay Aleksandrov 			       BIT(BOND_MODE_ALB),
2907bdb04edSNikolay Aleksandrov 		.values = bond_intmax_tbl,
2917bdb04edSNikolay Aleksandrov 		.set = bond_option_arp_interval_set
2927bdb04edSNikolay Aleksandrov 	},
2935944b5abSHangbin Liu 	[BOND_OPT_MISSED_MAX] = {
2945944b5abSHangbin Liu 		.id = BOND_OPT_MISSED_MAX,
2955944b5abSHangbin Liu 		.name = "arp_missed_max",
2965944b5abSHangbin Liu 		.desc = "Maximum number of missed ARP interval",
2975944b5abSHangbin Liu 		.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
2985944b5abSHangbin Liu 			       BIT(BOND_MODE_ALB),
2995944b5abSHangbin Liu 		.values = bond_missed_max_tbl,
3005944b5abSHangbin Liu 		.set = bond_option_missed_max_set
3015944b5abSHangbin Liu 	},
3024fb0ef58SNikolay Aleksandrov 	[BOND_OPT_ARP_TARGETS] = {
3034fb0ef58SNikolay Aleksandrov 		.id = BOND_OPT_ARP_TARGETS,
3044fb0ef58SNikolay Aleksandrov 		.name = "arp_ip_target",
3054fb0ef58SNikolay Aleksandrov 		.desc = "arp targets in n.n.n.n form",
3064fb0ef58SNikolay Aleksandrov 		.flags = BOND_OPTFLAG_RAWVAL,
3074fb0ef58SNikolay Aleksandrov 		.set = bond_option_arp_ip_targets_set
3084fb0ef58SNikolay Aleksandrov 	},
309129e3c1bSHangbin Liu 	[BOND_OPT_NS_TARGETS] = {
310129e3c1bSHangbin Liu 		.id = BOND_OPT_NS_TARGETS,
311129e3c1bSHangbin Liu 		.name = "ns_ip6_target",
312129e3c1bSHangbin Liu 		.desc = "NS targets in ffff:ffff::ffff:ffff form",
313129e3c1bSHangbin Liu 		.flags = BOND_OPTFLAG_RAWVAL,
314129e3c1bSHangbin Liu 		.set = bond_option_ns_ip6_targets_set
315129e3c1bSHangbin Liu 	},
31625a9b54aSNikolay Aleksandrov 	[BOND_OPT_DOWNDELAY] = {
31725a9b54aSNikolay Aleksandrov 		.id = BOND_OPT_DOWNDELAY,
31825a9b54aSNikolay Aleksandrov 		.name = "downdelay",
31925a9b54aSNikolay Aleksandrov 		.desc = "Delay before considering link down, in milliseconds",
32025a9b54aSNikolay Aleksandrov 		.values = bond_intmax_tbl,
32125a9b54aSNikolay Aleksandrov 		.set = bond_option_downdelay_set
32225a9b54aSNikolay Aleksandrov 	},
323e4994612SNikolay Aleksandrov 	[BOND_OPT_UPDELAY] = {
324e4994612SNikolay Aleksandrov 		.id = BOND_OPT_UPDELAY,
325e4994612SNikolay Aleksandrov 		.name = "updelay",
326e4994612SNikolay Aleksandrov 		.desc = "Delay before considering link up, in milliseconds",
327e4994612SNikolay Aleksandrov 		.values = bond_intmax_tbl,
328e4994612SNikolay Aleksandrov 		.set = bond_option_updelay_set
329e4994612SNikolay Aleksandrov 	},
3303a755cd8SHangbin Liu 	[BOND_OPT_LACP_ACTIVE] = {
3313a755cd8SHangbin Liu 		.id = BOND_OPT_LACP_ACTIVE,
3323a755cd8SHangbin Liu 		.name = "lacp_active",
3333a755cd8SHangbin Liu 		.desc = "Send LACPDU frames with configured lacp rate or acts as speak when spoken to",
3343a755cd8SHangbin Liu 		.flags = BOND_OPTFLAG_IFDOWN,
3353a755cd8SHangbin Liu 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
3363a755cd8SHangbin Liu 		.values = bond_lacp_active,
3373a755cd8SHangbin Liu 		.set = bond_option_lacp_active_set
3383a755cd8SHangbin Liu 	},
339d3131de7SNikolay Aleksandrov 	[BOND_OPT_LACP_RATE] = {
340d3131de7SNikolay Aleksandrov 		.id = BOND_OPT_LACP_RATE,
341d3131de7SNikolay Aleksandrov 		.name = "lacp_rate",
342d3131de7SNikolay Aleksandrov 		.desc = "LACPDU tx rate to request from 802.3ad partner",
343d3131de7SNikolay Aleksandrov 		.flags = BOND_OPTFLAG_IFDOWN,
344d3131de7SNikolay Aleksandrov 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
345d3131de7SNikolay Aleksandrov 		.values = bond_lacp_rate_tbl,
346d3131de7SNikolay Aleksandrov 		.set = bond_option_lacp_rate_set
347d3131de7SNikolay Aleksandrov 	},
348633ddc9eSNikolay Aleksandrov 	[BOND_OPT_MINLINKS] = {
349633ddc9eSNikolay Aleksandrov 		.id = BOND_OPT_MINLINKS,
350633ddc9eSNikolay Aleksandrov 		.name = "min_links",
351633ddc9eSNikolay Aleksandrov 		.desc = "Minimum number of available links before turning on carrier",
352633ddc9eSNikolay Aleksandrov 		.values = bond_intmax_tbl,
353633ddc9eSNikolay Aleksandrov 		.set = bond_option_min_links_set
354633ddc9eSNikolay Aleksandrov 	},
3559e5f5eebSNikolay Aleksandrov 	[BOND_OPT_AD_SELECT] = {
3569e5f5eebSNikolay Aleksandrov 		.id = BOND_OPT_AD_SELECT,
3579e5f5eebSNikolay Aleksandrov 		.name = "ad_select",
3589e5f5eebSNikolay Aleksandrov 		.desc = "803.ad aggregation selection logic",
3599e5f5eebSNikolay Aleksandrov 		.flags = BOND_OPTFLAG_IFDOWN,
3609e5f5eebSNikolay Aleksandrov 		.values = bond_ad_select_tbl,
3619e5f5eebSNikolay Aleksandrov 		.set = bond_option_ad_select_set
3629e5f5eebSNikolay Aleksandrov 	},
363ef56becbSNikolay Aleksandrov 	[BOND_OPT_NUM_PEER_NOTIF] = {
364ef56becbSNikolay Aleksandrov 		.id = BOND_OPT_NUM_PEER_NOTIF,
365ef56becbSNikolay Aleksandrov 		.name = "num_unsol_na",
366ef56becbSNikolay Aleksandrov 		.desc = "Number of peer notifications to send on failover event",
367ef56becbSNikolay Aleksandrov 		.values = bond_num_peer_notif_tbl,
368ef56becbSNikolay Aleksandrov 		.set = bond_option_num_peer_notif_set
369ef56becbSNikolay Aleksandrov 	},
370b98d9c66SNikolay Aleksandrov 	[BOND_OPT_MIIMON] = {
371b98d9c66SNikolay Aleksandrov 		.id = BOND_OPT_MIIMON,
372b98d9c66SNikolay Aleksandrov 		.name = "miimon",
373b98d9c66SNikolay Aleksandrov 		.desc = "Link check interval in milliseconds",
374b98d9c66SNikolay Aleksandrov 		.values = bond_intmax_tbl,
375b98d9c66SNikolay Aleksandrov 		.set = bond_option_miimon_set
376b98d9c66SNikolay Aleksandrov 	},
3770a2ff7ccSHangbin Liu 	[BOND_OPT_PRIO] = {
3780a2ff7ccSHangbin Liu 		.id = BOND_OPT_PRIO,
3790a2ff7ccSHangbin Liu 		.name = "prio",
3800a2ff7ccSHangbin Liu 		.desc = "Link priority for failover re-selection",
3810a2ff7ccSHangbin Liu 		.flags = BOND_OPTFLAG_RAWVAL,
3820a2ff7ccSHangbin Liu 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
3830a2ff7ccSHangbin Liu 						BIT(BOND_MODE_TLB) |
3840a2ff7ccSHangbin Liu 						BIT(BOND_MODE_ALB)),
3850a2ff7ccSHangbin Liu 		.set = bond_option_prio_set
3860a2ff7ccSHangbin Liu 	},
387180222f0SNikolay Aleksandrov 	[BOND_OPT_PRIMARY] = {
388180222f0SNikolay Aleksandrov 		.id = BOND_OPT_PRIMARY,
389180222f0SNikolay Aleksandrov 		.name = "primary",
390180222f0SNikolay Aleksandrov 		.desc = "Primary network device to use",
391180222f0SNikolay Aleksandrov 		.flags = BOND_OPTFLAG_RAWVAL,
392180222f0SNikolay Aleksandrov 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
393180222f0SNikolay Aleksandrov 						BIT(BOND_MODE_TLB) |
394180222f0SNikolay Aleksandrov 						BIT(BOND_MODE_ALB)),
395180222f0SNikolay Aleksandrov 		.set = bond_option_primary_set
396180222f0SNikolay Aleksandrov 	},
397388d3a6dSNikolay Aleksandrov 	[BOND_OPT_PRIMARY_RESELECT] = {
398388d3a6dSNikolay Aleksandrov 		.id = BOND_OPT_PRIMARY_RESELECT,
399388d3a6dSNikolay Aleksandrov 		.name = "primary_reselect",
400388d3a6dSNikolay Aleksandrov 		.desc = "Reselect primary slave once it comes up",
401388d3a6dSNikolay Aleksandrov 		.values = bond_primary_reselect_tbl,
402388d3a6dSNikolay Aleksandrov 		.set = bond_option_primary_reselect_set
403388d3a6dSNikolay Aleksandrov 	},
4040fff0608SNikolay Aleksandrov 	[BOND_OPT_USE_CARRIER] = {
4050fff0608SNikolay Aleksandrov 		.id = BOND_OPT_USE_CARRIER,
4060fff0608SNikolay Aleksandrov 		.name = "use_carrier",
4070fff0608SNikolay Aleksandrov 		.desc = "Use netif_carrier_ok (vs MII ioctls) in miimon",
4080fff0608SNikolay Aleksandrov 		.values = bond_use_carrier_tbl,
4090fff0608SNikolay Aleksandrov 		.set = bond_option_use_carrier_set
4100fff0608SNikolay Aleksandrov 	},
411d1fbd3edSNikolay Aleksandrov 	[BOND_OPT_ACTIVE_SLAVE] = {
412d1fbd3edSNikolay Aleksandrov 		.id = BOND_OPT_ACTIVE_SLAVE,
413d1fbd3edSNikolay Aleksandrov 		.name = "active_slave",
414d1fbd3edSNikolay Aleksandrov 		.desc = "Currently active slave",
415d1fbd3edSNikolay Aleksandrov 		.flags = BOND_OPTFLAG_RAWVAL,
416d1fbd3edSNikolay Aleksandrov 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
417d1fbd3edSNikolay Aleksandrov 						BIT(BOND_MODE_TLB) |
418d1fbd3edSNikolay Aleksandrov 						BIT(BOND_MODE_ALB)),
419d1fbd3edSNikolay Aleksandrov 		.set = bond_option_active_slave_set
420d1fbd3edSNikolay Aleksandrov 	},
42124089ba1SNikolay Aleksandrov 	[BOND_OPT_QUEUE_ID] = {
42224089ba1SNikolay Aleksandrov 		.id = BOND_OPT_QUEUE_ID,
42324089ba1SNikolay Aleksandrov 		.name = "queue_id",
42424089ba1SNikolay Aleksandrov 		.desc = "Set queue id of a slave",
42524089ba1SNikolay Aleksandrov 		.flags = BOND_OPTFLAG_RAWVAL,
42624089ba1SNikolay Aleksandrov 		.set = bond_option_queue_id_set
42724089ba1SNikolay Aleksandrov 	},
4283df01162SNikolay Aleksandrov 	[BOND_OPT_ALL_SLAVES_ACTIVE] = {
4293df01162SNikolay Aleksandrov 		.id = BOND_OPT_ALL_SLAVES_ACTIVE,
4303df01162SNikolay Aleksandrov 		.name = "all_slaves_active",
4313df01162SNikolay Aleksandrov 		.desc = "Keep all frames received on an interface by setting active flag for all slaves",
4323df01162SNikolay Aleksandrov 		.values = bond_all_slaves_active_tbl,
4333df01162SNikolay Aleksandrov 		.set = bond_option_all_slaves_active_set
4343df01162SNikolay Aleksandrov 	},
435105c8fb6SNikolay Aleksandrov 	[BOND_OPT_RESEND_IGMP] = {
436105c8fb6SNikolay Aleksandrov 		.id = BOND_OPT_RESEND_IGMP,
437105c8fb6SNikolay Aleksandrov 		.name = "resend_igmp",
438105c8fb6SNikolay Aleksandrov 		.desc = "Number of IGMP membership reports to send on link failure",
439105c8fb6SNikolay Aleksandrov 		.values = bond_resend_igmp_tbl,
440105c8fb6SNikolay Aleksandrov 		.set = bond_option_resend_igmp_set
441105c8fb6SNikolay Aleksandrov 	},
4424325b374SNikolay Aleksandrov 	[BOND_OPT_LP_INTERVAL] = {
4434325b374SNikolay Aleksandrov 		.id = BOND_OPT_LP_INTERVAL,
4444325b374SNikolay Aleksandrov 		.name = "lp_interval",
4454325b374SNikolay Aleksandrov 		.desc = "The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch",
4464325b374SNikolay Aleksandrov 		.values = bond_lp_interval_tbl,
4474325b374SNikolay Aleksandrov 		.set = bond_option_lp_interval_set
4484325b374SNikolay Aleksandrov 	},
4490e2e5b66SNikolay Aleksandrov 	[BOND_OPT_SLAVES] = {
4500e2e5b66SNikolay Aleksandrov 		.id = BOND_OPT_SLAVES,
4510e2e5b66SNikolay Aleksandrov 		.name = "slaves",
4520e2e5b66SNikolay Aleksandrov 		.desc = "Slave membership management",
4530e2e5b66SNikolay Aleksandrov 		.flags = BOND_OPTFLAG_RAWVAL,
4540e2e5b66SNikolay Aleksandrov 		.set = bond_option_slaves_set
4550e2e5b66SNikolay Aleksandrov 	},
456e9f0fb88SMahesh Bandewar 	[BOND_OPT_TLB_DYNAMIC_LB] = {
457e9f0fb88SMahesh Bandewar 		.id = BOND_OPT_TLB_DYNAMIC_LB,
458dc3e5d18SNikolay Aleksandrov 		.name = "tlb_dynamic_lb",
459e9f0fb88SMahesh Bandewar 		.desc = "Enable dynamic flow shuffling",
460e79c1055SDebabrata Banerjee 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_TLB) | BIT(BOND_MODE_ALB)),
461e9f0fb88SMahesh Bandewar 		.values = bond_tlb_dynamic_lb_tbl,
462e9f0fb88SMahesh Bandewar 		.flags = BOND_OPTFLAG_IFDOWN,
463e9f0fb88SMahesh Bandewar 		.set = bond_option_tlb_dynamic_lb_set,
4646791e466SMahesh Bandewar 	},
4656791e466SMahesh Bandewar 	[BOND_OPT_AD_ACTOR_SYS_PRIO] = {
4666791e466SMahesh Bandewar 		.id = BOND_OPT_AD_ACTOR_SYS_PRIO,
4676791e466SMahesh Bandewar 		.name = "ad_actor_sys_prio",
4686791e466SMahesh Bandewar 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
4696791e466SMahesh Bandewar 		.values = bond_ad_actor_sys_prio_tbl,
4706791e466SMahesh Bandewar 		.set = bond_option_ad_actor_sys_prio_set,
4716791e466SMahesh Bandewar 	},
47274514957SMahesh Bandewar 	[BOND_OPT_AD_ACTOR_SYSTEM] = {
47374514957SMahesh Bandewar 		.id = BOND_OPT_AD_ACTOR_SYSTEM,
47474514957SMahesh Bandewar 		.name = "ad_actor_system",
47574514957SMahesh Bandewar 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
4767f20cd25SNikolay Aleksandrov 		.flags = BOND_OPTFLAG_RAWVAL,
47774514957SMahesh Bandewar 		.set = bond_option_ad_actor_system_set,
47874514957SMahesh Bandewar 	},
479d22a5fc0SMahesh Bandewar 	[BOND_OPT_AD_USER_PORT_KEY] = {
480d22a5fc0SMahesh Bandewar 		.id = BOND_OPT_AD_USER_PORT_KEY,
481d22a5fc0SMahesh Bandewar 		.name = "ad_user_port_key",
482d22a5fc0SMahesh Bandewar 		.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
483d22a5fc0SMahesh Bandewar 		.flags = BOND_OPTFLAG_IFDOWN,
484d22a5fc0SMahesh Bandewar 		.values = bond_ad_user_port_key_tbl,
485d22a5fc0SMahesh Bandewar 		.set = bond_option_ad_user_port_key_set,
486205845a3SNikolay Aleksandrov 	},
487205845a3SNikolay Aleksandrov 	[BOND_OPT_NUM_PEER_NOTIF_ALIAS] = {
488205845a3SNikolay Aleksandrov 		.id = BOND_OPT_NUM_PEER_NOTIF_ALIAS,
489205845a3SNikolay Aleksandrov 		.name = "num_grat_arp",
490205845a3SNikolay Aleksandrov 		.desc = "Number of peer notifications to send on failover event",
491205845a3SNikolay Aleksandrov 		.values = bond_num_peer_notif_tbl,
492205845a3SNikolay Aleksandrov 		.set = bond_option_num_peer_notif_set
49307a4ddecSVincent Bernat 	},
49407a4ddecSVincent Bernat 	[BOND_OPT_PEER_NOTIF_DELAY] = {
49507a4ddecSVincent Bernat 		.id = BOND_OPT_PEER_NOTIF_DELAY,
49607a4ddecSVincent Bernat 		.name = "peer_notif_delay",
49707a4ddecSVincent Bernat 		.desc = "Delay between each peer notification on failover event, in milliseconds",
4989949e2efSHangbin Liu 		.values = bond_peer_notif_delay_tbl,
49907a4ddecSVincent Bernat 		.set = bond_option_peer_notif_delay_set
500d22a5fc0SMahesh Bandewar 	}
50109117362SNikolay Aleksandrov };
50209117362SNikolay Aleksandrov 
503dc3e5d18SNikolay Aleksandrov /* Searches for an option by name */
bond_opt_get_by_name(const char * name)504dc3e5d18SNikolay Aleksandrov const struct bond_option *bond_opt_get_by_name(const char *name)
505dc3e5d18SNikolay Aleksandrov {
506dc3e5d18SNikolay Aleksandrov 	const struct bond_option *opt;
507dc3e5d18SNikolay Aleksandrov 	int option;
508dc3e5d18SNikolay Aleksandrov 
509dc3e5d18SNikolay Aleksandrov 	for (option = 0; option < BOND_OPT_LAST; option++) {
510dc3e5d18SNikolay Aleksandrov 		opt = bond_opt_get(option);
511dc3e5d18SNikolay Aleksandrov 		if (opt && !strcmp(opt->name, name))
512dc3e5d18SNikolay Aleksandrov 			return opt;
513dc3e5d18SNikolay Aleksandrov 	}
514dc3e5d18SNikolay Aleksandrov 
515dc3e5d18SNikolay Aleksandrov 	return NULL;
516dc3e5d18SNikolay Aleksandrov }
517dc3e5d18SNikolay Aleksandrov 
51809117362SNikolay Aleksandrov /* Searches for a value in opt's values[] table */
bond_opt_get_val(unsigned int option,u64 val)519f3253339Sstephen hemminger const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
52009117362SNikolay Aleksandrov {
521f3253339Sstephen hemminger 	const struct bond_option *opt;
52209117362SNikolay Aleksandrov 	int i;
52309117362SNikolay Aleksandrov 
52409117362SNikolay Aleksandrov 	opt = bond_opt_get(option);
52509117362SNikolay Aleksandrov 	if (WARN_ON(!opt))
52609117362SNikolay Aleksandrov 		return NULL;
52709117362SNikolay Aleksandrov 	for (i = 0; opt->values && opt->values[i].string; i++)
52809117362SNikolay Aleksandrov 		if (opt->values[i].value == val)
52909117362SNikolay Aleksandrov 			return &opt->values[i];
53009117362SNikolay Aleksandrov 
53109117362SNikolay Aleksandrov 	return NULL;
53209117362SNikolay Aleksandrov }
53309117362SNikolay Aleksandrov 
53409117362SNikolay Aleksandrov /* Searches for a value in opt's values[] table which matches the flagmask */
bond_opt_get_flags(const struct bond_option * opt,u32 flagmask)535f3253339Sstephen hemminger static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
53609117362SNikolay Aleksandrov 						       u32 flagmask)
53709117362SNikolay Aleksandrov {
53809117362SNikolay Aleksandrov 	int i;
53909117362SNikolay Aleksandrov 
54009117362SNikolay Aleksandrov 	for (i = 0; opt->values && opt->values[i].string; i++)
54109117362SNikolay Aleksandrov 		if (opt->values[i].flags & flagmask)
54209117362SNikolay Aleksandrov 			return &opt->values[i];
54309117362SNikolay Aleksandrov 
54409117362SNikolay Aleksandrov 	return NULL;
54509117362SNikolay Aleksandrov }
54609117362SNikolay Aleksandrov 
54709117362SNikolay Aleksandrov /* If maxval is missing then there's no range to check. In case minval is
54809117362SNikolay Aleksandrov  * missing then it's considered to be 0.
54909117362SNikolay Aleksandrov  */
bond_opt_check_range(const struct bond_option * opt,u64 val)55009117362SNikolay Aleksandrov static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
55109117362SNikolay Aleksandrov {
552f3253339Sstephen hemminger 	const struct bond_opt_value *minval, *maxval;
55309117362SNikolay Aleksandrov 
55409117362SNikolay Aleksandrov 	minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
55509117362SNikolay Aleksandrov 	maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
55609117362SNikolay Aleksandrov 	if (!maxval || (minval && val < minval->value) || val > maxval->value)
55709117362SNikolay Aleksandrov 		return false;
55809117362SNikolay Aleksandrov 
55909117362SNikolay Aleksandrov 	return true;
56009117362SNikolay Aleksandrov }
56109117362SNikolay Aleksandrov 
56209117362SNikolay Aleksandrov /**
56309117362SNikolay Aleksandrov  * bond_opt_parse - parse option value
56409117362SNikolay Aleksandrov  * @opt: the option to parse against
56509117362SNikolay Aleksandrov  * @val: value to parse
56609117362SNikolay Aleksandrov  *
56709117362SNikolay Aleksandrov  * This function tries to extract the value from @val and check if it's
56809117362SNikolay Aleksandrov  * a possible match for the option and returns NULL if a match isn't found,
56909117362SNikolay Aleksandrov  * or the struct_opt_value that matched. It also strips the new line from
57009117362SNikolay Aleksandrov  * @val->string if it's present.
57109117362SNikolay Aleksandrov  */
bond_opt_parse(const struct bond_option * opt,struct bond_opt_value * val)572f3253339Sstephen hemminger const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
57309117362SNikolay Aleksandrov 					    struct bond_opt_value *val)
57409117362SNikolay Aleksandrov {
57509117362SNikolay Aleksandrov 	char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, };
576f3253339Sstephen hemminger 	const struct bond_opt_value *tbl;
577f3253339Sstephen hemminger 	const struct bond_opt_value *ret = NULL;
57809117362SNikolay Aleksandrov 	bool checkval;
57909117362SNikolay Aleksandrov 	int i, rv;
58009117362SNikolay Aleksandrov 
58109117362SNikolay Aleksandrov 	/* No parsing if the option wants a raw val */
58209117362SNikolay Aleksandrov 	if (opt->flags & BOND_OPTFLAG_RAWVAL)
58309117362SNikolay Aleksandrov 		return val;
58409117362SNikolay Aleksandrov 
58509117362SNikolay Aleksandrov 	tbl = opt->values;
58609117362SNikolay Aleksandrov 	if (!tbl)
58709117362SNikolay Aleksandrov 		goto out;
58809117362SNikolay Aleksandrov 
58909117362SNikolay Aleksandrov 	/* ULLONG_MAX is used to bypass string processing */
59009117362SNikolay Aleksandrov 	checkval = val->value != ULLONG_MAX;
59109117362SNikolay Aleksandrov 	if (!checkval) {
59209117362SNikolay Aleksandrov 		if (!val->string)
59309117362SNikolay Aleksandrov 			goto out;
59409117362SNikolay Aleksandrov 		p = strchr(val->string, '\n');
59509117362SNikolay Aleksandrov 		if (p)
59609117362SNikolay Aleksandrov 			*p = '\0';
59709117362SNikolay Aleksandrov 		for (p = val->string; *p; p++)
59809117362SNikolay Aleksandrov 			if (!(isdigit(*p) || isspace(*p)))
59909117362SNikolay Aleksandrov 				break;
60009117362SNikolay Aleksandrov 		/* The following code extracts the string to match or the value
60109117362SNikolay Aleksandrov 		 * and sets checkval appropriately
60209117362SNikolay Aleksandrov 		 */
60309117362SNikolay Aleksandrov 		if (*p) {
60409117362SNikolay Aleksandrov 			rv = sscanf(val->string, "%32s", valstr);
60509117362SNikolay Aleksandrov 		} else {
60609117362SNikolay Aleksandrov 			rv = sscanf(val->string, "%llu", &val->value);
60709117362SNikolay Aleksandrov 			checkval = true;
60809117362SNikolay Aleksandrov 		}
60909117362SNikolay Aleksandrov 		if (!rv)
61009117362SNikolay Aleksandrov 			goto out;
61109117362SNikolay Aleksandrov 	}
61209117362SNikolay Aleksandrov 
61309117362SNikolay Aleksandrov 	for (i = 0; tbl[i].string; i++) {
61409117362SNikolay Aleksandrov 		/* Check for exact match */
61509117362SNikolay Aleksandrov 		if (checkval) {
61609117362SNikolay Aleksandrov 			if (val->value == tbl[i].value)
61709117362SNikolay Aleksandrov 				ret = &tbl[i];
61809117362SNikolay Aleksandrov 		} else {
61909117362SNikolay Aleksandrov 			if (!strcmp(valstr, "default") &&
62009117362SNikolay Aleksandrov 			    (tbl[i].flags & BOND_VALFLAG_DEFAULT))
62109117362SNikolay Aleksandrov 				ret = &tbl[i];
62209117362SNikolay Aleksandrov 
62309117362SNikolay Aleksandrov 			if (!strcmp(valstr, tbl[i].string))
62409117362SNikolay Aleksandrov 				ret = &tbl[i];
62509117362SNikolay Aleksandrov 		}
62609117362SNikolay Aleksandrov 		/* Found an exact match */
62709117362SNikolay Aleksandrov 		if (ret)
62809117362SNikolay Aleksandrov 			goto out;
62909117362SNikolay Aleksandrov 	}
63009117362SNikolay Aleksandrov 	/* Possible range match */
63109117362SNikolay Aleksandrov 	if (checkval && bond_opt_check_range(opt, val->value))
63209117362SNikolay Aleksandrov 		ret = val;
63309117362SNikolay Aleksandrov out:
63409117362SNikolay Aleksandrov 	return ret;
63509117362SNikolay Aleksandrov }
63609117362SNikolay Aleksandrov 
63709117362SNikolay Aleksandrov /* Check opt's dependencies against bond mode and currently set options */
bond_opt_check_deps(struct bonding * bond,const struct bond_option * opt)63809117362SNikolay Aleksandrov static int bond_opt_check_deps(struct bonding *bond,
63909117362SNikolay Aleksandrov 			       const struct bond_option *opt)
64009117362SNikolay Aleksandrov {
64109117362SNikolay Aleksandrov 	struct bond_params *params = &bond->params;
64209117362SNikolay Aleksandrov 
64309117362SNikolay Aleksandrov 	if (test_bit(params->mode, &opt->unsuppmodes))
64409117362SNikolay Aleksandrov 		return -EACCES;
64509117362SNikolay Aleksandrov 	if ((opt->flags & BOND_OPTFLAG_NOSLAVES) && bond_has_slaves(bond))
64609117362SNikolay Aleksandrov 		return -ENOTEMPTY;
64709117362SNikolay Aleksandrov 	if ((opt->flags & BOND_OPTFLAG_IFDOWN) && (bond->dev->flags & IFF_UP))
64809117362SNikolay Aleksandrov 		return -EBUSY;
64909117362SNikolay Aleksandrov 
65009117362SNikolay Aleksandrov 	return 0;
65109117362SNikolay Aleksandrov }
65209117362SNikolay Aleksandrov 
bond_opt_dep_print(struct bonding * bond,const struct bond_option * opt,struct nlattr * bad_attr,struct netlink_ext_ack * extack)65309117362SNikolay Aleksandrov static void bond_opt_dep_print(struct bonding *bond,
6542bff369bSJonathan Toppins 			       const struct bond_option *opt,
6552bff369bSJonathan Toppins 			       struct nlattr *bad_attr,
6562bff369bSJonathan Toppins 			       struct netlink_ext_ack *extack)
65709117362SNikolay Aleksandrov {
65828f084ccSstephen hemminger 	const struct bond_opt_value *modeval;
65909117362SNikolay Aleksandrov 	struct bond_params *params;
66009117362SNikolay Aleksandrov 
66109117362SNikolay Aleksandrov 	params = &bond->params;
6622b3798d5SNikolay Aleksandrov 	modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode);
6632bff369bSJonathan Toppins 	if (test_bit(params->mode, &opt->unsuppmodes)) {
6642de390baSVeaceslav Falico 		netdev_err(bond->dev, "option %s: mode dependency failed, not supported in mode %s(%llu)\n",
6652de390baSVeaceslav Falico 			   opt->name, modeval->string, modeval->value);
6662bff369bSJonathan Toppins 		NL_SET_ERR_MSG_ATTR(extack, bad_attr,
6672bff369bSJonathan Toppins 				    "option not supported in mode");
6682bff369bSJonathan Toppins 	}
66909117362SNikolay Aleksandrov }
67009117362SNikolay Aleksandrov 
bond_opt_error_interpret(struct bonding * bond,const struct bond_option * opt,int error,const struct bond_opt_value * val,struct nlattr * bad_attr,struct netlink_ext_ack * extack)67109117362SNikolay Aleksandrov static void bond_opt_error_interpret(struct bonding *bond,
67209117362SNikolay Aleksandrov 				     const struct bond_option *opt,
6732bff369bSJonathan Toppins 				     int error, const struct bond_opt_value *val,
6742bff369bSJonathan Toppins 				     struct nlattr *bad_attr,
6752bff369bSJonathan Toppins 				     struct netlink_ext_ack *extack)
67609117362SNikolay Aleksandrov {
67728f084ccSstephen hemminger 	const struct bond_opt_value *minval, *maxval;
67809117362SNikolay Aleksandrov 	char *p;
67909117362SNikolay Aleksandrov 
68009117362SNikolay Aleksandrov 	switch (error) {
68109117362SNikolay Aleksandrov 	case -EINVAL:
6822bff369bSJonathan Toppins 		NL_SET_ERR_MSG_ATTR(extack, bad_attr, "invalid option value");
68309117362SNikolay Aleksandrov 		if (val) {
68409117362SNikolay Aleksandrov 			if (val->string) {
68509117362SNikolay Aleksandrov 				/* sometimes RAWVAL opts may have new lines */
68609117362SNikolay Aleksandrov 				p = strchr(val->string, '\n');
68709117362SNikolay Aleksandrov 				if (p)
68809117362SNikolay Aleksandrov 					*p = '\0';
6892de390baSVeaceslav Falico 				netdev_err(bond->dev, "option %s: invalid value (%s)\n",
6902de390baSVeaceslav Falico 					   opt->name, val->string);
69109117362SNikolay Aleksandrov 			} else {
6922de390baSVeaceslav Falico 				netdev_err(bond->dev, "option %s: invalid value (%llu)\n",
6932de390baSVeaceslav Falico 					   opt->name, val->value);
69409117362SNikolay Aleksandrov 			}
69509117362SNikolay Aleksandrov 		}
69609117362SNikolay Aleksandrov 		minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
69709117362SNikolay Aleksandrov 		maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
69809117362SNikolay Aleksandrov 		if (!maxval)
69909117362SNikolay Aleksandrov 			break;
7002de390baSVeaceslav Falico 		netdev_err(bond->dev, "option %s: allowed values %llu - %llu\n",
7012de390baSVeaceslav Falico 			   opt->name, minval ? minval->value : 0, maxval->value);
70209117362SNikolay Aleksandrov 		break;
70309117362SNikolay Aleksandrov 	case -EACCES:
7042bff369bSJonathan Toppins 		bond_opt_dep_print(bond, opt, bad_attr, extack);
70509117362SNikolay Aleksandrov 		break;
70609117362SNikolay Aleksandrov 	case -ENOTEMPTY:
7072bff369bSJonathan Toppins 		NL_SET_ERR_MSG_ATTR(extack, bad_attr,
7082bff369bSJonathan Toppins 				    "unable to set option because the bond device has slaves");
7092de390baSVeaceslav Falico 		netdev_err(bond->dev, "option %s: unable to set because the bond device has slaves\n",
7102de390baSVeaceslav Falico 			   opt->name);
71109117362SNikolay Aleksandrov 		break;
71209117362SNikolay Aleksandrov 	case -EBUSY:
7132bff369bSJonathan Toppins 		NL_SET_ERR_MSG_ATTR(extack, bad_attr,
7142bff369bSJonathan Toppins 				    "unable to set option because the bond is up");
7152de390baSVeaceslav Falico 		netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n",
7162de390baSVeaceslav Falico 			   opt->name);
71709117362SNikolay Aleksandrov 		break;
718acdff0dfSJianlin Lv 	case -ENODEV:
719acdff0dfSJianlin Lv 		if (val && val->string) {
720acdff0dfSJianlin Lv 			p = strchr(val->string, '\n');
721acdff0dfSJianlin Lv 			if (p)
722acdff0dfSJianlin Lv 				*p = '\0';
723acdff0dfSJianlin Lv 			netdev_err(bond->dev, "option %s: interface %s does not exist!\n",
724acdff0dfSJianlin Lv 				   opt->name, val->string);
7252bff369bSJonathan Toppins 			NL_SET_ERR_MSG_ATTR(extack, bad_attr,
7262bff369bSJonathan Toppins 					    "interface does not exist");
727acdff0dfSJianlin Lv 		}
728acdff0dfSJianlin Lv 		break;
72909117362SNikolay Aleksandrov 	default:
73009117362SNikolay Aleksandrov 		break;
73109117362SNikolay Aleksandrov 	}
73209117362SNikolay Aleksandrov }
73309117362SNikolay Aleksandrov 
73409117362SNikolay Aleksandrov /**
73509117362SNikolay Aleksandrov  * __bond_opt_set - set a bonding option
73609117362SNikolay Aleksandrov  * @bond: target bond device
73709117362SNikolay Aleksandrov  * @option: option to set
73809117362SNikolay Aleksandrov  * @val: value to set it to
7392bff369bSJonathan Toppins  * @bad_attr: netlink attribue that caused the error
7402bff369bSJonathan Toppins  * @extack: extended netlink error structure, used when an error message
7412bff369bSJonathan Toppins  *          needs to be returned to the caller via netlink
74209117362SNikolay Aleksandrov  *
74309117362SNikolay Aleksandrov  * This function is used to change the bond's option value, it can be
74409117362SNikolay Aleksandrov  * used for both enabling/changing an option and for disabling it. RTNL lock
74509117362SNikolay Aleksandrov  * must be obtained before calling this function.
74609117362SNikolay Aleksandrov  */
__bond_opt_set(struct bonding * bond,unsigned int option,struct bond_opt_value * val,struct nlattr * bad_attr,struct netlink_ext_ack * extack)74709117362SNikolay Aleksandrov int __bond_opt_set(struct bonding *bond,
7482bff369bSJonathan Toppins 		   unsigned int option, struct bond_opt_value *val,
7492bff369bSJonathan Toppins 		   struct nlattr *bad_attr, struct netlink_ext_ack *extack)
75009117362SNikolay Aleksandrov {
75128f084ccSstephen hemminger 	const struct bond_opt_value *retval = NULL;
75209117362SNikolay Aleksandrov 	const struct bond_option *opt;
75309117362SNikolay Aleksandrov 	int ret = -ENOENT;
75409117362SNikolay Aleksandrov 
75509117362SNikolay Aleksandrov 	ASSERT_RTNL();
75609117362SNikolay Aleksandrov 
75709117362SNikolay Aleksandrov 	opt = bond_opt_get(option);
75809117362SNikolay Aleksandrov 	if (WARN_ON(!val) || WARN_ON(!opt))
75909117362SNikolay Aleksandrov 		goto out;
76009117362SNikolay Aleksandrov 	ret = bond_opt_check_deps(bond, opt);
76109117362SNikolay Aleksandrov 	if (ret)
76209117362SNikolay Aleksandrov 		goto out;
76309117362SNikolay Aleksandrov 	retval = bond_opt_parse(opt, val);
76409117362SNikolay Aleksandrov 	if (!retval) {
76509117362SNikolay Aleksandrov 		ret = -EINVAL;
76609117362SNikolay Aleksandrov 		goto out;
76709117362SNikolay Aleksandrov 	}
76809117362SNikolay Aleksandrov 	ret = opt->set(bond, retval);
76909117362SNikolay Aleksandrov out:
77009117362SNikolay Aleksandrov 	if (ret)
7712bff369bSJonathan Toppins 		bond_opt_error_interpret(bond, opt, ret, val, bad_attr, extack);
7727a7e96e0SVlad Yasevich 
7737a7e96e0SVlad Yasevich 	return ret;
7747a7e96e0SVlad Yasevich }
7757a7e96e0SVlad Yasevich /**
7767a7e96e0SVlad Yasevich  * __bond_opt_set_notify - set a bonding option
7777a7e96e0SVlad Yasevich  * @bond: target bond device
7787a7e96e0SVlad Yasevich  * @option: option to set
7797a7e96e0SVlad Yasevich  * @val: value to set it to
7807a7e96e0SVlad Yasevich  *
7817a7e96e0SVlad Yasevich  * This function is used to change the bond's option value and trigger
7827a7e96e0SVlad Yasevich  * a notification to user sapce. It can be used for both enabling/changing
7837a7e96e0SVlad Yasevich  * an option and for disabling it. RTNL lock must be obtained before calling
7847a7e96e0SVlad Yasevich  * this function.
7857a7e96e0SVlad Yasevich  */
__bond_opt_set_notify(struct bonding * bond,unsigned int option,struct bond_opt_value * val)7867a7e96e0SVlad Yasevich int __bond_opt_set_notify(struct bonding *bond,
7877a7e96e0SVlad Yasevich 			  unsigned int option, struct bond_opt_value *val)
7887a7e96e0SVlad Yasevich {
78992e1b57cSColin Ian King 	int ret;
7907a7e96e0SVlad Yasevich 
7917a7e96e0SVlad Yasevich 	ASSERT_RTNL();
7927a7e96e0SVlad Yasevich 
7932bff369bSJonathan Toppins 	ret = __bond_opt_set(bond, option, val, NULL, NULL);
7947a7e96e0SVlad Yasevich 
7957a7e96e0SVlad Yasevich 	if (!ret && (bond->dev->reg_state == NETREG_REGISTERED))
796d4261e56SJiri Pirko 		call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
79709117362SNikolay Aleksandrov 
79809117362SNikolay Aleksandrov 	return ret;
79909117362SNikolay Aleksandrov }
80009117362SNikolay Aleksandrov 
80109117362SNikolay Aleksandrov /**
80209117362SNikolay Aleksandrov  * bond_opt_tryset_rtnl - try to acquire rtnl and call __bond_opt_set
80309117362SNikolay Aleksandrov  * @bond: target bond device
80409117362SNikolay Aleksandrov  * @option: option to set
80509117362SNikolay Aleksandrov  * @buf: value to set it to
80609117362SNikolay Aleksandrov  *
80709117362SNikolay Aleksandrov  * This function tries to acquire RTNL without blocking and if successful
80809117362SNikolay Aleksandrov  * calls __bond_opt_set. It is mainly used for sysfs option manipulation.
80909117362SNikolay Aleksandrov  */
bond_opt_tryset_rtnl(struct bonding * bond,unsigned int option,char * buf)81009117362SNikolay Aleksandrov int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf)
81109117362SNikolay Aleksandrov {
81209117362SNikolay Aleksandrov 	struct bond_opt_value optval;
81309117362SNikolay Aleksandrov 	int ret;
81409117362SNikolay Aleksandrov 
81509117362SNikolay Aleksandrov 	if (!rtnl_trylock())
81609117362SNikolay Aleksandrov 		return restart_syscall();
81709117362SNikolay Aleksandrov 	bond_opt_initstr(&optval, buf);
8187a7e96e0SVlad Yasevich 	ret = __bond_opt_set_notify(bond, option, &optval);
81909117362SNikolay Aleksandrov 	rtnl_unlock();
82009117362SNikolay Aleksandrov 
82109117362SNikolay Aleksandrov 	return ret;
82209117362SNikolay Aleksandrov }
82309117362SNikolay Aleksandrov 
82409117362SNikolay Aleksandrov /**
82509117362SNikolay Aleksandrov  * bond_opt_get - get a pointer to an option
82609117362SNikolay Aleksandrov  * @option: option for which to return a pointer
82709117362SNikolay Aleksandrov  *
82809117362SNikolay Aleksandrov  * This function checks if option is valid and if so returns a pointer
82909117362SNikolay Aleksandrov  * to its entry in the bond_opts[] option array.
83009117362SNikolay Aleksandrov  */
bond_opt_get(unsigned int option)831f3253339Sstephen hemminger const struct bond_option *bond_opt_get(unsigned int option)
83209117362SNikolay Aleksandrov {
83309117362SNikolay Aleksandrov 	if (!BOND_OPT_VALID(option))
83409117362SNikolay Aleksandrov 		return NULL;
83509117362SNikolay Aleksandrov 
83609117362SNikolay Aleksandrov 	return &bond_opts[option];
83709117362SNikolay Aleksandrov }
83809117362SNikolay Aleksandrov 
bond_set_xfrm_features(struct bonding * bond)839f45583deSTariq Toukan static bool bond_set_xfrm_features(struct bonding *bond)
840007ab534SJarod Wilson {
841007ab534SJarod Wilson 	if (!IS_ENABLED(CONFIG_XFRM_OFFLOAD))
842f45583deSTariq Toukan 		return false;
843007ab534SJarod Wilson 
844f45583deSTariq Toukan 	if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
845f45583deSTariq Toukan 		bond->dev->wanted_features |= BOND_XFRM_FEATURES;
846007ab534SJarod Wilson 	else
847f45583deSTariq Toukan 		bond->dev->wanted_features &= ~BOND_XFRM_FEATURES;
848007ab534SJarod Wilson 
849f45583deSTariq Toukan 	return true;
850007ab534SJarod Wilson }
851007ab534SJarod Wilson 
bond_option_mode_set(struct bonding * bond,const struct bond_opt_value * newval)852ff11d8b2SNikolay Aleksandrov static int bond_option_mode_set(struct bonding *bond,
853ff11d8b2SNikolay Aleksandrov 				const struct bond_opt_value *newval)
85472be35feSJiri Pirko {
855c1f897ceSJarod Wilson 	if (!bond_mode_uses_arp(newval->value)) {
856c1f897ceSJarod Wilson 		if (bond->params.arp_interval) {
857eac306b4SMichael Dilmore 			netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n",
8582de390baSVeaceslav Falico 				   newval->string);
859fe9d04afSdingtianhong 			/* disable arp monitoring */
860fe9d04afSdingtianhong 			bond->params.arp_interval = 0;
861c1f897ceSJarod Wilson 		}
862c1f897ceSJarod Wilson 
863c1f897ceSJarod Wilson 		if (!bond->params.miimon) {
864fe9d04afSdingtianhong 			/* set miimon to default value */
865fe9d04afSdingtianhong 			bond->params.miimon = BOND_DEFAULT_MIIMON;
866eac306b4SMichael Dilmore 			netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n",
8672de390baSVeaceslav Falico 				   bond->params.miimon);
86872be35feSJiri Pirko 		}
869c1f897ceSJarod Wilson 	}
87072be35feSJiri Pirko 
871c6644d07SKosuke Tatsukawa 	if (newval->value == BOND_MODE_ALB)
872c6644d07SKosuke Tatsukawa 		bond->params.tlb_dynamic_lb = 1;
873c6644d07SKosuke Tatsukawa 
87472be35feSJiri Pirko 	/* don't cache arp_validate between modes */
87572be35feSJiri Pirko 	bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
8762b3798d5SNikolay Aleksandrov 	bond->params.mode = newval->value;
8772b3798d5SNikolay Aleksandrov 
87889df6a81STariq Toukan 	if (bond->dev->reg_state == NETREG_REGISTERED) {
87989df6a81STariq Toukan 		bool update = false;
88089df6a81STariq Toukan 
88189df6a81STariq Toukan 		update |= bond_set_xfrm_features(bond);
88289df6a81STariq Toukan 
88389df6a81STariq Toukan 		if (update)
884f45583deSTariq Toukan 			netdev_update_features(bond->dev);
88589df6a81STariq Toukan 	}
886f45583deSTariq Toukan 
887cb9e6e58SLorenzo Bianconi 	bond_xdp_set_features(bond->dev);
888cb9e6e58SLorenzo Bianconi 
88972be35feSJiri Pirko 	return 0;
89072be35feSJiri Pirko }
891d9e32b21SJiri Pirko 
bond_option_active_slave_set(struct bonding * bond,const struct bond_opt_value * newval)892f3253339Sstephen hemminger static int bond_option_active_slave_set(struct bonding *bond,
89328f084ccSstephen hemminger 					const struct bond_opt_value *newval)
894d9e32b21SJiri Pirko {
895d1fbd3edSNikolay Aleksandrov 	char ifname[IFNAMSIZ] = { 0, };
896d1fbd3edSNikolay Aleksandrov 	struct net_device *slave_dev;
897d9e32b21SJiri Pirko 	int ret = 0;
898d9e32b21SJiri Pirko 
899d1fbd3edSNikolay Aleksandrov 	sscanf(newval->string, "%15s", ifname); /* IFNAMSIZ */
900d1fbd3edSNikolay Aleksandrov 	if (!strlen(ifname) || newval->string[0] == '\n') {
901d1fbd3edSNikolay Aleksandrov 		slave_dev = NULL;
902d1fbd3edSNikolay Aleksandrov 	} else {
903d1fbd3edSNikolay Aleksandrov 		slave_dev = __dev_get_by_name(dev_net(bond->dev), ifname);
904d1fbd3edSNikolay Aleksandrov 		if (!slave_dev)
905d1fbd3edSNikolay Aleksandrov 			return -ENODEV;
906d1fbd3edSNikolay Aleksandrov 	}
907d1fbd3edSNikolay Aleksandrov 
908d9e32b21SJiri Pirko 	if (slave_dev) {
909d9e32b21SJiri Pirko 		if (!netif_is_bond_slave(slave_dev)) {
910f887e54cSJarod Wilson 			slave_err(bond->dev, slave_dev, "Device is not bonding slave\n");
911d9e32b21SJiri Pirko 			return -EINVAL;
912d9e32b21SJiri Pirko 		}
913d9e32b21SJiri Pirko 
914d9e32b21SJiri Pirko 		if (bond->dev != netdev_master_upper_dev_get(slave_dev)) {
915f887e54cSJarod Wilson 			slave_err(bond->dev, slave_dev, "Device is not our slave\n");
916d9e32b21SJiri Pirko 			return -EINVAL;
917d9e32b21SJiri Pirko 		}
918d9e32b21SJiri Pirko 	}
919d9e32b21SJiri Pirko 
920d9e32b21SJiri Pirko 	block_netpoll_tx();
921d9e32b21SJiri Pirko 	/* check to see if we are clearing active */
922d9e32b21SJiri Pirko 	if (!slave_dev) {
923eac306b4SMichael Dilmore 		netdev_dbg(bond->dev, "Clearing current active slave\n");
924996ba2f0SNikolay Aleksandrov 		bond_change_active_slave(bond, NULL);
925d9e32b21SJiri Pirko 		bond_select_active_slave(bond);
926d9e32b21SJiri Pirko 	} else {
9271c72cfdcSNikolay Aleksandrov 		struct slave *old_active = rtnl_dereference(bond->curr_active_slave);
928d9e32b21SJiri Pirko 		struct slave *new_active = bond_slave_get_rtnl(slave_dev);
929d9e32b21SJiri Pirko 
930d9e32b21SJiri Pirko 		BUG_ON(!new_active);
931d9e32b21SJiri Pirko 
932d9e32b21SJiri Pirko 		if (new_active == old_active) {
933d9e32b21SJiri Pirko 			/* do nothing */
934f887e54cSJarod Wilson 			slave_dbg(bond->dev, new_active->dev, "is already the current active slave\n");
935d9e32b21SJiri Pirko 		} else {
936d9e32b21SJiri Pirko 			if (old_active && (new_active->link == BOND_LINK_UP) &&
937b6adc610SVeaceslav Falico 			    bond_slave_is_up(new_active)) {
938f887e54cSJarod Wilson 				slave_dbg(bond->dev, new_active->dev, "Setting as active slave\n");
939d9e32b21SJiri Pirko 				bond_change_active_slave(bond, new_active);
940d9e32b21SJiri Pirko 			} else {
941f887e54cSJarod Wilson 				slave_err(bond->dev, new_active->dev, "Could not set as active slave; either %s is down or the link is down\n",
942d9e32b21SJiri Pirko 					  new_active->dev->name);
943d9e32b21SJiri Pirko 				ret = -EINVAL;
944d9e32b21SJiri Pirko 			}
945d9e32b21SJiri Pirko 		}
946d9e32b21SJiri Pirko 	}
947d9e32b21SJiri Pirko 	unblock_netpoll_tx();
948d1fbd3edSNikolay Aleksandrov 
949d9e32b21SJiri Pirko 	return ret;
950d9e32b21SJiri Pirko }
951eecdaa6eSsfeldma@cumulusnetworks.com 
952dc3e5d18SNikolay Aleksandrov /* There are two tricky bits here.  First, if MII monitoring is activated, then
953dc3e5d18SNikolay Aleksandrov  * we must disable ARP monitoring.  Second, if the timer isn't running, we must
954dc3e5d18SNikolay Aleksandrov  * start it.
955dc3e5d18SNikolay Aleksandrov  */
bond_option_miimon_set(struct bonding * bond,const struct bond_opt_value * newval)956f3253339Sstephen hemminger static int bond_option_miimon_set(struct bonding *bond,
95728f084ccSstephen hemminger 				  const struct bond_opt_value *newval)
958eecdaa6eSsfeldma@cumulusnetworks.com {
959eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting MII monitoring interval to %llu\n",
9602de390baSVeaceslav Falico 		   newval->value);
961b98d9c66SNikolay Aleksandrov 	bond->params.miimon = newval->value;
962eecdaa6eSsfeldma@cumulusnetworks.com 	if (bond->params.updelay)
963eac306b4SMichael Dilmore 		netdev_dbg(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n",
964eecdaa6eSsfeldma@cumulusnetworks.com 			   bond->params.updelay * bond->params.miimon);
965eecdaa6eSsfeldma@cumulusnetworks.com 	if (bond->params.downdelay)
966eac306b4SMichael Dilmore 		netdev_dbg(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
967eecdaa6eSsfeldma@cumulusnetworks.com 			   bond->params.downdelay * bond->params.miimon);
96807a4ddecSVincent Bernat 	if (bond->params.peer_notif_delay)
96907a4ddecSVincent Bernat 		netdev_dbg(bond->dev, "Note: Updating peer_notif_delay (to %d) since it is a multiple of the miimon value\n",
97007a4ddecSVincent Bernat 			   bond->params.peer_notif_delay * bond->params.miimon);
971b98d9c66SNikolay Aleksandrov 	if (newval->value && bond->params.arp_interval) {
972eac306b4SMichael Dilmore 		netdev_dbg(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n");
973eecdaa6eSsfeldma@cumulusnetworks.com 		bond->params.arp_interval = 0;
974eecdaa6eSsfeldma@cumulusnetworks.com 		if (bond->params.arp_validate)
975eecdaa6eSsfeldma@cumulusnetworks.com 			bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
976eecdaa6eSsfeldma@cumulusnetworks.com 	}
977eecdaa6eSsfeldma@cumulusnetworks.com 	if (bond->dev->flags & IFF_UP) {
978eecdaa6eSsfeldma@cumulusnetworks.com 		/* If the interface is up, we may need to fire off
979eecdaa6eSsfeldma@cumulusnetworks.com 		 * the MII timer. If the interface is down, the
980eecdaa6eSsfeldma@cumulusnetworks.com 		 * timer will get fired off when the open function
981eecdaa6eSsfeldma@cumulusnetworks.com 		 * is called.
982eecdaa6eSsfeldma@cumulusnetworks.com 		 */
983b98d9c66SNikolay Aleksandrov 		if (!newval->value) {
984eecdaa6eSsfeldma@cumulusnetworks.com 			cancel_delayed_work_sync(&bond->mii_work);
985eecdaa6eSsfeldma@cumulusnetworks.com 		} else {
986eecdaa6eSsfeldma@cumulusnetworks.com 			cancel_delayed_work_sync(&bond->arp_work);
987eecdaa6eSsfeldma@cumulusnetworks.com 			queue_delayed_work(bond->wq, &bond->mii_work, 0);
988eecdaa6eSsfeldma@cumulusnetworks.com 		}
989eecdaa6eSsfeldma@cumulusnetworks.com 	}
990b98d9c66SNikolay Aleksandrov 
991eecdaa6eSsfeldma@cumulusnetworks.com 	return 0;
992eecdaa6eSsfeldma@cumulusnetworks.com }
99325852e29Ssfeldma@cumulusnetworks.com 
99407a4ddecSVincent Bernat /* Set up, down and peer notification delays. These must be multiples
99507a4ddecSVincent Bernat  * of the MII monitoring value, and are stored internally as the
99607a4ddecSVincent Bernat  * multiplier. Thus, we must translate to MS for the real world.
997dc3e5d18SNikolay Aleksandrov  */
_bond_option_delay_set(struct bonding * bond,const struct bond_opt_value * newval,const char * name,int * target)99807a4ddecSVincent Bernat static int _bond_option_delay_set(struct bonding *bond,
99907a4ddecSVincent Bernat 				  const struct bond_opt_value *newval,
100007a4ddecSVincent Bernat 				  const char *name,
100107a4ddecSVincent Bernat 				  int *target)
100225852e29Ssfeldma@cumulusnetworks.com {
10030681a282SNikolay Aleksandrov 	int value = newval->value;
10040681a282SNikolay Aleksandrov 
1005e4994612SNikolay Aleksandrov 	if (!bond->params.miimon) {
100607a4ddecSVincent Bernat 		netdev_err(bond->dev, "Unable to set %s as MII monitoring is disabled\n",
100707a4ddecSVincent Bernat 			   name);
100825852e29Ssfeldma@cumulusnetworks.com 		return -EPERM;
100925852e29Ssfeldma@cumulusnetworks.com 	}
10100681a282SNikolay Aleksandrov 	if ((value % bond->params.miimon) != 0) {
101107a4ddecSVincent Bernat 		netdev_warn(bond->dev,
101207a4ddecSVincent Bernat 			    "%s (%d) is not a multiple of miimon (%d), value rounded to %d ms\n",
101307a4ddecSVincent Bernat 			    name,
10142de390baSVeaceslav Falico 			    value, bond->params.miimon,
10150681a282SNikolay Aleksandrov 			    (value / bond->params.miimon) *
101625852e29Ssfeldma@cumulusnetworks.com 			    bond->params.miimon);
101725852e29Ssfeldma@cumulusnetworks.com 	}
101807a4ddecSVincent Bernat 	*target = value / bond->params.miimon;
101907a4ddecSVincent Bernat 	netdev_dbg(bond->dev, "Setting %s to %d\n",
102007a4ddecSVincent Bernat 		   name,
102107a4ddecSVincent Bernat 		   *target * bond->params.miimon);
102225852e29Ssfeldma@cumulusnetworks.com 
102325852e29Ssfeldma@cumulusnetworks.com 	return 0;
102425852e29Ssfeldma@cumulusnetworks.com }
1025c7461f9bSsfeldma@cumulusnetworks.com 
bond_option_updelay_set(struct bonding * bond,const struct bond_opt_value * newval)102607a4ddecSVincent Bernat static int bond_option_updelay_set(struct bonding *bond,
102707a4ddecSVincent Bernat 				   const struct bond_opt_value *newval)
102807a4ddecSVincent Bernat {
102907a4ddecSVincent Bernat 	return _bond_option_delay_set(bond, newval, "up delay",
103007a4ddecSVincent Bernat 				      &bond->params.updelay);
103107a4ddecSVincent Bernat }
103207a4ddecSVincent Bernat 
bond_option_downdelay_set(struct bonding * bond,const struct bond_opt_value * newval)1033f3253339Sstephen hemminger static int bond_option_downdelay_set(struct bonding *bond,
103428f084ccSstephen hemminger 				     const struct bond_opt_value *newval)
1035c7461f9bSsfeldma@cumulusnetworks.com {
103607a4ddecSVincent Bernat 	return _bond_option_delay_set(bond, newval, "down delay",
103707a4ddecSVincent Bernat 				      &bond->params.downdelay);
1038c7461f9bSsfeldma@cumulusnetworks.com }
1039c7461f9bSsfeldma@cumulusnetworks.com 
bond_option_peer_notif_delay_set(struct bonding * bond,const struct bond_opt_value * newval)104007a4ddecSVincent Bernat static int bond_option_peer_notif_delay_set(struct bonding *bond,
104107a4ddecSVincent Bernat 					    const struct bond_opt_value *newval)
104207a4ddecSVincent Bernat {
104307a4ddecSVincent Bernat 	int ret = _bond_option_delay_set(bond, newval,
104407a4ddecSVincent Bernat 					 "peer notification delay",
104507a4ddecSVincent Bernat 					 &bond->params.peer_notif_delay);
104607a4ddecSVincent Bernat 	return ret;
1047c7461f9bSsfeldma@cumulusnetworks.com }
10489f53e14eSsfeldma@cumulusnetworks.com 
bond_option_use_carrier_set(struct bonding * bond,const struct bond_opt_value * newval)1049f3253339Sstephen hemminger static int bond_option_use_carrier_set(struct bonding *bond,
105028f084ccSstephen hemminger 				       const struct bond_opt_value *newval)
10519f53e14eSsfeldma@cumulusnetworks.com {
1052eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting use_carrier to %llu\n",
10532de390baSVeaceslav Falico 		   newval->value);
10540fff0608SNikolay Aleksandrov 	bond->params.use_carrier = newval->value;
10559f53e14eSsfeldma@cumulusnetworks.com 
10569f53e14eSsfeldma@cumulusnetworks.com 	return 0;
10579f53e14eSsfeldma@cumulusnetworks.com }
105806151dbcSsfeldma@cumulusnetworks.com 
1059dc3e5d18SNikolay Aleksandrov /* There are two tricky bits here.  First, if ARP monitoring is activated, then
1060dc3e5d18SNikolay Aleksandrov  * we must disable MII monitoring.  Second, if the ARP timer isn't running,
1061dc3e5d18SNikolay Aleksandrov  * we must start it.
1062dc3e5d18SNikolay Aleksandrov  */
bond_option_arp_interval_set(struct bonding * bond,const struct bond_opt_value * newval)1063f3253339Sstephen hemminger static int bond_option_arp_interval_set(struct bonding *bond,
106428f084ccSstephen hemminger 					const struct bond_opt_value *newval)
106506151dbcSsfeldma@cumulusnetworks.com {
1066eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting ARP monitoring interval to %llu\n",
10672de390baSVeaceslav Falico 		   newval->value);
10687bdb04edSNikolay Aleksandrov 	bond->params.arp_interval = newval->value;
10697bdb04edSNikolay Aleksandrov 	if (newval->value) {
107006151dbcSsfeldma@cumulusnetworks.com 		if (bond->params.miimon) {
1071eac306b4SMichael Dilmore 			netdev_dbg(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n");
107206151dbcSsfeldma@cumulusnetworks.com 			bond->params.miimon = 0;
107306151dbcSsfeldma@cumulusnetworks.com 		}
107406151dbcSsfeldma@cumulusnetworks.com 		if (!bond->params.arp_targets[0])
1075eac306b4SMichael Dilmore 			netdev_dbg(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n");
107606151dbcSsfeldma@cumulusnetworks.com 	}
107706151dbcSsfeldma@cumulusnetworks.com 	if (bond->dev->flags & IFF_UP) {
107806151dbcSsfeldma@cumulusnetworks.com 		/* If the interface is up, we may need to fire off
107906151dbcSsfeldma@cumulusnetworks.com 		 * the ARP timer.  If the interface is down, the
108006151dbcSsfeldma@cumulusnetworks.com 		 * timer will get fired off when the open function
108106151dbcSsfeldma@cumulusnetworks.com 		 * is called.
108206151dbcSsfeldma@cumulusnetworks.com 		 */
10837bdb04edSNikolay Aleksandrov 		if (!newval->value) {
108406151dbcSsfeldma@cumulusnetworks.com 			if (bond->params.arp_validate)
108506151dbcSsfeldma@cumulusnetworks.com 				bond->recv_probe = NULL;
108606151dbcSsfeldma@cumulusnetworks.com 			cancel_delayed_work_sync(&bond->arp_work);
108706151dbcSsfeldma@cumulusnetworks.com 		} else {
108806151dbcSsfeldma@cumulusnetworks.com 			/* arp_validate can be set only in active-backup mode */
10894e24be01SHangbin Liu 			bond->recv_probe = bond_rcv_validate;
109006151dbcSsfeldma@cumulusnetworks.com 			cancel_delayed_work_sync(&bond->mii_work);
109106151dbcSsfeldma@cumulusnetworks.com 			queue_delayed_work(bond->wq, &bond->arp_work, 0);
109206151dbcSsfeldma@cumulusnetworks.com 		}
109306151dbcSsfeldma@cumulusnetworks.com 	}
109406151dbcSsfeldma@cumulusnetworks.com 
109506151dbcSsfeldma@cumulusnetworks.com 	return 0;
109606151dbcSsfeldma@cumulusnetworks.com }
10977f28fa10Ssfeldma@cumulusnetworks.com 
_bond_options_arp_ip_target_set(struct bonding * bond,int slot,__be32 target,unsigned long last_rx)10987f28fa10Ssfeldma@cumulusnetworks.com static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
10997f28fa10Ssfeldma@cumulusnetworks.com 					    __be32 target,
11007f28fa10Ssfeldma@cumulusnetworks.com 					    unsigned long last_rx)
11017f28fa10Ssfeldma@cumulusnetworks.com {
11027f28fa10Ssfeldma@cumulusnetworks.com 	__be32 *targets = bond->params.arp_targets;
11037f28fa10Ssfeldma@cumulusnetworks.com 	struct list_head *iter;
11047f28fa10Ssfeldma@cumulusnetworks.com 	struct slave *slave;
11057f28fa10Ssfeldma@cumulusnetworks.com 
11067f28fa10Ssfeldma@cumulusnetworks.com 	if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) {
11077f28fa10Ssfeldma@cumulusnetworks.com 		bond_for_each_slave(bond, slave, iter)
11087f28fa10Ssfeldma@cumulusnetworks.com 			slave->target_last_arp_rx[slot] = last_rx;
11097f28fa10Ssfeldma@cumulusnetworks.com 		targets[slot] = target;
11107f28fa10Ssfeldma@cumulusnetworks.com 	}
11117f28fa10Ssfeldma@cumulusnetworks.com }
11127f28fa10Ssfeldma@cumulusnetworks.com 
_bond_option_arp_ip_target_add(struct bonding * bond,__be32 target)11137f28fa10Ssfeldma@cumulusnetworks.com static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
11147f28fa10Ssfeldma@cumulusnetworks.com {
11157f28fa10Ssfeldma@cumulusnetworks.com 	__be32 *targets = bond->params.arp_targets;
11167f28fa10Ssfeldma@cumulusnetworks.com 	int ind;
11177f28fa10Ssfeldma@cumulusnetworks.com 
11182807a9feSVeaceslav Falico 	if (!bond_is_ip_target_ok(target)) {
11192de390baSVeaceslav Falico 		netdev_err(bond->dev, "invalid ARP target %pI4 specified for addition\n",
11202de390baSVeaceslav Falico 			   &target);
11217f28fa10Ssfeldma@cumulusnetworks.com 		return -EINVAL;
11227f28fa10Ssfeldma@cumulusnetworks.com 	}
11237f28fa10Ssfeldma@cumulusnetworks.com 
11247f28fa10Ssfeldma@cumulusnetworks.com 	if (bond_get_targets_ip(targets, target) != -1) { /* dup */
11252de390baSVeaceslav Falico 		netdev_err(bond->dev, "ARP target %pI4 is already present\n",
11262de390baSVeaceslav Falico 			   &target);
11277f28fa10Ssfeldma@cumulusnetworks.com 		return -EINVAL;
11287f28fa10Ssfeldma@cumulusnetworks.com 	}
11297f28fa10Ssfeldma@cumulusnetworks.com 
11307f28fa10Ssfeldma@cumulusnetworks.com 	ind = bond_get_targets_ip(targets, 0); /* first free slot */
11317f28fa10Ssfeldma@cumulusnetworks.com 	if (ind == -1) {
11322de390baSVeaceslav Falico 		netdev_err(bond->dev, "ARP target table is full!\n");
11337f28fa10Ssfeldma@cumulusnetworks.com 		return -EINVAL;
11347f28fa10Ssfeldma@cumulusnetworks.com 	}
11357f28fa10Ssfeldma@cumulusnetworks.com 
1136eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Adding ARP target %pI4\n", &target);
11377f28fa10Ssfeldma@cumulusnetworks.com 
11387f28fa10Ssfeldma@cumulusnetworks.com 	_bond_options_arp_ip_target_set(bond, ind, target, jiffies);
11397f28fa10Ssfeldma@cumulusnetworks.com 
11407f28fa10Ssfeldma@cumulusnetworks.com 	return 0;
11417f28fa10Ssfeldma@cumulusnetworks.com }
11427f28fa10Ssfeldma@cumulusnetworks.com 
bond_option_arp_ip_target_add(struct bonding * bond,__be32 target)1143f3253339Sstephen hemminger static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
11447f28fa10Ssfeldma@cumulusnetworks.com {
1145246df7b4SNikolay Aleksandrov 	return _bond_option_arp_ip_target_add(bond, target);
11467f28fa10Ssfeldma@cumulusnetworks.com }
11477f28fa10Ssfeldma@cumulusnetworks.com 
bond_option_arp_ip_target_rem(struct bonding * bond,__be32 target)1148f3253339Sstephen hemminger static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
11497f28fa10Ssfeldma@cumulusnetworks.com {
11507f28fa10Ssfeldma@cumulusnetworks.com 	__be32 *targets = bond->params.arp_targets;
11517f28fa10Ssfeldma@cumulusnetworks.com 	struct list_head *iter;
11527f28fa10Ssfeldma@cumulusnetworks.com 	struct slave *slave;
11537f28fa10Ssfeldma@cumulusnetworks.com 	unsigned long *targets_rx;
11547f28fa10Ssfeldma@cumulusnetworks.com 	int ind, i;
11557f28fa10Ssfeldma@cumulusnetworks.com 
11562807a9feSVeaceslav Falico 	if (!bond_is_ip_target_ok(target)) {
11572de390baSVeaceslav Falico 		netdev_err(bond->dev, "invalid ARP target %pI4 specified for removal\n",
11582de390baSVeaceslav Falico 			   &target);
11597f28fa10Ssfeldma@cumulusnetworks.com 		return -EINVAL;
11607f28fa10Ssfeldma@cumulusnetworks.com 	}
11617f28fa10Ssfeldma@cumulusnetworks.com 
11627f28fa10Ssfeldma@cumulusnetworks.com 	ind = bond_get_targets_ip(targets, target);
11637f28fa10Ssfeldma@cumulusnetworks.com 	if (ind == -1) {
11642de390baSVeaceslav Falico 		netdev_err(bond->dev, "unable to remove nonexistent ARP target %pI4\n",
11652de390baSVeaceslav Falico 			   &target);
11667f28fa10Ssfeldma@cumulusnetworks.com 		return -EINVAL;
11677f28fa10Ssfeldma@cumulusnetworks.com 	}
11687f28fa10Ssfeldma@cumulusnetworks.com 
11697f28fa10Ssfeldma@cumulusnetworks.com 	if (ind == 0 && !targets[1] && bond->params.arp_interval)
11702de390baSVeaceslav Falico 		netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
11717f28fa10Ssfeldma@cumulusnetworks.com 
1172eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target);
11737f28fa10Ssfeldma@cumulusnetworks.com 
11747f28fa10Ssfeldma@cumulusnetworks.com 	bond_for_each_slave(bond, slave, iter) {
11757f28fa10Ssfeldma@cumulusnetworks.com 		targets_rx = slave->target_last_arp_rx;
11767f28fa10Ssfeldma@cumulusnetworks.com 		for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
11777f28fa10Ssfeldma@cumulusnetworks.com 			targets_rx[i] = targets_rx[i+1];
11787f28fa10Ssfeldma@cumulusnetworks.com 		targets_rx[i] = 0;
11797f28fa10Ssfeldma@cumulusnetworks.com 	}
11807f28fa10Ssfeldma@cumulusnetworks.com 	for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
11817f28fa10Ssfeldma@cumulusnetworks.com 		targets[i] = targets[i+1];
11827f28fa10Ssfeldma@cumulusnetworks.com 	targets[i] = 0;
11837f28fa10Ssfeldma@cumulusnetworks.com 
11847f28fa10Ssfeldma@cumulusnetworks.com 	return 0;
11857f28fa10Ssfeldma@cumulusnetworks.com }
11867f28fa10Ssfeldma@cumulusnetworks.com 
bond_option_arp_ip_targets_clear(struct bonding * bond)11874fb0ef58SNikolay Aleksandrov void bond_option_arp_ip_targets_clear(struct bonding *bond)
11887f28fa10Ssfeldma@cumulusnetworks.com {
11894fb0ef58SNikolay Aleksandrov 	int i;
11907f28fa10Ssfeldma@cumulusnetworks.com 
11917f28fa10Ssfeldma@cumulusnetworks.com 	for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
11927f28fa10Ssfeldma@cumulusnetworks.com 		_bond_options_arp_ip_target_set(bond, i, 0, 0);
11937f28fa10Ssfeldma@cumulusnetworks.com }
11947f28fa10Ssfeldma@cumulusnetworks.com 
bond_option_arp_ip_targets_set(struct bonding * bond,const struct bond_opt_value * newval)1195f3253339Sstephen hemminger static int bond_option_arp_ip_targets_set(struct bonding *bond,
119628f084ccSstephen hemminger 					  const struct bond_opt_value *newval)
11974fb0ef58SNikolay Aleksandrov {
11984fb0ef58SNikolay Aleksandrov 	int ret = -EPERM;
11994fb0ef58SNikolay Aleksandrov 	__be32 target;
12004fb0ef58SNikolay Aleksandrov 
12014fb0ef58SNikolay Aleksandrov 	if (newval->string) {
1202b75e33eaSSam Sun 		if (strlen(newval->string) < 1 ||
1203b75e33eaSSam Sun 		    !in4_pton(newval->string + 1, -1, (u8 *)&target, -1, NULL)) {
1204b75e33eaSSam Sun 			netdev_err(bond->dev, "invalid ARP target specified\n");
12054fb0ef58SNikolay Aleksandrov 			return ret;
12064fb0ef58SNikolay Aleksandrov 		}
12074fb0ef58SNikolay Aleksandrov 		if (newval->string[0] == '+')
12084fb0ef58SNikolay Aleksandrov 			ret = bond_option_arp_ip_target_add(bond, target);
12094fb0ef58SNikolay Aleksandrov 		else if (newval->string[0] == '-')
12104fb0ef58SNikolay Aleksandrov 			ret = bond_option_arp_ip_target_rem(bond, target);
12114fb0ef58SNikolay Aleksandrov 		else
12122de390baSVeaceslav Falico 			netdev_err(bond->dev, "no command found in arp_ip_targets file - use +<addr> or -<addr>\n");
12134fb0ef58SNikolay Aleksandrov 	} else {
12144fb0ef58SNikolay Aleksandrov 		target = newval->value;
12154fb0ef58SNikolay Aleksandrov 		ret = bond_option_arp_ip_target_add(bond, target);
12164fb0ef58SNikolay Aleksandrov 	}
12174fb0ef58SNikolay Aleksandrov 
12187f28fa10Ssfeldma@cumulusnetworks.com 	return ret;
12197f28fa10Ssfeldma@cumulusnetworks.com }
122029c49482Ssfeldma@cumulusnetworks.com 
1221129e3c1bSHangbin Liu #if IS_ENABLED(CONFIG_IPV6)
slave_can_set_ns_maddr(const struct bonding * bond,struct slave * slave)12229ea6b70fSHangbin Liu static bool slave_can_set_ns_maddr(const struct bonding *bond, struct slave *slave)
12239ea6b70fSHangbin Liu {
12249ea6b70fSHangbin Liu 	return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
12259ea6b70fSHangbin Liu 	       !bond_is_active_slave(slave) &&
12269ea6b70fSHangbin Liu 	       slave->dev->flags & IFF_MULTICAST;
12279ea6b70fSHangbin Liu }
12289ea6b70fSHangbin Liu 
1229*6e4edd9eSHangbin Liu /**
1230*6e4edd9eSHangbin Liu  * slave_set_ns_maddrs - add/del all NS mac addresses for slave
1231*6e4edd9eSHangbin Liu  * @bond: bond device
1232*6e4edd9eSHangbin Liu  * @slave: slave device
1233*6e4edd9eSHangbin Liu  * @add: add or remove all the NS mac addresses
1234*6e4edd9eSHangbin Liu  *
1235*6e4edd9eSHangbin Liu  * This function tries to add or delete all the NS mac addresses on the slave
1236*6e4edd9eSHangbin Liu  *
1237*6e4edd9eSHangbin Liu  * Note, the IPv6 NS target address is the unicast address in Neighbor
1238*6e4edd9eSHangbin Liu  * Solicitation (NS) message. The dest address of NS message should be
1239*6e4edd9eSHangbin Liu  * solicited-node multicast address of the target. The dest mac of NS message
1240*6e4edd9eSHangbin Liu  * is converted from the solicited-node multicast address.
1241*6e4edd9eSHangbin Liu  *
1242*6e4edd9eSHangbin Liu  * This function is called when
1243*6e4edd9eSHangbin Liu  *   * arp_validate changes
1244*6e4edd9eSHangbin Liu  *   * enslaving, releasing new slaves
1245*6e4edd9eSHangbin Liu  */
slave_set_ns_maddrs(struct bonding * bond,struct slave * slave,bool add)12469ea6b70fSHangbin Liu static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add)
12479ea6b70fSHangbin Liu {
12489ea6b70fSHangbin Liu 	struct in6_addr *targets = bond->params.ns_targets;
12499ea6b70fSHangbin Liu 	char slot_maddr[MAX_ADDR_LEN];
1250*6e4edd9eSHangbin Liu 	struct in6_addr mcaddr;
12519ea6b70fSHangbin Liu 	int i;
12529ea6b70fSHangbin Liu 
12539ea6b70fSHangbin Liu 	if (!slave_can_set_ns_maddr(bond, slave))
12549ea6b70fSHangbin Liu 		return;
12559ea6b70fSHangbin Liu 
12569ea6b70fSHangbin Liu 	for (i = 0; i < BOND_MAX_NS_TARGETS; i++) {
12579ea6b70fSHangbin Liu 		if (ipv6_addr_any(&targets[i]))
12589ea6b70fSHangbin Liu 			break;
12599ea6b70fSHangbin Liu 
1260*6e4edd9eSHangbin Liu 		addrconf_addr_solict_mult(&targets[i], &mcaddr);
1261*6e4edd9eSHangbin Liu 		if (!ndisc_mc_map(&mcaddr, slot_maddr, slave->dev, 0)) {
12629ea6b70fSHangbin Liu 			if (add)
12639ea6b70fSHangbin Liu 				dev_mc_add(slave->dev, slot_maddr);
12649ea6b70fSHangbin Liu 			else
12659ea6b70fSHangbin Liu 				dev_mc_del(slave->dev, slot_maddr);
12669ea6b70fSHangbin Liu 		}
12679ea6b70fSHangbin Liu 	}
12689ea6b70fSHangbin Liu }
12699ea6b70fSHangbin Liu 
bond_slave_ns_maddrs_add(struct bonding * bond,struct slave * slave)12709ea6b70fSHangbin Liu void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave)
12719ea6b70fSHangbin Liu {
12729ea6b70fSHangbin Liu 	if (!bond->params.arp_validate)
12739ea6b70fSHangbin Liu 		return;
12749ea6b70fSHangbin Liu 	slave_set_ns_maddrs(bond, slave, true);
12759ea6b70fSHangbin Liu }
12769ea6b70fSHangbin Liu 
bond_slave_ns_maddrs_del(struct bonding * bond,struct slave * slave)12779ea6b70fSHangbin Liu void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave)
12789ea6b70fSHangbin Liu {
12799ea6b70fSHangbin Liu 	if (!bond->params.arp_validate)
12809ea6b70fSHangbin Liu 		return;
12819ea6b70fSHangbin Liu 	slave_set_ns_maddrs(bond, slave, false);
12829ea6b70fSHangbin Liu }
12839ea6b70fSHangbin Liu 
1284*6e4edd9eSHangbin Liu /**
1285*6e4edd9eSHangbin Liu  * slave_set_ns_maddr - set new NS mac address for slave
1286*6e4edd9eSHangbin Liu  * @bond: bond device
1287*6e4edd9eSHangbin Liu  * @slave: slave device
1288*6e4edd9eSHangbin Liu  * @target: the new IPv6 target
1289*6e4edd9eSHangbin Liu  * @slot: the old IPv6 target in the slot
1290*6e4edd9eSHangbin Liu  *
1291*6e4edd9eSHangbin Liu  * This function tries to replace the old mac address to new one on the slave.
1292*6e4edd9eSHangbin Liu  *
1293*6e4edd9eSHangbin Liu  * Note, the target/slot IPv6 address is the unicast address in Neighbor
1294*6e4edd9eSHangbin Liu  * Solicitation (NS) message. The dest address of NS message should be
1295*6e4edd9eSHangbin Liu  * solicited-node multicast address of the target. The dest mac of NS message
1296*6e4edd9eSHangbin Liu  * is converted from the solicited-node multicast address.
1297*6e4edd9eSHangbin Liu  *
1298*6e4edd9eSHangbin Liu  * This function is called when
1299*6e4edd9eSHangbin Liu  *   * An IPv6 NS target is added or removed.
1300*6e4edd9eSHangbin Liu  */
slave_set_ns_maddr(struct bonding * bond,struct slave * slave,struct in6_addr * target,struct in6_addr * slot)13019ea6b70fSHangbin Liu static void slave_set_ns_maddr(struct bonding *bond, struct slave *slave,
13029ea6b70fSHangbin Liu 			       struct in6_addr *target, struct in6_addr *slot)
13039ea6b70fSHangbin Liu {
1304*6e4edd9eSHangbin Liu 	char mac_addr[MAX_ADDR_LEN];
1305*6e4edd9eSHangbin Liu 	struct in6_addr mcast_addr;
13069ea6b70fSHangbin Liu 
13079ea6b70fSHangbin Liu 	if (!bond->params.arp_validate || !slave_can_set_ns_maddr(bond, slave))
13089ea6b70fSHangbin Liu 		return;
13099ea6b70fSHangbin Liu 
1310*6e4edd9eSHangbin Liu 	/* remove the previous mac addr from slave */
1311*6e4edd9eSHangbin Liu 	addrconf_addr_solict_mult(slot, &mcast_addr);
13129ea6b70fSHangbin Liu 	if (!ipv6_addr_any(slot) &&
1313*6e4edd9eSHangbin Liu 	    !ndisc_mc_map(&mcast_addr, mac_addr, slave->dev, 0))
1314*6e4edd9eSHangbin Liu 		dev_mc_del(slave->dev, mac_addr);
13159ea6b70fSHangbin Liu 
1316*6e4edd9eSHangbin Liu 	/* add new mac addr on slave if target is set */
1317*6e4edd9eSHangbin Liu 	addrconf_addr_solict_mult(target, &mcast_addr);
13189ea6b70fSHangbin Liu 	if (!ipv6_addr_any(target) &&
1319*6e4edd9eSHangbin Liu 	    !ndisc_mc_map(&mcast_addr, mac_addr, slave->dev, 0))
1320*6e4edd9eSHangbin Liu 		dev_mc_add(slave->dev, mac_addr);
13219ea6b70fSHangbin Liu }
13229ea6b70fSHangbin Liu 
_bond_options_ns_ip6_target_set(struct bonding * bond,int slot,struct in6_addr * target,unsigned long last_rx)1323129e3c1bSHangbin Liu static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
1324129e3c1bSHangbin Liu 					    struct in6_addr *target,
1325129e3c1bSHangbin Liu 					    unsigned long last_rx)
1326129e3c1bSHangbin Liu {
1327129e3c1bSHangbin Liu 	struct in6_addr *targets = bond->params.ns_targets;
1328129e3c1bSHangbin Liu 	struct list_head *iter;
1329129e3c1bSHangbin Liu 	struct slave *slave;
1330129e3c1bSHangbin Liu 
1331129e3c1bSHangbin Liu 	if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
13329ea6b70fSHangbin Liu 		bond_for_each_slave(bond, slave, iter) {
1333129e3c1bSHangbin Liu 			slave->target_last_arp_rx[slot] = last_rx;
13349ea6b70fSHangbin Liu 			slave_set_ns_maddr(bond, slave, target, &targets[slot]);
13359ea6b70fSHangbin Liu 		}
1336129e3c1bSHangbin Liu 		targets[slot] = *target;
1337129e3c1bSHangbin Liu 	}
1338129e3c1bSHangbin Liu }
1339129e3c1bSHangbin Liu 
bond_option_ns_ip6_targets_clear(struct bonding * bond)1340129e3c1bSHangbin Liu void bond_option_ns_ip6_targets_clear(struct bonding *bond)
1341129e3c1bSHangbin Liu {
1342129e3c1bSHangbin Liu 	struct in6_addr addr_any = in6addr_any;
1343129e3c1bSHangbin Liu 	int i;
1344129e3c1bSHangbin Liu 
1345129e3c1bSHangbin Liu 	for (i = 0; i < BOND_MAX_NS_TARGETS; i++)
1346129e3c1bSHangbin Liu 		_bond_options_ns_ip6_target_set(bond, i, &addr_any, 0);
1347129e3c1bSHangbin Liu }
1348129e3c1bSHangbin Liu 
bond_option_ns_ip6_targets_set(struct bonding * bond,const struct bond_opt_value * newval)1349129e3c1bSHangbin Liu static int bond_option_ns_ip6_targets_set(struct bonding *bond,
1350129e3c1bSHangbin Liu 					  const struct bond_opt_value *newval)
1351129e3c1bSHangbin Liu {
1352129e3c1bSHangbin Liu 	struct in6_addr *target = (struct in6_addr *)newval->extra;
1353129e3c1bSHangbin Liu 	struct in6_addr *targets = bond->params.ns_targets;
1354129e3c1bSHangbin Liu 	struct in6_addr addr_any = in6addr_any;
1355129e3c1bSHangbin Liu 	int index;
1356129e3c1bSHangbin Liu 
1357129e3c1bSHangbin Liu 	if (!bond_is_ip6_target_ok(target)) {
1358129e3c1bSHangbin Liu 		netdev_err(bond->dev, "invalid NS target %pI6c specified for addition\n",
1359129e3c1bSHangbin Liu 			   target);
1360129e3c1bSHangbin Liu 		return -EINVAL;
1361129e3c1bSHangbin Liu 	}
1362129e3c1bSHangbin Liu 
1363129e3c1bSHangbin Liu 	if (bond_get_targets_ip6(targets, target) != -1) { /* dup */
1364129e3c1bSHangbin Liu 		netdev_err(bond->dev, "NS target %pI6c is already present\n",
1365129e3c1bSHangbin Liu 			   target);
1366129e3c1bSHangbin Liu 		return -EINVAL;
1367129e3c1bSHangbin Liu 	}
1368129e3c1bSHangbin Liu 
1369129e3c1bSHangbin Liu 	index = bond_get_targets_ip6(targets, &addr_any); /* first free slot */
1370129e3c1bSHangbin Liu 	if (index == -1) {
1371129e3c1bSHangbin Liu 		netdev_err(bond->dev, "NS target table is full!\n");
1372129e3c1bSHangbin Liu 		return -EINVAL;
1373129e3c1bSHangbin Liu 	}
1374129e3c1bSHangbin Liu 
1375129e3c1bSHangbin Liu 	netdev_dbg(bond->dev, "Adding NS target %pI6c\n", target);
1376129e3c1bSHangbin Liu 
1377129e3c1bSHangbin Liu 	_bond_options_ns_ip6_target_set(bond, index, target, jiffies);
1378129e3c1bSHangbin Liu 
1379129e3c1bSHangbin Liu 	return 0;
1380129e3c1bSHangbin Liu }
1381c4caa500SHangbin Liu #else
bond_option_ns_ip6_targets_set(struct bonding * bond,const struct bond_opt_value * newval)1382c4caa500SHangbin Liu static int bond_option_ns_ip6_targets_set(struct bonding *bond,
1383c4caa500SHangbin Liu 					  const struct bond_opt_value *newval)
1384c4caa500SHangbin Liu {
1385c4caa500SHangbin Liu 	return -EPERM;
1386c4caa500SHangbin Liu }
13879ea6b70fSHangbin Liu 
slave_set_ns_maddrs(struct bonding * bond,struct slave * slave,bool add)13889ea6b70fSHangbin Liu static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add) {}
13899ea6b70fSHangbin Liu 
bond_slave_ns_maddrs_add(struct bonding * bond,struct slave * slave)13909ea6b70fSHangbin Liu void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave) {}
13919ea6b70fSHangbin Liu 
bond_slave_ns_maddrs_del(struct bonding * bond,struct slave * slave)13929ea6b70fSHangbin Liu void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave) {}
1393129e3c1bSHangbin Liu #endif
1394129e3c1bSHangbin Liu 
bond_option_arp_validate_set(struct bonding * bond,const struct bond_opt_value * newval)1395f3253339Sstephen hemminger static int bond_option_arp_validate_set(struct bonding *bond,
139628f084ccSstephen hemminger 					const struct bond_opt_value *newval)
139729c49482Ssfeldma@cumulusnetworks.com {
13989ea6b70fSHangbin Liu 	bool changed = !!bond->params.arp_validate != !!newval->value;
13999ea6b70fSHangbin Liu 	struct list_head *iter;
14009ea6b70fSHangbin Liu 	struct slave *slave;
14019ea6b70fSHangbin Liu 
1402eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
14032de390baSVeaceslav Falico 		   newval->string, newval->value);
140416228881SNikolay Aleksandrov 	bond->params.arp_validate = newval->value;
140529c49482Ssfeldma@cumulusnetworks.com 
14069ea6b70fSHangbin Liu 	if (changed) {
14079ea6b70fSHangbin Liu 		bond_for_each_slave(bond, slave, iter)
14089ea6b70fSHangbin Liu 			slave_set_ns_maddrs(bond, slave, !!bond->params.arp_validate);
14099ea6b70fSHangbin Liu 	}
14109ea6b70fSHangbin Liu 
141129c49482Ssfeldma@cumulusnetworks.com 	return 0;
141229c49482Ssfeldma@cumulusnetworks.com }
1413d5c84254Ssfeldma@cumulusnetworks.com 
bond_option_arp_all_targets_set(struct bonding * bond,const struct bond_opt_value * newval)1414f3253339Sstephen hemminger static int bond_option_arp_all_targets_set(struct bonding *bond,
141528f084ccSstephen hemminger 					   const struct bond_opt_value *newval)
1416d5c84254Ssfeldma@cumulusnetworks.com {
1417eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting arp_all_targets to %s (%llu)\n",
14182de390baSVeaceslav Falico 		   newval->string, newval->value);
1419edf36b24SNikolay Aleksandrov 	bond->params.arp_all_targets = newval->value;
1420d5c84254Ssfeldma@cumulusnetworks.com 
1421d5c84254Ssfeldma@cumulusnetworks.com 	return 0;
1422d5c84254Ssfeldma@cumulusnetworks.com }
14230a98a0d1Ssfeldma@cumulusnetworks.com 
bond_option_missed_max_set(struct bonding * bond,const struct bond_opt_value * newval)14245944b5abSHangbin Liu static int bond_option_missed_max_set(struct bonding *bond,
14255944b5abSHangbin Liu 				      const struct bond_opt_value *newval)
14265944b5abSHangbin Liu {
14275944b5abSHangbin Liu 	netdev_dbg(bond->dev, "Setting missed max to %s (%llu)\n",
14285944b5abSHangbin Liu 		   newval->string, newval->value);
14295944b5abSHangbin Liu 	bond->params.missed_max = newval->value;
14305944b5abSHangbin Liu 
14315944b5abSHangbin Liu 	return 0;
14325944b5abSHangbin Liu }
14335944b5abSHangbin Liu 
bond_option_prio_set(struct bonding * bond,const struct bond_opt_value * newval)14340a2ff7ccSHangbin Liu static int bond_option_prio_set(struct bonding *bond,
14350a2ff7ccSHangbin Liu 				const struct bond_opt_value *newval)
14360a2ff7ccSHangbin Liu {
14370a2ff7ccSHangbin Liu 	struct slave *slave;
14380a2ff7ccSHangbin Liu 
14390a2ff7ccSHangbin Liu 	slave = bond_slave_get_rtnl(newval->slave_dev);
14400a2ff7ccSHangbin Liu 	if (!slave) {
14410a2ff7ccSHangbin Liu 		netdev_dbg(newval->slave_dev, "%s called on NULL slave\n", __func__);
14420a2ff7ccSHangbin Liu 		return -ENODEV;
14430a2ff7ccSHangbin Liu 	}
14440a2ff7ccSHangbin Liu 	slave->prio = newval->value;
14450a2ff7ccSHangbin Liu 
14460a2ff7ccSHangbin Liu 	if (rtnl_dereference(bond->primary_slave))
14470a2ff7ccSHangbin Liu 		slave_warn(bond->dev, slave->dev,
14480a2ff7ccSHangbin Liu 			   "prio updated, but will not affect failover re-selection as primary slave have been set\n");
14490a2ff7ccSHangbin Liu 	else
14500a2ff7ccSHangbin Liu 		bond_select_active_slave(bond);
14510a2ff7ccSHangbin Liu 
14520a2ff7ccSHangbin Liu 	return 0;
14530a2ff7ccSHangbin Liu }
14540a2ff7ccSHangbin Liu 
bond_option_primary_set(struct bonding * bond,const struct bond_opt_value * newval)1455f3253339Sstephen hemminger static int bond_option_primary_set(struct bonding *bond,
145628f084ccSstephen hemminger 				   const struct bond_opt_value *newval)
14570a98a0d1Ssfeldma@cumulusnetworks.com {
1458180222f0SNikolay Aleksandrov 	char *p, *primary = newval->string;
14590a98a0d1Ssfeldma@cumulusnetworks.com 	struct list_head *iter;
14600a98a0d1Ssfeldma@cumulusnetworks.com 	struct slave *slave;
14610a98a0d1Ssfeldma@cumulusnetworks.com 
14620a98a0d1Ssfeldma@cumulusnetworks.com 	block_netpoll_tx();
14630a98a0d1Ssfeldma@cumulusnetworks.com 
1464180222f0SNikolay Aleksandrov 	p = strchr(primary, '\n');
1465180222f0SNikolay Aleksandrov 	if (p)
1466180222f0SNikolay Aleksandrov 		*p = '\0';
14670a98a0d1Ssfeldma@cumulusnetworks.com 	/* check to see if we are clearing primary */
14680a98a0d1Ssfeldma@cumulusnetworks.com 	if (!strlen(primary)) {
1469eac306b4SMichael Dilmore 		netdev_dbg(bond->dev, "Setting primary slave to None\n");
1470059b47e8SNikolay Aleksandrov 		RCU_INIT_POINTER(bond->primary_slave, NULL);
14710a98a0d1Ssfeldma@cumulusnetworks.com 		memset(bond->params.primary, 0, sizeof(bond->params.primary));
14720a98a0d1Ssfeldma@cumulusnetworks.com 		bond_select_active_slave(bond);
14730a98a0d1Ssfeldma@cumulusnetworks.com 		goto out;
14740a98a0d1Ssfeldma@cumulusnetworks.com 	}
14750a98a0d1Ssfeldma@cumulusnetworks.com 
14760a98a0d1Ssfeldma@cumulusnetworks.com 	bond_for_each_slave(bond, slave, iter) {
14770a98a0d1Ssfeldma@cumulusnetworks.com 		if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
1478f887e54cSJarod Wilson 			slave_dbg(bond->dev, slave->dev, "Setting as primary slave\n");
1479059b47e8SNikolay Aleksandrov 			rcu_assign_pointer(bond->primary_slave, slave);
14800a98a0d1Ssfeldma@cumulusnetworks.com 			strcpy(bond->params.primary, slave->dev->name);
1481eb55bbf8SXiangning Yu 			bond->force_primary = true;
14820a98a0d1Ssfeldma@cumulusnetworks.com 			bond_select_active_slave(bond);
14830a98a0d1Ssfeldma@cumulusnetworks.com 			goto out;
14840a98a0d1Ssfeldma@cumulusnetworks.com 		}
14850a98a0d1Ssfeldma@cumulusnetworks.com 	}
14860a98a0d1Ssfeldma@cumulusnetworks.com 
1487059b47e8SNikolay Aleksandrov 	if (rtnl_dereference(bond->primary_slave)) {
1488eac306b4SMichael Dilmore 		netdev_dbg(bond->dev, "Setting primary slave to None\n");
1489059b47e8SNikolay Aleksandrov 		RCU_INIT_POINTER(bond->primary_slave, NULL);
1490c59ab673Sdingtianhong 		bond_select_active_slave(bond);
1491c59ab673Sdingtianhong 	}
149243902070SKees Cook 	strscpy_pad(bond->params.primary, primary, IFNAMSIZ);
14930a98a0d1Ssfeldma@cumulusnetworks.com 
1494f887e54cSJarod Wilson 	netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved yet\n",
1495f887e54cSJarod Wilson 		   primary);
14960a98a0d1Ssfeldma@cumulusnetworks.com 
14970a98a0d1Ssfeldma@cumulusnetworks.com out:
14980a98a0d1Ssfeldma@cumulusnetworks.com 	unblock_netpoll_tx();
14990a98a0d1Ssfeldma@cumulusnetworks.com 
1500180222f0SNikolay Aleksandrov 	return 0;
15010a98a0d1Ssfeldma@cumulusnetworks.com }
15028a41ae44Ssfeldma@cumulusnetworks.com 
bond_option_primary_reselect_set(struct bonding * bond,const struct bond_opt_value * newval)1503f3253339Sstephen hemminger static int bond_option_primary_reselect_set(struct bonding *bond,
150428f084ccSstephen hemminger 					    const struct bond_opt_value *newval)
15058a41ae44Ssfeldma@cumulusnetworks.com {
1506eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting primary_reselect to %s (%llu)\n",
15072de390baSVeaceslav Falico 		   newval->string, newval->value);
1508388d3a6dSNikolay Aleksandrov 	bond->params.primary_reselect = newval->value;
15098a41ae44Ssfeldma@cumulusnetworks.com 
15108a41ae44Ssfeldma@cumulusnetworks.com 	block_netpoll_tx();
15118a41ae44Ssfeldma@cumulusnetworks.com 	bond_select_active_slave(bond);
15128a41ae44Ssfeldma@cumulusnetworks.com 	unblock_netpoll_tx();
15138a41ae44Ssfeldma@cumulusnetworks.com 
15148a41ae44Ssfeldma@cumulusnetworks.com 	return 0;
15158a41ae44Ssfeldma@cumulusnetworks.com }
151689901972Ssfeldma@cumulusnetworks.com 
bond_option_fail_over_mac_set(struct bonding * bond,const struct bond_opt_value * newval)1517f3253339Sstephen hemminger static int bond_option_fail_over_mac_set(struct bonding *bond,
151828f084ccSstephen hemminger 					 const struct bond_opt_value *newval)
151989901972Ssfeldma@cumulusnetworks.com {
1520eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting fail_over_mac to %s (%llu)\n",
15212de390baSVeaceslav Falico 		   newval->string, newval->value);
15221df6b6aaSNikolay Aleksandrov 	bond->params.fail_over_mac = newval->value;
152389901972Ssfeldma@cumulusnetworks.com 
152489901972Ssfeldma@cumulusnetworks.com 	return 0;
152589901972Ssfeldma@cumulusnetworks.com }
1526f70161c6Ssfeldma@cumulusnetworks.com 
bond_option_xmit_hash_policy_set(struct bonding * bond,const struct bond_opt_value * newval)1527f3253339Sstephen hemminger static int bond_option_xmit_hash_policy_set(struct bonding *bond,
152828f084ccSstephen hemminger 					    const struct bond_opt_value *newval)
1529f70161c6Ssfeldma@cumulusnetworks.com {
1530eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
15312de390baSVeaceslav Falico 		   newval->string, newval->value);
1532a4b32ce7SNikolay Aleksandrov 	bond->params.xmit_policy = newval->value;
1533f70161c6Ssfeldma@cumulusnetworks.com 
1534f70161c6Ssfeldma@cumulusnetworks.com 	return 0;
1535f70161c6Ssfeldma@cumulusnetworks.com }
1536d8838de7Ssfeldma@cumulusnetworks.com 
bond_option_resend_igmp_set(struct bonding * bond,const struct bond_opt_value * newval)1537f3253339Sstephen hemminger static int bond_option_resend_igmp_set(struct bonding *bond,
153828f084ccSstephen hemminger 				       const struct bond_opt_value *newval)
1539d8838de7Ssfeldma@cumulusnetworks.com {
1540eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting resend_igmp to %llu\n",
15412de390baSVeaceslav Falico 		   newval->value);
1542105c8fb6SNikolay Aleksandrov 	bond->params.resend_igmp = newval->value;
1543d8838de7Ssfeldma@cumulusnetworks.com 
1544d8838de7Ssfeldma@cumulusnetworks.com 	return 0;
1545d8838de7Ssfeldma@cumulusnetworks.com }
15462c9839c1Ssfeldma@cumulusnetworks.com 
bond_option_num_peer_notif_set(struct bonding * bond,const struct bond_opt_value * newval)1547f3253339Sstephen hemminger static int bond_option_num_peer_notif_set(struct bonding *bond,
154828f084ccSstephen hemminger 				   const struct bond_opt_value *newval)
15492c9839c1Ssfeldma@cumulusnetworks.com {
1550ef56becbSNikolay Aleksandrov 	bond->params.num_peer_notif = newval->value;
1551ef56becbSNikolay Aleksandrov 
15522c9839c1Ssfeldma@cumulusnetworks.com 	return 0;
15532c9839c1Ssfeldma@cumulusnetworks.com }
15541cc0b1e3Ssfeldma@cumulusnetworks.com 
bond_option_all_slaves_active_set(struct bonding * bond,const struct bond_opt_value * newval)1555f3253339Sstephen hemminger static int bond_option_all_slaves_active_set(struct bonding *bond,
155628f084ccSstephen hemminger 					     const struct bond_opt_value *newval)
15571cc0b1e3Ssfeldma@cumulusnetworks.com {
15581cc0b1e3Ssfeldma@cumulusnetworks.com 	struct list_head *iter;
15591cc0b1e3Ssfeldma@cumulusnetworks.com 	struct slave *slave;
15601cc0b1e3Ssfeldma@cumulusnetworks.com 
15613df01162SNikolay Aleksandrov 	if (newval->value == bond->params.all_slaves_active)
15621cc0b1e3Ssfeldma@cumulusnetworks.com 		return 0;
15633df01162SNikolay Aleksandrov 	bond->params.all_slaves_active = newval->value;
15641cc0b1e3Ssfeldma@cumulusnetworks.com 	bond_for_each_slave(bond, slave, iter) {
15651cc0b1e3Ssfeldma@cumulusnetworks.com 		if (!bond_is_active_slave(slave)) {
15663df01162SNikolay Aleksandrov 			if (newval->value)
15671cc0b1e3Ssfeldma@cumulusnetworks.com 				slave->inactive = 0;
15681cc0b1e3Ssfeldma@cumulusnetworks.com 			else
15691cc0b1e3Ssfeldma@cumulusnetworks.com 				slave->inactive = 1;
15701cc0b1e3Ssfeldma@cumulusnetworks.com 		}
15711cc0b1e3Ssfeldma@cumulusnetworks.com 	}
15721cc0b1e3Ssfeldma@cumulusnetworks.com 
15731cc0b1e3Ssfeldma@cumulusnetworks.com 	return 0;
15741cc0b1e3Ssfeldma@cumulusnetworks.com }
15757d101008Ssfeldma@cumulusnetworks.com 
bond_option_min_links_set(struct bonding * bond,const struct bond_opt_value * newval)1576f3253339Sstephen hemminger static int bond_option_min_links_set(struct bonding *bond,
157728f084ccSstephen hemminger 				     const struct bond_opt_value *newval)
15787d101008Ssfeldma@cumulusnetworks.com {
1579eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting min links value to %llu\n",
15802de390baSVeaceslav Falico 		   newval->value);
1581633ddc9eSNikolay Aleksandrov 	bond->params.min_links = newval->value;
15822477bc9aSJonathan Toppins 	bond_set_carrier(bond);
15837d101008Ssfeldma@cumulusnetworks.com 
15847d101008Ssfeldma@cumulusnetworks.com 	return 0;
15857d101008Ssfeldma@cumulusnetworks.com }
15868d836d09Ssfeldma@cumulusnetworks.com 
bond_option_lp_interval_set(struct bonding * bond,const struct bond_opt_value * newval)1587f3253339Sstephen hemminger static int bond_option_lp_interval_set(struct bonding *bond,
158828f084ccSstephen hemminger 				       const struct bond_opt_value *newval)
15898d836d09Ssfeldma@cumulusnetworks.com {
15904325b374SNikolay Aleksandrov 	bond->params.lp_interval = newval->value;
15918d836d09Ssfeldma@cumulusnetworks.com 
15928d836d09Ssfeldma@cumulusnetworks.com 	return 0;
15938d836d09Ssfeldma@cumulusnetworks.com }
1594c13ab3ffSsfeldma@cumulusnetworks.com 
bond_option_pps_set(struct bonding * bond,const struct bond_opt_value * newval)1595f3253339Sstephen hemminger static int bond_option_pps_set(struct bonding *bond,
159628f084ccSstephen hemminger 			       const struct bond_opt_value *newval)
1597c13ab3ffSsfeldma@cumulusnetworks.com {
1598eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting packets per slave to %llu\n",
1599eac306b4SMichael Dilmore 		   newval->value);
1600aa59d851SNikolay Aleksandrov 	bond->params.packets_per_slave = newval->value;
1601aa59d851SNikolay Aleksandrov 	if (newval->value > 0) {
1602809fa972SHannes Frederic Sowa 		bond->params.reciprocal_packets_per_slave =
1603aa59d851SNikolay Aleksandrov 			reciprocal_value(newval->value);
1604809fa972SHannes Frederic Sowa 	} else {
1605809fa972SHannes Frederic Sowa 		/* reciprocal_packets_per_slave is unused if
1606809fa972SHannes Frederic Sowa 		 * packets_per_slave is 0 or 1, just initialize it
1607809fa972SHannes Frederic Sowa 		 */
1608809fa972SHannes Frederic Sowa 		bond->params.reciprocal_packets_per_slave =
1609809fa972SHannes Frederic Sowa 			(struct reciprocal_value) { 0 };
1610809fa972SHannes Frederic Sowa 	}
1611c13ab3ffSsfeldma@cumulusnetworks.com 
1612c13ab3ffSsfeldma@cumulusnetworks.com 	return 0;
1613c13ab3ffSsfeldma@cumulusnetworks.com }
1614998e40bbSsfeldma@cumulusnetworks.com 
bond_option_lacp_active_set(struct bonding * bond,const struct bond_opt_value * newval)16153a755cd8SHangbin Liu static int bond_option_lacp_active_set(struct bonding *bond,
16163a755cd8SHangbin Liu 				       const struct bond_opt_value *newval)
16173a755cd8SHangbin Liu {
16183a755cd8SHangbin Liu 	netdev_dbg(bond->dev, "Setting LACP active to %s (%llu)\n",
16193a755cd8SHangbin Liu 		   newval->string, newval->value);
16203a755cd8SHangbin Liu 	bond->params.lacp_active = newval->value;
16213a755cd8SHangbin Liu 
16223a755cd8SHangbin Liu 	return 0;
16233a755cd8SHangbin Liu }
16243a755cd8SHangbin Liu 
bond_option_lacp_rate_set(struct bonding * bond,const struct bond_opt_value * newval)1625f3253339Sstephen hemminger static int bond_option_lacp_rate_set(struct bonding *bond,
162628f084ccSstephen hemminger 				     const struct bond_opt_value *newval)
1627998e40bbSsfeldma@cumulusnetworks.com {
1628eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting LACP rate to %s (%llu)\n",
16292de390baSVeaceslav Falico 		   newval->string, newval->value);
1630d3131de7SNikolay Aleksandrov 	bond->params.lacp_fast = newval->value;
1631998e40bbSsfeldma@cumulusnetworks.com 	bond_3ad_update_lacp_rate(bond);
1632998e40bbSsfeldma@cumulusnetworks.com 
1633998e40bbSsfeldma@cumulusnetworks.com 	return 0;
1634998e40bbSsfeldma@cumulusnetworks.com }
1635ec029facSsfeldma@cumulusnetworks.com 
bond_option_ad_select_set(struct bonding * bond,const struct bond_opt_value * newval)1636f3253339Sstephen hemminger static int bond_option_ad_select_set(struct bonding *bond,
163728f084ccSstephen hemminger 				     const struct bond_opt_value *newval)
1638ec029facSsfeldma@cumulusnetworks.com {
1639eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting ad_select to %s (%llu)\n",
16402de390baSVeaceslav Falico 		   newval->string, newval->value);
16419e5f5eebSNikolay Aleksandrov 	bond->params.ad_select = newval->value;
1642ec029facSsfeldma@cumulusnetworks.com 
1643ec029facSsfeldma@cumulusnetworks.com 	return 0;
1644ec029facSsfeldma@cumulusnetworks.com }
164524089ba1SNikolay Aleksandrov 
bond_option_queue_id_set(struct bonding * bond,const struct bond_opt_value * newval)1646f3253339Sstephen hemminger static int bond_option_queue_id_set(struct bonding *bond,
164728f084ccSstephen hemminger 				    const struct bond_opt_value *newval)
164824089ba1SNikolay Aleksandrov {
164924089ba1SNikolay Aleksandrov 	struct slave *slave, *update_slave;
165024089ba1SNikolay Aleksandrov 	struct net_device *sdev;
165124089ba1SNikolay Aleksandrov 	struct list_head *iter;
165224089ba1SNikolay Aleksandrov 	char *delim;
165324089ba1SNikolay Aleksandrov 	int ret = 0;
165424089ba1SNikolay Aleksandrov 	u16 qid;
165524089ba1SNikolay Aleksandrov 
165624089ba1SNikolay Aleksandrov 	/* delim will point to queue id if successful */
165724089ba1SNikolay Aleksandrov 	delim = strchr(newval->string, ':');
165824089ba1SNikolay Aleksandrov 	if (!delim)
165924089ba1SNikolay Aleksandrov 		goto err_no_cmd;
166024089ba1SNikolay Aleksandrov 
166124089ba1SNikolay Aleksandrov 	/* Terminate string that points to device name and bump it
166224089ba1SNikolay Aleksandrov 	 * up one, so we can read the queue id there.
166324089ba1SNikolay Aleksandrov 	 */
166424089ba1SNikolay Aleksandrov 	*delim = '\0';
166524089ba1SNikolay Aleksandrov 	if (sscanf(++delim, "%hd\n", &qid) != 1)
166624089ba1SNikolay Aleksandrov 		goto err_no_cmd;
166724089ba1SNikolay Aleksandrov 
166824089ba1SNikolay Aleksandrov 	/* Check buffer length, valid ifname and queue id */
1669c313c89eSdingtianhong 	if (!dev_valid_name(newval->string) ||
167024089ba1SNikolay Aleksandrov 	    qid > bond->dev->real_num_tx_queues)
167124089ba1SNikolay Aleksandrov 		goto err_no_cmd;
167224089ba1SNikolay Aleksandrov 
167324089ba1SNikolay Aleksandrov 	/* Get the pointer to that interface if it exists */
167424089ba1SNikolay Aleksandrov 	sdev = __dev_get_by_name(dev_net(bond->dev), newval->string);
167524089ba1SNikolay Aleksandrov 	if (!sdev)
167624089ba1SNikolay Aleksandrov 		goto err_no_cmd;
167724089ba1SNikolay Aleksandrov 
167824089ba1SNikolay Aleksandrov 	/* Search for thes slave and check for duplicate qids */
167924089ba1SNikolay Aleksandrov 	update_slave = NULL;
168024089ba1SNikolay Aleksandrov 	bond_for_each_slave(bond, slave, iter) {
168124089ba1SNikolay Aleksandrov 		if (sdev == slave->dev)
168224089ba1SNikolay Aleksandrov 			/* We don't need to check the matching
168324089ba1SNikolay Aleksandrov 			 * slave for dups, since we're overwriting it
168424089ba1SNikolay Aleksandrov 			 */
168524089ba1SNikolay Aleksandrov 			update_slave = slave;
168624089ba1SNikolay Aleksandrov 		else if (qid && qid == slave->queue_id) {
168724089ba1SNikolay Aleksandrov 			goto err_no_cmd;
168824089ba1SNikolay Aleksandrov 		}
168924089ba1SNikolay Aleksandrov 	}
169024089ba1SNikolay Aleksandrov 
169124089ba1SNikolay Aleksandrov 	if (!update_slave)
169224089ba1SNikolay Aleksandrov 		goto err_no_cmd;
169324089ba1SNikolay Aleksandrov 
169424089ba1SNikolay Aleksandrov 	/* Actually set the qids for the slave */
169524089ba1SNikolay Aleksandrov 	update_slave->queue_id = qid;
169624089ba1SNikolay Aleksandrov 
169724089ba1SNikolay Aleksandrov out:
169824089ba1SNikolay Aleksandrov 	return ret;
169924089ba1SNikolay Aleksandrov 
170024089ba1SNikolay Aleksandrov err_no_cmd:
1701eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "invalid input for queue_id set\n");
170224089ba1SNikolay Aleksandrov 	ret = -EPERM;
170324089ba1SNikolay Aleksandrov 	goto out;
170424089ba1SNikolay Aleksandrov 
170524089ba1SNikolay Aleksandrov }
17060e2e5b66SNikolay Aleksandrov 
bond_option_slaves_set(struct bonding * bond,const struct bond_opt_value * newval)1707f3253339Sstephen hemminger static int bond_option_slaves_set(struct bonding *bond,
170828f084ccSstephen hemminger 				  const struct bond_opt_value *newval)
17090e2e5b66SNikolay Aleksandrov {
17100e2e5b66SNikolay Aleksandrov 	char command[IFNAMSIZ + 1] = { 0, };
17110e2e5b66SNikolay Aleksandrov 	struct net_device *dev;
17120e2e5b66SNikolay Aleksandrov 	char *ifname;
17130e2e5b66SNikolay Aleksandrov 	int ret;
17140e2e5b66SNikolay Aleksandrov 
17150e2e5b66SNikolay Aleksandrov 	sscanf(newval->string, "%16s", command); /* IFNAMSIZ*/
17160e2e5b66SNikolay Aleksandrov 	ifname = command + 1;
17170e2e5b66SNikolay Aleksandrov 	if ((strlen(command) <= 1) ||
1718415d3942STonghao Zhang 	    (command[0] != '+' && command[0] != '-') ||
17190e2e5b66SNikolay Aleksandrov 	    !dev_valid_name(ifname))
17200e2e5b66SNikolay Aleksandrov 		goto err_no_cmd;
17210e2e5b66SNikolay Aleksandrov 
17220e2e5b66SNikolay Aleksandrov 	dev = __dev_get_by_name(dev_net(bond->dev), ifname);
17230e2e5b66SNikolay Aleksandrov 	if (!dev) {
1724eac306b4SMichael Dilmore 		netdev_dbg(bond->dev, "interface %s does not exist!\n",
17252de390baSVeaceslav Falico 			   ifname);
17260e2e5b66SNikolay Aleksandrov 		ret = -ENODEV;
17270e2e5b66SNikolay Aleksandrov 		goto out;
17280e2e5b66SNikolay Aleksandrov 	}
17290e2e5b66SNikolay Aleksandrov 
17300e2e5b66SNikolay Aleksandrov 	switch (command[0]) {
17310e2e5b66SNikolay Aleksandrov 	case '+':
1732f887e54cSJarod Wilson 		slave_dbg(bond->dev, dev, "Enslaving interface\n");
173333eaf2a6SDavid Ahern 		ret = bond_enslave(bond->dev, dev, NULL);
17340e2e5b66SNikolay Aleksandrov 		break;
17350e2e5b66SNikolay Aleksandrov 
17360e2e5b66SNikolay Aleksandrov 	case '-':
1737f887e54cSJarod Wilson 		slave_dbg(bond->dev, dev, "Releasing interface\n");
17380e2e5b66SNikolay Aleksandrov 		ret = bond_release(bond->dev, dev);
17390e2e5b66SNikolay Aleksandrov 		break;
17400e2e5b66SNikolay Aleksandrov 
17410e2e5b66SNikolay Aleksandrov 	default:
1742415d3942STonghao Zhang 		/* should not run here. */
17430e2e5b66SNikolay Aleksandrov 		goto err_no_cmd;
17440e2e5b66SNikolay Aleksandrov 	}
17450e2e5b66SNikolay Aleksandrov 
17460e2e5b66SNikolay Aleksandrov out:
17470e2e5b66SNikolay Aleksandrov 	return ret;
17480e2e5b66SNikolay Aleksandrov 
17490e2e5b66SNikolay Aleksandrov err_no_cmd:
17502de390baSVeaceslav Falico 	netdev_err(bond->dev, "no command found in slaves file - use +ifname or -ifname\n");
17510e2e5b66SNikolay Aleksandrov 	ret = -EPERM;
17520e2e5b66SNikolay Aleksandrov 	goto out;
17530e2e5b66SNikolay Aleksandrov }
1754e9f0fb88SMahesh Bandewar 
bond_option_tlb_dynamic_lb_set(struct bonding * bond,const struct bond_opt_value * newval)1755e9f0fb88SMahesh Bandewar static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
1756e9f0fb88SMahesh Bandewar 					  const struct bond_opt_value *newval)
1757e9f0fb88SMahesh Bandewar {
1758eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting dynamic-lb to %s (%llu)\n",
17592de390baSVeaceslav Falico 		   newval->string, newval->value);
1760e9f0fb88SMahesh Bandewar 	bond->params.tlb_dynamic_lb = newval->value;
1761e9f0fb88SMahesh Bandewar 
1762e9f0fb88SMahesh Bandewar 	return 0;
1763e9f0fb88SMahesh Bandewar }
17646791e466SMahesh Bandewar 
bond_option_ad_actor_sys_prio_set(struct bonding * bond,const struct bond_opt_value * newval)17656791e466SMahesh Bandewar static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
17666791e466SMahesh Bandewar 					     const struct bond_opt_value *newval)
17676791e466SMahesh Bandewar {
1768eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting ad_actor_sys_prio to %llu\n",
17696791e466SMahesh Bandewar 		   newval->value);
17706791e466SMahesh Bandewar 
17716791e466SMahesh Bandewar 	bond->params.ad_actor_sys_prio = newval->value;
17725ee14e6dSNikolay Aleksandrov 	bond_3ad_update_ad_actor_settings(bond);
17735ee14e6dSNikolay Aleksandrov 
17746791e466SMahesh Bandewar 	return 0;
17756791e466SMahesh Bandewar }
177674514957SMahesh Bandewar 
bond_option_ad_actor_system_set(struct bonding * bond,const struct bond_opt_value * newval)177774514957SMahesh Bandewar static int bond_option_ad_actor_system_set(struct bonding *bond,
177874514957SMahesh Bandewar 					   const struct bond_opt_value *newval)
177974514957SMahesh Bandewar {
178074514957SMahesh Bandewar 	u8 macaddr[ETH_ALEN];
1781171a42c3SAndy Gospodarek 	u8 *mac;
178274514957SMahesh Bandewar 
1783171a42c3SAndy Gospodarek 	if (newval->string) {
1784ce5c144fSAndy Shevchenko 		if (!mac_pton(newval->string, macaddr))
1785171a42c3SAndy Gospodarek 			goto err;
1786171a42c3SAndy Gospodarek 		mac = macaddr;
1787171a42c3SAndy Gospodarek 	} else {
1788171a42c3SAndy Gospodarek 		mac = (u8 *)&newval->value;
178974514957SMahesh Bandewar 	}
179074514957SMahesh Bandewar 
17911c15b05bSFernando Fernandez Mancera 	if (is_multicast_ether_addr(mac))
1792171a42c3SAndy Gospodarek 		goto err;
1793171a42c3SAndy Gospodarek 
1794eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting ad_actor_system to %pM\n", mac);
1795171a42c3SAndy Gospodarek 	ether_addr_copy(bond->params.ad_actor_system, mac);
17965ee14e6dSNikolay Aleksandrov 	bond_3ad_update_ad_actor_settings(bond);
17975ee14e6dSNikolay Aleksandrov 
179874514957SMahesh Bandewar 	return 0;
1799171a42c3SAndy Gospodarek 
1800171a42c3SAndy Gospodarek err:
1801f887e54cSJarod Wilson 	netdev_err(bond->dev, "Invalid ad_actor_system MAC address.\n");
1802171a42c3SAndy Gospodarek 	return -EINVAL;
180374514957SMahesh Bandewar }
1804d22a5fc0SMahesh Bandewar 
bond_option_ad_user_port_key_set(struct bonding * bond,const struct bond_opt_value * newval)1805d22a5fc0SMahesh Bandewar static int bond_option_ad_user_port_key_set(struct bonding *bond,
1806d22a5fc0SMahesh Bandewar 					    const struct bond_opt_value *newval)
1807d22a5fc0SMahesh Bandewar {
1808eac306b4SMichael Dilmore 	netdev_dbg(bond->dev, "Setting ad_user_port_key to %llu\n",
1809d22a5fc0SMahesh Bandewar 		   newval->value);
1810d22a5fc0SMahesh Bandewar 
1811d22a5fc0SMahesh Bandewar 	bond->params.ad_user_port_key = newval->value;
1812d22a5fc0SMahesh Bandewar 	return 0;
1813d22a5fc0SMahesh Bandewar }
1814