diff options
author | Tom Herbert <therbert@google.com> | 2014-11-04 12:06:51 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-05 16:30:02 -0500 |
commit | 63487babf08d6d67483c67ed21d8cea6674a44ec (patch) | |
tree | f0e11d54e33a689a25bed43f7bd3c720b49a6bcd | |
parent | 890b7916d0965829ad1c457aa61f049a210c19f8 (diff) |
net: Move fou_build_header into fou.c and refactor
Move fou_build_header out of ip_tunnel.c and into fou.c splitting
it up into fou_build_header, gue_build_header, and fou_build_udp.
This allows for other users for TX of FOU or GUE. Change ip_tunnel_encap
to call fou_build_header or gue_build_header based on the tunnel
encapsulation type. Similarly, added fou_encap_hlen and gue_encap_hlen
functions which are called by ip_encap_hlen. New net/fou.h has
prototypes and defines for this.
Added NET_FOU_IP_TUNNELS configuration. When this is set, IP tunnels
can use FOU/GUE and fou module is also selected.
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/fou.h | 26 | ||||
-rw-r--r-- | net/ipv4/Kconfig | 9 | ||||
-rw-r--r-- | net/ipv4/fou.c | 73 | ||||
-rw-r--r-- | net/ipv4/ip_tunnel.c | 61 |
4 files changed, 120 insertions, 49 deletions
diff --git a/include/net/fou.h b/include/net/fou.h new file mode 100644 index 000000000000..cf4ce8874f92 --- /dev/null +++ b/include/net/fou.h | |||
@@ -0,0 +1,26 @@ | |||
1 | #ifndef __NET_FOU_H | ||
2 | #define __NET_FOU_H | ||
3 | |||
4 | #include <linux/skbuff.h> | ||
5 | |||
6 | #include <net/flow.h> | ||
7 | #include <net/gue.h> | ||
8 | #include <net/ip_tunnels.h> | ||
9 | #include <net/udp.h> | ||
10 | |||
11 | int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
12 | u8 *protocol, struct flowi4 *fl4); | ||
13 | int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
14 | u8 *protocol, struct flowi4 *fl4); | ||
15 | |||
16 | static size_t fou_encap_hlen(struct ip_tunnel_encap *e) | ||
17 | { | ||
18 | return sizeof(struct udphdr); | ||
19 | } | ||
20 | |||
21 | static size_t gue_encap_hlen(struct ip_tunnel_encap *e) | ||
22 | { | ||
23 | return sizeof(struct udphdr) + sizeof(struct guehdr); | ||
24 | } | ||
25 | |||
26 | #endif | ||
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index e682b48e0709..bd2901604842 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
@@ -322,6 +322,15 @@ config NET_FOU | |||
322 | network mechanisms and optimizations for UDP (such as ECMP | 322 | network mechanisms and optimizations for UDP (such as ECMP |
323 | and RSS) can be leveraged to provide better service. | 323 | and RSS) can be leveraged to provide better service. |
324 | 324 | ||
325 | config NET_FOU_IP_TUNNELS | ||
326 | bool "IP: FOU encapsulation of IP tunnels" | ||
327 | depends on NET_IPIP || NET_IPGRE || IPV6_SIT | ||
328 | select NET_FOU | ||
329 | ---help--- | ||
330 | Allow configuration of FOU or GUE encapsulation for IP tunnels. | ||
331 | When this option is enabled IP tunnels can be configured to use | ||
332 | FOU or GUE encapsulation. | ||
333 | |||
325 | config GENEVE | 334 | config GENEVE |
326 | tristate "Generic Network Virtualization Encapsulation (Geneve)" | 335 | tristate "Generic Network Virtualization Encapsulation (Geneve)" |
327 | depends on INET | 336 | depends on INET |
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 32e78924e246..5446c1c8c26c 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
@@ -487,6 +487,79 @@ static const struct genl_ops fou_nl_ops[] = { | |||
487 | }, | 487 | }, |
488 | }; | 488 | }; |
489 | 489 | ||
490 | static void fou_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
491 | struct flowi4 *fl4, u8 *protocol, __be16 sport) | ||
492 | { | ||
493 | struct udphdr *uh; | ||
494 | |||
495 | skb_push(skb, sizeof(struct udphdr)); | ||
496 | skb_reset_transport_header(skb); | ||
497 | |||
498 | uh = udp_hdr(skb); | ||
499 | |||
500 | uh->dest = e->dport; | ||
501 | uh->source = sport; | ||
502 | uh->len = htons(skb->len); | ||
503 | uh->check = 0; | ||
504 | udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb, | ||
505 | fl4->saddr, fl4->daddr, skb->len); | ||
506 | |||
507 | *protocol = IPPROTO_UDP; | ||
508 | } | ||
509 | |||
510 | int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
511 | u8 *protocol, struct flowi4 *fl4) | ||
512 | { | ||
513 | bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM); | ||
514 | int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
515 | __be16 sport; | ||
516 | |||
517 | skb = iptunnel_handle_offloads(skb, csum, type); | ||
518 | |||
519 | if (IS_ERR(skb)) | ||
520 | return PTR_ERR(skb); | ||
521 | |||
522 | sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev), | ||
523 | skb, 0, 0, false); | ||
524 | fou_build_udp(skb, e, fl4, protocol, sport); | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | EXPORT_SYMBOL(fou_build_header); | ||
529 | |||
530 | int gue_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
531 | u8 *protocol, struct flowi4 *fl4) | ||
532 | { | ||
533 | bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM); | ||
534 | int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
535 | struct guehdr *guehdr; | ||
536 | size_t hdr_len = sizeof(struct guehdr); | ||
537 | __be16 sport; | ||
538 | |||
539 | skb = iptunnel_handle_offloads(skb, csum, type); | ||
540 | |||
541 | if (IS_ERR(skb)) | ||
542 | return PTR_ERR(skb); | ||
543 | |||
544 | /* Get source port (based on flow hash) before skb_push */ | ||
545 | sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev), | ||
546 | skb, 0, 0, false); | ||
547 | |||
548 | skb_push(skb, hdr_len); | ||
549 | |||
550 | guehdr = (struct guehdr *)skb->data; | ||
551 | |||
552 | guehdr->version = 0; | ||
553 | guehdr->hlen = 0; | ||
554 | guehdr->flags = 0; | ||
555 | guehdr->next_hdr = *protocol; | ||
556 | |||
557 | fou_build_udp(skb, e, fl4, protocol, sport); | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | EXPORT_SYMBOL(gue_build_header); | ||
562 | |||
490 | static int __init fou_init(void) | 563 | static int __init fou_init(void) |
491 | { | 564 | { |
492 | int ret; | 565 | int ret; |
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 0bb8e141eacc..c3587e1c8b82 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c | |||
@@ -56,7 +56,10 @@ | |||
56 | #include <net/netns/generic.h> | 56 | #include <net/netns/generic.h> |
57 | #include <net/rtnetlink.h> | 57 | #include <net/rtnetlink.h> |
58 | #include <net/udp.h> | 58 | #include <net/udp.h> |
59 | #include <net/gue.h> | 59 | |
60 | #if IS_ENABLED(CONFIG_NET_FOU) | ||
61 | #include <net/fou.h> | ||
62 | #endif | ||
60 | 63 | ||
61 | #if IS_ENABLED(CONFIG_IPV6) | 64 | #if IS_ENABLED(CONFIG_IPV6) |
62 | #include <net/ipv6.h> | 65 | #include <net/ipv6.h> |
@@ -494,10 +497,12 @@ static int ip_encap_hlen(struct ip_tunnel_encap *e) | |||
494 | switch (e->type) { | 497 | switch (e->type) { |
495 | case TUNNEL_ENCAP_NONE: | 498 | case TUNNEL_ENCAP_NONE: |
496 | return 0; | 499 | return 0; |
500 | #if IS_ENABLED(CONFIG_NET_FOU) | ||
497 | case TUNNEL_ENCAP_FOU: | 501 | case TUNNEL_ENCAP_FOU: |
498 | return sizeof(struct udphdr); | 502 | return fou_encap_hlen(e); |
499 | case TUNNEL_ENCAP_GUE: | 503 | case TUNNEL_ENCAP_GUE: |
500 | return sizeof(struct udphdr) + sizeof(struct guehdr); | 504 | return gue_encap_hlen(e); |
505 | #endif | ||
501 | default: | 506 | default: |
502 | return -EINVAL; | 507 | return -EINVAL; |
503 | } | 508 | } |
@@ -526,60 +531,18 @@ int ip_tunnel_encap_setup(struct ip_tunnel *t, | |||
526 | } | 531 | } |
527 | EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup); | 532 | EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup); |
528 | 533 | ||
529 | static int fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
530 | size_t hdr_len, u8 *protocol, struct flowi4 *fl4) | ||
531 | { | ||
532 | struct udphdr *uh; | ||
533 | __be16 sport; | ||
534 | bool csum = !!(e->flags & TUNNEL_ENCAP_FLAG_CSUM); | ||
535 | int type = csum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
536 | |||
537 | skb = iptunnel_handle_offloads(skb, csum, type); | ||
538 | |||
539 | if (IS_ERR(skb)) | ||
540 | return PTR_ERR(skb); | ||
541 | |||
542 | /* Get length and hash before making space in skb */ | ||
543 | |||
544 | sport = e->sport ? : udp_flow_src_port(dev_net(skb->dev), | ||
545 | skb, 0, 0, false); | ||
546 | |||
547 | skb_push(skb, hdr_len); | ||
548 | |||
549 | skb_reset_transport_header(skb); | ||
550 | uh = udp_hdr(skb); | ||
551 | |||
552 | if (e->type == TUNNEL_ENCAP_GUE) { | ||
553 | struct guehdr *guehdr = (struct guehdr *)&uh[1]; | ||
554 | |||
555 | guehdr->version = 0; | ||
556 | guehdr->hlen = 0; | ||
557 | guehdr->flags = 0; | ||
558 | guehdr->next_hdr = *protocol; | ||
559 | } | ||
560 | |||
561 | uh->dest = e->dport; | ||
562 | uh->source = sport; | ||
563 | uh->len = htons(skb->len); | ||
564 | uh->check = 0; | ||
565 | udp_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM), skb, | ||
566 | fl4->saddr, fl4->daddr, skb->len); | ||
567 | |||
568 | *protocol = IPPROTO_UDP; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, | 534 | int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, |
574 | u8 *protocol, struct flowi4 *fl4) | 535 | u8 *protocol, struct flowi4 *fl4) |
575 | { | 536 | { |
576 | switch (t->encap.type) { | 537 | switch (t->encap.type) { |
577 | case TUNNEL_ENCAP_NONE: | 538 | case TUNNEL_ENCAP_NONE: |
578 | return 0; | 539 | return 0; |
540 | #if IS_ENABLED(CONFIG_NET_FOU) | ||
579 | case TUNNEL_ENCAP_FOU: | 541 | case TUNNEL_ENCAP_FOU: |
542 | return fou_build_header(skb, &t->encap, protocol, fl4); | ||
580 | case TUNNEL_ENCAP_GUE: | 543 | case TUNNEL_ENCAP_GUE: |
581 | return fou_build_header(skb, &t->encap, t->encap_hlen, | 544 | return gue_build_header(skb, &t->encap, protocol, fl4); |
582 | protocol, fl4); | 545 | #endif |
583 | default: | 546 | default: |
584 | return -EINVAL; | 547 | return -EINVAL; |
585 | } | 548 | } |