diff options
-rw-r--r-- | drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 4 | ||||
-rw-r--r-- | include/linux/netdev_features.h | 2 | ||||
-rw-r--r-- | include/linux/skbuff.h | 13 | ||||
-rw-r--r-- | include/net/gre.h | 8 | ||||
-rw-r--r-- | include/net/ip_tunnels.h | 3 | ||||
-rw-r--r-- | net/core/dev.c | 2 | ||||
-rw-r--r-- | net/core/ethtool.c | 1 | ||||
-rw-r--r-- | net/core/skbuff.c | 22 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 34 | ||||
-rw-r--r-- | net/ipv4/gre_demux.c | 29 | ||||
-rw-r--r-- | net/ipv4/gre_offload.c | 3 | ||||
-rw-r--r-- | net/ipv4/ip_tunnel_core.c | 33 | ||||
-rw-r--r-- | net/ipv4/ipip.c | 11 | ||||
-rw-r--r-- | net/ipv4/tcp_offload.c | 1 | ||||
-rw-r--r-- | net/ipv4/udp_offload.c | 1 | ||||
-rw-r--r-- | net/ipv6/ip6_offload.c | 1 | ||||
-rw-r--r-- | net/ipv6/udp_offload.c | 1 | ||||
-rw-r--r-- | net/mpls/mpls_gso.c | 1 |
18 files changed, 105 insertions, 65 deletions
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 8fd343201576..6e5b35ff7af4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | |||
@@ -12260,10 +12260,12 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev, | |||
12260 | NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO | | 12260 | NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_GRO | |
12261 | NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX; | 12261 | NETIF_F_RXHASH | NETIF_F_HW_VLAN_CTAG_TX; |
12262 | if (!CHIP_IS_E1x(bp)) { | 12262 | if (!CHIP_IS_E1x(bp)) { |
12263 | dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL; | 12263 | dev->hw_features |= NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL | |
12264 | NETIF_F_GSO_IPIP; | ||
12264 | dev->hw_enc_features = | 12265 | dev->hw_enc_features = |
12265 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SG | | 12266 | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_SG | |
12266 | NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | | 12267 | NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | |
12268 | NETIF_F_GSO_IPIP | | ||
12267 | NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL; | 12269 | NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL; |
12268 | } | 12270 | } |
12269 | 12271 | ||
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index a2a89a5c7be5..8dad68cede1c 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h | |||
@@ -42,6 +42,7 @@ enum { | |||
42 | NETIF_F_TSO6_BIT, /* ... TCPv6 segmentation */ | 42 | NETIF_F_TSO6_BIT, /* ... TCPv6 segmentation */ |
43 | NETIF_F_FSO_BIT, /* ... FCoE segmentation */ | 43 | NETIF_F_FSO_BIT, /* ... FCoE segmentation */ |
44 | NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */ | 44 | NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */ |
45 | NETIF_F_GSO_IPIP_BIT, /* ... IPIP tunnel with TSO */ | ||
45 | NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ | 46 | NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ |
46 | NETIF_F_GSO_MPLS_BIT, /* ... MPLS segmentation */ | 47 | NETIF_F_GSO_MPLS_BIT, /* ... MPLS segmentation */ |
47 | /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ | 48 | /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ |
@@ -107,6 +108,7 @@ enum { | |||
107 | #define NETIF_F_RXFCS __NETIF_F(RXFCS) | 108 | #define NETIF_F_RXFCS __NETIF_F(RXFCS) |
108 | #define NETIF_F_RXALL __NETIF_F(RXALL) | 109 | #define NETIF_F_RXALL __NETIF_F(RXALL) |
109 | #define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE) | 110 | #define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE) |
111 | #define NETIF_F_GSO_IPIP __NETIF_F(GSO_IPIP) | ||
110 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) | 112 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) |
111 | #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) | 113 | #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) |
112 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) | 114 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ba74474836c0..60729134d253 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -318,9 +318,11 @@ enum { | |||
318 | 318 | ||
319 | SKB_GSO_GRE = 1 << 6, | 319 | SKB_GSO_GRE = 1 << 6, |
320 | 320 | ||
321 | SKB_GSO_UDP_TUNNEL = 1 << 7, | 321 | SKB_GSO_IPIP = 1 << 7, |
322 | 322 | ||
323 | SKB_GSO_MPLS = 1 << 8, | 323 | SKB_GSO_UDP_TUNNEL = 1 << 8, |
324 | |||
325 | SKB_GSO_MPLS = 1 << 9, | ||
324 | }; | 326 | }; |
325 | 327 | ||
326 | #if BITS_PER_LONG > 32 | 328 | #if BITS_PER_LONG > 32 |
@@ -2722,9 +2724,12 @@ static inline struct sec_path *skb_sec_path(struct sk_buff *skb) | |||
2722 | /* Keeps track of mac header offset relative to skb->head. | 2724 | /* Keeps track of mac header offset relative to skb->head. |
2723 | * It is useful for TSO of Tunneling protocol. e.g. GRE. | 2725 | * It is useful for TSO of Tunneling protocol. e.g. GRE. |
2724 | * For non-tunnel skb it points to skb_mac_header() and for | 2726 | * For non-tunnel skb it points to skb_mac_header() and for |
2725 | * tunnel skb it points to outer mac header. */ | 2727 | * tunnel skb it points to outer mac header. |
2728 | * Keeps track of level of encapsulation of network headers. | ||
2729 | */ | ||
2726 | struct skb_gso_cb { | 2730 | struct skb_gso_cb { |
2727 | int mac_offset; | 2731 | int mac_offset; |
2732 | int encap_level; | ||
2728 | }; | 2733 | }; |
2729 | #define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb) | 2734 | #define SKB_GSO_CB(skb) ((struct skb_gso_cb *)(skb)->cb) |
2730 | 2735 | ||
diff --git a/include/net/gre.h b/include/net/gre.h index 57e4afdf7879..dcd9ae3270d3 100644 --- a/include/net/gre.h +++ b/include/net/gre.h | |||
@@ -38,7 +38,13 @@ void gre_offload_exit(void); | |||
38 | 38 | ||
39 | void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, | 39 | void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, |
40 | int hdr_len); | 40 | int hdr_len); |
41 | struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum); | 41 | |
42 | static inline struct sk_buff *gre_handle_offloads(struct sk_buff *skb, | ||
43 | bool gre_csum) | ||
44 | { | ||
45 | return iptunnel_handle_offloads(skb, gre_csum, SKB_GSO_GRE); | ||
46 | } | ||
47 | |||
42 | 48 | ||
43 | static inline int ip_gre_calc_hlen(__be16 o_flags) | 49 | static inline int ip_gre_calc_hlen(__be16 o_flags) |
44 | { | 50 | { |
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index a0a4a100f5c9..732f8c6ae975 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h | |||
@@ -150,6 +150,9 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb, | |||
150 | __be32 src, __be32 dst, __u8 proto, | 150 | __be32 src, __be32 dst, __u8 proto, |
151 | __u8 tos, __u8 ttl, __be16 df, bool xnet); | 151 | __u8 tos, __u8 ttl, __be16 df, bool xnet); |
152 | 152 | ||
153 | struct sk_buff *iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum, | ||
154 | int gso_type_mask); | ||
155 | |||
153 | static inline void iptunnel_xmit_stats(int err, | 156 | static inline void iptunnel_xmit_stats(int err, |
154 | struct net_device_stats *err_stats, | 157 | struct net_device_stats *err_stats, |
155 | struct pcpu_tstats __percpu *stats) | 158 | struct pcpu_tstats __percpu *stats) |
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/core/ethtool.c b/net/core/ethtool.c index 78e9d9223e40..8cab7744790e 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c | |||
@@ -81,6 +81,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] | |||
81 | [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation", | 81 | [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation", |
82 | [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", | 82 | [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", |
83 | [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", | 83 | [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", |
84 | [NETIF_F_GSO_IPIP_BIT] = "tx-ipip-segmentation", | ||
84 | [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", | 85 | [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", |
85 | [NETIF_F_GSO_MPLS_BIT] = "tx-mpls-segmentation", | 86 | [NETIF_F_GSO_MPLS_BIT] = "tx-mpls-segmentation", |
86 | 87 | ||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 8ead744fcc94..0ab32faa520f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -903,6 +903,9 @@ EXPORT_SYMBOL(skb_clone); | |||
903 | 903 | ||
904 | static void skb_headers_offset_update(struct sk_buff *skb, int off) | 904 | static void skb_headers_offset_update(struct sk_buff *skb, int off) |
905 | { | 905 | { |
906 | /* Only adjust this if it actually is csum_start rather than csum */ | ||
907 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
908 | skb->csum_start += off; | ||
906 | /* {transport,network,mac}_header and tail are relative to skb->head */ | 909 | /* {transport,network,mac}_header and tail are relative to skb->head */ |
907 | skb->transport_header += off; | 910 | skb->transport_header += off; |
908 | skb->network_header += off; | 911 | skb->network_header += off; |
@@ -1109,9 +1112,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, | |||
1109 | #endif | 1112 | #endif |
1110 | skb->tail += off; | 1113 | skb->tail += off; |
1111 | skb_headers_offset_update(skb, nhead); | 1114 | skb_headers_offset_update(skb, nhead); |
1112 | /* Only adjust this if it actually is csum_start rather than csum */ | ||
1113 | if (skb->ip_summed == CHECKSUM_PARTIAL) | ||
1114 | skb->csum_start += nhead; | ||
1115 | skb->cloned = 0; | 1115 | skb->cloned = 0; |
1116 | skb->hdr_len = 0; | 1116 | skb->hdr_len = 0; |
1117 | skb->nohdr = 0; | 1117 | skb->nohdr = 0; |
@@ -1176,7 +1176,6 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, | |||
1176 | NUMA_NO_NODE); | 1176 | NUMA_NO_NODE); |
1177 | int oldheadroom = skb_headroom(skb); | 1177 | int oldheadroom = skb_headroom(skb); |
1178 | int head_copy_len, head_copy_off; | 1178 | int head_copy_len, head_copy_off; |
1179 | int off; | ||
1180 | 1179 | ||
1181 | if (!n) | 1180 | if (!n) |
1182 | return NULL; | 1181 | return NULL; |
@@ -1200,11 +1199,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb, | |||
1200 | 1199 | ||
1201 | copy_skb_header(n, skb); | 1200 | copy_skb_header(n, skb); |
1202 | 1201 | ||
1203 | off = newheadroom - oldheadroom; | 1202 | skb_headers_offset_update(n, newheadroom - oldheadroom); |
1204 | if (n->ip_summed == CHECKSUM_PARTIAL) | ||
1205 | n->csum_start += off; | ||
1206 | |||
1207 | skb_headers_offset_update(n, off); | ||
1208 | 1203 | ||
1209 | return n; | 1204 | return n; |
1210 | } | 1205 | } |
@@ -2837,14 +2832,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features) | |||
2837 | __copy_skb_header(nskb, skb); | 2832 | __copy_skb_header(nskb, skb); |
2838 | nskb->mac_len = skb->mac_len; | 2833 | nskb->mac_len = skb->mac_len; |
2839 | 2834 | ||
2840 | /* nskb and skb might have different headroom */ | 2835 | skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); |
2841 | if (nskb->ip_summed == CHECKSUM_PARTIAL) | ||
2842 | nskb->csum_start += skb_headroom(nskb) - headroom; | ||
2843 | |||
2844 | skb_reset_mac_header(nskb); | ||
2845 | skb_set_network_header(nskb, skb->mac_len); | ||
2846 | nskb->transport_header = (nskb->network_header + | ||
2847 | skb_network_header_len(skb)); | ||
2848 | 2836 | ||
2849 | skb_copy_from_linear_data_offset(skb, -tnl_hlen, | 2837 | skb_copy_from_linear_data_offset(skb, -tnl_hlen, |
2850 | nskb->data - tnl_hlen, | 2838 | nskb->data - tnl_hlen, |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4f8cd4fc451d..4049906010f7 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 | |
@@ -1290,12 +1291,15 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1290 | SKB_GSO_DODGY | | 1291 | SKB_GSO_DODGY | |
1291 | SKB_GSO_TCP_ECN | | 1292 | SKB_GSO_TCP_ECN | |
1292 | SKB_GSO_GRE | | 1293 | SKB_GSO_GRE | |
1294 | SKB_GSO_IPIP | | ||
1293 | SKB_GSO_TCPV6 | | 1295 | SKB_GSO_TCPV6 | |
1294 | SKB_GSO_UDP_TUNNEL | | 1296 | SKB_GSO_UDP_TUNNEL | |
1295 | SKB_GSO_MPLS | | 1297 | SKB_GSO_MPLS | |
1296 | 0))) | 1298 | 0))) |
1297 | goto out; | 1299 | goto out; |
1298 | 1300 | ||
1301 | skb_reset_network_header(skb); | ||
1302 | nhoff = skb_network_header(skb) - skb_mac_header(skb); | ||
1299 | if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) | 1303 | if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) |
1300 | goto out; | 1304 | goto out; |
1301 | 1305 | ||
@@ -1312,7 +1316,10 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1312 | goto out; | 1316 | goto out; |
1313 | __skb_pull(skb, ihl); | 1317 | __skb_pull(skb, ihl); |
1314 | 1318 | ||
1315 | tunnel = !!skb->encapsulation; | 1319 | tunnel = SKB_GSO_CB(skb)->encap_level > 0; |
1320 | if (tunnel) | ||
1321 | features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
1322 | SKB_GSO_CB(skb)->encap_level += ihl; | ||
1316 | 1323 | ||
1317 | skb_reset_transport_header(skb); | 1324 | skb_reset_transport_header(skb); |
1318 | 1325 | ||
@@ -1327,18 +1334,23 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1327 | 1334 | ||
1328 | skb = segs; | 1335 | skb = segs; |
1329 | do { | 1336 | do { |
1330 | iph = ip_hdr(skb); | 1337 | iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); |
1331 | if (!tunnel && proto == IPPROTO_UDP) { | 1338 | if (!tunnel && proto == IPPROTO_UDP) { |
1332 | iph->id = htons(id); | 1339 | iph->id = htons(id); |
1333 | iph->frag_off = htons(offset >> 3); | 1340 | iph->frag_off = htons(offset >> 3); |
1334 | if (skb->next != NULL) | 1341 | if (skb->next != NULL) |
1335 | iph->frag_off |= htons(IP_MF); | 1342 | iph->frag_off |= htons(IP_MF); |
1336 | offset += (skb->len - skb->mac_len - iph->ihl * 4); | 1343 | offset += skb->len - nhoff - ihl; |
1337 | } else { | 1344 | } else { |
1338 | iph->id = htons(id++); | 1345 | iph->id = htons(id++); |
1339 | } | 1346 | } |
1340 | iph->tot_len = htons(skb->len - skb->mac_len); | 1347 | iph->tot_len = htons(skb->len - nhoff); |
1341 | ip_send_check(iph); | 1348 | ip_send_check(iph); |
1349 | if (tunnel) { | ||
1350 | skb_reset_inner_headers(skb); | ||
1351 | skb->encapsulation = 1; | ||
1352 | } | ||
1353 | skb->network_header = (u8 *)iph - skb->head; | ||
1342 | } while ((skb = skb->next)); | 1354 | } while ((skb = skb->next)); |
1343 | 1355 | ||
1344 | out: | 1356 | out: |
@@ -1645,6 +1657,13 @@ static struct packet_offload ip_packet_offload __read_mostly = { | |||
1645 | }, | 1657 | }, |
1646 | }; | 1658 | }; |
1647 | 1659 | ||
1660 | static const struct net_offload ipip_offload = { | ||
1661 | .callbacks = { | ||
1662 | .gso_send_check = inet_gso_send_check, | ||
1663 | .gso_segment = inet_gso_segment, | ||
1664 | }, | ||
1665 | }; | ||
1666 | |||
1648 | static int __init ipv4_offload_init(void) | 1667 | static int __init ipv4_offload_init(void) |
1649 | { | 1668 | { |
1650 | /* | 1669 | /* |
@@ -1656,6 +1675,7 @@ static int __init ipv4_offload_init(void) | |||
1656 | pr_crit("%s: Cannot add TCP protocol offload\n", __func__); | 1675 | pr_crit("%s: Cannot add TCP protocol offload\n", __func__); |
1657 | 1676 | ||
1658 | dev_add_offload(&ip_packet_offload); | 1677 | dev_add_offload(&ip_packet_offload); |
1678 | inet_add_offload(&ipip_offload, IPPROTO_IPIP); | ||
1659 | return 0; | 1679 | return 0; |
1660 | } | 1680 | } |
1661 | 1681 | ||
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c index 736c9fc3ef93..5893e99e8299 100644 --- a/net/ipv4/gre_demux.c +++ b/net/ipv4/gre_demux.c | |||
@@ -93,35 +93,6 @@ void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, | |||
93 | } | 93 | } |
94 | EXPORT_SYMBOL_GPL(gre_build_header); | 94 | EXPORT_SYMBOL_GPL(gre_build_header); |
95 | 95 | ||
96 | struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum) | ||
97 | { | ||
98 | int err; | ||
99 | |||
100 | if (likely(!skb->encapsulation)) { | ||
101 | skb_reset_inner_headers(skb); | ||
102 | skb->encapsulation = 1; | ||
103 | } | ||
104 | |||
105 | if (skb_is_gso(skb)) { | ||
106 | err = skb_unclone(skb, GFP_ATOMIC); | ||
107 | if (unlikely(err)) | ||
108 | goto error; | ||
109 | skb_shinfo(skb)->gso_type |= SKB_GSO_GRE; | ||
110 | return skb; | ||
111 | } else if (skb->ip_summed == CHECKSUM_PARTIAL && gre_csum) { | ||
112 | err = skb_checksum_help(skb); | ||
113 | if (unlikely(err)) | ||
114 | goto error; | ||
115 | } else if (skb->ip_summed != CHECKSUM_PARTIAL) | ||
116 | skb->ip_summed = CHECKSUM_NONE; | ||
117 | |||
118 | return skb; | ||
119 | error: | ||
120 | kfree_skb(skb); | ||
121 | return ERR_PTR(err); | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(gre_handle_offloads); | ||
124 | |||
125 | static __sum16 check_checksum(struct sk_buff *skb) | 96 | static __sum16 check_checksum(struct sk_buff *skb) |
126 | { | 97 | { |
127 | __sum16 csum = 0; | 98 | __sum16 csum = 0; |
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c index 55e6bfb3a289..e5d436188464 100644 --- a/net/ipv4/gre_offload.c +++ b/net/ipv4/gre_offload.c | |||
@@ -39,7 +39,8 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | |||
39 | SKB_GSO_UDP | | 39 | SKB_GSO_UDP | |
40 | SKB_GSO_DODGY | | 40 | SKB_GSO_DODGY | |
41 | SKB_GSO_TCP_ECN | | 41 | SKB_GSO_TCP_ECN | |
42 | SKB_GSO_GRE))) | 42 | SKB_GSO_GRE | |
43 | SKB_GSO_IPIP))) | ||
43 | goto out; | 44 | goto out; |
44 | 45 | ||
45 | if (unlikely(!pskb_may_pull(skb, sizeof(*greh)))) | 46 | if (unlikely(!pskb_may_pull(skb, sizeof(*greh)))) |
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index c31e3ad98ef2..42ffbc8d65c6 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c | |||
@@ -116,3 +116,36 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto) | |||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | EXPORT_SYMBOL_GPL(iptunnel_pull_header); | 118 | EXPORT_SYMBOL_GPL(iptunnel_pull_header); |
119 | |||
120 | struct sk_buff *iptunnel_handle_offloads(struct sk_buff *skb, | ||
121 | bool csum_help, | ||
122 | int gso_type_mask) | ||
123 | { | ||
124 | int err; | ||
125 | |||
126 | if (likely(!skb->encapsulation)) { | ||
127 | skb_reset_inner_headers(skb); | ||
128 | skb->encapsulation = 1; | ||
129 | } | ||
130 | |||
131 | if (skb_is_gso(skb)) { | ||
132 | err = skb_unclone(skb, GFP_ATOMIC); | ||
133 | if (unlikely(err)) | ||
134 | goto error; | ||
135 | skb_shinfo(skb)->gso_type |= gso_type_mask; | ||
136 | return skb; | ||
137 | } | ||
138 | |||
139 | if (skb->ip_summed == CHECKSUM_PARTIAL && csum_help) { | ||
140 | err = skb_checksum_help(skb); | ||
141 | if (unlikely(err)) | ||
142 | goto error; | ||
143 | } else if (skb->ip_summed != CHECKSUM_PARTIAL) | ||
144 | skb->ip_summed = CHECKSUM_NONE; | ||
145 | |||
146 | return skb; | ||
147 | error: | ||
148 | kfree_skb(skb); | ||
149 | return ERR_PTR(err); | ||
150 | } | ||
151 | EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); | ||
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 7f80fb4b82d3..fe3e9f7f1f0b 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -220,17 +220,17 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
220 | if (unlikely(skb->protocol != htons(ETH_P_IP))) | 220 | if (unlikely(skb->protocol != htons(ETH_P_IP))) |
221 | goto tx_error; | 221 | goto tx_error; |
222 | 222 | ||
223 | if (likely(!skb->encapsulation)) { | 223 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_IPIP); |
224 | skb_reset_inner_headers(skb); | 224 | if (IS_ERR(skb)) |
225 | skb->encapsulation = 1; | 225 | goto out; |
226 | } | ||
227 | 226 | ||
228 | ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); | 227 | ip_tunnel_xmit(skb, dev, tiph, tiph->protocol); |
229 | return NETDEV_TX_OK; | 228 | return NETDEV_TX_OK; |
230 | 229 | ||
231 | tx_error: | 230 | tx_error: |
232 | dev->stats.tx_errors++; | ||
233 | dev_kfree_skb(skb); | 231 | dev_kfree_skb(skb); |
232 | out: | ||
233 | dev->stats.tx_errors++; | ||
234 | return NETDEV_TX_OK; | 234 | return NETDEV_TX_OK; |
235 | } | 235 | } |
236 | 236 | ||
@@ -275,6 +275,7 @@ static const struct net_device_ops ipip_netdev_ops = { | |||
275 | #define IPIP_FEATURES (NETIF_F_SG | \ | 275 | #define IPIP_FEATURES (NETIF_F_SG | \ |
276 | NETIF_F_FRAGLIST | \ | 276 | NETIF_F_FRAGLIST | \ |
277 | NETIF_F_HIGHDMA | \ | 277 | NETIF_F_HIGHDMA | \ |
278 | NETIF_F_GSO_SOFTWARE | \ | ||
278 | NETIF_F_HW_CSUM) | 279 | NETIF_F_HW_CSUM) |
279 | 280 | ||
280 | static void ipip_tunnel_setup(struct net_device *dev) | 281 | static void ipip_tunnel_setup(struct net_device *dev) |
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 8e3113f46ec1..dfc96b00673e 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c | |||
@@ -56,6 +56,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb, | |||
56 | SKB_GSO_TCP_ECN | | 56 | SKB_GSO_TCP_ECN | |
57 | SKB_GSO_TCPV6 | | 57 | SKB_GSO_TCPV6 | |
58 | SKB_GSO_GRE | | 58 | SKB_GSO_GRE | |
59 | SKB_GSO_IPIP | | ||
59 | SKB_GSO_MPLS | | 60 | SKB_GSO_MPLS | |
60 | SKB_GSO_UDP_TUNNEL | | 61 | SKB_GSO_UDP_TUNNEL | |
61 | 0) || | 62 | 0) || |
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index f35eccaa855e..83206de2bc76 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c | |||
@@ -52,6 +52,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | |||
52 | 52 | ||
53 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | | 53 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | |
54 | SKB_GSO_UDP_TUNNEL | | 54 | SKB_GSO_UDP_TUNNEL | |
55 | SKB_GSO_IPIP | | ||
55 | SKB_GSO_GRE | SKB_GSO_MPLS) || | 56 | SKB_GSO_GRE | SKB_GSO_MPLS) || |
56 | !(type & (SKB_GSO_UDP)))) | 57 | !(type & (SKB_GSO_UDP)))) |
57 | goto out; | 58 | goto out; |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index b405fba91c72..5c2fc1d04196 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -96,6 +96,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | |||
96 | SKB_GSO_DODGY | | 96 | SKB_GSO_DODGY | |
97 | SKB_GSO_TCP_ECN | | 97 | SKB_GSO_TCP_ECN | |
98 | SKB_GSO_GRE | | 98 | SKB_GSO_GRE | |
99 | SKB_GSO_IPIP | | ||
99 | SKB_GSO_UDP_TUNNEL | | 100 | SKB_GSO_UDP_TUNNEL | |
100 | SKB_GSO_MPLS | | 101 | SKB_GSO_MPLS | |
101 | SKB_GSO_TCPV6 | | 102 | SKB_GSO_TCPV6 | |
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 60559511bd9c..f63780ff3732 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c | |||
@@ -64,6 +64,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
64 | SKB_GSO_DODGY | | 64 | SKB_GSO_DODGY | |
65 | SKB_GSO_UDP_TUNNEL | | 65 | SKB_GSO_UDP_TUNNEL | |
66 | SKB_GSO_GRE | | 66 | SKB_GSO_GRE | |
67 | SKB_GSO_IPIP | | ||
67 | SKB_GSO_MPLS) || | 68 | SKB_GSO_MPLS) || |
68 | !(type & (SKB_GSO_UDP)))) | 69 | !(type & (SKB_GSO_UDP)))) |
69 | goto out; | 70 | goto out; |
diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c index 1bec1219ab81..851cd880b0c0 100644 --- a/net/mpls/mpls_gso.c +++ b/net/mpls/mpls_gso.c | |||
@@ -33,6 +33,7 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb, | |||
33 | SKB_GSO_DODGY | | 33 | SKB_GSO_DODGY | |
34 | SKB_GSO_TCP_ECN | | 34 | SKB_GSO_TCP_ECN | |
35 | SKB_GSO_GRE | | 35 | SKB_GSO_GRE | |
36 | SKB_GSO_IPIP | | ||
36 | SKB_GSO_MPLS))) | 37 | SKB_GSO_MPLS))) |
37 | goto out; | 38 | goto out; |
38 | 39 | ||