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