|
|
@@ -3852,8 +3852,8 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
|
|
|
struct net_device *bond_dev)
|
|
|
{
|
|
|
struct bonding *bond = netdev_priv(bond_dev);
|
|
|
- struct iphdr *iph = ip_hdr(skb);
|
|
|
struct slave *slave;
|
|
|
+ int slave_cnt;
|
|
|
u32 slave_id;
|
|
|
|
|
|
/* Start with the curr_active_slave that joined the bond as the
|
|
|
@@ -3862,23 +3862,32 @@ static netdev_tx_t bond_xmit_roundrobin(struct sk_buff *skb,
|
|
|
* send the join/membership reports. The curr_active_slave found
|
|
|
* will send all of this type of traffic.
|
|
|
*/
|
|
|
- if (iph->protocol == IPPROTO_IGMP && skb->protocol == htons(ETH_P_IP)) {
|
|
|
- slave = rcu_dereference(bond->curr_active_slave);
|
|
|
- if (slave)
|
|
|
- bond_dev_queue_xmit(bond, skb, slave->dev);
|
|
|
- else
|
|
|
- bond_xmit_slave_id(bond, skb, 0);
|
|
|
- } else {
|
|
|
- int slave_cnt = READ_ONCE(bond->slave_cnt);
|
|
|
+ if (skb->protocol == htons(ETH_P_IP)) {
|
|
|
+ int noff = skb_network_offset(skb);
|
|
|
+ struct iphdr *iph;
|
|
|
|
|
|
- if (likely(slave_cnt)) {
|
|
|
- slave_id = bond_rr_gen_slave_id(bond);
|
|
|
- bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
|
|
|
- } else {
|
|
|
- bond_tx_drop(bond_dev, skb);
|
|
|
+ if (unlikely(!pskb_may_pull(skb, noff + sizeof(*iph))))
|
|
|
+ goto non_igmp;
|
|
|
+
|
|
|
+ iph = ip_hdr(skb);
|
|
|
+ if (iph->protocol == IPPROTO_IGMP) {
|
|
|
+ slave = rcu_dereference(bond->curr_active_slave);
|
|
|
+ if (slave)
|
|
|
+ bond_dev_queue_xmit(bond, skb, slave->dev);
|
|
|
+ else
|
|
|
+ bond_xmit_slave_id(bond, skb, 0);
|
|
|
+ return NETDEV_TX_OK;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+non_igmp:
|
|
|
+ slave_cnt = READ_ONCE(bond->slave_cnt);
|
|
|
+ if (likely(slave_cnt)) {
|
|
|
+ slave_id = bond_rr_gen_slave_id(bond);
|
|
|
+ bond_xmit_slave_id(bond, skb, slave_id % slave_cnt);
|
|
|
+ } else {
|
|
|
+ bond_tx_drop(bond_dev, skb);
|
|
|
+ }
|
|
|
return NETDEV_TX_OK;
|
|
|
}
|
|
|
|