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