diff options
author | Wei-Chun Chao <weichunc@plumgrid.com> | 2013-12-26 16:10:22 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-01-02 19:06:47 -0500 |
commit | 7a7ffbabf99445704be01bff5d7e360da908cf8e (patch) | |
tree | 3b4f71699307ac2853a8fdffde60fb7055cb1b04 /net/ipv4/udp.c | |
parent | 619a60ee04be33238721a15c1f9704a2a515a33e (diff) |
ipv4: fix tunneled VM traffic over hw VXLAN/GRE GSO NIC
VM to VM GSO traffic is broken if it goes through VXLAN or GRE
tunnel and the physical NIC on the host supports hardware VXLAN/GRE
GSO offload (e.g. bnx2x and next-gen mlx4).
Two issues -
(VXLAN) VM traffic has SKB_GSO_DODGY and SKB_GSO_UDP_TUNNEL with
SKB_GSO_TCP/UDP set depending on the inner protocol. GSO header
integrity check fails in udp4_ufo_fragment if inner protocol is
TCP. Also gso_segs is calculated incorrectly using skb->len that
includes tunnel header. Fix: robust check should only be applied
to the inner packet.
(VXLAN & GRE) Once GSO header integrity check passes, NULL segs
is returned and the original skb is sent to hardware. However the
tunnel header is already pulled. Fix: tunnel header needs to be
restored so that hardware can perform GSO properly on the original
packet.
Signed-off-by: Wei-Chun Chao <weichunc@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index f140048334ce..a7e4729e974b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -2478,6 +2478,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | |||
2478 | netdev_features_t features) | 2478 | netdev_features_t features) |
2479 | { | 2479 | { |
2480 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 2480 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
2481 | u16 mac_offset = skb->mac_header; | ||
2481 | int mac_len = skb->mac_len; | 2482 | int mac_len = skb->mac_len; |
2482 | int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); | 2483 | int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); |
2483 | __be16 protocol = skb->protocol; | 2484 | __be16 protocol = skb->protocol; |
@@ -2497,8 +2498,11 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, | |||
2497 | /* segment inner packet. */ | 2498 | /* segment inner packet. */ |
2498 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | 2499 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); |
2499 | segs = skb_mac_gso_segment(skb, enc_features); | 2500 | segs = skb_mac_gso_segment(skb, enc_features); |
2500 | if (!segs || IS_ERR(segs)) | 2501 | if (!segs || IS_ERR(segs)) { |
2502 | skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, | ||
2503 | mac_len); | ||
2501 | goto out; | 2504 | goto out; |
2505 | } | ||
2502 | 2506 | ||
2503 | outer_hlen = skb_tnl_header_len(skb); | 2507 | outer_hlen = skb_tnl_header_len(skb); |
2504 | skb = segs; | 2508 | skb = segs; |