diff options
author | Eric Dumazet <edumazet@google.com> | 2013-10-27 21:18:16 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-10-28 00:23:06 -0400 |
commit | 8c3a897bfab10f68f90252440bb29e6749a7312a (patch) | |
tree | ba8243600b6a8cd7b7fa5679f2405873aae70aea | |
parent | 1f2cd845d3827412e82bf26dde0abca332ede402 (diff) |
inet: restore gso for vxlan
Alexei reported a performance regression on vxlan, caused
by commit 3347c9602955 "ipv4: gso: make inet_gso_segment() stackable"
GSO vxlan packets were not properly segmented, adding IP fragments
while they were not expected.
Rename 'bool tunnel' to 'bool encap', and add a new boolean
to express the fact that UDP should be fragmented.
This fragmentation is triggered by skb->encapsulation being set.
Remove a "skb->encapsulation = 1" added in above commit,
as its not needed, as frags inherit skb->frag from original
GSO skb.
Reported-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Tested-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/af_inet.c | 15 |
1 files changed, 7 insertions, 8 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index f4a159e705c0..09d78d4a3cff 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1251,8 +1251,8 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1251 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 1251 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
1252 | const struct net_offload *ops; | 1252 | const struct net_offload *ops; |
1253 | unsigned int offset = 0; | 1253 | unsigned int offset = 0; |
1254 | bool udpfrag, encap; | ||
1254 | struct iphdr *iph; | 1255 | struct iphdr *iph; |
1255 | bool tunnel; | ||
1256 | int proto; | 1256 | int proto; |
1257 | int nhoff; | 1257 | int nhoff; |
1258 | int ihl; | 1258 | int ihl; |
@@ -1290,8 +1290,8 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1290 | goto out; | 1290 | goto out; |
1291 | __skb_pull(skb, ihl); | 1291 | __skb_pull(skb, ihl); |
1292 | 1292 | ||
1293 | tunnel = SKB_GSO_CB(skb)->encap_level > 0; | 1293 | encap = SKB_GSO_CB(skb)->encap_level > 0; |
1294 | if (tunnel) | 1294 | if (encap) |
1295 | features = skb->dev->hw_enc_features & netif_skb_features(skb); | 1295 | features = skb->dev->hw_enc_features & netif_skb_features(skb); |
1296 | SKB_GSO_CB(skb)->encap_level += ihl; | 1296 | SKB_GSO_CB(skb)->encap_level += ihl; |
1297 | 1297 | ||
@@ -1306,24 +1306,23 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1306 | if (IS_ERR_OR_NULL(segs)) | 1306 | if (IS_ERR_OR_NULL(segs)) |
1307 | goto out; | 1307 | goto out; |
1308 | 1308 | ||
1309 | udpfrag = !!skb->encapsulation && proto == IPPROTO_UDP; | ||
1309 | skb = segs; | 1310 | skb = segs; |
1310 | do { | 1311 | do { |
1311 | iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); | 1312 | iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); |
1312 | if (!tunnel && proto == IPPROTO_UDP) { | 1313 | if (udpfrag) { |
1313 | iph->id = htons(id); | 1314 | iph->id = htons(id); |
1314 | iph->frag_off = htons(offset >> 3); | 1315 | iph->frag_off = htons(offset >> 3); |
1315 | if (skb->next != NULL) | 1316 | if (skb->next != NULL) |
1316 | iph->frag_off |= htons(IP_MF); | 1317 | iph->frag_off |= htons(IP_MF); |
1317 | offset += skb->len - nhoff - ihl; | 1318 | offset += skb->len - nhoff - ihl; |
1318 | } else { | 1319 | } else { |
1319 | iph->id = htons(id++); | 1320 | iph->id = htons(id++); |
1320 | } | 1321 | } |
1321 | iph->tot_len = htons(skb->len - nhoff); | 1322 | iph->tot_len = htons(skb->len - nhoff); |
1322 | ip_send_check(iph); | 1323 | ip_send_check(iph); |
1323 | if (tunnel) { | 1324 | if (encap) |
1324 | skb_reset_inner_headers(skb); | 1325 | skb_reset_inner_headers(skb); |
1325 | skb->encapsulation = 1; | ||
1326 | } | ||
1327 | skb->network_header = (u8 *)iph - skb->head; | 1326 | skb->network_header = (u8 *)iph - skb->head; |
1328 | } while ((skb = skb->next)); | 1327 | } while ((skb = skb->next)); |
1329 | 1328 | ||