diff options
-rw-r--r-- | include/linux/skbuff.h | 7 | ||||
-rw-r--r-- | net/core/dev.c | 2 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 25 |
3 files changed, 25 insertions, 9 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ba74474836c0..cad1e0c5cc04 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -2722,9 +2722,12 @@ static inline struct sec_path *skb_sec_path(struct sk_buff *skb) | |||
2722 | /* Keeps track of mac header offset relative to skb->head. | 2722 | /* Keeps track of mac header offset relative to skb->head. |
2723 | * It is useful for TSO of Tunneling protocol. e.g. GRE. | 2723 | * It is useful for TSO of Tunneling protocol. e.g. GRE. |
2724 | * For non-tunnel skb it points to skb_mac_header() and for | 2724 | * For non-tunnel skb it points to skb_mac_header() and for |
2725 | * tunnel skb it points to outer mac header. */ | 2725 | * tunnel skb it points to outer mac header. |
2726 | * Keeps track of level of encapsulation of network headers. | ||
2727 | */ | ||
2726 | struct skb_gso_cb { | 2728 | struct skb_gso_cb { |
2727 | int mac_offset; | 2729 | int mac_offset; |
2730 | int encap_level; | ||
2728 | }; | 2731 | }; |
2729 | #define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb) | 2732 | #define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb) |
2730 | 2733 | ||
diff --git a/net/core/dev.c b/net/core/dev.c index 1b6eadf69289..0918aadc20fd 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -2377,6 +2377,8 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb, | |||
2377 | } | 2377 | } |
2378 | 2378 | ||
2379 | SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); | 2379 | SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); |
2380 | SKB_GSO_CB(skb)->encap_level = 0; | ||
2381 | |||
2380 | skb_reset_mac_header(skb); | 2382 | skb_reset_mac_header(skb); |
2381 | skb_reset_mac_len(skb); | 2383 | skb_reset_mac_len(skb); |
2382 | 2384 | ||
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4f8cd4fc451d..5783ab5b5ef8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1273,16 +1273,17 @@ out: | |||
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | 1275 | static struct sk_buff *inet_gso_segment(struct sk_buff *skb, |
1276 | netdev_features_t features) | 1276 | netdev_features_t features) |
1277 | { | 1277 | { |
1278 | struct sk_buff *segs = ERR_PTR(-EINVAL); | 1278 | struct sk_buff *segs = ERR_PTR(-EINVAL); |
1279 | const struct net_offload *ops; | 1279 | const struct net_offload *ops; |
1280 | unsigned int offset = 0; | ||
1280 | struct iphdr *iph; | 1281 | struct iphdr *iph; |
1282 | bool tunnel; | ||
1281 | int proto; | 1283 | int proto; |
1284 | int nhoff; | ||
1282 | int ihl; | 1285 | int ihl; |
1283 | int id; | 1286 | int id; |
1284 | unsigned int offset = 0; | ||
1285 | bool tunnel; | ||
1286 | 1287 | ||
1287 | if (unlikely(skb_shinfo(skb)->gso_type & | 1288 | if (unlikely(skb_shinfo(skb)->gso_type & |
1288 | ~(SKB_GSO_TCPV4 | | 1289 | ~(SKB_GSO_TCPV4 | |
@@ -1296,6 +1297,8 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1296 | 0))) | 1297 | 0))) |
1297 | goto out; | 1298 | goto out; |
1298 | 1299 | ||
1300 | skb_reset_network_header(skb); | ||
1301 | nhoff = skb_network_header(skb) - skb_mac_header(skb); | ||
1299 | if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) | 1302 | if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) |
1300 | goto out; | 1303 | goto out; |
1301 | 1304 | ||
@@ -1312,7 +1315,10 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1312 | goto out; | 1315 | goto out; |
1313 | __skb_pull(skb, ihl); | 1316 | __skb_pull(skb, ihl); |
1314 | 1317 | ||
1315 | tunnel = !!skb->encapsulation; | 1318 | tunnel = SKB_GSO_CB(skb)->encap_level > 0; |
1319 | if (tunnel) | ||
1320 | features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
1321 | SKB_GSO_CB(skb)->encap_level += ihl; | ||
1316 | 1322 | ||
1317 | skb_reset_transport_header(skb); | 1323 | skb_reset_transport_header(skb); |
1318 | 1324 | ||
@@ -1327,18 +1333,23 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1327 | 1333 | ||
1328 | skb = segs; | 1334 | skb = segs; |
1329 | do { | 1335 | do { |
1330 | iph = ip_hdr(skb); | 1336 | iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); |
1331 | if (!tunnel && proto == IPPROTO_UDP) { | 1337 | if (!tunnel && proto == IPPROTO_UDP) { |
1332 | iph->id = htons(id); | 1338 | iph->id = htons(id); |
1333 | iph->frag_off = htons(offset >> 3); | 1339 | iph->frag_off = htons(offset >> 3); |
1334 | if (skb->next != NULL) | 1340 | if (skb->next != NULL) |
1335 | iph->frag_off |= htons(IP_MF); | 1341 | iph->frag_off |= htons(IP_MF); |
1336 | offset += (skb->len - skb->mac_len - iph->ihl * 4); | 1342 | offset += skb->len - nhoff - ihl; |
1337 | } else { | 1343 | } else { |
1338 | iph->id = htons(id++); | 1344 | iph->id = htons(id++); |
1339 | } | 1345 | } |
1340 | iph->tot_len = htons(skb->len - skb->mac_len); | 1346 | iph->tot_len = htons(skb->len - nhoff); |
1341 | ip_send_check(iph); | 1347 | ip_send_check(iph); |
1348 | if (tunnel) { | ||
1349 | skb_reset_inner_headers(skb); | ||
1350 | skb->encapsulation = 1; | ||
1351 | } | ||
1352 | skb->network_header = (u8 *)iph - skb->head; | ||
1342 | } while ((skb = skb->next)); | 1353 | } while ((skb = skb->next)); |
1343 | 1354 | ||
1344 | out: | 1355 | out: |