Message ID | 20220112125418.55118-1-huangguangbin2@huawei.com (mailing list archive) |
---|---|
State | Accepted |
Commit | 4e5bd03ae34652cd932ab4c91c71c511793df75c |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [net] net: bonding: fix bond_xmit_broadcast return value error bug | expand |
Hello: This patch was applied to netdev/net.git (master) by David S. Miller <davem@davemloft.net>: On Wed, 12 Jan 2022 20:54:18 +0800 you wrote: > From: Jie Wang <wangjie125@huawei.com> > > In Linux bonding scenario, one packet is copied to several copies and sent > by all slave device of bond0 in mode 3(broadcast mode). The mode 3 xmit > function bond_xmit_broadcast() only ueses the last slave device's tx result > as the final result. In this case, if the last slave device is down, then > it always return NET_XMIT_DROP, even though the other slave devices xmit > success. It may cause the tx statistics error, and cause the application > (e.g. scp) consider the network is unreachable. > > [...] Here is the summary with links: - [net] net: bonding: fix bond_xmit_broadcast return value error bug https://git.kernel.org/netdev/net/c/4e5bd03ae346 You are awesome, thank you!
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 07fc603c2fa7..fce80b57f15b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4884,25 +4884,39 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, struct bonding *bond = netdev_priv(bond_dev); struct slave *slave = NULL; struct list_head *iter; + bool xmit_suc = false; + bool skb_used = false; bond_for_each_slave_rcu(bond, slave, iter) { - if (bond_is_last_slave(bond, slave)) - break; - if (bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + struct sk_buff *skb2; + + if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)) + continue; + if (bond_is_last_slave(bond, slave)) { + skb2 = skb; + skb_used = true; + } else { + skb2 = skb_clone(skb, GFP_ATOMIC); if (!skb2) { net_err_ratelimited("%s: Error: %s: skb_clone() failed\n", bond_dev->name, __func__); continue; } - bond_dev_queue_xmit(bond, skb2, slave->dev); } + + if (bond_dev_queue_xmit(bond, skb2, slave->dev) == NETDEV_TX_OK) + xmit_suc = true; } - if (slave && bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) - return bond_dev_queue_xmit(bond, skb, slave->dev); - return bond_tx_drop(bond_dev, skb); + if (!skb_used) + dev_kfree_skb_any(skb); + + if (xmit_suc) + return NETDEV_TX_OK; + + atomic_long_inc(&bond_dev->tx_dropped); + return NET_XMIT_DROP; } /*------------------------- Device initialization ---------------------------*/