1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IPV6 GSO/GRO offload support
4 * Linux INET6 implementation
7 #include <linux/kernel.h>
8 #include <linux/socket.h>
9 #include <linux/netdevice.h>
10 #include <linux/skbuff.h>
11 #include <linux/printk.h>
13 #include <net/protocol.h>
15 #include <net/inet_common.h>
21 #include "ip6_offload.h"
23 /* All GRO functions are always builtin, except UDP over ipv6, which lays in
24 * ipv6 module, as it depends on UDPv6 lookup function, so we need special care
25 * when ipv6 is built as a module
27 #if IS_BUILTIN(CONFIG_IPV6)
28 #define INDIRECT_CALL_L4(f, f2, f1, ...) INDIRECT_CALL_2(f, f2, f1, __VA_ARGS__)
30 #define INDIRECT_CALL_L4(f, f2, f1, ...) INDIRECT_CALL_1(f, f2, __VA_ARGS__)
33 #define indirect_call_gro_receive_l4(f2, f1, cb, head, skb) \
35 unlikely(gro_recursion_inc_test(skb)) ? \
36 NAPI_GRO_CB(skb)->flush |= 1, NULL : \
37 INDIRECT_CALL_L4(cb, f2, f1, head, skb); \
40 static int ipv6_gro_pull_exthdrs(struct sk_buff
*skb
, int off
, int proto
)
42 const struct net_offload
*ops
= NULL
;
43 struct ipv6_opt_hdr
*opth
;
48 ops
= rcu_dereference(inet6_offloads
[proto
]);
53 if (!(ops
->flags
& INET6_PROTO_GSO_EXTHDR
))
56 opth
= skb_gro_header(skb
, off
+ sizeof(*opth
), off
);
60 len
= ipv6_optlen(opth
);
62 opth
= skb_gro_header(skb
, off
+ len
, off
);
65 proto
= opth
->nexthdr
;
70 skb_gro_pull(skb
, off
- skb_gro_receive_network_offset(skb
));
74 static int ipv6_gso_pull_exthdrs(struct sk_buff
*skb
, int proto
)
76 const struct net_offload
*ops
= NULL
;
79 struct ipv6_opt_hdr
*opth
;
82 ops
= rcu_dereference(inet6_offloads
[proto
]);
87 if (!(ops
->flags
& INET6_PROTO_GSO_EXTHDR
))
90 if (unlikely(!pskb_may_pull(skb
, 8)))
93 opth
= (void *)skb
->data
;
94 len
= ipv6_optlen(opth
);
96 if (unlikely(!pskb_may_pull(skb
, len
)))
99 opth
= (void *)skb
->data
;
100 proto
= opth
->nexthdr
;
101 __skb_pull(skb
, len
);
107 static struct sk_buff
*ipv6_gso_segment(struct sk_buff
*skb
,
108 netdev_features_t features
)
110 struct sk_buff
*segs
= ERR_PTR(-EINVAL
);
111 struct ipv6hdr
*ipv6h
;
112 const struct net_offload
*ops
;
114 struct frag_hdr
*fptr
;
115 unsigned int payload_len
;
122 skb_reset_network_header(skb
);
123 err
= ipv6_hopopt_jumbo_remove(skb
);
126 nhoff
= skb_network_header(skb
) - skb_mac_header(skb
);
127 if (unlikely(!pskb_may_pull(skb
, sizeof(*ipv6h
))))
130 encap
= SKB_GSO_CB(skb
)->encap_level
> 0;
132 features
&= skb
->dev
->hw_enc_features
;
133 SKB_GSO_CB(skb
)->encap_level
+= sizeof(*ipv6h
);
135 ipv6h
= ipv6_hdr(skb
);
136 __skb_pull(skb
, sizeof(*ipv6h
));
137 segs
= ERR_PTR(-EPROTONOSUPPORT
);
139 proto
= ipv6_gso_pull_exthdrs(skb
, ipv6h
->nexthdr
);
141 if (skb
->encapsulation
&&
142 skb_shinfo(skb
)->gso_type
& (SKB_GSO_IPXIP4
| SKB_GSO_IPXIP6
))
143 udpfrag
= proto
== IPPROTO_UDP
&& encap
&&
144 (skb_shinfo(skb
)->gso_type
& SKB_GSO_UDP
);
146 udpfrag
= proto
== IPPROTO_UDP
&& !skb
->encapsulation
&&
147 (skb_shinfo(skb
)->gso_type
& SKB_GSO_UDP
);
149 ops
= rcu_dereference(inet6_offloads
[proto
]);
150 if (likely(ops
&& ops
->callbacks
.gso_segment
)) {
151 skb_reset_transport_header(skb
);
152 segs
= ops
->callbacks
.gso_segment(skb
, features
);
154 skb
->network_header
= skb_mac_header(skb
) + nhoff
- skb
->head
;
157 if (IS_ERR_OR_NULL(segs
))
160 gso_partial
= !!(skb_shinfo(segs
)->gso_type
& SKB_GSO_PARTIAL
);
162 for (skb
= segs
; skb
; skb
= skb
->next
) {
163 ipv6h
= (struct ipv6hdr
*)(skb_mac_header(skb
) + nhoff
);
164 if (gso_partial
&& skb_is_gso(skb
))
165 payload_len
= skb_shinfo(skb
)->gso_size
+
166 SKB_GSO_CB(skb
)->data_offset
+
167 skb
->head
- (unsigned char *)(ipv6h
+ 1);
169 payload_len
= skb
->len
- nhoff
- sizeof(*ipv6h
);
170 ipv6h
->payload_len
= htons(payload_len
);
171 skb
->network_header
= (u8
*)ipv6h
- skb
->head
;
172 skb_reset_mac_len(skb
);
175 int err
= ip6_find_1stfragopt(skb
, &prevhdr
);
177 kfree_skb_list(segs
);
180 fptr
= (struct frag_hdr
*)((u8
*)ipv6h
+ err
);
181 fptr
->frag_off
= htons(offset
);
183 fptr
->frag_off
|= htons(IP6_MF
);
184 offset
+= (ntohs(ipv6h
->payload_len
) -
185 sizeof(struct frag_hdr
));
188 skb_reset_inner_headers(skb
);
195 /* Return the total length of all the extension hdrs, following the same
196 * logic in ipv6_gso_pull_exthdrs() when parsing ext-hdrs.
198 static int ipv6_exthdrs_len(struct ipv6hdr
*iph
,
199 const struct net_offload
**opps
)
201 struct ipv6_opt_hdr
*opth
= (void *)iph
;
202 int len
= 0, proto
, optlen
= sizeof(*iph
);
204 proto
= iph
->nexthdr
;
206 *opps
= rcu_dereference(inet6_offloads
[proto
]);
207 if (unlikely(!(*opps
)))
209 if (!((*opps
)->flags
& INET6_PROTO_GSO_EXTHDR
))
212 opth
= (void *)opth
+ optlen
;
213 optlen
= ipv6_optlen(opth
);
215 proto
= opth
->nexthdr
;
220 INDIRECT_CALLABLE_SCOPE
struct sk_buff
*ipv6_gro_receive(struct list_head
*head
,
223 const struct net_offload
*ops
;
224 struct sk_buff
*pp
= NULL
;
233 off
= skb_gro_offset(skb
);
234 hlen
= off
+ sizeof(*iph
);
235 iph
= skb_gro_header(skb
, hlen
, off
);
239 NAPI_GRO_CB(skb
)->network_offsets
[NAPI_GRO_CB(skb
)->encap_mark
] = off
;
241 flush
+= ntohs(iph
->payload_len
) != skb
->len
- hlen
;
243 proto
= iph
->nexthdr
;
244 ops
= rcu_dereference(inet6_offloads
[proto
]);
245 if (!ops
|| !ops
->callbacks
.gro_receive
) {
246 proto
= ipv6_gro_pull_exthdrs(skb
, hlen
, proto
);
248 ops
= rcu_dereference(inet6_offloads
[proto
]);
249 if (!ops
|| !ops
->callbacks
.gro_receive
)
252 iph
= skb_gro_network_header(skb
);
254 skb_gro_pull(skb
, sizeof(*iph
));
257 skb_set_transport_header(skb
, skb_gro_offset(skb
));
259 NAPI_GRO_CB(skb
)->proto
= proto
;
262 nlen
= skb_gro_offset(skb
) - off
;
264 list_for_each_entry(p
, head
, list
) {
265 const struct ipv6hdr
*iph2
;
266 __be32 first_word
; /* <Version:4><Traffic_Class:8><Flow_Label:20> */
268 if (!NAPI_GRO_CB(p
)->same_flow
)
271 iph2
= (struct ipv6hdr
*)(p
->data
+ off
);
272 first_word
= *(__be32
*)iph
^ *(__be32
*)iph2
;
274 /* All fields must match except length and Traffic Class.
275 * XXX skbs on the gro_list have all been parsed and pulled
276 * already so we don't need to compare nlen
277 * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops)))
278 * memcmp() alone below is sufficient, right?
280 if ((first_word
& htonl(0xF00FFFFF)) ||
281 !ipv6_addr_equal(&iph
->saddr
, &iph2
->saddr
) ||
282 !ipv6_addr_equal(&iph
->daddr
, &iph2
->daddr
) ||
283 iph
->nexthdr
!= iph2
->nexthdr
) {
285 NAPI_GRO_CB(p
)->same_flow
= 0;
288 if (unlikely(nlen
> sizeof(struct ipv6hdr
))) {
289 if (memcmp(iph
+ 1, iph2
+ 1,
290 nlen
- sizeof(struct ipv6hdr
)))
295 NAPI_GRO_CB(skb
)->flush
|= flush
;
297 skb_gro_postpull_rcsum(skb
, iph
, nlen
);
299 pp
= indirect_call_gro_receive_l4(tcp6_gro_receive
, udp6_gro_receive
,
300 ops
->callbacks
.gro_receive
, head
, skb
);
303 skb_gro_flush_final(skb
, pp
, flush
);
308 static struct sk_buff
*sit_ip6ip6_gro_receive(struct list_head
*head
,
311 /* Common GRO receive for SIT and IP6IP6 */
313 if (NAPI_GRO_CB(skb
)->encap_mark
) {
314 NAPI_GRO_CB(skb
)->flush
= 1;
318 NAPI_GRO_CB(skb
)->encap_mark
= 1;
320 return ipv6_gro_receive(head
, skb
);
323 static struct sk_buff
*ip4ip6_gro_receive(struct list_head
*head
,
326 /* Common GRO receive for SIT and IP6IP6 */
328 if (NAPI_GRO_CB(skb
)->encap_mark
) {
329 NAPI_GRO_CB(skb
)->flush
= 1;
333 NAPI_GRO_CB(skb
)->encap_mark
= 1;
335 return inet_gro_receive(head
, skb
);
338 INDIRECT_CALLABLE_SCOPE
int ipv6_gro_complete(struct sk_buff
*skb
, int nhoff
)
340 const struct net_offload
*ops
;
345 if (skb
->encapsulation
) {
346 skb_set_inner_protocol(skb
, cpu_to_be16(ETH_P_IPV6
));
347 skb_set_inner_network_header(skb
, nhoff
);
350 payload_len
= skb
->len
- nhoff
- sizeof(*iph
);
351 if (unlikely(payload_len
> IPV6_MAXPLEN
)) {
352 struct hop_jumbo_hdr
*hop_jumbo
;
353 int hoplen
= sizeof(*hop_jumbo
);
355 /* Move network header left */
356 memmove(skb_mac_header(skb
) - hoplen
, skb_mac_header(skb
),
357 skb
->transport_header
- skb
->mac_header
);
360 skb
->mac_header
-= hoplen
;
361 skb
->network_header
-= hoplen
;
362 iph
= (struct ipv6hdr
*)(skb
->data
+ nhoff
);
363 hop_jumbo
= (struct hop_jumbo_hdr
*)(iph
+ 1);
365 /* Build hop-by-hop options */
366 hop_jumbo
->nexthdr
= iph
->nexthdr
;
367 hop_jumbo
->hdrlen
= 0;
368 hop_jumbo
->tlv_type
= IPV6_TLV_JUMBO
;
369 hop_jumbo
->tlv_len
= 4;
370 hop_jumbo
->jumbo_payload_len
= htonl(payload_len
+ hoplen
);
372 iph
->nexthdr
= NEXTHDR_HOP
;
373 iph
->payload_len
= 0;
375 iph
= (struct ipv6hdr
*)(skb
->data
+ nhoff
);
376 iph
->payload_len
= htons(payload_len
);
379 nhoff
+= sizeof(*iph
) + ipv6_exthdrs_len(iph
, &ops
);
380 if (WARN_ON(!ops
|| !ops
->callbacks
.gro_complete
))
383 err
= INDIRECT_CALL_L4(ops
->callbacks
.gro_complete
, tcp6_gro_complete
,
384 udp6_gro_complete
, skb
, nhoff
);
390 static int sit_gro_complete(struct sk_buff
*skb
, int nhoff
)
392 skb
->encapsulation
= 1;
393 skb_shinfo(skb
)->gso_type
|= SKB_GSO_IPXIP4
;
394 return ipv6_gro_complete(skb
, nhoff
);
397 static int ip6ip6_gro_complete(struct sk_buff
*skb
, int nhoff
)
399 skb
->encapsulation
= 1;
400 skb_shinfo(skb
)->gso_type
|= SKB_GSO_IPXIP6
;
401 return ipv6_gro_complete(skb
, nhoff
);
404 static int ip4ip6_gro_complete(struct sk_buff
*skb
, int nhoff
)
406 skb
->encapsulation
= 1;
407 skb_shinfo(skb
)->gso_type
|= SKB_GSO_IPXIP6
;
408 return inet_gro_complete(skb
, nhoff
);
412 static struct sk_buff
*sit_gso_segment(struct sk_buff
*skb
,
413 netdev_features_t features
)
415 if (!(skb_shinfo(skb
)->gso_type
& SKB_GSO_IPXIP4
))
416 return ERR_PTR(-EINVAL
);
418 return ipv6_gso_segment(skb
, features
);
421 static struct sk_buff
*ip4ip6_gso_segment(struct sk_buff
*skb
,
422 netdev_features_t features
)
424 if (!(skb_shinfo(skb
)->gso_type
& SKB_GSO_IPXIP6
))
425 return ERR_PTR(-EINVAL
);
427 return inet_gso_segment(skb
, features
);
430 static struct sk_buff
*ip6ip6_gso_segment(struct sk_buff
*skb
,
431 netdev_features_t features
)
433 if (!(skb_shinfo(skb
)->gso_type
& SKB_GSO_IPXIP6
))
434 return ERR_PTR(-EINVAL
);
436 return ipv6_gso_segment(skb
, features
);
439 static const struct net_offload sit_offload
= {
441 .gso_segment
= sit_gso_segment
,
442 .gro_receive
= sit_ip6ip6_gro_receive
,
443 .gro_complete
= sit_gro_complete
,
447 static const struct net_offload ip4ip6_offload
= {
449 .gso_segment
= ip4ip6_gso_segment
,
450 .gro_receive
= ip4ip6_gro_receive
,
451 .gro_complete
= ip4ip6_gro_complete
,
455 static const struct net_offload ip6ip6_offload
= {
457 .gso_segment
= ip6ip6_gso_segment
,
458 .gro_receive
= sit_ip6ip6_gro_receive
,
459 .gro_complete
= ip6ip6_gro_complete
,
462 static int __init
ipv6_offload_init(void)
465 if (tcpv6_offload_init() < 0)
466 pr_crit("%s: Cannot add TCP protocol offload\n", __func__
);
467 if (ipv6_exthdrs_offload_init() < 0)
468 pr_crit("%s: Cannot add EXTHDRS protocol offload\n", __func__
);
470 net_hotdata
.ipv6_packet_offload
= (struct packet_offload
) {
471 .type
= cpu_to_be16(ETH_P_IPV6
),
473 .gso_segment
= ipv6_gso_segment
,
474 .gro_receive
= ipv6_gro_receive
,
475 .gro_complete
= ipv6_gro_complete
,
478 dev_add_offload(&net_hotdata
.ipv6_packet_offload
);
480 inet_add_offload(&sit_offload
, IPPROTO_IPV6
);
481 inet6_add_offload(&ip6ip6_offload
, IPPROTO_IPV6
);
482 inet6_add_offload(&ip4ip6_offload
, IPPROTO_IPIP
);
487 fs_initcall(ipv6_offload_init
);