Thomas Bogendoerfer 450565
From: Jie Wang <wangjie125@huawei.com>
Thomas Bogendoerfer 450565
Date: Wed, 12 Jan 2022 20:54:18 +0800
Thomas Bogendoerfer 450565
Subject: net: bonding: fix bond_xmit_broadcast return value error bug
Thomas Bogendoerfer 450565
Patch-mainline: v5.17-rc1
Thomas Bogendoerfer 450565
Git-commit: 4e5bd03ae34652cd932ab4c91c71c511793df75c
Thomas Bogendoerfer 450565
References: git-fixes
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
In Linux bonding scenario, one packet is copied to several copies and sent
Thomas Bogendoerfer 450565
by all slave device of bond0 in mode 3(broadcast mode). The mode 3 xmit
Thomas Bogendoerfer 450565
function bond_xmit_broadcast() only ueses the last slave device's tx result
Thomas Bogendoerfer 450565
as the final result. In this case, if the last slave device is down, then
Thomas Bogendoerfer 450565
it always return NET_XMIT_DROP, even though the other slave devices xmit
Thomas Bogendoerfer 450565
success. It may cause the tx statistics error, and cause the application
Thomas Bogendoerfer 450565
(e.g. scp) consider the network is unreachable.
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
For example, use the following command to configure server A.
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
echo 3 > /sys/class/net/bond0/bonding/mode
Thomas Bogendoerfer 450565
ifconfig bond0 up
Thomas Bogendoerfer 450565
ifenslave bond0 eth0 eth1
Thomas Bogendoerfer 450565
ifconfig bond0 192.168.1.125
Thomas Bogendoerfer 450565
ifconfig eth0 up
Thomas Bogendoerfer 450565
ifconfig eth1 down
Thomas Bogendoerfer 450565
The slave device eth0 and eth1 are connected to server B(192.168.1.107).
Thomas Bogendoerfer 450565
Run the ping 192.168.1.107 -c 3 -i 0.2 command, the following information
Thomas Bogendoerfer 450565
is displayed.
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
PING 192.168.1.107 (192.168.1.107) 56(84) bytes of data.
Thomas Bogendoerfer 450565
64 bytes from 192.168.1.107: icmp_seq=1 ttl=64 time=0.077 ms
Thomas Bogendoerfer 450565
64 bytes from 192.168.1.107: icmp_seq=2 ttl=64 time=0.056 ms
Thomas Bogendoerfer 450565
64 bytes from 192.168.1.107: icmp_seq=3 ttl=64 time=0.051 ms
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
 192.168.1.107 ping statistics
Thomas Bogendoerfer 450565
0 packets transmitted, 3 received
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
Actually, the slave device eth0 of the bond successfully sends three
Thomas Bogendoerfer 450565
ICMP packets, but the result shows that 0 packets are transmitted.
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
Also if we use scp command to get remote files, the command end with the
Thomas Bogendoerfer 450565
following printings.
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
ssh_exchange_identification: read: Connection timed out
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
So this patch modifies the bond_xmit_broadcast to return NET_XMIT_SUCCESS
Thomas Bogendoerfer 450565
if one slave device in the bond sends packets successfully. If all slave
Thomas Bogendoerfer 450565
devices send packets fail, the discarded packets stats is increased. The
Thomas Bogendoerfer 450565
skb is released when there is no slave device in the bond or the last slave
Thomas Bogendoerfer 450565
device is down.
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
Fixes: ae46f184bc1f ("bonding: propagate transmit status")
Thomas Bogendoerfer 450565
Signed-off-by: Jie Wang <wangjie125@huawei.com>
Thomas Bogendoerfer 450565
Signed-off-by: Guangbin Huang <huangguangbin2@huawei.com>
Thomas Bogendoerfer 450565
Signed-off-by: David S. Miller <davem@davemloft.net>
Thomas Bogendoerfer 450565
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
Thomas Bogendoerfer 450565
---
Thomas Bogendoerfer 450565
 drivers/net/bonding/bond_main.c |   30 ++++++++++++++++++++++--------
