diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2013-07-01 13:24:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-07-03 17:37:39 -0400 |
commit | c50cd357887acf9fd7af3a5d492911bd825555a2 (patch) | |
tree | 8b2c00e46461e9959b4ecc339d8fcdef1ca69f03 /net | |
parent | 419076f59fc5916bd200b45225c83437b37ab189 (diff) |
net: gre: move GSO functions to gre_offload
Similarly to TCP/UDP offloading, move all related GRE functions to
gre_offload.c to make things more explicit and similar to the rest
of the code.
Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/gre_demux.c (renamed from net/ipv4/gre.c) | 106 | ||||
-rw-r--r-- | net/ipv4/gre_offload.c | 127 |
3 files changed, 131 insertions, 103 deletions
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 86ded0bac9c7..4b81e91c80fe 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_PROC_FS) += proc.o | |||
19 | obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o | 19 | obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o |
20 | obj-$(CONFIG_IP_MROUTE) += ipmr.o | 20 | obj-$(CONFIG_IP_MROUTE) += ipmr.o |
21 | obj-$(CONFIG_NET_IPIP) += ipip.o | 21 | obj-$(CONFIG_NET_IPIP) += ipip.o |
22 | gre-y := gre_demux.o gre_offload.o | ||
22 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o | 23 | obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o |
23 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o | 24 | obj-$(CONFIG_NET_IPGRE) += ip_gre.o |
24 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o | 25 | obj-$(CONFIG_NET_IPVTI) += ip_vti.o |
diff --git a/net/ipv4/gre.c b/net/ipv4/gre_demux.c index ba4803e609b5..736c9fc3ef93 100644 --- a/net/ipv4/gre.c +++ b/net/ipv4/gre_demux.c | |||
@@ -334,113 +334,12 @@ static void gre_err(struct sk_buff *skb, u32 info) | |||
334 | rcu_read_unlock(); | 334 | rcu_read_unlock(); |
335 | } | 335 | } |
336 | 336 | ||
337 | static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | ||
338 | netdev_features_t features) | ||
339 | { | ||
340 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
341 | netdev_features_t enc_features; | ||
342 | int ghl = GRE_HEADER_SECTION; | ||
343 | struct gre_base_hdr *greh; | ||
344 | int mac_len = skb->mac_len; | ||
345 | __be16 protocol = skb->protocol; | ||
346 | int tnl_hlen; | ||
347 | bool csum; | ||
348 | |||
349 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
350 | ~(SKB_GSO_TCPV4 | | ||
351 | SKB_GSO_TCPV6 | | ||
352 | SKB_GSO_UDP | | ||
353 | SKB_GSO_DODGY | | ||
354 | SKB_GSO_TCP_ECN | | ||
355 | SKB_GSO_GRE))) | ||
356 | goto out; | ||
357 | |||
358 | if (unlikely(!pskb_may_pull(skb, sizeof(*greh)))) | ||
359 | goto out; | ||
360 | |||
361 | greh = (struct gre_base_hdr *)skb_transport_header(skb); | ||
362 | |||
363 | if (greh->flags & GRE_KEY) | ||
364 | ghl += GRE_HEADER_SECTION; | ||
365 | if (greh->flags & GRE_SEQ) | ||
366 | ghl += GRE_HEADER_SECTION; | ||
367 | if (greh->flags & GRE_CSUM) { | ||
368 | ghl += GRE_HEADER_SECTION; | ||
369 | csum = true; | ||
370 | } else | ||
371 | csum = false; | ||
372 | |||
373 | /* setup inner skb. */ | ||
374 | skb->protocol = greh->protocol; | ||
375 | skb->encapsulation = 0; | ||
376 | |||
377 | if (unlikely(!pskb_may_pull(skb, ghl))) | ||
378 | goto out; | ||
379 | __skb_pull(skb, ghl); | ||
380 | skb_reset_mac_header(skb); | ||
381 | skb_set_network_header(skb, skb_inner_network_offset(skb)); | ||
382 | skb->mac_len = skb_inner_network_offset(skb); | ||
383 | |||
384 | /* segment inner packet. */ | ||
385 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
386 | segs = skb_mac_gso_segment(skb, enc_features); | ||
387 | if (!segs || IS_ERR(segs)) | ||
388 | goto out; | ||
389 | |||
390 | skb = segs; | ||
391 | tnl_hlen = skb_tnl_header_len(skb); | ||
392 | do { | ||
393 | __skb_push(skb, ghl); | ||
394 | if (csum) { | ||
395 | __be32 *pcsum; | ||
396 | |||
397 | if (skb_has_shared_frag(skb)) { | ||
398 | int err; | ||
399 | |||
400 | err = __skb_linearize(skb); | ||
401 | if (err) { | ||
402 | kfree_skb(segs); | ||
403 | segs = ERR_PTR(err); | ||
404 | goto out; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | greh = (struct gre_base_hdr *)(skb->data); | ||
409 | pcsum = (__be32 *)(greh + 1); | ||
410 | *pcsum = 0; | ||
411 | *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0)); | ||
412 | } | ||
413 | __skb_push(skb, tnl_hlen - ghl); | ||
414 | |||
415 | skb_reset_mac_header(skb); | ||
416 | skb_set_network_header(skb, mac_len); | ||
417 | skb->mac_len = mac_len; | ||
418 | skb->protocol = protocol; | ||
419 | } while ((skb = skb->next)); | ||
420 | out: | ||
421 | return segs; | ||
422 | } | ||
423 | |||
424 | static int gre_gso_send_check(struct sk_buff *skb) | ||
425 | { | ||
426 | if (!skb->encapsulation) | ||
427 | return -EINVAL; | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static const struct net_protocol net_gre_protocol = { | 337 | static const struct net_protocol net_gre_protocol = { |
432 | .handler = gre_rcv, | 338 | .handler = gre_rcv, |
433 | .err_handler = gre_err, | 339 | .err_handler = gre_err, |
434 | .netns_ok = 1, | 340 | .netns_ok = 1, |
435 | }; | 341 | }; |
436 | 342 | ||
437 | static const struct net_offload gre_offload = { | ||
438 | .callbacks = { | ||
439 | .gso_send_check = gre_gso_send_check, | ||
440 | .gso_segment = gre_gso_segment, | ||
441 | }, | ||
442 | }; | ||
443 | |||
444 | static const struct gre_protocol ipgre_protocol = { | 343 | static const struct gre_protocol ipgre_protocol = { |
445 | .handler = gre_cisco_rcv, | 344 | .handler = gre_cisco_rcv, |
446 | .err_handler = gre_cisco_err, | 345 | .err_handler = gre_cisco_err, |
@@ -485,7 +384,7 @@ static int __init gre_init(void) | |||
485 | goto err_gre; | 384 | goto err_gre; |
486 | } | 385 | } |
487 | 386 | ||
488 | if (inet_add_offload(&gre_offload, IPPROTO_GRE)) { | 387 | if (gre_offload_init()) { |
489 | pr_err("can't add protocol offload\n"); | 388 | pr_err("can't add protocol offload\n"); |
490 | goto err_gso; | 389 | goto err_gso; |
491 | } | 390 | } |
@@ -501,7 +400,8 @@ err: | |||
501 | 400 | ||
502 | static void __exit gre_exit(void) | 401 | static void __exit gre_exit(void) |
503 | { | 402 | { |
504 | inet_del_offload(&gre_offload, IPPROTO_GRE); | 403 | gre_offload_exit(); |
404 | |||
505 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | 405 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); |
506 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | 406 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); |
507 | } | 407 | } |
diff --git a/net/ipv4/gre_offload.c b/net/ipv4/gre_offload.c new file mode 100644 index 000000000000..a9d8cd2bff4b --- /dev/null +++ b/net/ipv4/gre_offload.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * IPV4 GSO/GRO offload support | ||
3 | * Linux INET 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. | ||
9 | * | ||
10 | * GRE GSO support | ||
11 | */ | ||
12 | |||
13 | #include <linux/skbuff.h> | ||
14 | #include <net/protocol.h> | ||
15 | #include <net/gre.h> | ||
16 | |||
17 | static int gre_gso_send_check(struct sk_buff *skb) | ||
18 | { | ||
19 | if (!skb->encapsulation) | ||
20 | return -EINVAL; | ||
21 | return 0; | ||
22 | } | ||
23 | |||
24 | static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | ||
25 | netdev_features_t features) | ||
26 | { | ||
27 | struct sk_buff *segs = ERR_PTR(-EINVAL); | ||
28 | netdev_features_t enc_features; | ||
29 | int ghl = GRE_HEADER_SECTION; | ||
30 | struct gre_base_hdr *greh; | ||
31 | int mac_len = skb->mac_len; | ||
32 | __be16 protocol = skb->protocol; | ||
33 | int tnl_hlen; | ||
34 | bool csum; | ||
35 | |||
36 | if (unlikely(skb_shinfo(skb)->gso_type & | ||
37 | ~(SKB_GSO_TCPV4 | | ||
38 | SKB_GSO_TCPV6 | | ||
39 | SKB_GSO_UDP | | ||
40 | SKB_GSO_DODGY | | ||
41 | SKB_GSO_TCP_ECN | | ||
42 | SKB_GSO_GRE))) | ||
43 | goto out; | ||
44 | |||
45 | if (unlikely(!pskb_may_pull(skb, sizeof(*greh)))) | ||
46 | goto out; | ||
47 | |||
48 | greh = (struct gre_base_hdr *)skb_transport_header(skb); | ||
49 | |||
50 | if (greh->flags & GRE_KEY) | ||
51 | ghl += GRE_HEADER_SECTION; | ||
52 | if (greh->flags & GRE_SEQ) | ||
53 | ghl += GRE_HEADER_SECTION; | ||
54 | if (greh->flags & GRE_CSUM) { | ||
55 | ghl += GRE_HEADER_SECTION; | ||
56 | csum = true; | ||
57 | } else | ||
58 | csum = false; | ||
59 | |||
60 | /* setup inner skb. */ | ||
61 | skb->protocol = greh->protocol; | ||
62 | skb->encapsulation = 0; | ||
63 | |||
64 | if (unlikely(!pskb_may_pull(skb, ghl))) | ||
65 | goto out; | ||
66 | |||
67 | __skb_pull(skb, ghl); | ||
68 | skb_reset_mac_header(skb); | ||
69 | skb_set_network_header(skb, skb_inner_network_offset(skb)); | ||
70 | skb->mac_len = skb_inner_network_offset(skb); | ||
71 | |||
72 | /* segment inner packet. */ | ||
73 | enc_features = skb->dev->hw_enc_features & netif_skb_features(skb); | ||
74 | segs = skb_mac_gso_segment(skb, enc_features); | ||
75 | if (!segs || IS_ERR(segs)) | ||
76 | goto out; | ||
77 | |||
78 | skb = segs; | ||
79 | tnl_hlen = skb_tnl_header_len(skb); | ||
80 | do { | ||
81 | __skb_push(skb, ghl); | ||
82 | if (csum) { | ||
83 | __be32 *pcsum; | ||
84 | |||
85 | if (skb_has_shared_frag(skb)) { | ||
86 | int err; | ||
87 | |||
88 | err = __skb_linearize(skb); | ||
89 | if (err) { | ||
90 | kfree_skb(segs); | ||
91 | segs = ERR_PTR(err); | ||
92 | goto out; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | greh = (struct gre_base_hdr *)(skb->data); | ||
97 | pcsum = (__be32 *)(greh + 1); | ||
98 | *pcsum = 0; | ||
99 | *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0)); | ||
100 | } | ||
101 | __skb_push(skb, tnl_hlen - ghl); | ||
102 | |||
103 | skb_reset_mac_header(skb); | ||
104 | skb_set_network_header(skb, mac_len); | ||
105 | skb->mac_len = mac_len; | ||
106 | skb->protocol = protocol; | ||
107 | } while ((skb = skb->next)); | ||
108 | out: | ||
109 | return segs; | ||
110 | } | ||
111 | |||
112 | static const struct net_offload gre_offload = { | ||
113 | .callbacks = { | ||
114 | .gso_send_check = gre_gso_send_check, | ||
115 | .gso_segment = gre_gso_segment, | ||
116 | }, | ||
117 | }; | ||
118 | |||
119 | int __init gre_offload_init(void) | ||
120 | { | ||
121 | return inet_add_offload(&gre_offload, IPPROTO_GRE); | ||
122 | } | ||
123 | |||
124 | void __exit gre_offload_exit(void) | ||
125 | { | ||
126 | inet_del_offload(&gre_offload, IPPROTO_GRE); | ||
127 | } | ||