bridge: Fix network header pointer for vlan tagged packets
There are several devices that can receive vlan tagged packets with CHECKSUM_PARTIAL like tap, possibly veth and xennet. When (multiple) vlan tagged packets with CHECKSUM_PARTIAL are forwarded by bridge to a device with the IP_CSUM feature, they end up with checksum error because before entering bridge, the network header is set to ETH_HLEN (not including vlan header length) in __netif_receive_skb_core(), get_rps_cpu(), or drivers' rx functions, and nobody fixes the pointer later. Since the network header is exepected to be ETH_HLEN in flow-dissection and hash-calculation in RPS in rx path, and since the header pointer fix is needed only in tx path, set the appropriate network header on forwarding packets. Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
dbd46ab412
commit
df356d5e81
@ -37,15 +37,30 @@ static inline int should_deliver(const struct net_bridge_port *p,
|
|||||||
|
|
||||||
int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb)
|
int br_dev_queue_push_xmit(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
if (!is_skb_forwardable(skb->dev, skb)) {
|
if (!is_skb_forwardable(skb->dev, skb))
|
||||||
kfree_skb(skb);
|
goto drop;
|
||||||
} else {
|
|
||||||
skb_push(skb, ETH_HLEN);
|
skb_push(skb, ETH_HLEN);
|
||||||
br_drop_fake_rtable(skb);
|
br_drop_fake_rtable(skb);
|
||||||
skb_sender_cpu_clear(skb);
|
skb_sender_cpu_clear(skb);
|
||||||
dev_queue_xmit(skb);
|
|
||||||
|
if (skb->ip_summed == CHECKSUM_PARTIAL &&
|
||||||
|
(skb->protocol == htons(ETH_P_8021Q) ||
|
||||||
|
skb->protocol == htons(ETH_P_8021AD))) {
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
if (!__vlan_get_protocol(skb, skb->protocol, &depth))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
skb_set_network_header(skb, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_queue_xmit(skb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
kfree_skb(skb);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
|
EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit);
|
||||||
|
Loading…
Reference in New Issue
Block a user