Skip to content

Commit 6a32e4f

Browse files
Eric Dumazetdavem330
authored andcommitted
vlan: allow nested vlan_do_receive()
commit 2425717 (net: allow vlan traffic to be received under bond) broke ARP processing on vlan on top of bonding. +-------+ eth0 --| bond0 |---bond0.103 eth1 --| | +-------+ 52870.115435: skb_gro_reset_offset <-napi_gro_receive 52870.115435: dev_gro_receive <-napi_gro_receive 52870.115435: napi_skb_finish <-napi_gro_receive 52870.115435: netif_receive_skb <-napi_skb_finish 52870.115435: get_rps_cpu <-netif_receive_skb 52870.115435: __netif_receive_skb <-netif_receive_skb 52870.115436: vlan_do_receive <-__netif_receive_skb 52870.115436: bond_handle_frame <-__netif_receive_skb 52870.115436: vlan_do_receive <-__netif_receive_skb 52870.115436: arp_rcv <-__netif_receive_skb 52870.115436: kfree_skb <-arp_rcv Packet is dropped in arp_rcv() because its pkt_type was set to PACKET_OTHERHOST in the first vlan_do_receive() call, since no eth0.103 exists. We really need to change pkt_type only if no more rx_handler is about to be called for the packet. Signed-off-by: Eric Dumazet <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 14ef37b commit 6a32e4f

File tree

3 files changed

+10
-7
lines changed

3 files changed

+10
-7
lines changed

include/linux/if_vlan.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
106106
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
107107
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
108108

109-
extern bool vlan_do_receive(struct sk_buff **skb);
109+
extern bool vlan_do_receive(struct sk_buff **skb, bool last_handler);
110110
extern struct sk_buff *vlan_untag(struct sk_buff *skb);
111111

112112
#else
@@ -128,9 +128,9 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
128128
return 0;
129129
}
130130

131-
static inline bool vlan_do_receive(struct sk_buff **skb)
131+
static inline bool vlan_do_receive(struct sk_buff **skb, bool last_handler)
132132
{
133-
if ((*skb)->vlan_tci & VLAN_VID_MASK)
133+
if (((*skb)->vlan_tci & VLAN_VID_MASK) && last_handler)
134134
(*skb)->pkt_type = PACKET_OTHERHOST;
135135
return false;
136136
}

net/8021q/vlan_core.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <linux/netpoll.h>
55
#include "vlan.h"
66

7-
bool vlan_do_receive(struct sk_buff **skbp)
7+
bool vlan_do_receive(struct sk_buff **skbp, bool last_handler)
88
{
99
struct sk_buff *skb = *skbp;
1010
u16 vlan_id = skb->vlan_tci & VLAN_VID_MASK;
@@ -13,7 +13,10 @@ bool vlan_do_receive(struct sk_buff **skbp)
1313

1414
vlan_dev = vlan_find_dev(skb->dev, vlan_id);
1515
if (!vlan_dev) {
16-
if (vlan_id)
16+
/* Only the last call to vlan_do_receive() should change
17+
* pkt_type to PACKET_OTHERHOST
18+
*/
19+
if (vlan_id && last_handler)
1720
skb->pkt_type = PACKET_OTHERHOST;
1821
return false;
1922
}

net/core/dev.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3283,18 +3283,18 @@ static int __netif_receive_skb(struct sk_buff *skb)
32833283
ncls:
32843284
#endif
32853285

3286+
rx_handler = rcu_dereference(skb->dev->rx_handler);
32863287
if (vlan_tx_tag_present(skb)) {
32873288
if (pt_prev) {
32883289
ret = deliver_skb(skb, pt_prev, orig_dev);
32893290
pt_prev = NULL;
32903291
}
3291-
if (vlan_do_receive(&skb))
3292+
if (vlan_do_receive(&skb, !rx_handler))
32923293
goto another_round;
32933294
else if (unlikely(!skb))
32943295
goto out;
32953296
}
32963297

3297-
rx_handler = rcu_dereference(skb->dev->rx_handler);
32983298
if (rx_handler) {
32993299
if (pt_prev) {
33003300
ret = deliver_skb(skb, pt_prev, orig_dev);

0 commit comments

Comments
 (0)