From: Tony Lu <tonylu(a)linux.alibaba.com>
anolis inclusion from devel-5.10-v5.10.134-12 commit b90e28f7170e1ae40c572f9f80a50bbdc8f8b99f category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I8JTCU
Reference: https://gitee.com/anolis/cloud-kernel/commit/b90e28f7170e1ae40c572f9f80a50bb...
---------------------------
OpenAnolis Bug Tracker:0000282
This is achieved by broadcasting ARP or ND packets to all of its slave devices on transmit side. The switch will take further actions based on proper configuration.
A new sysctl knob "net.bonding.broadcast_arp_or_nd" is introduced which controls the behaviour of broadcasting.
Signed-off-by: Tony Lu <tonylu(a)linux.alibaba.com> Acked-by: Dust Li <dust.li(a)linux.alibaba.com> Signed-off-by: Qiao Ma <mqaio(a)linux.alibaba.com> Reviewed-by: Shile Zhang <shile.zhang(a)linux.alibaba.com> Acked-by: Dust Li <dust.li(a)linux.alibaba.com> Signed-off-by: Wang Yufen <wangyufen(a)huawei.com> (cherry picked from commit 7c902772d8ee8840b6092b1de94ed0c17c9a8a50) Signed-off-by: Zhengchao Shao shaozhengchao@huawei.com --- Documentation/networking/ip-sysctl.rst | 11 +++++++ drivers/net/bonding/Makefile | 2 +- drivers/net/bonding/bond_main.c | 40 ++++++++++++++++++++++++++ drivers/net/bonding/bond_sysctl.c | 32 +++++++++++++++++++++ include/net/bonding.h | 4 +++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 drivers/net/bonding/bond_sysctl.c
diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index a66054d0763a..12fa38639102 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -3206,3 +3206,14 @@ max_dgram_qlen - INTEGER
Default: 10
+ +``/proc/sys/net/bonding/*`` +======================== + +broadcast_arp_or_nd - INTEGER + Control broadcasting ARP or ND messages to all slaves + + 0: Not broadcasting + 1: Broadcasting + + Default: 0 diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 30e8ae3da2da..9dd55d91185a 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile @@ -5,7 +5,7 @@
obj-$(CONFIG_BONDING) += bonding.o
-bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_sysfs_slave.o bond_debugfs.o bond_netlink.o bond_options.o +bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_sysfs_slave.o bond_debugfs.o bond_netlink.o bond_options.o bond_sysctl.o
proc-$(CONFIG_PROC_FS) += bond_procfs.o bonding-objs += $(proc-y) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 51d47eda1c87..842a138a574d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5127,6 +5127,39 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) return ret; }
+/* Check whether the skb is arp or nd msg */ +static inline bool skb_is_arp_or_nd(struct sk_buff *skb) +{ + switch (ntohs(skb->protocol)) { + case ETH_P_ARP: + return true; + case ETH_P_IPV6: + if (pskb_may_pull(skb, sizeof(struct ipv6hdr) + + sizeof(struct nd_msg))) { + struct ipv6hdr *hdr = ipv6_hdr(skb); + u8 nexthdr = hdr->nexthdr; + struct icmp6hdr *icmp6; + + if (nexthdr == IPPROTO_ICMPV6) { + icmp6 = icmp6_hdr(skb); + + if ((icmp6->icmp6_type == + NDISC_NEIGHBOUR_SOLICITATION || + icmp6->icmp6_type == + NDISC_NEIGHBOUR_ADVERTISEMENT) && + icmp6->icmp6_code == 0) { + return true; + } + } + } + } + + return false; +} + +static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, + struct net_device *bond_dev); + static struct slave *bond_xmit_3ad_xor_slave_get(struct bonding *bond, struct sk_buff *skb, struct bond_up_slave *slaves) @@ -5171,6 +5204,10 @@ static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb, struct bond_up_slave *slaves; struct slave *slave;
+ /* Broadcast to all slaves. */ + if (sysctl_bond_broadcast_arp_or_nd && skb_is_arp_or_nd(skb)) + return bond_xmit_broadcast(skb, dev); + slaves = rcu_dereference(bond->usable_slaves); slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves); if (likely(slave)) @@ -6488,6 +6525,7 @@ static int __init bonding_init(void) goto err_link;
bond_create_debugfs(); + bond_create_sysctl();
for (i = 0; i < max_bonds; i++) { res = bond_create(&init_net, NULL); @@ -6504,6 +6542,7 @@ static int __init bonding_init(void) return res; err: bond_destroy_debugfs(); + bond_destroy_sysctl(); bond_netlink_fini(); err_link: unregister_pernet_subsys(&bond_net_ops); @@ -6516,6 +6555,7 @@ static void __exit bonding_exit(void) unregister_netdevice_notifier(&bond_netdev_notifier);
bond_destroy_debugfs(); + bond_destroy_sysctl();
bond_netlink_fini(); unregister_pernet_subsys(&bond_net_ops); diff --git a/drivers/net/bonding/bond_sysctl.c b/drivers/net/bonding/bond_sysctl.c new file mode 100644 index 000000000000..17404d37a2fd --- /dev/null +++ b/drivers/net/bonding/bond_sysctl.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <net/net_namespace.h> +#include <linux/sysctl.h> +#include <net/bonding.h> + +int sysctl_bond_broadcast_arp_or_nd __read_mostly; +EXPORT_SYMBOL(sysctl_bond_broadcast_arp_or_nd); + +struct ctl_table_header *bond_broadcast_arp_or_nd_table_header; + +static struct ctl_table bond_broadcast_arp_or_nd_table[] = { + { + .procname = "broadcast_arp_or_nd", + .data = &sysctl_bond_broadcast_arp_or_nd, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + {} +}; + +void bond_create_sysctl(void) +{ + bond_broadcast_arp_or_nd_table_header = + register_net_sysctl(&init_net, "net/bonding", + bond_broadcast_arp_or_nd_table); +} + +void bond_destroy_sysctl(void) +{ + unregister_net_sysctl_table(bond_broadcast_arp_or_nd_table_header); +} diff --git a/include/net/bonding.h b/include/net/bonding.h index 5b8b1b644a2d..0f065f150b81 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -115,6 +115,8 @@ static inline int is_netpoll_tx_blocked(struct net_device *dev) #define is_netpoll_tx_blocked(dev) (0) #endif
+extern int sysctl_bond_broadcast_arp_or_nd; + struct bond_params { int mode; int xmit_policy; @@ -684,6 +686,8 @@ struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave); void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay); void bond_work_init_all(struct bonding *bond); +void bond_create_sysctl(void); +void bond_destroy_sysctl(void);
#ifdef CONFIG_PROC_FS void bond_create_proc_entry(struct bonding *bond);