Thomas Bogendoerfer 450565
 1 file changed, 22 insertions(+), 8 deletions(-)
Thomas Bogendoerfer 450565
Thomas Bogendoerfer 450565
--- a/drivers/net/bonding/bond_main.c
Thomas Bogendoerfer 450565
+++ b/drivers/net/bonding/bond_main.c
Thomas Bogendoerfer 450565
@@ -4631,25 +4631,39 @@ static netdev_tx_t bond_xmit_broadcast(s
Thomas Bogendoerfer 450565
 	struct bonding *bond = netdev_priv(bond_dev);
Thomas Bogendoerfer 450565
 	struct slave *slave = NULL;
Thomas Bogendoerfer 450565
 	struct list_head *iter;
Thomas Bogendoerfer 450565
+	bool xmit_suc = false;
Thomas Bogendoerfer 450565
+	bool skb_used = false;
Thomas Bogendoerfer 450565
 
Thomas Bogendoerfer 450565
 	bond_for_each_slave_rcu(bond, slave, iter) {
Thomas Bogendoerfer 450565
-		if (bond_is_last_slave(bond, slave))
Thomas Bogendoerfer 450565
-			break;
Thomas Bogendoerfer 450565
-		if (bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) {
Thomas Bogendoerfer 450565
-			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
Thomas Bogendoerfer 450565
+		struct sk_buff *skb2;
Thomas Bogendoerfer 450565
 
Thomas Bogendoerfer 450565
+		if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP))
Thomas Bogendoerfer 450565
+			continue;
Thomas Bogendoerfer 450565
+
Thomas Bogendoerfer 450565
+		if (bond_is_last_slave(bond, slave)) {
Thomas Bogendoerfer 450565
+			skb2 = skb;
Thomas Bogendoerfer 450565
+			skb_used = true;
Thomas Bogendoerfer 450565
+		} else {
Thomas Bogendoerfer 450565
+			skb2 = skb_clone(skb, GFP_ATOMIC);
Thomas Bogendoerfer 450565
 			if (!skb2) {
Thomas Bogendoerfer 450565
 				net_err_ratelimited("%s: Error: %s: skb_clone() failed\n",
Thomas Bogendoerfer 450565
 						    bond_dev->name, __func__);
Thomas Bogendoerfer 450565
 				continue;
Thomas Bogendoerfer 450565
 			}
Thomas Bogendoerfer 450565
-			bond_dev_queue_xmit(bond, skb2, slave->dev);
Thomas Bogendoerfer 450565
 		}
Thomas Bogendoerfer 450565
+
Thomas Bogendoerfer 450565
+		if (bond_dev_queue_xmit(bond, skb2, slave->dev) == NETDEV_TX_OK)
Thomas Bogendoerfer 450565
+			xmit_suc = true;
Thomas Bogendoerfer 450565
 	}
Thomas Bogendoerfer 450565
-	if (slave && bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)
Thomas Bogendoerfer 450565
-		return bond_dev_queue_xmit(bond, skb, slave->dev);
Thomas Bogendoerfer 450565
 
Thomas Bogendoerfer 450565
-	return bond_tx_drop(bond_dev, skb);
Thomas Bogendoerfer 450565
+	if (!skb_used)
Thomas Bogendoerfer 450565
+		dev_kfree_skb_any(skb);
Thomas Bogendoerfer 450565
+
Thomas Bogendoerfer 450565
+	if (xmit_suc)
Thomas Bogendoerfer 450565
+		return NETDEV_TX_OK;
Thomas Bogendoerfer 450565
+
Thomas Bogendoerfer 450565
+	atomic_long_inc(&bond_dev->tx_dropped);
Thomas Bogendoerfer 450565
+	return NET_XMIT_DROP;
Thomas Bogendoerfer 450565
 }
Thomas Bogendoerfer 450565
 
Thomas Bogendoerfer 450565
 /*------------------------- Device initialization ---------------------------*/