diff options
author | Eric Dumazet <edumazet@google.com> | 2013-11-07 21:32:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-11-08 02:07:59 -0500 |
commit | dcd607718385d02ce3741de225927a57f528f93b (patch) | |
tree | 48dcb0b8e4a43c92d9ca90bfb4fdcb4482af159f /net/ipv4/af_inet.c | |
parent | 0b2e2d36d152a94082f05ad226a290d765ffb7d2 (diff) |
inet: fix a UFO regression
While testing virtio_net and skb_segment() changes, Hannes reported
that UFO was sending wrong frames.
It appears this was introduced by a recent commit :
8c3a897bfab1 ("inet: restore gso for vxlan")
The old condition to perform IP frag was :
tunnel = !!skb->encapsulation;
...
if (!tunnel && proto == IPPROTO_UDP) {
So the new one should be :
udpfrag = !skb->encapsulation && proto == IPPROTO_UDP;
...
if (udpfrag) {
Initialization of udpfrag must be done before call
to ops->callbacks.gso_segment(skb, features), as
skb_udp_tunnel_segment() clears skb->encapsulation
(We want udpfrag to be true for UFO, false for VXLAN)
With help from Alexei Starovoitov
Reported-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/af_inet.c')
-rw-r--r-- | net/ipv4/af_inet.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 09d78d4a3cff..68af9aac91d0 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1299,6 +1299,9 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1299 | 1299 | ||
1300 | segs = ERR_PTR(-EPROTONOSUPPORT); | 1300 | segs = ERR_PTR(-EPROTONOSUPPORT); |
1301 | 1301 | ||
1302 | /* Note : following gso_segment() might change skb->encapsulation */ | ||
1303 | udpfrag = !skb->encapsulation && proto == IPPROTO_UDP; | ||
1304 | |||
1302 | ops = rcu_dereference(inet_offloads[proto]); | 1305 | ops = rcu_dereference(inet_offloads[proto]); |
1303 | if (likely(ops && ops->callbacks.gso_segment)) | 1306 | if (likely(ops && ops->callbacks.gso_segment)) |
1304 | segs = ops->callbacks.gso_segment(skb, features); | 1307 | segs = ops->callbacks.gso_segment(skb, features); |
@@ -1306,7 +1309,6 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1306 | if (IS_ERR_OR_NULL(segs)) | 1309 | if (IS_ERR_OR_NULL(segs)) |
1307 | goto out; | 1310 | goto out; |
1308 | 1311 | ||
1309 | udpfrag = !!skb->encapsulation && proto == IPPROTO_UDP; | ||
1310 | skb = segs; | 1312 | skb = segs; |
1311 | do { | 1313 | do { |
1312 | iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); | 1314 | iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); |