linux/drivers/net/bonding/bond_options.c

1885 lines
54 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* drivers/net/bond/bond_options.c - bonding options
* Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
* Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com>
*/
#include <linux/errno.h>
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/sched/signal.h>
#include <net/bonding.h>
#include <net/ndisc.h>
static int bond_option_active_slave_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_miimon_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_updelay_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_downdelay_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_peer_notif_delay_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_use_carrier_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_arp_interval_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target);
static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target);
static int bond_option_arp_ip_targets_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ns_ip6_targets_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_arp_validate_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_arp_all_targets_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_prio_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_primary_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_primary_reselect_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_fail_over_mac_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_xmit_hash_policy_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_resend_igmp_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_num_peer_notif_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_all_slaves_active_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_min_links_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_lp_interval_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_pps_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_lacp_active_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_lacp_rate_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ad_select_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_queue_id_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_mode_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_slaves_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
const struct bond_opt_value *newval);
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
static int bond_option_ad_actor_system_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_ad_user_port_key_set(struct bonding *bond,
const struct bond_opt_value *newval);
static int bond_option_missed_max_set(struct bonding *bond,
const struct bond_opt_value *newval);
2024-02-02 17:58:58 +00:00
static int bond_option_coupled_control_set(struct bonding *bond,
const struct bond_opt_value *newval);
net: bonding: add broadcast_neighbor option for 802.3ad Stacking technology is a type of technology used to expand ports on Ethernet switches. It is widely used as a common access method in large-scale Internet data center architectures. Years of practice have proved that stacking technology has advantages and disadvantages in high-reliability network architecture scenarios. For instance, in stacking networking arch, conventional switch system upgrades require multiple stacked devices to restart at the same time. Therefore, it is inevitable that the business will be interrupted for a while. It is for this reason that "no-stacking" in data centers has become a trend. Additionally, when the stacking link connecting the switches fails or is abnormal, the stack will split. Although it is not common, it still happens in actual operation. The problem is that after the split, it is equivalent to two switches with the same configuration appearing in the network, causing network configuration conflicts and ultimately interrupting the services carried by the stacking system. To improve network stability, "non-stacking" solutions have been increasingly adopted, particularly by public cloud providers and tech companies like Alibaba, Tencent, and Didi. "non-stacking" is a method of mimicing switch stacking that convinces a LACP peer, bonding in this case, connected to a set of "non-stacked" switches that all of its ports are connected to a single switch (i.e., LACP aggregator), as if those switches were stacked. This enables the LACP peer's ports to aggregate together, and requires (a) special switch configuration, described in the linked article, and (b) modifications to the bonding 802.3ad (LACP) mode to send all ARP/ND packets across all ports of the active aggregator. Note that, with multiple aggregators, the current broadcast mode logic will send only packets to the selected aggregator(s). +-----------+ +-----------+ | switch1 | | switch2 | +-----------+ +-----------+ ^ ^ | | +-----------------+ | bond4 lacp | +-----------------+ | | | NIC1 | NIC2 +-----------------+ | server | +-----------------+ - https://www.ruijie.com/fr-fr/support/tech-gallery/de-stack-data-center-network-architecture/ Cc: Jay Vosburgh <jv@jvosburgh.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Simon Horman <horms@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Andrew Lunn <andrew+netdev@lunn.ch> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: Tonghao Zhang <tonghao@bamaicloud.com> Signed-off-by: Zengbing Tu <tuzengbing@didiglobal.com> Link: https://patch.msgid.link/84d0a044514157bb856a10b6d03a1028c4883561.1751031306.git.tonghao@bamaicloud.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2025-06-27 21:49:28 +08:00
static int bond_option_broadcast_neigh_set(struct bonding *bond,
const struct bond_opt_value *newval);
static const struct bond_opt_value bond_mode_tbl[] = {
{ "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT},
{ "active-backup", BOND_MODE_ACTIVEBACKUP, 0},
{ "balance-xor", BOND_MODE_XOR, 0},
{ "broadcast", BOND_MODE_BROADCAST, 0},
{ "802.3ad", BOND_MODE_8023AD, 0},
{ "balance-tlb", BOND_MODE_TLB, 0},
{ "balance-alb", BOND_MODE_ALB, 0},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_pps_tbl[] = {
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ "maxval", USHRT_MAX, BOND_VALFLAG_MAX},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_xmit_hashtype_tbl[] = {
bonding: add a vlan+srcmac tx hashing option This comes from an end-user request, where they're running multiple VMs on hosts with bonded interfaces connected to some interest switch topologies, where 802.3ad isn't an option. They're currently running a proprietary solution that effectively achieves load-balancing of VMs and bandwidth utilization improvements with a similar form of transmission algorithm. Basically, each VM has it's own vlan, so it always sends its traffic out the same interface, unless that interface fails. Traffic gets split between the interfaces, maintaining a consistent path, with failover still available if an interface goes down. Unlike bond_eth_hash(), this hash function is using the full source MAC address instead of just the last byte, as there are so few components to the hash, and in the no-vlan case, we would be returning just the last byte of the source MAC as the hash value. It's entirely possible to have two NICs in a bond with the same last byte of their MAC, but not the same MAC, so this adjustment should guarantee distinct hashes in all cases. This has been rudimetarily tested to provide similar results to the proprietary solution it is aiming to replace. A patch for iproute2 is also posted, to properly support the new mode there as well. Cc: Jay Vosburgh <j.vosburgh@gmail.com> Cc: Veaceslav Falico <vfalico@gmail.com> Cc: Andy Gospodarek <andy@greyhouse.net> Cc: Thomas Davis <tadavis@lbl.gov> Signed-off-by: Jarod Wilson <jarod@redhat.com> Link: https://lore.kernel.org/r/20210119010927.1191922-1-jarod@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2021-01-18 20:09:27 -05:00
{ "layer2", BOND_XMIT_POLICY_LAYER2, BOND_VALFLAG_DEFAULT},
{ "layer3+4", BOND_XMIT_POLICY_LAYER34, 0},
{ "layer2+3", BOND_XMIT_POLICY_LAYER23, 0},
{ "encap2+3", BOND_XMIT_POLICY_ENCAP23, 0},
{ "encap3+4", BOND_XMIT_POLICY_ENCAP34, 0},
{ "vlan+srcmac", BOND_XMIT_POLICY_VLAN_SRCMAC, 0},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_arp_validate_tbl[] = {
{ "none", BOND_ARP_VALIDATE_NONE, BOND_VALFLAG_DEFAULT},
{ "active", BOND_ARP_VALIDATE_ACTIVE, 0},
{ "backup", BOND_ARP_VALIDATE_BACKUP, 0},
{ "all", BOND_ARP_VALIDATE_ALL, 0},
{ "filter", BOND_ARP_FILTER, 0},
{ "filter_active", BOND_ARP_FILTER_ACTIVE, 0},
{ "filter_backup", BOND_ARP_FILTER_BACKUP, 0},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_arp_all_targets_tbl[] = {
{ "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT},
{ "all", BOND_ARP_TARGETS_ALL, 0},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_fail_over_mac_tbl[] = {
{ "none", BOND_FOM_NONE, BOND_VALFLAG_DEFAULT},
{ "active", BOND_FOM_ACTIVE, 0},
{ "follow", BOND_FOM_FOLLOW, 0},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_intmax_tbl[] = {
{ "off", 0, BOND_VALFLAG_DEFAULT},
{ "maxval", INT_MAX, BOND_VALFLAG_MAX},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_lacp_active[] = {
{ "off", 0, 0},
{ "on", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_lacp_rate_tbl[] = {
{ "slow", AD_LACP_SLOW, 0},
{ "fast", AD_LACP_FAST, 0},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_ad_select_tbl[] = {
{ "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT},
{ "bandwidth", BOND_AD_BANDWIDTH, 0},
{ "count", BOND_AD_COUNT, 0},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_num_peer_notif_tbl[] = {
{ "off", 0, 0},
{ "maxval", 255, BOND_VALFLAG_MAX},
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_peer_notif_delay_tbl[] = {
{ "off", 0, 0},
{ "maxval", 300000, BOND_VALFLAG_MAX},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_primary_reselect_tbl[] = {
{ "always", BOND_PRI_RESELECT_ALWAYS, BOND_VALFLAG_DEFAULT},
{ "better", BOND_PRI_RESELECT_BETTER, 0},
{ "failure", BOND_PRI_RESELECT_FAILURE, 0},
{ NULL, -1},
};
static const struct bond_opt_value bond_use_carrier_tbl[] = {
{ "off", 0, 0},
{ "on", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_all_slaves_active_tbl[] = {
{ "off", 0, BOND_VALFLAG_DEFAULT},
{ "on", 1, 0},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_resend_igmp_tbl[] = {
{ "off", 0, 0},
{ "maxval", 255, BOND_VALFLAG_MAX},
{ "default", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_lp_interval_tbl[] = {
{ "minval", 1, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
{ "maxval", INT_MAX, BOND_VALFLAG_MAX},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
{ "off", 0, 0},
{ "on", 1, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0}
};
static const struct bond_opt_value bond_ad_actor_sys_prio_tbl[] = {
{ "minval", 1, BOND_VALFLAG_MIN},
{ "maxval", 65535, BOND_VALFLAG_MAX | BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_ad_user_port_key_tbl[] = {
{ "minval", 0, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT},
{ "maxval", 1023, BOND_VALFLAG_MAX},
{ NULL, -1, 0},
};
static const struct bond_opt_value bond_missed_max_tbl[] = {
{ "minval", 1, BOND_VALFLAG_MIN},
{ "maxval", 255, BOND_VALFLAG_MAX},
{ "default", 2, BOND_VALFLAG_DEFAULT},
{ NULL, -1, 0},
};
2024-02-02 17:58:58 +00:00
static const struct bond_opt_value bond_coupled_control_tbl[] = {
{ "on", 1, BOND_VALFLAG_DEFAULT},
{ "off", 0, 0},
{ NULL, -1, 0},
};
net: bonding: add broadcast_neighbor option for 802.3ad Stacking technology is a type of technology used to expand ports on Ethernet switches. It is widely used as a common access method in large-scale Internet data center architectures. Years of practice have proved that stacking technology has advantages and disadvantages in high-reliability network architecture scenarios. For instance, in stacking networking arch, conventional switch system upgrades require multiple stacked devices to restart at the same time. Therefore, it is inevitable that the business will be interrupted for a while. It is for this reason that "no-stacking" in data centers has become a trend. Additionally, when the stacking link connecting the switches fails or is abnormal, the stack will split. Although it is not common, it still happens in actual operation. The problem is that after the split, it is equivalent to two switches with the same configuration appearing in the network, causing network configuration conflicts and ultimately interrupting the services carried by the stacking system. To improve network stability, "non-stacking" solutions have been increasingly adopted, particularly by public cloud providers and tech companies like Alibaba, Tencent, and Didi. "non-stacking" is a method of mimicing switch stacking that convinces a LACP peer, bonding in this case, connected to a set of "non-stacked" switches that all of its ports are connected to a single switch (i.e., LACP aggregator), as if those switches were stacked. This enables the LACP peer's ports to aggregate together, and requires (a) special switch configuration, described in the linked article, and (b) modifications to the bonding 802.3ad (LACP) mode to send all ARP/ND packets across all ports of the active aggregator. Note that, with multiple aggregators, the current broadcast mode logic will send only packets to the selected aggregator(s). +-----------+ +-----------+ | switch1 | | switch2 | +-----------+ +-----------+ ^ ^ | | +-----------------+ | bond4 lacp | +-----------------+ | | | NIC1 | NIC2 +-----------------+ | server | +-----------------+ - https://www.ruijie.com/fr-fr/support/tech-gallery/de-stack-data-center-network-architecture/ Cc: Jay Vosburgh <jv@jvosburgh.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Simon Horman <horms@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Andrew Lunn <andrew+netdev@lunn.ch> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: Tonghao Zhang <tonghao@bamaicloud.com> Signed-off-by: Zengbing Tu <tuzengbing@didiglobal.com> Link: https://patch.msgid.link/84d0a044514157bb856a10b6d03a1028c4883561.1751031306.git.tonghao@bamaicloud.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2025-06-27 21:49:28 +08:00
static const struct bond_opt_value bond_broadcast_neigh_tbl[] = {
{ "off", 0, BOND_VALFLAG_DEFAULT},
{ "on", 1, 0},
{ NULL, -1, 0}
};
static const struct bond_option bond_opts[BOND_OPT_LAST] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
.name = "mode",
.desc = "bond device mode",
.flags = BOND_OPTFLAG_NOSLAVES | BOND_OPTFLAG_IFDOWN,
.values = bond_mode_tbl,
.set = bond_option_mode_set
},
[BOND_OPT_PACKETS_PER_SLAVE] = {
.id = BOND_OPT_PACKETS_PER_SLAVE,
.name = "packets_per_slave",
.desc = "Packets to send per slave in RR mode",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ROUNDROBIN)),
.values = bond_pps_tbl,
.set = bond_option_pps_set
},
[BOND_OPT_XMIT_HASH] = {
.id = BOND_OPT_XMIT_HASH,
.name = "xmit_hash_policy",
.desc = "balance-xor, 802.3ad, and tlb hashing method",
.values = bond_xmit_hashtype_tbl,
.set = bond_option_xmit_hash_policy_set
},
[BOND_OPT_ARP_VALIDATE] = {
.id = BOND_OPT_ARP_VALIDATE,
.name = "arp_validate",
.desc = "validate src/dst of ARP probes",
.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB),
.values = bond_arp_validate_tbl,
.set = bond_option_arp_validate_set
},
[BOND_OPT_ARP_ALL_TARGETS] = {
.id = BOND_OPT_ARP_ALL_TARGETS,
.name = "arp_all_targets",
.desc = "fail on any/all arp targets timeout",
.values = bond_arp_all_targets_tbl,
.set = bond_option_arp_all_targets_set
},
[BOND_OPT_FAIL_OVER_MAC] = {
.id = BOND_OPT_FAIL_OVER_MAC,
.name = "fail_over_mac",
.desc = "For active-backup, do not set all slaves to the same MAC",
.flags = BOND_OPTFLAG_NOSLAVES,
.values = bond_fail_over_mac_tbl,
.set = bond_option_fail_over_mac_set
},
[BOND_OPT_ARP_INTERVAL] = {
.id = BOND_OPT_ARP_INTERVAL,
.name = "arp_interval",
.desc = "arp interval in milliseconds",
.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB),
.values = bond_intmax_tbl,
.set = bond_option_arp_interval_set
},
[BOND_OPT_MISSED_MAX] = {
.id = BOND_OPT_MISSED_MAX,
.name = "arp_missed_max",
.desc = "Maximum number of missed ARP interval",
.unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB),
.values = bond_missed_max_tbl,
.set = bond_option_missed_max_set
},
[BOND_OPT_ARP_TARGETS] = {
.id = BOND_OPT_ARP_TARGETS,
.name = "arp_ip_target",
.desc = "arp targets in n.n.n.n form",
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_arp_ip_targets_set
},
[BOND_OPT_NS_TARGETS] = {
.id = BOND_OPT_NS_TARGETS,
.name = "ns_ip6_target",
.desc = "NS targets in ffff:ffff::ffff:ffff form",
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_ns_ip6_targets_set
},
[BOND_OPT_DOWNDELAY] = {
.id = BOND_OPT_DOWNDELAY,
.name = "downdelay",
.desc = "Delay before considering link down, in milliseconds",
.values = bond_intmax_tbl,
.set = bond_option_downdelay_set
},
[BOND_OPT_UPDELAY] = {
.id = BOND_OPT_UPDELAY,
.name = "updelay",
.desc = "Delay before considering link up, in milliseconds",
.values = bond_intmax_tbl,
.set = bond_option_updelay_set
},
[BOND_OPT_LACP_ACTIVE] = {
.id = BOND_OPT_LACP_ACTIVE,
.name = "lacp_active",
.desc = "Send LACPDU frames with configured lacp rate or acts as speak when spoken to",
.flags = BOND_OPTFLAG_IFDOWN,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.values = bond_lacp_active,
.set = bond_option_lacp_active_set
},
[BOND_OPT_LACP_RATE] = {
.id = BOND_OPT_LACP_RATE,
.name = "lacp_rate",
.desc = "LACPDU tx rate to request from 802.3ad partner",
.flags = BOND_OPTFLAG_IFDOWN,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.values = bond_lacp_rate_tbl,
.set = bond_option_lacp_rate_set
},
[BOND_OPT_MINLINKS] = {
.id = BOND_OPT_MINLINKS,
.name = "min_links",
.desc = "Minimum number of available links before turning on carrier",
.values = bond_intmax_tbl,
.set = bond_option_min_links_set
},
[BOND_OPT_AD_SELECT] = {
.id = BOND_OPT_AD_SELECT,
.name = "ad_select",
.desc = "803.ad aggregation selection logic",
.flags = BOND_OPTFLAG_IFDOWN,
.values = bond_ad_select_tbl,
.set = bond_option_ad_select_set
},
[BOND_OPT_NUM_PEER_NOTIF] = {
.id = BOND_OPT_NUM_PEER_NOTIF,
.name = "num_unsol_na",
.desc = "Number of peer notifications to send on failover event",
.values = bond_num_peer_notif_tbl,
.set = bond_option_num_peer_notif_set
},
[BOND_OPT_MIIMON] = {
.id = BOND_OPT_MIIMON,
.name = "miimon",
.desc = "Link check interval in milliseconds",
.values = bond_intmax_tbl,
.set = bond_option_miimon_set
},
[BOND_OPT_PRIO] = {
.id = BOND_OPT_PRIO,
.name = "prio",
.desc = "Link priority for failover re-selection",
.flags = BOND_OPTFLAG_RAWVAL,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB)),
.set = bond_option_prio_set
},
[BOND_OPT_PRIMARY] = {
.id = BOND_OPT_PRIMARY,
.name = "primary",
.desc = "Primary network device to use",
.flags = BOND_OPTFLAG_RAWVAL,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB)),
.set = bond_option_primary_set
},
[BOND_OPT_PRIMARY_RESELECT] = {
.id = BOND_OPT_PRIMARY_RESELECT,
.name = "primary_reselect",
.desc = "Reselect primary slave once it comes up",
.values = bond_primary_reselect_tbl,
.set = bond_option_primary_reselect_set
},
[BOND_OPT_USE_CARRIER] = {
.id = BOND_OPT_USE_CARRIER,
.name = "use_carrier",
.desc = "Use netif_carrier_ok (vs MII ioctls) in miimon",
.values = bond_use_carrier_tbl,
.set = bond_option_use_carrier_set
},
[BOND_OPT_ACTIVE_SLAVE] = {
.id = BOND_OPT_ACTIVE_SLAVE,
.name = "active_slave",
.desc = "Currently active slave",
.flags = BOND_OPTFLAG_RAWVAL,
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP) |
BIT(BOND_MODE_TLB) |
BIT(BOND_MODE_ALB)),
.set = bond_option_active_slave_set
},
[BOND_OPT_QUEUE_ID] = {
.id = BOND_OPT_QUEUE_ID,
.name = "queue_id",
.desc = "Set queue id of a slave",
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_queue_id_set
},
[BOND_OPT_ALL_SLAVES_ACTIVE] = {
.id = BOND_OPT_ALL_SLAVES_ACTIVE,
.name = "all_slaves_active",
.desc = "Keep all frames received on an interface by setting active flag for all slaves",
.values = bond_all_slaves_active_tbl,
.set = bond_option_all_slaves_active_set
},
[BOND_OPT_RESEND_IGMP] = {
.id = BOND_OPT_RESEND_IGMP,
.name = "resend_igmp",
.desc = "Number of IGMP membership reports to send on link failure",
.values = bond_resend_igmp_tbl,
.set = bond_option_resend_igmp_set
},
[BOND_OPT_LP_INTERVAL] = {
.id = BOND_OPT_LP_INTERVAL,
.name = "lp_interval",
.desc = "The number of seconds between instances where the bonding driver sends learning packets to each slave's peer switch",
.values = bond_lp_interval_tbl,
.set = bond_option_lp_interval_set
},
[BOND_OPT_SLAVES] = {
.id = BOND_OPT_SLAVES,
.name = "slaves",
.desc = "Slave membership management",
.flags = BOND_OPTFLAG_RAWVAL,
.set = bond_option_slaves_set
},
[BOND_OPT_TLB_DYNAMIC_LB] = {
.id = BOND_OPT_TLB_DYNAMIC_LB,
.name = "tlb_dynamic_lb",
.desc = "Enable dynamic flow shuffling",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_TLB) | BIT(BOND_MODE_ALB)),
.values = bond_tlb_dynamic_lb_tbl,
.flags = BOND_OPTFLAG_IFDOWN,
.set = bond_option_tlb_dynamic_lb_set,
},
[BOND_OPT_AD_ACTOR_SYS_PRIO] = {
.id = BOND_OPT_AD_ACTOR_SYS_PRIO,
.name = "ad_actor_sys_prio",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.values = bond_ad_actor_sys_prio_tbl,
.set = bond_option_ad_actor_sys_prio_set,
},
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
[BOND_OPT_AD_ACTOR_SYSTEM] = {
.id = BOND_OPT_AD_ACTOR_SYSTEM,
.name = "ad_actor_system",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.flags = BOND_OPTFLAG_RAWVAL,
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
.set = bond_option_ad_actor_system_set,
},
[BOND_OPT_AD_USER_PORT_KEY] = {
.id = BOND_OPT_AD_USER_PORT_KEY,
.name = "ad_user_port_key",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.flags = BOND_OPTFLAG_IFDOWN,
.values = bond_ad_user_port_key_tbl,
.set = bond_option_ad_user_port_key_set,
},
[BOND_OPT_NUM_PEER_NOTIF_ALIAS] = {
.id = BOND_OPT_NUM_PEER_NOTIF_ALIAS,
.name = "num_grat_arp",
.desc = "Number of peer notifications to send on failover event",
.values = bond_num_peer_notif_tbl,
.set = bond_option_num_peer_notif_set
},
[BOND_OPT_PEER_NOTIF_DELAY] = {
.id = BOND_OPT_PEER_NOTIF_DELAY,
.name = "peer_notif_delay",
.desc = "Delay between each peer notification on failover event, in milliseconds",
.values = bond_peer_notif_delay_tbl,
.set = bond_option_peer_notif_delay_set
2024-02-02 17:58:58 +00:00
},
[BOND_OPT_COUPLED_CONTROL] = {
.id = BOND_OPT_COUPLED_CONTROL,
.name = "coupled_control",
.desc = "Opt into using coupled control MUX for LACP states",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.flags = BOND_OPTFLAG_IFDOWN,
.values = bond_coupled_control_tbl,
.set = bond_option_coupled_control_set,
net: bonding: add broadcast_neighbor option for 802.3ad Stacking technology is a type of technology used to expand ports on Ethernet switches. It is widely used as a common access method in large-scale Internet data center architectures. Years of practice have proved that stacking technology has advantages and disadvantages in high-reliability network architecture scenarios. For instance, in stacking networking arch, conventional switch system upgrades require multiple stacked devices to restart at the same time. Therefore, it is inevitable that the business will be interrupted for a while. It is for this reason that "no-stacking" in data centers has become a trend. Additionally, when the stacking link connecting the switches fails or is abnormal, the stack will split. Although it is not common, it still happens in actual operation. The problem is that after the split, it is equivalent to two switches with the same configuration appearing in the network, causing network configuration conflicts and ultimately interrupting the services carried by the stacking system. To improve network stability, "non-stacking" solutions have been increasingly adopted, particularly by public cloud providers and tech companies like Alibaba, Tencent, and Didi. "non-stacking" is a method of mimicing switch stacking that convinces a LACP peer, bonding in this case, connected to a set of "non-stacked" switches that all of its ports are connected to a single switch (i.e., LACP aggregator), as if those switches were stacked. This enables the LACP peer's ports to aggregate together, and requires (a) special switch configuration, described in the linked article, and (b) modifications to the bonding 802.3ad (LACP) mode to send all ARP/ND packets across all ports of the active aggregator. Note that, with multiple aggregators, the current broadcast mode logic will send only packets to the selected aggregator(s). +-----------+ +-----------+ | switch1 | | switch2 | +-----------+ +-----------+ ^ ^ | | +-----------------+ | bond4 lacp | +-----------------+ | | | NIC1 | NIC2 +-----------------+ | server | +-----------------+ - https://www.ruijie.com/fr-fr/support/tech-gallery/de-stack-data-center-network-architecture/ Cc: Jay Vosburgh <jv@jvosburgh.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Simon Horman <horms@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Andrew Lunn <andrew+netdev@lunn.ch> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: Tonghao Zhang <tonghao@bamaicloud.com> Signed-off-by: Zengbing Tu <tuzengbing@didiglobal.com> Link: https://patch.msgid.link/84d0a044514157bb856a10b6d03a1028c4883561.1751031306.git.tonghao@bamaicloud.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2025-06-27 21:49:28 +08:00
},
[BOND_OPT_BROADCAST_NEIGH] = {
.id = BOND_OPT_BROADCAST_NEIGH,
.name = "broadcast_neighbor",
.desc = "Broadcast neighbor packets to all active slaves",
.unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_8023AD)),
.values = bond_broadcast_neigh_tbl,
.set = bond_option_broadcast_neigh_set,
}
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
};
/* Searches for an option by name */
const struct bond_option *bond_opt_get_by_name(const char *name)
{
const struct bond_option *opt;
int option;
for (option = 0; option < BOND_OPT_LAST; option++) {
opt = bond_opt_get(option);
if (opt && !strcmp(opt->name, name))
return opt;
}
return NULL;
}
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
/* Searches for a value in opt's values[] table */
const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val)
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
{
const struct bond_option *opt;
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
int i;
opt = bond_opt_get(option);
if (WARN_ON(!opt))
return NULL;
for (i = 0; opt->values && opt->values[i].string; i++)
if (opt->values[i].value == val)
return &opt->values[i];
return NULL;
}
/* Searches for a value in opt's values[] table which matches the flagmask */
static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt,
u32 flagmask)
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
{
int i;
for (i = 0; opt->values && opt->values[i].string; i++)
if (opt->values[i].flags & flagmask)
return &opt->values[i];
return NULL;
}
/* If maxval is missing then there's no range to check. In case minval is
* missing then it's considered to be 0.
*/
static bool bond_opt_check_range(const struct bond_option *opt, u64 val)
{
const struct bond_opt_value *minval, *maxval;
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
if (!maxval || (minval && val < minval->value) || val > maxval->value)
return false;
return true;
}
/**
* bond_opt_parse - parse option value
* @opt: the option to parse against
* @val: value to parse
*
* This function tries to extract the value from @val and check if it's
* a possible match for the option and returns NULL if a match isn't found,
* or the struct_opt_value that matched. It also strips the new line from
* @val->string if it's present.
*/
const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt,
struct bond_opt_value *val)
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
{
char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, };
const struct bond_opt_value *tbl;
const struct bond_opt_value *ret = NULL;
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
bool checkval;
int i, rv;
/* No parsing if the option wants a raw val */
if (opt->flags & BOND_OPTFLAG_RAWVAL)
return val;
tbl = opt->values;
if (!tbl)
goto out;
/* ULLONG_MAX is used to bypass string processing */
checkval = val->value != ULLONG_MAX;
if (!checkval) {
if (!val->string)
goto out;
p = strchr(val->string, '\n');
if (p)
*p = '\0';
for (p = val->string; *p; p++)
if (!(isdigit(*p) || isspace(*p)))
break;
/* The following code extracts the string to match or the value
* and sets checkval appropriately
*/
if (*p) {
rv = sscanf(val->string, "%32s", valstr);
} else {
rv = sscanf(val->string, "%llu", &val->value);
checkval = true;
}
if (!rv)
goto out;
}
for (i = 0; tbl[i].string; i++) {
/* Check for exact match */
if (checkval) {
if (val->value == tbl[i].value)
ret = &tbl[i];
} else {
if (!strcmp(valstr, "default") &&
(tbl[i].flags & BOND_VALFLAG_DEFAULT))
ret = &tbl[i];
if (!strcmp(valstr, tbl[i].string))
ret = &tbl[i];
}
/* Found an exact match */
if (ret)
goto out;
}
/* Possible range match */
if (checkval && bond_opt_check_range(opt, val->value))
ret = val;
out:
return ret;
}
/* Check opt's dependencies against bond mode and currently set options */
static int bond_opt_check_deps(struct bonding *bond,
const struct bond_option *opt)
{
struct bond_params *params = &bond->params;
if (test_bit(params->mode, &opt->unsuppmodes))
return -EACCES;
if ((opt->flags & BOND_OPTFLAG_NOSLAVES) && bond_has_slaves(bond))
return -ENOTEMPTY;
if ((opt->flags & BOND_OPTFLAG_IFDOWN) && (bond->dev->flags & IFF_UP))
return -EBUSY;
return 0;
}
static void bond_opt_dep_print(struct bonding *bond,
const struct bond_option *opt,
struct nlattr *bad_attr,
struct netlink_ext_ack *extack)
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
{
const struct bond_opt_value *modeval;
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
struct bond_params *params;
params = &bond->params;
modeval = bond_opt_get_val(BOND_OPT_MODE, params->mode);
if (test_bit(params->mode, &opt->unsuppmodes)) {
netdev_err(bond->dev, "option %s: mode dependency failed, not supported in mode %s(%llu)\n",
opt->name, modeval->string, modeval->value);
NL_SET_ERR_MSG_ATTR(extack, bad_attr,
"option not supported in mode");
}
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
}
static void 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)
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
{
const struct bond_opt_value *minval, *maxval;
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
char *p;
switch (error) {
case -EINVAL:
NL_SET_ERR_MSG_ATTR(extack, bad_attr, "invalid option value");
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
if (val) {
if (val->string) {
/* sometimes RAWVAL opts may have new lines */
p = strchr(val->string, '\n');
if (p)
*p = '\0';
netdev_err(bond->dev, "option %s: invalid value (%s)\n",
opt->name, val->string);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
} else {
netdev_err(bond->dev, "option %s: invalid value (%llu)\n",
opt->name, val->value);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
}
}
minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN);
maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX);
if (!maxval)
break;
netdev_err(bond->dev, "option %s: allowed values %llu - %llu\n",
opt->name, minval ? minval->value : 0, maxval->value);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
break;
case -EACCES:
bond_opt_dep_print(bond, opt, bad_attr, extack);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
break;
case -ENOTEMPTY:
NL_SET_ERR_MSG_ATTR(extack, bad_attr,
"unable to set option because the bond device has slaves");
netdev_err(bond->dev, "option %s: unable to set because the bond device has slaves\n",
opt->name);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
break;
case -EBUSY:
NL_SET_ERR_MSG_ATTR(extack, bad_attr,
"unable to set option because the bond is up");
netdev_err(bond->dev, "option %s: unable to set because the bond device is up\n",
opt->name);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
break;
case -ENODEV:
if (val && val->string) {
p = strchr(val->string, '\n');
if (p)
*p = '\0';
netdev_err(bond->dev, "option %s: interface %s does not exist!\n",
opt->name, val->string);
NL_SET_ERR_MSG_ATTR(extack, bad_attr,
"interface does not exist");
}
break;
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
default:
break;
}
}
/**
* __bond_opt_set - set a bonding option
* @bond: target bond device
* @option: option to set
* @val: value to set it to
* @bad_attr: netlink attribue that caused the error
* @extack: extended netlink error structure, used when an error message
* needs to be returned to the caller via netlink
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
*
* This function is used to change the bond's option value, it can be
* used for both enabling/changing an option and for disabling it. RTNL lock
* must be obtained before calling this function.
*/
int __bond_opt_set(struct bonding *bond,
unsigned int option, struct bond_opt_value *val,
struct nlattr *bad_attr, struct netlink_ext_ack *extack)
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
{
const struct bond_opt_value *retval = NULL;
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
const struct bond_option *opt;
int ret = -ENOENT;
ASSERT_RTNL();
opt = bond_opt_get(option);
if (WARN_ON(!val) || WARN_ON(!opt))
goto out;
ret = bond_opt_check_deps(bond, opt);
if (ret)
goto out;
retval = bond_opt_parse(opt, val);
if (!retval) {
ret = -EINVAL;
goto out;
}
ret = opt->set(bond, retval);
out:
if (ret)
bond_opt_error_interpret(bond, opt, ret, val, bad_attr, extack);
return ret;
}
/**
* __bond_opt_set_notify - set a bonding option
* @bond: target bond device
* @option: option to set
* @val: value to set it to
*
* This function is used to change the bond's option value and trigger
* a notification to user sapce. It can be used for both enabling/changing
* an option and for disabling it. RTNL lock must be obtained before calling
* this function.
*/
int __bond_opt_set_notify(struct bonding *bond,
unsigned int option, struct bond_opt_value *val)
{
int ret;
ASSERT_RTNL();
ret = __bond_opt_set(bond, option, val, NULL, NULL);
if (!ret && (bond->dev->reg_state == NETREG_REGISTERED))
call_netdevice_notifiers(NETDEV_CHANGEINFODATA, bond->dev);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
return ret;
}
/**
* bond_opt_tryset_rtnl - try to acquire rtnl and call __bond_opt_set
* @bond: target bond device
* @option: option to set
* @buf: value to set it to
*
* This function tries to acquire RTNL without blocking and if successful
* calls __bond_opt_set. It is mainly used for sysfs option manipulation.
*/
int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf)
{
struct bond_opt_value optval;
int ret;
if (!rtnl_trylock())
return restart_syscall();
bond_opt_initstr(&optval, buf);
ret = __bond_opt_set_notify(bond, option, &optval);
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
rtnl_unlock();
return ret;
}
/**
* bond_opt_get - get a pointer to an option
* @option: option for which to return a pointer
*
* This function checks if option is valid and if so returns a pointer
* to its entry in the bond_opts[] option array.
*/
const struct bond_option *bond_opt_get(unsigned int option)
bonding: add infrastructure for an option API This patch adds the necessary basic infrastructure to support centralized and unified option manipulation API for the bonding. The new structure bond_option will be used to describe each option with its dependencies on modes which will be checked automatically thus removing a lot of duplicated code. Also automatic range checking is added for some options. Currently the option setting function requires RTNL to be acquired prior to calling it, since many options already rely on RTNL it seemed like the best choice to protect all against common race conditions. In order to add an option the following steps need to be done: 1. Add an entry BOND_OPT_<option> to bond_options.h so it gets a unique id and a bit corresponding to the id 2. Add a bond_option entry to the bond_opts[] array in bond_options.c which describes the option, its dependencies and its manipulation function 3. Add code to export the option through sysfs and/or as a module parameter (the sysfs export will be made automatically in the future) The options can have different flags set, currently the following are supported: BOND_OPTFLAG_NOSLAVES - require that the bond device has no slaves prior to setting the option BOND_OPTFLAG_IFDOWN - require that the bond device is down prior to setting the option BOND_OPTFLAG_RAWVAL - don't parse the value but return it raw for the option to parse There's a new value structure to describe different types of values which can have the following flags: BOND_VALFLAG_DEFAULT - marks the default option (permanent string alias to this option is "default") BOND_VALFLAG_MIN - the minimum value that this option can have BOND_VALFLAG_MAX - the maximum value that this option can have An example would be nice here, so if we have an option which can have the values "off"(2), "special"(4, default) and supports a range, say 16 - 32, it should be defined as follows: "off", 2, "special", 4, BOND_VALFLAG_DEFAULT, "rangemin", 16, BOND_VALFLAG_MIN, "rangemax", 32, BOND_VALFLAG_MAX So we have the valid intervals: [2, 2], [4, 4], [16, 32] Also the valid strings: "off" = 2, "special" and "default" = 4 "rangemin" = 16, "rangemax" = 32 BOND_VALFLAG_(MIN|MAX) can be used to specify a valid range for an option, if MIN is omitted then 0 is considered as a minimum. If an exact match is found in the values[] table it will be returned, otherwise the range is tried (if available). The option parameter passing is done by using a special structure called bond_opt_value which can take either a string or a value to parse. One of the bond_opt_init(val|str) macros should be used depending on which one does the user want to parse (string or value). Then a call to __bond_opt_set should be done under RTNL. Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 14:53:16 +01:00
{
if (!BOND_OPT_VALID(option))
return NULL;
return &bond_opts[option];
}
static bool bond_set_xfrm_features(struct bonding *bond)
bonding: fix feature flag setting at init time Don't try to adjust XFRM support flags if the bond device isn't yet registered. Bad things can currently happen when netdev_change_features() is called without having wanted_features fully filled in yet. This code runs both on post-module-load mode changes, as well as at module init time, and when run at module init time, it is before register_netdevice() has been called and filled in wanted_features. The empty wanted_features led to features also getting emptied out, which was definitely not the intended behavior, so prevent that from happening. Originally, I'd hoped to stop adjusting wanted_features at all in the bonding driver, as it's documented as being something only the network core should touch, but we actually do need to do this to properly update both the features and wanted_features fields when changing the bond type, or we get to a situation where ethtool sees: esp-hw-offload: off [requested on] I do think we should be using netdev_update_features instead of netdev_change_features here though, so we only send notifiers when the features actually changed. Fixes: a3b658cfb664 ("bonding: allow xfrm offload setup post-module-load") Reported-by: Ivan Vecera <ivecera@redhat.com> Suggested-by: Ivan Vecera <ivecera@redhat.com> Cc: Jay Vosburgh <j.vosburgh@gmail.com> Cc: Veaceslav Falico <vfalico@gmail.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Jarod Wilson <jarod@redhat.com> Link: https://lore.kernel.org/r/20201205172229.576587-1-jarod@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-12-05 12:22:29 -05:00
{
if (!IS_ENABLED(CONFIG_XFRM_OFFLOAD))
return false;
bonding: fix feature flag setting at init time Don't try to adjust XFRM support flags if the bond device isn't yet registered. Bad things can currently happen when netdev_change_features() is called without having wanted_features fully filled in yet. This code runs both on post-module-load mode changes, as well as at module init time, and when run at module init time, it is before register_netdevice() has been called and filled in wanted_features. The empty wanted_features led to features also getting emptied out, which was definitely not the intended behavior, so prevent that from happening. Originally, I'd hoped to stop adjusting wanted_features at all in the bonding driver, as it's documented as being something only the network core should touch, but we actually do need to do this to properly update both the features and wanted_features fields when changing the bond type, or we get to a situation where ethtool sees: esp-hw-offload: off [requested on] I do think we should be using netdev_update_features instead of netdev_change_features here though, so we only send notifiers when the features actually changed. Fixes: a3b658cfb664 ("bonding: allow xfrm offload setup post-module-load") Reported-by: Ivan Vecera <ivecera@redhat.com> Suggested-by: Ivan Vecera <ivecera@redhat.com> Cc: Jay Vosburgh <j.vosburgh@gmail.com> Cc: Veaceslav Falico <vfalico@gmail.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Jarod Wilson <jarod@redhat.com> Link: https://lore.kernel.org/r/20201205172229.576587-1-jarod@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-12-05 12:22:29 -05:00
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
bond->dev->wanted_features |= BOND_XFRM_FEATURES;
bonding: fix feature flag setting at init time Don't try to adjust XFRM support flags if the bond device isn't yet registered. Bad things can currently happen when netdev_change_features() is called without having wanted_features fully filled in yet. This code runs both on post-module-load mode changes, as well as at module init time, and when run at module init time, it is before register_netdevice() has been called and filled in wanted_features. The empty wanted_features led to features also getting emptied out, which was definitely not the intended behavior, so prevent that from happening. Originally, I'd hoped to stop adjusting wanted_features at all in the bonding driver, as it's documented as being something only the network core should touch, but we actually do need to do this to properly update both the features and wanted_features fields when changing the bond type, or we get to a situation where ethtool sees: esp-hw-offload: off [requested on] I do think we should be using netdev_update_features instead of netdev_change_features here though, so we only send notifiers when the features actually changed. Fixes: a3b658cfb664 ("bonding: allow xfrm offload setup post-module-load") Reported-by: Ivan Vecera <ivecera@redhat.com> Suggested-by: Ivan Vecera <ivecera@redhat.com> Cc: Jay Vosburgh <j.vosburgh@gmail.com> Cc: Veaceslav Falico <vfalico@gmail.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Jarod Wilson <jarod@redhat.com> Link: https://lore.kernel.org/r/20201205172229.576587-1-jarod@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-12-05 12:22:29 -05:00
else
bond->dev->wanted_features &= ~BOND_XFRM_FEATURES;
bonding: fix feature flag setting at init time Don't try to adjust XFRM support flags if the bond device isn't yet registered. Bad things can currently happen when netdev_change_features() is called without having wanted_features fully filled in yet. This code runs both on post-module-load mode changes, as well as at module init time, and when run at module init time, it is before register_netdevice() has been called and filled in wanted_features. The empty wanted_features led to features also getting emptied out, which was definitely not the intended behavior, so prevent that from happening. Originally, I'd hoped to stop adjusting wanted_features at all in the bonding driver, as it's documented as being something only the network core should touch, but we actually do need to do this to properly update both the features and wanted_features fields when changing the bond type, or we get to a situation where ethtool sees: esp-hw-offload: off [requested on] I do think we should be using netdev_update_features instead of netdev_change_features here though, so we only send notifiers when the features actually changed. Fixes: a3b658cfb664 ("bonding: allow xfrm offload setup post-module-load") Reported-by: Ivan Vecera <ivecera@redhat.com> Suggested-by: Ivan Vecera <ivecera@redhat.com> Cc: Jay Vosburgh <j.vosburgh@gmail.com> Cc: Veaceslav Falico <vfalico@gmail.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Jarod Wilson <jarod@redhat.com> Link: https://lore.kernel.org/r/20201205172229.576587-1-jarod@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-12-05 12:22:29 -05:00
return true;
bonding: fix feature flag setting at init time Don't try to adjust XFRM support flags if the bond device isn't yet registered. Bad things can currently happen when netdev_change_features() is called without having wanted_features fully filled in yet. This code runs both on post-module-load mode changes, as well as at module init time, and when run at module init time, it is before register_netdevice() has been called and filled in wanted_features. The empty wanted_features led to features also getting emptied out, which was definitely not the intended behavior, so prevent that from happening. Originally, I'd hoped to stop adjusting wanted_features at all in the bonding driver, as it's documented as being something only the network core should touch, but we actually do need to do this to properly update both the features and wanted_features fields when changing the bond type, or we get to a situation where ethtool sees: esp-hw-offload: off [requested on] I do think we should be using netdev_update_features instead of netdev_change_features here though, so we only send notifiers when the features actually changed. Fixes: a3b658cfb664 ("bonding: allow xfrm offload setup post-module-load") Reported-by: Ivan Vecera <ivecera@redhat.com> Suggested-by: Ivan Vecera <ivecera@redhat.com> Cc: Jay Vosburgh <j.vosburgh@gmail.com> Cc: Veaceslav Falico <vfalico@gmail.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Jarod Wilson <jarod@redhat.com> Link: https://lore.kernel.org/r/20201205172229.576587-1-jarod@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2020-12-05 12:22:29 -05:00
}
static int bond_option_mode_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
bonding: check xdp prog when set bond mode Following operations can trigger a warning[1]: ip netns add ns1 ip netns exec ns1 ip link add bond0 type bond mode balance-rr ip netns exec ns1 ip link set dev bond0 xdp obj af_xdp_kern.o sec xdp ip netns exec ns1 ip link set bond0 type bond mode broadcast ip netns del ns1 When delete the namespace, dev_xdp_uninstall() is called to remove xdp program on bond dev, and bond_xdp_set() will check the bond mode. If bond mode is changed after attaching xdp program, the warning may occur. Some bond modes (broadcast, etc.) do not support native xdp. Set bond mode with xdp program attached is not good. Add check for xdp program when set bond mode. [1] ------------[ cut here ]------------ WARNING: CPU: 0 PID: 11 at net/core/dev.c:9912 unregister_netdevice_many_notify+0x8d9/0x930 Modules linked in: CPU: 0 UID: 0 PID: 11 Comm: kworker/u4:0 Not tainted 6.14.0-rc4 #107 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.15.0-0-g2dd4b9b3f840-prebuilt.qemu.org 04/01/2014 Workqueue: netns cleanup_net RIP: 0010:unregister_netdevice_many_notify+0x8d9/0x930 Code: 00 00 48 c7 c6 6f e3 a2 82 48 c7 c7 d0 b3 96 82 e8 9c 10 3e ... RSP: 0018:ffffc90000063d80 EFLAGS: 00000282 RAX: 00000000ffffffa1 RBX: ffff888004959000 RCX: 00000000ffffdfff RDX: 0000000000000000 RSI: 00000000ffffffea RDI: ffffc90000063b48 RBP: ffffc90000063e28 R08: ffffffff82d39b28 R09: 0000000000009ffb R10: 0000000000000175 R11: ffffffff82d09b40 R12: ffff8880049598e8 R13: 0000000000000001 R14: dead000000000100 R15: ffffc90000045000 FS: 0000000000000000(0000) GS:ffff888007a00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000000d406b60 CR3: 000000000483e000 CR4: 00000000000006f0 Call Trace: <TASK> ? __warn+0x83/0x130 ? unregister_netdevice_many_notify+0x8d9/0x930 ? report_bug+0x18e/0x1a0 ? handle_bug+0x54/0x90 ? exc_invalid_op+0x18/0x70 ? asm_exc_invalid_op+0x1a/0x20 ? unregister_netdevice_many_notify+0x8d9/0x930 ? bond_net_exit_batch_rtnl+0x5c/0x90 cleanup_net+0x237/0x3d0 process_one_work+0x163/0x390 worker_thread+0x293/0x3b0 ? __pfx_worker_thread+0x10/0x10 kthread+0xec/0x1e0 ? __pfx_kthread+0x10/0x10 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x2f/0x50 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> ---[ end trace 0000000000000000 ]--- Fixes: 9e2ee5c7e7c3 ("net, bonding: Add XDP support to the bonding driver") Signed-off-by: Wang Liang <wangliang74@huawei.com> Acked-by: Jussi Maki <joamaki@gmail.com> Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org> Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://patch.msgid.link/20250321044852.1086551-1-wangliang74@huawei.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-03-21 12:48:52 +08:00
if (bond->xdp_prog && !bond_xdp_check(bond, newval->value))
return -EOPNOTSUPP;
bonding: set default miimon value for non-arp modes if not set For some time now, if you load the bonding driver and configure bond parameters via sysfs using minimal config options, such as specifying nothing but the mode, relying on defaults for everything else, modes that cannot use arp monitoring (802.3ad, balance-tlb, balance-alb) all wind up with both arp_interval=0 (as it should be) and miimon=0, which means the miimon monitor thread never actually runs. This is particularly problematic for 802.3ad. For example, from an LNST recipe I've set up: $ modprobe bonding max_bonds=0" $ echo "+t_bond0" > /sys/class/net/bonding_masters" $ ip link set t_bond0 down" $ echo "802.3ad" > /sys/class/net/t_bond0/bonding/mode" $ ip link set ens1f1 down" $ echo "+ens1f1" > /sys/class/net/t_bond0/bonding/slaves" $ ip link set ens1f0 down" $ echo "+ens1f0" > /sys/class/net/t_bond0/bonding/slaves" $ ethtool -i t_bond0" $ ip link set ens1f1 up" $ ip link set ens1f0 up" $ ip link set t_bond0 up" $ ip addr add 192.168.9.1/24 dev t_bond0" $ ip addr add 2002::1/64 dev t_bond0" This bond comes up okay, but things look slightly suspect in /proc/net/bonding/t_bond0 output: $ grep -i mii /proc/net/bonding/t_bond0 MII Status: up MII Polling Interval (ms): 0 MII Status: up MII Status: up Now, pull a cable on one of the ports in the bond, then reconnect it, and you'll see: Slave Interface: ens1f0 MII Status: down Speed: 1000 Mbps Duplex: full I believe this became a major issue as of commit 4d2c0cda0744, which for 802.3ad bonds, sets slave->link = BOND_LINK_DOWN, with a comment about relying on link monitoring via miimon to set it correctly, but since the miimon work queue never runs, the link just stays marked down. If we simply tweak bond_option_mode_set() slightly, we can check for the non-arp modes having no miimon value set, and insert BOND_DEFAULT_MIIMON, which gets things back in full working order. This problem exists as far back as 4.14, and might be worth fixing in all stable trees since, though the work-around is to simply specify an miimon value yourself. Reported-by: Bob Ball <ball@umich.edu> Signed-off-by: Jarod Wilson <jarod@redhat.com> Acked-by: Mahesh Bandewar <maheshb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2018-07-18 14:49:36 -04:00
if (!bond_mode_uses_arp(newval->value)) {
if (bond->params.arp_interval) {
netdev_dbg(bond->dev, "%s mode is incompatible with arp monitoring, start mii monitoring\n",
newval->string);
/* disable arp monitoring */
bond->params.arp_interval = 0;
}
if (!bond->params.miimon) {
/* set miimon to default value */
bond->params.miimon = BOND_DEFAULT_MIIMON;
netdev_dbg(bond->dev, "Setting MII monitoring interval to %d\n",
bond->params.miimon);
}
}
net: bonding: Fix transmit load balancing in balance-alb mode if specified by sysfs Commit cbf5ecb30560 ("net: bonding: Fix transmit load balancing in balance-alb mode") tried to fix transmit dynamic load balancing in balance-alb mode, which wasn't working after commit 8b426dc54cf4 ("bonding: remove hardcoded value"). It turned out that my previous patch only fixed the case when balance-alb was specified as bonding module parameter, and not when balance-alb mode was set using /sys/class/net/*/bonding/mode (the most common usage). In the latter case, tlb_dynamic_lb was set up according to the default mode of the bonding interface, which happens to be balance-rr. This additional patch addresses this issue by setting up tlb_dynamic_lb to 1 if "mode" is set to balance-alb through the sysfs interface. I didn't add code to change tlb_balance_lb back to the default value for other modes, because "mode" is usually set up only once during initialization, and it's not worthwhile to change the static variable bonding_defaults in bond_main.c to a global variable just for this purpose. Commit 8b426dc54cf4 also changes the value of tlb_dynamic_lb for balance-tlb mode if it is set up using the sysfs interface. I didn't change that behavior, because the value of tlb_balance_lb can be changed using the sysfs interface for balance-tlb, and I didn't like changing the default value back and forth for balance-tlb. As for balance-alb, /sys/class/net/*/bonding/tlb_balance_lb cannot be written to. However, I think balance-alb with tlb_dynamic_lb set to 0 is not an intended usage, so there is little use making it writable at this moment. Fixes: 8b426dc54cf4 ("bonding: remove hardcoded value") Reported-by: Reinis Rozitis <r@roze.lv> Signed-off-by: Kosuke Tatsukawa <tatsu@ab.jp.nec.com> Cc: stable@vger.kernel.org # v4.12+ Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Acked-by: Mahesh Bandewar <maheshb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2017-09-06 22:47:59 +00:00
if (newval->value == BOND_MODE_ALB)
bond->params.tlb_dynamic_lb = 1;
/* don't cache arp_validate between modes */
bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
bond->params.mode = newval->value;
net: bonding: add broadcast_neighbor option for 802.3ad Stacking technology is a type of technology used to expand ports on Ethernet switches. It is widely used as a common access method in large-scale Internet data center architectures. Years of practice have proved that stacking technology has advantages and disadvantages in high-reliability network architecture scenarios. For instance, in stacking networking arch, conventional switch system upgrades require multiple stacked devices to restart at the same time. Therefore, it is inevitable that the business will be interrupted for a while. It is for this reason that "no-stacking" in data centers has become a trend. Additionally, when the stacking link connecting the switches fails or is abnormal, the stack will split. Although it is not common, it still happens in actual operation. The problem is that after the split, it is equivalent to two switches with the same configuration appearing in the network, causing network configuration conflicts and ultimately interrupting the services carried by the stacking system. To improve network stability, "non-stacking" solutions have been increasingly adopted, particularly by public cloud providers and tech companies like Alibaba, Tencent, and Didi. "non-stacking" is a method of mimicing switch stacking that convinces a LACP peer, bonding in this case, connected to a set of "non-stacked" switches that all of its ports are connected to a single switch (i.e., LACP aggregator), as if those switches were stacked. This enables the LACP peer's ports to aggregate together, and requires (a) special switch configuration, described in the linked article, and (b) modifications to the bonding 802.3ad (LACP) mode to send all ARP/ND packets across all ports of the active aggregator. Note that, with multiple aggregators, the current broadcast mode logic will send only packets to the selected aggregator(s). +-----------+ +-----------+ | switch1 | | switch2 | +-----------+ +-----------+ ^ ^ | | +-----------------+ | bond4 lacp | +-----------------+ | | | NIC1 | NIC2 +-----------------+ | server | +-----------------+ - https://www.ruijie.com/fr-fr/support/tech-gallery/de-stack-data-center-network-architecture/ Cc: Jay Vosburgh <jv@jvosburgh.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Simon Horman <horms@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Andrew Lunn <andrew+netdev@lunn.ch> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: Tonghao Zhang <tonghao@bamaicloud.com> Signed-off-by: Zengbing Tu <tuzengbing@didiglobal.com> Link: https://patch.msgid.link/84d0a044514157bb856a10b6d03a1028c4883561.1751031306.git.tonghao@bamaicloud.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2025-06-27 21:49:28 +08:00
/* When changing mode, the bond device is down, we may reduce
* the bond_bcast_neigh_enabled in bond_close() if broadcast_neighbor
* enabled in 8023ad mode. Therefore, only clear broadcast_neighbor
* to 0.
*/
bond->params.broadcast_neighbor = 0;
if (bond->dev->reg_state == NETREG_REGISTERED) {
bool update = false;
update |= bond_set_xfrm_features(bond);
if (update)
netdev_update_features(bond->dev);
}
bond_xdp_set_features(bond->dev);
return 0;
}
static int bond_option_active_slave_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
char ifname[IFNAMSIZ] = { 0, };
struct net_device *slave_dev;
int ret = 0;
sscanf(newval->string, "%15s", ifname); /* IFNAMSIZ */
if (!strlen(ifname) || newval->string[0] == '\n') {
slave_dev = NULL;
} else {
slave_dev = __dev_get_by_name(dev_net(bond->dev), ifname);
if (!slave_dev)
return -ENODEV;
}
if (slave_dev) {
if (!netif_is_bond_slave(slave_dev)) {
slave_err(bond->dev, slave_dev, "Device is not bonding slave\n");
return -EINVAL;
}
if (bond->dev != netdev_master_upper_dev_get(slave_dev)) {
slave_err(bond->dev, slave_dev, "Device is not our slave\n");
return -EINVAL;
}
}
block_netpoll_tx();
/* check to see if we are clearing active */
if (!slave_dev) {
netdev_dbg(bond->dev, "Clearing current active slave\n");
bond_change_active_slave(bond, NULL);
bond_select_active_slave(bond);
} else {
struct slave *old_active = rtnl_dereference(bond->curr_active_slave);
struct slave *new_active = bond_slave_get_rtnl(slave_dev);
BUG_ON(!new_active);
if (new_active == old_active) {
/* do nothing */
slave_dbg(bond->dev, new_active->dev, "is already the current active slave\n");
} else {
if (old_active && (new_active->link == BOND_LINK_UP) &&
bond_slave_is_up(new_active)) {
slave_dbg(bond->dev, new_active->dev, "Setting as active slave\n");
bond_change_active_slave(bond, new_active);
} else {
slave_err(bond->dev, new_active->dev, "Could not set as active slave; either %s is down or the link is down\n",
new_active->dev->name);
ret = -EINVAL;
}
}
}
unblock_netpoll_tx();
return ret;
}
/* There are two tricky bits here. First, if MII monitoring is activated, then
* we must disable ARP monitoring. Second, if the timer isn't running, we must
* start it.
*/
static int bond_option_miimon_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting MII monitoring interval to %llu\n",
newval->value);
bond->params.miimon = newval->value;
if (bond->params.updelay)
netdev_dbg(bond->dev, "Note: Updating updelay (to %d) since it is a multiple of the miimon value\n",
bond->params.updelay * bond->params.miimon);
if (bond->params.downdelay)
netdev_dbg(bond->dev, "Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n",
bond->params.downdelay * bond->params.miimon);
if (bond->params.peer_notif_delay)
netdev_dbg(bond->dev, "Note: Updating peer_notif_delay (to %d) since it is a multiple of the miimon value\n",
bond->params.peer_notif_delay * bond->params.miimon);
if (newval->value && bond->params.arp_interval) {
netdev_dbg(bond->dev, "MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n");
bond->params.arp_interval = 0;
if (bond->params.arp_validate)
bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
}
if (bond->dev->flags & IFF_UP) {
/* If the interface is up, we may need to fire off
* the MII timer. If the interface is down, the
* timer will get fired off when the open function
* is called.
*/
if (!newval->value) {
cancel_delayed_work_sync(&bond->mii_work);
} else {
cancel_delayed_work_sync(&bond->arp_work);
queue_delayed_work(bond->wq, &bond->mii_work, 0);
}
}
return 0;
}
/* Set up, down and peer notification delays. These must be multiples
* of the MII monitoring value, and are stored internally as the
* multiplier. Thus, we must translate to MS for the real world.
*/
static int _bond_option_delay_set(struct bonding *bond,
const struct bond_opt_value *newval,
const char *name,
int *target)
{
int value = newval->value;
if (!bond->params.miimon) {
netdev_err(bond->dev, "Unable to set %s as MII monitoring is disabled\n",
name);
return -EPERM;
}
if ((value % bond->params.miimon) != 0) {
netdev_warn(bond->dev,
"%s (%d) is not a multiple of miimon (%d), value rounded to %d ms\n",
name,
value, bond->params.miimon,
(value / bond->params.miimon) *
bond->params.miimon);
}
*target = value / bond->params.miimon;
netdev_dbg(bond->dev, "Setting %s to %d\n",
name,
*target * bond->params.miimon);
return 0;
}
static int bond_option_updelay_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
return _bond_option_delay_set(bond, newval, "up delay",
&bond->params.updelay);
}
static int bond_option_downdelay_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
return _bond_option_delay_set(bond, newval, "down delay",
&bond->params.downdelay);
}
static int bond_option_peer_notif_delay_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
int ret = _bond_option_delay_set(bond, newval,
"peer notification delay",
&bond->params.peer_notif_delay);
return ret;
}
static int bond_option_use_carrier_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting use_carrier to %llu\n",
newval->value);
bond->params.use_carrier = newval->value;
return 0;
}
/* There are two tricky bits here. First, if ARP monitoring is activated, then
* we must disable MII monitoring. Second, if the ARP timer isn't running,
* we must start it.
*/
static int bond_option_arp_interval_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting ARP monitoring interval to %llu\n",
newval->value);
bond->params.arp_interval = newval->value;
if (newval->value) {
if (bond->params.miimon) {
netdev_dbg(bond->dev, "ARP monitoring cannot be used with MII monitoring. Disabling MII monitoring\n");
bond->params.miimon = 0;
}
if (!bond->params.arp_targets[0])
netdev_dbg(bond->dev, "ARP monitoring has been set up, but no ARP targets have been specified\n");
}
if (bond->dev->flags & IFF_UP) {
/* If the interface is up, we may need to fire off
* the ARP timer. If the interface is down, the
* timer will get fired off when the open function
* is called.
*/
if (!newval->value) {
if (bond->params.arp_validate)
bond->recv_probe = NULL;
cancel_delayed_work_sync(&bond->arp_work);
} else {
/* arp_validate can be set only in active-backup mode */
bond->recv_probe = bond_rcv_validate;
cancel_delayed_work_sync(&bond->mii_work);
queue_delayed_work(bond->wq, &bond->arp_work, 0);
}
}
return 0;
}
static void _bond_options_arp_ip_target_set(struct bonding *bond, int slot,
__be32 target,
unsigned long last_rx)
{
__be32 *targets = bond->params.arp_targets;
struct list_head *iter;
struct slave *slave;
if (slot >= 0 && slot < BOND_MAX_ARP_TARGETS) {
bond_for_each_slave(bond, slave, iter)
slave->target_last_arp_rx[slot] = last_rx;
targets[slot] = target;
}
}
static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
{
__be32 *targets = bond->params.arp_targets;
int ind;
if (!bond_is_ip_target_ok(target)) {
netdev_err(bond->dev, "invalid ARP target %pI4 specified for addition\n",
&target);
return -EINVAL;
}
if (bond_get_targets_ip(targets, target) != -1) { /* dup */
netdev_err(bond->dev, "ARP target %pI4 is already present\n",
&target);
return -EINVAL;
}
ind = bond_get_targets_ip(targets, 0); /* first free slot */
if (ind == -1) {
netdev_err(bond->dev, "ARP target table is full!\n");
return -EINVAL;
}
netdev_dbg(bond->dev, "Adding ARP target %pI4\n", &target);
_bond_options_arp_ip_target_set(bond, ind, target, jiffies);
return 0;
}
static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target)
{
return _bond_option_arp_ip_target_add(bond, target);
}
static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target)
{
__be32 *targets = bond->params.arp_targets;
struct list_head *iter;
struct slave *slave;
unsigned long *targets_rx;
int ind, i;
if (!bond_is_ip_target_ok(target)) {
netdev_err(bond->dev, "invalid ARP target %pI4 specified for removal\n",
&target);
return -EINVAL;
}
ind = bond_get_targets_ip(targets, target);
if (ind == -1) {
netdev_err(bond->dev, "unable to remove nonexistent ARP target %pI4\n",
&target);
return -EINVAL;
}
if (ind == 0 && !targets[1] && bond->params.arp_interval)
netdev_warn(bond->dev, "Removing last arp target with arp_interval on\n");
netdev_dbg(bond->dev, "Removing ARP target %pI4\n", &target);
bond_for_each_slave(bond, slave, iter) {
targets_rx = slave->target_last_arp_rx;
for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
targets_rx[i] = targets_rx[i+1];
targets_rx[i] = 0;
}
for (i = ind; (i < BOND_MAX_ARP_TARGETS-1) && targets[i+1]; i++)
targets[i] = targets[i+1];
targets[i] = 0;
return 0;
}
void bond_option_arp_ip_targets_clear(struct bonding *bond)
{
int i;
for (i = 0; i < BOND_MAX_ARP_TARGETS; i++)
_bond_options_arp_ip_target_set(bond, i, 0, 0);
}
static int bond_option_arp_ip_targets_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
int ret = -EPERM;
__be32 target;
if (newval->string) {
bonding: Fix out-of-bounds read in bond_option_arp_ip_targets_set() In function bond_option_arp_ip_targets_set(), if newval->string is an empty string, newval->string+1 will point to the byte after the string, causing an out-of-bound read. BUG: KASAN: slab-out-of-bounds in strlen+0x7d/0xa0 lib/string.c:418 Read of size 1 at addr ffff8881119c4781 by task syz-executor665/8107 CPU: 1 PID: 8107 Comm: syz-executor665 Not tainted 6.7.0-rc7 #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 Call Trace: <TASK> __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xd9/0x150 lib/dump_stack.c:106 print_address_description mm/kasan/report.c:364 [inline] print_report+0xc1/0x5e0 mm/kasan/report.c:475 kasan_report+0xbe/0xf0 mm/kasan/report.c:588 strlen+0x7d/0xa0 lib/string.c:418 __fortify_strlen include/linux/fortify-string.h:210 [inline] in4_pton+0xa3/0x3f0 net/core/utils.c:130 bond_option_arp_ip_targets_set+0xc2/0x910 drivers/net/bonding/bond_options.c:1201 __bond_opt_set+0x2a4/0x1030 drivers/net/bonding/bond_options.c:767 __bond_opt_set_notify+0x48/0x150 drivers/net/bonding/bond_options.c:792 bond_opt_tryset_rtnl+0xda/0x160 drivers/net/bonding/bond_options.c:817 bonding_sysfs_store_option+0xa1/0x120 drivers/net/bonding/bond_sysfs.c:156 dev_attr_store+0x54/0x80 drivers/base/core.c:2366 sysfs_kf_write+0x114/0x170 fs/sysfs/file.c:136 kernfs_fop_write_iter+0x337/0x500 fs/kernfs/file.c:334 call_write_iter include/linux/fs.h:2020 [inline] new_sync_write fs/read_write.c:491 [inline] vfs_write+0x96a/0xd80 fs/read_write.c:584 ksys_write+0x122/0x250 fs/read_write.c:637 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0x40/0x110 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x63/0x6b ---[ end trace ]--- Fix it by adding a check of string length before using it. Fixes: f9de11a16594 ("bonding: add ip checks when store ip target") Signed-off-by: Yue Sun <samsun1006219@gmail.com> Signed-off-by: Simon Horman <horms@kernel.org> Acked-by: Jay Vosburgh <jay.vosburgh@canonical.com> Reviewed-by: Hangbin Liu <liuhangbin@gmail.com> Link: https://patch.msgid.link/20240702-bond-oob-v6-1-2dfdba195c19@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-07-02 14:55:55 +01:00
if (strlen(newval->string) < 1 ||
!in4_pton(newval->string + 1, -1, (u8 *)&target, -1, NULL)) {
netdev_err(bond->dev, "invalid ARP target specified\n");
return ret;
}
if (newval->string[0] == '+')
ret = bond_option_arp_ip_target_add(bond, target);
else if (newval->string[0] == '-')
ret = bond_option_arp_ip_target_rem(bond, target);
else
netdev_err(bond->dev, "no command found in arp_ip_targets file - use +<addr> or -<addr>\n");
} else {
target = newval->value;
ret = bond_option_arp_ip_target_add(bond, target);
}
return ret;
}
#if IS_ENABLED(CONFIG_IPV6)
static bool slave_can_set_ns_maddr(const struct bonding *bond, struct slave *slave)
{
return BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP &&
!bond_is_active_slave(slave) &&
slave->dev->flags & IFF_MULTICAST;
}
/**
* slave_set_ns_maddrs - add/del all NS mac addresses for slave
* @bond: bond device
* @slave: slave device
* @add: add or remove all the NS mac addresses
*
* This function tries to add or delete all the NS mac addresses on the slave
*
* Note, the IPv6 NS target address is the unicast address in Neighbor
* Solicitation (NS) message. The dest address of NS message should be
* solicited-node multicast address of the target. The dest mac of NS message
* is converted from the solicited-node multicast address.
*
* This function is called when
* * arp_validate changes
* * enslaving, releasing new slaves
*/
static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add)
{
struct in6_addr *targets = bond->params.ns_targets;
char slot_maddr[MAX_ADDR_LEN];
struct in6_addr mcaddr;
int i;
if (!slave_can_set_ns_maddr(bond, slave))
return;
for (i = 0; i < BOND_MAX_NS_TARGETS; i++) {
if (ipv6_addr_any(&targets[i]))
break;
addrconf_addr_solict_mult(&targets[i], &mcaddr);
if (!ndisc_mc_map(&mcaddr, slot_maddr, slave->dev, 0)) {
if (add)
dev_mc_add(slave->dev, slot_maddr);
else
dev_mc_del(slave->dev, slot_maddr);
}
}
}
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave)
{
if (!bond->params.arp_validate)
return;
slave_set_ns_maddrs(bond, slave, true);
}
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave)
{
if (!bond->params.arp_validate)
return;
slave_set_ns_maddrs(bond, slave, false);
}
/**
* slave_set_ns_maddr - set new NS mac address for slave
* @bond: bond device
* @slave: slave device
* @target: the new IPv6 target
* @slot: the old IPv6 target in the slot
*
* This function tries to replace the old mac address to new one on the slave.
*
* Note, the target/slot IPv6 address is the unicast address in Neighbor
* Solicitation (NS) message. The dest address of NS message should be
* solicited-node multicast address of the target. The dest mac of NS message
* is converted from the solicited-node multicast address.
*
* This function is called when
* * An IPv6 NS target is added or removed.
*/
static void slave_set_ns_maddr(struct bonding *bond, struct slave *slave,
struct in6_addr *target, struct in6_addr *slot)
{
char mac_addr[MAX_ADDR_LEN];
struct in6_addr mcast_addr;
if (!bond->params.arp_validate || !slave_can_set_ns_maddr(bond, slave))
return;
/* remove the previous mac addr from slave */
addrconf_addr_solict_mult(slot, &mcast_addr);
if (!ipv6_addr_any(slot) &&
!ndisc_mc_map(&mcast_addr, mac_addr, slave->dev, 0))
dev_mc_del(slave->dev, mac_addr);
/* add new mac addr on slave if target is set */
addrconf_addr_solict_mult(target, &mcast_addr);
if (!ipv6_addr_any(target) &&
!ndisc_mc_map(&mcast_addr, mac_addr, slave->dev, 0))
dev_mc_add(slave->dev, mac_addr);
}
static void _bond_options_ns_ip6_target_set(struct bonding *bond, int slot,
struct in6_addr *target,
unsigned long last_rx)
{
struct in6_addr *targets = bond->params.ns_targets;
struct list_head *iter;
struct slave *slave;
if (slot >= 0 && slot < BOND_MAX_NS_TARGETS) {
bond_for_each_slave(bond, slave, iter) {
slave->target_last_arp_rx[slot] = last_rx;
slave_set_ns_maddr(bond, slave, target, &targets[slot]);
}
targets[slot] = *target;
}
}
void bond_option_ns_ip6_targets_clear(struct bonding *bond)
{
struct in6_addr addr_any = in6addr_any;
int i;
for (i = 0; i < BOND_MAX_NS_TARGETS; i++)
_bond_options_ns_ip6_target_set(bond, i, &addr_any, 0);
}
static int bond_option_ns_ip6_targets_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
struct in6_addr *target = (struct in6_addr *)newval->extra;
struct in6_addr *targets = bond->params.ns_targets;
struct in6_addr addr_any = in6addr_any;
int index;
if (!bond_is_ip6_target_ok(target)) {
netdev_err(bond->dev, "invalid NS target %pI6c specified for addition\n",
target);
return -EINVAL;
}
if (bond_get_targets_ip6(targets, target) != -1) { /* dup */
netdev_err(bond->dev, "NS target %pI6c is already present\n",
target);
return -EINVAL;
}
index = bond_get_targets_ip6(targets, &addr_any); /* first free slot */
if (index == -1) {
netdev_err(bond->dev, "NS target table is full!\n");
return -EINVAL;
}
netdev_dbg(bond->dev, "Adding NS target %pI6c\n", target);
_bond_options_ns_ip6_target_set(bond, index, target, jiffies);
return 0;
}
#else
static int bond_option_ns_ip6_targets_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
return -EPERM;
}
static void slave_set_ns_maddrs(struct bonding *bond, struct slave *slave, bool add) {}
void bond_slave_ns_maddrs_add(struct bonding *bond, struct slave *slave) {}
void bond_slave_ns_maddrs_del(struct bonding *bond, struct slave *slave) {}
#endif
static int bond_option_arp_validate_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
bool changed = !!bond->params.arp_validate != !!newval->value;
struct list_head *iter;
struct slave *slave;
netdev_dbg(bond->dev, "Setting arp_validate to %s (%llu)\n",
newval->string, newval->value);
bond->params.arp_validate = newval->value;
if (changed) {
bond_for_each_slave(bond, slave, iter)
slave_set_ns_maddrs(bond, slave, !!bond->params.arp_validate);
}
return 0;
}
static int bond_option_arp_all_targets_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting arp_all_targets to %s (%llu)\n",
newval->string, newval->value);
bond->params.arp_all_targets = newval->value;
return 0;
}
static int bond_option_missed_max_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting missed max to %s (%llu)\n",
newval->string, newval->value);
bond->params.missed_max = newval->value;
return 0;
}
static int bond_option_prio_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
struct slave *slave;
slave = bond_slave_get_rtnl(newval->slave_dev);
if (!slave) {
netdev_dbg(newval->slave_dev, "%s called on NULL slave\n", __func__);
return -ENODEV;
}
slave->prio = newval->value;
if (rtnl_dereference(bond->primary_slave))
slave_warn(bond->dev, slave->dev,
"prio updated, but will not affect failover re-selection as primary slave have been set\n");
else
bond_select_active_slave(bond);
return 0;
}
static int bond_option_primary_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
char *p, *primary = newval->string;
struct list_head *iter;
struct slave *slave;
block_netpoll_tx();
p = strchr(primary, '\n');
if (p)
*p = '\0';
/* check to see if we are clearing primary */
if (!strlen(primary)) {
netdev_dbg(bond->dev, "Setting primary slave to None\n");
RCU_INIT_POINTER(bond->primary_slave, NULL);
memset(bond->params.primary, 0, sizeof(bond->params.primary));
bond_select_active_slave(bond);
goto out;
}
bond_for_each_slave(bond, slave, iter) {
if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) {
slave_dbg(bond->dev, slave->dev, "Setting as primary slave\n");
rcu_assign_pointer(bond->primary_slave, slave);
strcpy(bond->params.primary, slave->dev->name);
bond->force_primary = true;
bond_select_active_slave(bond);
goto out;
}
}
if (rtnl_dereference(bond->primary_slave)) {
netdev_dbg(bond->dev, "Setting primary slave to None\n");
RCU_INIT_POINTER(bond->primary_slave, NULL);
bond_select_active_slave(bond);
}
strscpy_pad(bond->params.primary, primary, IFNAMSIZ);
netdev_dbg(bond->dev, "Recording %s as primary, but it has not been enslaved yet\n",
primary);
out:
unblock_netpoll_tx();
return 0;
}
static int bond_option_primary_reselect_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting primary_reselect to %s (%llu)\n",
newval->string, newval->value);
bond->params.primary_reselect = newval->value;
block_netpoll_tx();
bond_select_active_slave(bond);
unblock_netpoll_tx();
return 0;
}
static int bond_option_fail_over_mac_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting fail_over_mac to %s (%llu)\n",
newval->string, newval->value);
bond->params.fail_over_mac = newval->value;
return 0;
}
static int bond_option_xmit_hash_policy_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
newval->string, newval->value);
bond->params.xmit_policy = newval->value;
return 0;
}
static int bond_option_resend_igmp_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting resend_igmp to %llu\n",
newval->value);
bond->params.resend_igmp = newval->value;
return 0;
}
static int bond_option_num_peer_notif_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
bond->params.num_peer_notif = newval->value;
return 0;
}
static int bond_option_all_slaves_active_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
struct list_head *iter;
struct slave *slave;
if (newval->value == bond->params.all_slaves_active)
return 0;
bond->params.all_slaves_active = newval->value;
bond_for_each_slave(bond, slave, iter) {
if (!bond_is_active_slave(slave)) {
if (newval->value)
slave->inactive = 0;
else
slave->inactive = 1;
}
}
return 0;
}
static int bond_option_min_links_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting min links value to %llu\n",
newval->value);
bond->params.min_links = newval->value;
bond_set_carrier(bond);
return 0;
}
static int bond_option_lp_interval_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
bond->params.lp_interval = newval->value;
return 0;
}
static int bond_option_pps_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting packets per slave to %llu\n",
newval->value);
bond->params.packets_per_slave = newval->value;
if (newval->value > 0) {
reciprocal_divide: update/correction of the algorithm Jakub Zawadzki noticed that some divisions by reciprocal_divide() were not correct [1][2], which he could also show with BPF code after divisions are transformed into reciprocal_value() for runtime invariance which can be passed to reciprocal_divide() later on; reverse in BPF dump ended up with a different, off-by-one K in some situations. This has been fixed by Eric Dumazet in commit aee636c4809fa5 ("bpf: do not use reciprocal divide"). This follow-up patch improves reciprocal_value() and reciprocal_divide() to work in all cases by using Granlund and Montgomery method, so that also future use is safe and without any non-obvious side-effects. Known problems with the old implementation were that division by 1 always returned 0 and some off-by-ones when the dividend and divisor where very large. This seemed to not be problematic with its current users, as far as we can tell. Eric Dumazet checked for the slab usage, we cannot surely say so in the case of flex_array. Still, in order to fix that, we propose an extension from the original implementation from commit 6a2d7a955d8d resp. [3][4], by using the algorithm proposed in "Division by Invariant Integers Using Multiplication" [5], Torbjörn Granlund and Peter L. Montgomery, that is, pseudocode for q = n/d where q, n, d is in u32 universe: 1) Initialization: int l = ceil(log_2 d) uword m' = floor((1<<32)*((1<<l)-d)/d)+1 int sh_1 = min(l,1) int sh_2 = max(l-1,0) 2) For q = n/d, all uword: uword t = (n*m')>>32 q = (t+((n-t)>>sh_1))>>sh_2 The assembler implementation from Agner Fog [6] also helped a lot while implementing. We have tested the implementation on x86_64, ppc64, i686, s390x; on x86_64/haswell we're still half the latency compared to normal divide. Joint work with Daniel Borkmann. [1] http://www.wireshark.org/~darkjames/reciprocal-buggy.c [2] http://www.wireshark.org/~darkjames/set-and-dump-filter-k-bug.c [3] https://gmplib.org/~tege/division-paper.pdf [4] http://homepage.cs.uiowa.edu/~jones/bcd/divide.html [5] http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.1.2556 [6] http://www.agner.org/optimize/asmlib.zip Reported-by: Jakub Zawadzki <darkjames-ws@darkjames.pl> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Austin S Hemmelgarn <ahferroin7@gmail.com> Cc: linux-kernel@vger.kernel.org Cc: Jesse Gross <jesse@nicira.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Stephen Hemminger <stephen@networkplumber.org> Cc: Matt Mackall <mpm@selenic.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: Christoph Lameter <cl@linux-foundation.org> Cc: Andy Gospodarek <andy@greyhouse.net> Cc: Veaceslav Falico <vfalico@redhat.com> Cc: Jay Vosburgh <fubar@us.ibm.com> Cc: Jakub Zawadzki <darkjames-ws@darkjames.pl> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 02:29:41 +01:00
bond->params.reciprocal_packets_per_slave =
reciprocal_value(newval->value);
reciprocal_divide: update/correction of the algorithm Jakub Zawadzki noticed that some divisions by reciprocal_divide() were not correct [1][2], which he could also show with BPF code after divisions are transformed into reciprocal_value() for runtime invariance which can be passed to reciprocal_divide() later on; reverse in BPF dump ended up with a different, off-by-one K in some situations. This has been fixed by Eric Dumazet in commit aee636c4809fa5 ("bpf: do not use reciprocal divide"). This follow-up patch improves reciprocal_value() and reciprocal_divide() to work in all cases by using Granlund and Montgomery method, so that also future use is safe and without any non-obvious side-effects. Known problems with the old implementation were that division by 1 always returned 0 and some off-by-ones when the dividend and divisor where very large. This seemed to not be problematic with its current users, as far as we can tell. Eric Dumazet checked for the slab usage, we cannot surely say so in the case of flex_array. Still, in order to fix that, we propose an extension from the original implementation from commit 6a2d7a955d8d resp. [3][4], by using the algorithm proposed in "Division by Invariant Integers Using Multiplication" [5], Torbjörn Granlund and Peter L. Montgomery, that is, pseudocode for q = n/d where q, n, d is in u32 universe: 1) Initialization: int l = ceil(log_2 d) uword m' = floor((1<<32)*((1<<l)-d)/d)+1 int sh_1 = min(l,1) int sh_2 = max(l-1,0) 2) For q = n/d, all uword: uword t = (n*m')>>32 q = (t+((n-t)>>sh_1))>>sh_2 The assembler implementation from Agner Fog [6] also helped a lot while implementing. We have tested the implementation on x86_64, ppc64, i686, s390x; on x86_64/haswell we're still half the latency compared to normal divide. Joint work with Daniel Borkmann. [1] http://www.wireshark.org/~darkjames/reciprocal-buggy.c [2] http://www.wireshark.org/~darkjames/set-and-dump-filter-k-bug.c [3] https://gmplib.org/~tege/division-paper.pdf [4] http://homepage.cs.uiowa.edu/~jones/bcd/divide.html [5] http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.1.2556 [6] http://www.agner.org/optimize/asmlib.zip Reported-by: Jakub Zawadzki <darkjames-ws@darkjames.pl> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Austin S Hemmelgarn <ahferroin7@gmail.com> Cc: linux-kernel@vger.kernel.org Cc: Jesse Gross <jesse@nicira.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: Stephen Hemminger <stephen@networkplumber.org> Cc: Matt Mackall <mpm@selenic.com> Cc: Pekka Enberg <penberg@kernel.org> Cc: Christoph Lameter <cl@linux-foundation.org> Cc: Andy Gospodarek <andy@greyhouse.net> Cc: Veaceslav Falico <vfalico@redhat.com> Cc: Jay Vosburgh <fubar@us.ibm.com> Cc: Jakub Zawadzki <darkjames-ws@darkjames.pl> Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
2014-01-22 02:29:41 +01:00
} else {
/* reciprocal_packets_per_slave is unused if
* packets_per_slave is 0 or 1, just initialize it
*/
bond->params.reciprocal_packets_per_slave =
(struct reciprocal_value) { 0 };
}
return 0;
}
static int bond_option_lacp_active_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting LACP active to %s (%llu)\n",
newval->string, newval->value);
bond->params.lacp_active = newval->value;
return 0;
}
static int bond_option_lacp_rate_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting LACP rate to %s (%llu)\n",
newval->string, newval->value);
bond->params.lacp_fast = newval->value;
bond_3ad_update_lacp_rate(bond);
return 0;
}
static int bond_option_ad_select_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting ad_select to %s (%llu)\n",
newval->string, newval->value);
bond->params.ad_select = newval->value;
return 0;
}
static int bond_option_queue_id_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
struct slave *slave, *update_slave;
struct net_device *sdev;
struct list_head *iter;
char *delim;
int ret = 0;
u16 qid;
/* delim will point to queue id if successful */
delim = strchr(newval->string, ':');
if (!delim)
goto err_no_cmd;
/* Terminate string that points to device name and bump it
* up one, so we can read the queue id there.
*/
*delim = '\0';
if (sscanf(++delim, "%hd\n", &qid) != 1)
goto err_no_cmd;
/* Check buffer length, valid ifname and queue id */
if (!dev_valid_name(newval->string) ||
qid > bond->dev->real_num_tx_queues)
goto err_no_cmd;
/* Get the pointer to that interface if it exists */
sdev = __dev_get_by_name(dev_net(bond->dev), newval->string);
if (!sdev)
goto err_no_cmd;
/* Search for thes slave and check for duplicate qids */
update_slave = NULL;
bond_for_each_slave(bond, slave, iter) {
if (sdev == slave->dev)
/* We don't need to check the matching
* slave for dups, since we're overwriting it
*/
update_slave = slave;
else if (qid && qid == slave->queue_id) {
goto err_no_cmd;
}
}
if (!update_slave)
goto err_no_cmd;
/* Actually set the qids for the slave */
WRITE_ONCE(update_slave->queue_id, qid);
out:
return ret;
err_no_cmd:
netdev_dbg(bond->dev, "invalid input for queue_id set\n");
ret = -EPERM;
goto out;
}
static int bond_option_slaves_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
char command[IFNAMSIZ + 1] = { 0, };
struct net_device *dev;
char *ifname;
int ret;
sscanf(newval->string, "%16s", command); /* IFNAMSIZ*/
ifname = command + 1;
if ((strlen(command) <= 1) ||
(command[0] != '+' && command[0] != '-') ||
!dev_valid_name(ifname))
goto err_no_cmd;
dev = __dev_get_by_name(dev_net(bond->dev), ifname);
if (!dev) {
netdev_dbg(bond->dev, "interface %s does not exist!\n",
ifname);
ret = -ENODEV;
goto out;
}
switch (command[0]) {
case '+':
slave_dbg(bond->dev, dev, "Enslaving interface\n");
ret = bond_enslave(bond->dev, dev, NULL);
break;
case '-':
slave_dbg(bond->dev, dev, "Releasing interface\n");
ret = bond_release(bond->dev, dev);
break;
default:
/* should not run here. */
goto err_no_cmd;
}
out:
return ret;
err_no_cmd:
netdev_err(bond->dev, "no command found in slaves file - use +ifname or -ifname\n");
ret = -EPERM;
goto out;
}
static int bond_option_tlb_dynamic_lb_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting dynamic-lb to %s (%llu)\n",
newval->string, newval->value);
bond->params.tlb_dynamic_lb = newval->value;
return 0;
}
static int bond_option_ad_actor_sys_prio_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting ad_actor_sys_prio to %llu\n",
newval->value);
bond->params.ad_actor_sys_prio = newval->value;
bond_3ad_update_ad_actor_settings(bond);
return 0;
}
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
static int bond_option_ad_actor_system_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
u8 macaddr[ETH_ALEN];
u8 *mac;
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
if (newval->string) {
if (!mac_pton(newval->string, macaddr))
goto err;
mac = macaddr;
} else {
mac = (u8 *)&newval->value;
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
}
if (is_multicast_ether_addr(mac))
goto err;
netdev_dbg(bond->dev, "Setting ad_actor_system to %pM\n", mac);
ether_addr_copy(bond->params.ad_actor_system, mac);
bond_3ad_update_ad_actor_settings(bond);
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
return 0;
err:
netdev_err(bond->dev, "Invalid ad_actor_system MAC address.\n");
return -EINVAL;
bonding: Allow userspace to set actors' macaddr in an AD-system. In an AD system, the communication between actor and partner is the business between these two entities. In the current setup anyone on the same L2 can "guess" the LACPDU contents and then possibly send the spoofed LACPDUs and trick the partner causing connectivity issues for the AD system. This patch allows to use a random mac-address obscuring it's identity making it harder for someone in the L2 is do the same thing. This patch allows user-space to choose the mac-address for the AD-system. This mac-address can not be NULL or a Multicast. If the mac-address is set from user-space; kernel will honor it and will not overwrite it. In the absence (value from user space); the logic will default to using the masters' mac as the mac-address for the AD-system. It can be set using example code below - # modprobe bonding mode=4 # sys_mac_addr=$(printf '%02x:%02x:%02x:%02x:%02x:%02x' \ $(( (RANDOM & 0xFE) | 0x02 )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF )) \ $(( RANDOM & 0xFF ))) # echo $sys_mac_addr > /sys/class/net/bond0/bonding/ad_actor_system # echo +eth1 > /sys/class/net/bond0/bonding/slaves ... # ip link set bond0 up Signed-off-by: Mahesh Bandewar <maheshb@google.com> Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com> [jt: fixed up style issues reported by checkpatch] Signed-off-by: Jonathan Toppins <jtoppins@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2015-05-09 00:01:56 -07:00
}
static int bond_option_ad_user_port_key_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_dbg(bond->dev, "Setting ad_user_port_key to %llu\n",
newval->value);
bond->params.ad_user_port_key = newval->value;
return 0;
}
2024-02-02 17:58:58 +00:00
static int bond_option_coupled_control_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
netdev_info(bond->dev, "Setting coupled_control to %s (%llu)\n",
newval->string, newval->value);
bond->params.coupled_control = newval->value;
return 0;
}
net: bonding: add broadcast_neighbor option for 802.3ad Stacking technology is a type of technology used to expand ports on Ethernet switches. It is widely used as a common access method in large-scale Internet data center architectures. Years of practice have proved that stacking technology has advantages and disadvantages in high-reliability network architecture scenarios. For instance, in stacking networking arch, conventional switch system upgrades require multiple stacked devices to restart at the same time. Therefore, it is inevitable that the business will be interrupted for a while. It is for this reason that "no-stacking" in data centers has become a trend. Additionally, when the stacking link connecting the switches fails or is abnormal, the stack will split. Although it is not common, it still happens in actual operation. The problem is that after the split, it is equivalent to two switches with the same configuration appearing in the network, causing network configuration conflicts and ultimately interrupting the services carried by the stacking system. To improve network stability, "non-stacking" solutions have been increasingly adopted, particularly by public cloud providers and tech companies like Alibaba, Tencent, and Didi. "non-stacking" is a method of mimicing switch stacking that convinces a LACP peer, bonding in this case, connected to a set of "non-stacked" switches that all of its ports are connected to a single switch (i.e., LACP aggregator), as if those switches were stacked. This enables the LACP peer's ports to aggregate together, and requires (a) special switch configuration, described in the linked article, and (b) modifications to the bonding 802.3ad (LACP) mode to send all ARP/ND packets across all ports of the active aggregator. Note that, with multiple aggregators, the current broadcast mode logic will send only packets to the selected aggregator(s). +-----------+ +-----------+ | switch1 | | switch2 | +-----------+ +-----------+ ^ ^ | | +-----------------+ | bond4 lacp | +-----------------+ | | | NIC1 | NIC2 +-----------------+ | server | +-----------------+ - https://www.ruijie.com/fr-fr/support/tech-gallery/de-stack-data-center-network-architecture/ Cc: Jay Vosburgh <jv@jvosburgh.net> Cc: "David S. Miller" <davem@davemloft.net> Cc: Eric Dumazet <edumazet@google.com> Cc: Jakub Kicinski <kuba@kernel.org> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Simon Horman <horms@kernel.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Andrew Lunn <andrew+netdev@lunn.ch> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Nikolay Aleksandrov <razor@blackwall.org> Signed-off-by: Tonghao Zhang <tonghao@bamaicloud.com> Signed-off-by: Zengbing Tu <tuzengbing@didiglobal.com> Link: https://patch.msgid.link/84d0a044514157bb856a10b6d03a1028c4883561.1751031306.git.tonghao@bamaicloud.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2025-06-27 21:49:28 +08:00
static int bond_option_broadcast_neigh_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
if (bond->params.broadcast_neighbor == newval->value)
return 0;
bond->params.broadcast_neighbor = newval->value;
if (bond->dev->flags & IFF_UP) {
if (bond->params.broadcast_neighbor)
static_branch_inc(&bond_bcast_neigh_enabled);
else
static_branch_dec(&bond_bcast_neigh_enabled);
}
netdev_dbg(bond->dev, "Setting broadcast_neighbor to %s (%llu)\n",
newval->string, newval->value);
return 0;
}