hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/net/ipv6/ip6_offload.c
....@@ -1,11 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * IPV6 GSO/GRO offload support
34 * Linux INET6 implementation
4
- *
5
- * This program is free software; you can redistribute it and/or
6
- * modify it under the terms of the GNU General Public License
7
- * as published by the Free Software Foundation; either version
8
- * 2 of the License, or (at your option) any later version.
95 */
106
117 #include <linux/kernel.h>
....@@ -17,8 +13,27 @@
1713 #include <net/protocol.h>
1814 #include <net/ipv6.h>
1915 #include <net/inet_common.h>
16
+#include <net/tcp.h>
17
+#include <net/udp.h>
2018
2119 #include "ip6_offload.h"
20
+
21
+/* All GRO functions are always builtin, except UDP over ipv6, which lays in
22
+ * ipv6 module, as it depends on UDPv6 lookup function, so we need special care
23
+ * when ipv6 is built as a module
24
+ */
25
+#if IS_BUILTIN(CONFIG_IPV6)
26
+#define INDIRECT_CALL_L4(f, f2, f1, ...) INDIRECT_CALL_2(f, f2, f1, __VA_ARGS__)
27
+#else
28
+#define INDIRECT_CALL_L4(f, f2, f1, ...) INDIRECT_CALL_1(f, f2, __VA_ARGS__)
29
+#endif
30
+
31
+#define indirect_call_gro_receive_l4(f2, f1, cb, head, skb) \
32
+({ \
33
+ unlikely(gro_recursion_inc_test(skb)) ? \
34
+ NAPI_GRO_CB(skb)->flush |= 1, NULL : \
35
+ INDIRECT_CALL_L4(cb, f2, f1, head, skb); \
36
+})
2237
2338 static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
2439 {
....@@ -166,8 +181,8 @@
166181 return len;
167182 }
168183
169
-static struct sk_buff *ipv6_gro_receive(struct list_head *head,
170
- struct sk_buff *skb)
184
+INDIRECT_CALLABLE_SCOPE struct sk_buff *ipv6_gro_receive(struct list_head *head,
185
+ struct sk_buff *skb)
171186 {
172187 const struct net_offload *ops;
173188 struct sk_buff *pp = NULL;
....@@ -231,13 +246,20 @@
231246 * XXX skbs on the gro_list have all been parsed and pulled
232247 * already so we don't need to compare nlen
233248 * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops)))
234
- * memcmp() alone below is suffcient, right?
249
+ * memcmp() alone below is sufficient, right?
235250 */
236251 if ((first_word & htonl(0xF00FFFFF)) ||
237
- memcmp(&iph->nexthdr, &iph2->nexthdr,
238
- nlen - offsetof(struct ipv6hdr, nexthdr))) {
252
+ !ipv6_addr_equal(&iph->saddr, &iph2->saddr) ||
253
+ !ipv6_addr_equal(&iph->daddr, &iph2->daddr) ||
254
+ *(u16 *)&iph->nexthdr != *(u16 *)&iph2->nexthdr) {
255
+not_same_flow:
239256 NAPI_GRO_CB(p)->same_flow = 0;
240257 continue;
258
+ }
259
+ if (unlikely(nlen > sizeof(struct ipv6hdr))) {
260
+ if (memcmp(iph + 1, iph2 + 1,
261
+ nlen - sizeof(struct ipv6hdr)))
262
+ goto not_same_flow;
241263 }
242264 /* flush if Traffic Class fields are different */
243265 NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000));
....@@ -255,7 +277,8 @@
255277
256278 skb_gro_postpull_rcsum(skb, iph, nlen);
257279
258
- pp = call_gro_receive(ops->callbacks.gro_receive, head, skb);
280
+ pp = indirect_call_gro_receive_l4(tcp6_gro_receive, udp6_gro_receive,
281
+ ops->callbacks.gro_receive, head, skb);
259282
260283 out_unlock:
261284 rcu_read_unlock();
....@@ -296,7 +319,7 @@
296319 return inet_gro_receive(head, skb);
297320 }
298321
299
-static int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
322
+INDIRECT_CALLABLE_SCOPE int ipv6_gro_complete(struct sk_buff *skb, int nhoff)
300323 {
301324 const struct net_offload *ops;
302325 struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + nhoff);
....@@ -315,7 +338,8 @@
315338 if (WARN_ON(!ops || !ops->callbacks.gro_complete))
316339 goto out_unlock;
317340
318
- err = ops->callbacks.gro_complete(skb, nhoff);
341
+ err = INDIRECT_CALL_L4(ops->callbacks.gro_complete, tcp6_gro_complete,
342
+ udp6_gro_complete, skb, nhoff);
319343
320344 out_unlock:
321345 rcu_read_unlock();
....@@ -353,9 +377,36 @@
353377 },
354378 };
355379
380
+static struct sk_buff *sit_gso_segment(struct sk_buff *skb,
381
+ netdev_features_t features)
382
+{
383
+ if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP4))
384
+ return ERR_PTR(-EINVAL);
385
+
386
+ return ipv6_gso_segment(skb, features);
387
+}
388
+
389
+static struct sk_buff *ip4ip6_gso_segment(struct sk_buff *skb,
390
+ netdev_features_t features)
391
+{
392
+ if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP6))
393
+ return ERR_PTR(-EINVAL);
394
+
395
+ return inet_gso_segment(skb, features);
396
+}
397
+
398
+static struct sk_buff *ip6ip6_gso_segment(struct sk_buff *skb,
399
+ netdev_features_t features)
400
+{
401
+ if (!(skb_shinfo(skb)->gso_type & SKB_GSO_IPXIP6))
402
+ return ERR_PTR(-EINVAL);
403
+
404
+ return ipv6_gso_segment(skb, features);
405
+}
406
+
356407 static const struct net_offload sit_offload = {
357408 .callbacks = {
358
- .gso_segment = ipv6_gso_segment,
409
+ .gso_segment = sit_gso_segment,
359410 .gro_receive = sit_ip6ip6_gro_receive,
360411 .gro_complete = sit_gro_complete,
361412 },
....@@ -363,7 +414,7 @@
363414
364415 static const struct net_offload ip4ip6_offload = {
365416 .callbacks = {
366
- .gso_segment = inet_gso_segment,
417
+ .gso_segment = ip4ip6_gso_segment,
367418 .gro_receive = ip4ip6_gro_receive,
368419 .gro_complete = ip4ip6_gro_complete,
369420 },
....@@ -371,7 +422,7 @@
371422
372423 static const struct net_offload ip6ip6_offload = {
373424 .callbacks = {
374
- .gso_segment = ipv6_gso_segment,
425
+ .gso_segment = ip6ip6_gso_segment,
375426 .gro_receive = sit_ip6ip6_gro_receive,
376427 .gro_complete = ip6ip6_gro_complete,
377428 },