aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netdev_features.h3
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--include/linux/skbuff.h20
-rw-r--r--net/core/dev.c34
-rw-r--r--net/core/ethtool.c1
-rw-r--r--net/ipv4/af_inet.c19
-rw-r--r--net/ipv4/gre_offload.c1
-rw-r--r--net/ipv4/tcp_offload.c4
-rw-r--r--net/ipv6/ip6_offload.c3
-rw-r--r--net/mpls/mpls_gso.c1
10 files changed, 63 insertions, 24 deletions
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index a734bf43d190..7cf272a4b5c8 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -39,6 +39,7 @@ enum {
39 NETIF_F_UFO_BIT, /* ... UDPv4 fragmentation */ 39 NETIF_F_UFO_BIT, /* ... UDPv4 fragmentation */
40 NETIF_F_GSO_ROBUST_BIT, /* ... ->SKB_GSO_DODGY */ 40 NETIF_F_GSO_ROBUST_BIT, /* ... ->SKB_GSO_DODGY */
41 NETIF_F_TSO_ECN_BIT, /* ... TCP ECN support */ 41 NETIF_F_TSO_ECN_BIT, /* ... TCP ECN support */
42 NETIF_F_TSO_MANGLEID_BIT, /* ... IPV4 ID mangling allowed */
42 NETIF_F_TSO6_BIT, /* ... TCPv6 segmentation */ 43 NETIF_F_TSO6_BIT, /* ... TCPv6 segmentation */
43 NETIF_F_FSO_BIT, /* ... FCoE segmentation */ 44 NETIF_F_FSO_BIT, /* ... FCoE segmentation */
44 NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */ 45 NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */
@@ -120,6 +121,7 @@ enum {
120#define NETIF_F_GSO_SIT __NETIF_F(GSO_SIT) 121#define NETIF_F_GSO_SIT __NETIF_F(GSO_SIT)
121#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) 122#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL)
122#define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM) 123#define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM)
124#define NETIF_F_TSO_MANGLEID __NETIF_F(TSO_MANGLEID)
123#define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM) 125#define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM)
124#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) 126#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
125#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) 127#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
@@ -147,6 +149,7 @@ enum {
147 149
148/* List of features with software fallbacks. */ 150/* List of features with software fallbacks. */
149#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \ 151#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | \
152 NETIF_F_TSO_MANGLEID | \
150 NETIF_F_TSO6 | NETIF_F_UFO) 153 NETIF_F_TSO6 | NETIF_F_UFO)
151 154
152/* List of IP checksum features. Note that NETIF_F_ HW_CSUM should not be 155/* List of IP checksum features. Note that NETIF_F_ HW_CSUM should not be
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9884fe9a6552..8e372d01b3c1 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3992,6 +3992,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
3992 BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_UFO >> NETIF_F_GSO_SHIFT)); 3992 BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_UFO >> NETIF_F_GSO_SHIFT));
3993 BUILD_BUG_ON(SKB_GSO_DODGY != (NETIF_F_GSO_ROBUST >> NETIF_F_GSO_SHIFT)); 3993 BUILD_BUG_ON(SKB_GSO_DODGY != (NETIF_F_GSO_ROBUST >> NETIF_F_GSO_SHIFT));
3994 BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT)); 3994 BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT));
3995 BUILD_BUG_ON(SKB_GSO_TCP_FIXEDID != (NETIF_F_TSO_MANGLEID >> NETIF_F_GSO_SHIFT));
3995 BUILD_BUG_ON(SKB_GSO_TCPV6 != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT)); 3996 BUILD_BUG_ON(SKB_GSO_TCPV6 != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT));
3996 BUILD_BUG_ON(SKB_GSO_FCOE != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT)); 3997 BUILD_BUG_ON(SKB_GSO_FCOE != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT));
3997 BUILD_BUG_ON(SKB_GSO_GRE != (NETIF_F_GSO_GRE >> NETIF_F_GSO_SHIFT)); 3998 BUILD_BUG_ON(SKB_GSO_GRE != (NETIF_F_GSO_GRE >> NETIF_F_GSO_SHIFT));
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 007381270ff8..5fba16658f9d 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -465,23 +465,25 @@ enum {
465 /* This indicates the tcp segment has CWR set. */ 465 /* This indicates the tcp segment has CWR set. */
466 SKB_GSO_TCP_ECN = 1 << 3, 466 SKB_GSO_TCP_ECN = 1 << 3,
467 467
468 SKB_GSO_TCPV6 = 1 << 4, 468 SKB_GSO_TCP_FIXEDID = 1 << 4,
469 469
470 SKB_GSO_FCOE = 1 << 5, 470 SKB_GSO_TCPV6 = 1 << 5,
471 471
472 SKB_GSO_GRE = 1 << 6, 472 SKB_GSO_FCOE = 1 << 6,
473 473
474 SKB_GSO_GRE_CSUM = 1 << 7, 474 SKB_GSO_GRE = 1 << 7,
475 475
476 SKB_GSO_IPIP = 1 << 8, 476 SKB_GSO_GRE_CSUM = 1 << 8,
477 477
478 SKB_GSO_SIT = 1 << 9, 478 SKB_GSO_IPIP = 1 << 9,
479 479
480 SKB_GSO_UDP_TUNNEL = 1 << 10, 480 SKB_GSO_SIT = 1 << 10,
481 481
482 SKB_GSO_UDP_TUNNEL_CSUM = 1 << 11, 482 SKB_GSO_UDP_TUNNEL = 1 << 11,
483 483
484 SKB_GSO_TUNNEL_REMCSUM = 1 << 12, 484 SKB_GSO_UDP_TUNNEL_CSUM = 1 << 12,
485
486 SKB_GSO_TUNNEL_REMCSUM = 1 << 13,
485}; 487};
486 488
487#if BITS_PER_LONG > 32 489#if BITS_PER_LONG > 32
diff --git a/net/core/dev.c b/net/core/dev.c
index 09fb1ace9dc8..e896b1953ab6 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2825,14 +2825,36 @@ static netdev_features_t dflt_features_check(const struct sk_buff *skb,
2825 return vlan_features_check(skb, features); 2825 return vlan_features_check(skb, features);
2826} 2826}
2827 2827
2828static netdev_features_t gso_features_check(const struct sk_buff *skb,
2829 struct net_device *dev,
2830 netdev_features_t features)
2831{
2832 u16 gso_segs = skb_shinfo(skb)->gso_segs;
2833
2834 if (gso_segs > dev->gso_max_segs)
2835 return features & ~NETIF_F_GSO_MASK;
2836
2837 /* Make sure to clear the IPv4 ID mangling feature if
2838 * the IPv4 header has the potential to be fragmented.
2839 */
2840 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
2841 struct iphdr *iph = skb->encapsulation ?
2842 inner_ip_hdr(skb) : ip_hdr(skb);
2843
2844 if (!(iph->frag_off & htons(IP_DF)))
2845 features &= ~NETIF_F_TSO_MANGLEID;
2846 }
2847
2848 return features;
2849}
2850
2828netdev_features_t netif_skb_features(struct sk_buff *skb) 2851netdev_features_t netif_skb_features(struct sk_buff *skb)
2829{ 2852{
2830 struct net_device *dev = skb->dev; 2853 struct net_device *dev = skb->dev;
2831 netdev_features_t features = dev->features; 2854 netdev_features_t features = dev->features;
2832 u16 gso_segs = skb_shinfo(skb)->gso_segs;
2833 2855
2834 if (gso_segs > dev->gso_max_segs) 2856 if (skb_is_gso(skb))
2835 features &= ~NETIF_F_GSO_MASK; 2857 features = gso_features_check(skb, dev, features);
2836 2858
2837 /* If encapsulation offload request, verify we are testing 2859 /* If encapsulation offload request, verify we are testing
2838 * hardware encapsulation features instead of standard 2860 * hardware encapsulation features instead of standard
@@ -6976,9 +6998,11 @@ int register_netdevice(struct net_device *dev)
6976 dev->features |= NETIF_F_SOFT_FEATURES; 6998 dev->features |= NETIF_F_SOFT_FEATURES;
6977 dev->wanted_features = dev->features & dev->hw_features; 6999 dev->wanted_features = dev->features & dev->hw_features;
6978 7000
6979 if (!(dev->flags & IFF_LOOPBACK)) { 7001 if (!(dev->flags & IFF_LOOPBACK))
6980 dev->hw_features |= NETIF_F_NOCACHE_COPY; 7002 dev->hw_features |= NETIF_F_NOCACHE_COPY;
6981 } 7003
7004 if (dev->hw_features & NETIF_F_TSO)
7005 dev->hw_features |= NETIF_F_TSO_MANGLEID;
6982 7006
6983 /* Make NETIF_F_HIGHDMA inheritable to VLAN devices. 7007 /* Make NETIF_F_HIGHDMA inheritable to VLAN devices.
6984 */ 7008 */
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 6a7f99661c2f..9494c41cc77c 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -79,6 +79,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
79 [NETIF_F_UFO_BIT] = "tx-udp-fragmentation", 79 [NETIF_F_UFO_BIT] = "tx-udp-fragmentation",
80 [NETIF_F_GSO_ROBUST_BIT] = "tx-gso-robust", 80 [NETIF_F_GSO_ROBUST_BIT] = "tx-gso-robust",
81 [NETIF_F_TSO_ECN_BIT] = "tx-tcp-ecn-segmentation", 81 [NETIF_F_TSO_ECN_BIT] = "tx-tcp-ecn-segmentation",
82 [NETIF_F_TSO_MANGLEID_BIT] = "tx-tcp-mangleid-segmentation",
82 [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation", 83 [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation",
83 [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", 84 [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
84 [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", 85 [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation",
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 8217cd22f921..5bbea9a0ce96 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1195,10 +1195,10 @@ EXPORT_SYMBOL(inet_sk_rebuild_header);
1195static struct sk_buff *inet_gso_segment(struct sk_buff *skb, 1195static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
1196 netdev_features_t features) 1196 netdev_features_t features)
1197{ 1197{
1198 bool udpfrag = false, fixedid = false, encap;
1198 struct sk_buff *segs = ERR_PTR(-EINVAL); 1199 struct sk_buff *segs = ERR_PTR(-EINVAL);
1199 const struct net_offload *ops; 1200 const struct net_offload *ops;
1200 unsigned int offset = 0; 1201 unsigned int offset = 0;
1201 bool udpfrag, encap;
1202 struct iphdr *iph; 1202 struct iphdr *iph;
1203 int proto; 1203 int proto;
1204 int nhoff; 1204 int nhoff;
@@ -1217,6 +1217,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
1217 SKB_GSO_TCPV6 | 1217 SKB_GSO_TCPV6 |
1218 SKB_GSO_UDP_TUNNEL | 1218 SKB_GSO_UDP_TUNNEL |
1219 SKB_GSO_UDP_TUNNEL_CSUM | 1219 SKB_GSO_UDP_TUNNEL_CSUM |
1220 SKB_GSO_TCP_FIXEDID |
1220 SKB_GSO_TUNNEL_REMCSUM | 1221 SKB_GSO_TUNNEL_REMCSUM |
1221 0))) 1222 0)))
1222 goto out; 1223 goto out;
@@ -1248,11 +1249,14 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
1248 1249
1249 segs = ERR_PTR(-EPROTONOSUPPORT); 1250 segs = ERR_PTR(-EPROTONOSUPPORT);
1250 1251
1251 if (skb->encapsulation && 1252 if (!skb->encapsulation || encap) {
1252 skb_shinfo(skb)->gso_type & (SKB_GSO_SIT|SKB_GSO_IPIP)) 1253 udpfrag = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP);
1253 udpfrag = proto == IPPROTO_UDP && encap; 1254 fixedid = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID);
1254 else 1255
1255 udpfrag = proto == IPPROTO_UDP && !skb->encapsulation; 1256 /* fixed ID is invalid if DF bit is not set */
1257 if (fixedid && !(iph->frag_off & htons(IP_DF)))
1258 goto out;
1259 }
1256 1260
1257 ops = rcu_dereference(inet_offloads[proto]); 1261 ops = rcu_dereference(inet_offloads[proto]);
1258 if (likely(ops && ops->callbacks.gso_segment)) 1262 if (likely(ops && ops->callbacks.gso_segment))
@@ -1265,12 +1269,11 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
1265 do { 1269 do {
1266 iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); 1270 iph = (struct iphdr *)(skb_mac_header(skb) + nhoff);
1267 if (udpfrag) { 1271 if (udpfrag) {
1268 iph->id = htons(id);
1269 iph->frag_off = htons(offset >> 3); 1272 iph->frag_off = htons(offset >> 3);
1270 if (skb->next) 1273 if (skb->next)
1271 iph->frag_off |= htons(IP_MF); 1274 iph->frag_off |= htons(IP_MF);
1272 offset += skb->len - nhoff - ihl; 1275 offset += skb->len - nhoff - ihl;
1273 } else { 1276 } else if (!fixedid) {
1274 iph->id = htons(id++); 1277 iph->id = htons(id++);
1275 } 1278 }
1276 iph->tot_len = htons(skb->len - nhoff); 1279 iph->tot_len = htons(skb->len - nhoff);
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c
index 6a5bd4317866..6376b0cdf693 100644
--- a/net/ipv4/gre_offload.c
+++ b/net/ipv4/gre_offload.c
@@ -32,6 +32,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
32 SKB_GSO_UDP | 32 SKB_GSO_UDP |
33 SKB_GSO_DODGY | 33 SKB_GSO_DODGY |
34 SKB_GSO_TCP_ECN | 34 SKB_GSO_TCP_ECN |
35 SKB_GSO_TCP_FIXEDID |
35 SKB_GSO_GRE | 36 SKB_GSO_GRE |
36 SKB_GSO_GRE_CSUM | 37 SKB_GSO_GRE_CSUM |
37 SKB_GSO_IPIP | 38 SKB_GSO_IPIP |
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index 773083b7f1e9..08dd25d835af 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -89,6 +89,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
89 ~(SKB_GSO_TCPV4 | 89 ~(SKB_GSO_TCPV4 |
90 SKB_GSO_DODGY | 90 SKB_GSO_DODGY |
91 SKB_GSO_TCP_ECN | 91 SKB_GSO_TCP_ECN |
92 SKB_GSO_TCP_FIXEDID |
92 SKB_GSO_TCPV6 | 93 SKB_GSO_TCPV6 |
93 SKB_GSO_GRE | 94 SKB_GSO_GRE |
94 SKB_GSO_GRE_CSUM | 95 SKB_GSO_GRE_CSUM |
@@ -98,7 +99,8 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
98 SKB_GSO_UDP_TUNNEL_CSUM | 99 SKB_GSO_UDP_TUNNEL_CSUM |
99 SKB_GSO_TUNNEL_REMCSUM | 100 SKB_GSO_TUNNEL_REMCSUM |
100 0) || 101 0) ||
101 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) 102 !(type & (SKB_GSO_TCPV4 |
103 SKB_GSO_TCPV6))))
102 goto out; 104 goto out;
103 105
104 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); 106 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 204af2219471..b3a779393d71 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -73,6 +73,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
73 SKB_GSO_UDP | 73 SKB_GSO_UDP |
74 SKB_GSO_DODGY | 74 SKB_GSO_DODGY |
75 SKB_GSO_TCP_ECN | 75 SKB_GSO_TCP_ECN |
76 SKB_GSO_TCP_FIXEDID |
77 SKB_GSO_TCPV6 |
76 SKB_GSO_GRE | 78 SKB_GSO_GRE |
77 SKB_GSO_GRE_CSUM | 79 SKB_GSO_GRE_CSUM |
78 SKB_GSO_IPIP | 80 SKB_GSO_IPIP |
@@ -80,7 +82,6 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
80 SKB_GSO_UDP_TUNNEL | 82 SKB_GSO_UDP_TUNNEL |
81 SKB_GSO_UDP_TUNNEL_CSUM | 83 SKB_GSO_UDP_TUNNEL_CSUM |
82 SKB_GSO_TUNNEL_REMCSUM | 84 SKB_GSO_TUNNEL_REMCSUM |
83 SKB_GSO_TCPV6 |
84 0))) 85 0)))
85 goto out; 86 goto out;
86 87
diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c
index 0183b32da942..bbcf60465e5c 100644
--- a/net/mpls/mpls_gso.c
+++ b/net/mpls/mpls_gso.c
@@ -31,6 +31,7 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,
31 SKB_GSO_TCPV6 | 31 SKB_GSO_TCPV6 |
32 SKB_GSO_UDP | 32 SKB_GSO_UDP |
33 SKB_GSO_DODGY | 33 SKB_GSO_DODGY |
34 SKB_GSO_TCP_FIXEDID |
34 SKB_GSO_TCP_ECN))) 35 SKB_GSO_TCP_ECN)))
35 goto out; 36 goto out;
36 37