diff options
author | Tom Herbert <tom@herbertland.com> | 2016-05-18 12:06:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-05-20 18:03:16 -0400 |
commit | aa3463d65e7b9f5ae322db4a12214c2cb041bc8e (patch) | |
tree | e5cb72e8a272093850bdf1ba21c1865eab5edcb5 | |
parent | 058214a4d1dfefed9f01a277fadd3590acb5f990 (diff) |
fou: Add encap ops for IPv6 tunnels
This patch add a new fou6 module that provides encapsulation
operations for IPv6.
Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/fou.h | 2 | ||||
-rw-r--r-- | net/ipv6/Makefile | 1 | ||||
-rw-r--r-- | net/ipv6/fou6.c | 140 |
3 files changed, 142 insertions, 1 deletions
diff --git a/include/net/fou.h b/include/net/fou.h index 7d2fda2a3a9c..f5cc6910a27e 100644 --- a/include/net/fou.h +++ b/include/net/fou.h | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <net/udp.h> | 9 | #include <net/udp.h> |
10 | 10 | ||
11 | size_t fou_encap_hlen(struct ip_tunnel_encap *e); | 11 | size_t fou_encap_hlen(struct ip_tunnel_encap *e); |
12 | static size_t gue_encap_hlen(struct ip_tunnel_encap *e); | 12 | size_t gue_encap_hlen(struct ip_tunnel_encap *e); |
13 | 13 | ||
14 | int __fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | 14 | int __fou_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, |
15 | u8 *protocol, __be16 *sport, int type); | 15 | u8 *protocol, __be16 *sport, int type); |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 5e9d6bf4aaca..7ec3129c9ace 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
@@ -42,6 +42,7 @@ obj-$(CONFIG_IPV6_VTI) += ip6_vti.o | |||
42 | obj-$(CONFIG_IPV6_SIT) += sit.o | 42 | obj-$(CONFIG_IPV6_SIT) += sit.o |
43 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 43 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
44 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o | 44 | obj-$(CONFIG_IPV6_GRE) += ip6_gre.o |
45 | obj-$(CONFIG_NET_FOU) += fou6.o | ||
45 | 46 | ||
46 | obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o | 47 | obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o |
47 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) | 48 | obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) |
diff --git a/net/ipv6/fou6.c b/net/ipv6/fou6.c new file mode 100644 index 000000000000..c972d0b52579 --- /dev/null +++ b/net/ipv6/fou6.c | |||
@@ -0,0 +1,140 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/errno.h> | ||
3 | #include <linux/socket.h> | ||
4 | #include <linux/skbuff.h> | ||
5 | #include <linux/ip.h> | ||
6 | #include <linux/udp.h> | ||
7 | #include <linux/types.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <net/fou.h> | ||
10 | #include <net/ip.h> | ||
11 | #include <net/ip6_tunnel.h> | ||
12 | #include <net/ip6_checksum.h> | ||
13 | #include <net/protocol.h> | ||
14 | #include <net/udp.h> | ||
15 | #include <net/udp_tunnel.h> | ||
16 | |||
17 | static void fou6_build_udp(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
18 | struct flowi6 *fl6, u8 *protocol, __be16 sport) | ||
19 | { | ||
20 | struct udphdr *uh; | ||
21 | |||
22 | skb_push(skb, sizeof(struct udphdr)); | ||
23 | skb_reset_transport_header(skb); | ||
24 | |||
25 | uh = udp_hdr(skb); | ||
26 | |||
27 | uh->dest = e->dport; | ||
28 | uh->source = sport; | ||
29 | uh->len = htons(skb->len); | ||
30 | udp6_set_csum(!(e->flags & TUNNEL_ENCAP_FLAG_CSUM6), skb, | ||
31 | &fl6->saddr, &fl6->daddr, skb->len); | ||
32 | |||
33 | *protocol = IPPROTO_UDP; | ||
34 | } | ||
35 | |||
36 | int fou6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
37 | u8 *protocol, struct flowi6 *fl6) | ||
38 | { | ||
39 | __be16 sport; | ||
40 | int err; | ||
41 | int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ? | ||
42 | SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
43 | |||
44 | err = __fou_build_header(skb, e, protocol, &sport, type); | ||
45 | if (err) | ||
46 | return err; | ||
47 | |||
48 | fou6_build_udp(skb, e, fl6, protocol, sport); | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | EXPORT_SYMBOL(fou6_build_header); | ||
53 | |||
54 | int gue6_build_header(struct sk_buff *skb, struct ip_tunnel_encap *e, | ||
55 | u8 *protocol, struct flowi6 *fl6) | ||
56 | { | ||
57 | __be16 sport; | ||
58 | int err; | ||
59 | int type = e->flags & TUNNEL_ENCAP_FLAG_CSUM6 ? | ||
60 | SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL; | ||
61 | |||
62 | err = __gue_build_header(skb, e, protocol, &sport, type); | ||
63 | if (err) | ||
64 | return err; | ||
65 | |||
66 | fou6_build_udp(skb, e, fl6, protocol, sport); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | EXPORT_SYMBOL(gue6_build_header); | ||
71 | |||
72 | #ifdef CONFIG_NET_FOU_IP_TUNNELS | ||
73 | |||
74 | static const struct ip6_tnl_encap_ops fou_ip6tun_ops = { | ||
75 | .encap_hlen = fou_encap_hlen, | ||
76 | .build_header = fou6_build_header, | ||
77 | }; | ||
78 | |||
79 | static const struct ip6_tnl_encap_ops gue_ip6tun_ops = { | ||
80 | .encap_hlen = gue_encap_hlen, | ||
81 | .build_header = gue6_build_header, | ||
82 | }; | ||
83 | |||
84 | static int ip6_tnl_encap_add_fou_ops(void) | ||
85 | { | ||
86 | int ret; | ||
87 | |||
88 | ret = ip6_tnl_encap_add_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU); | ||
89 | if (ret < 0) { | ||
90 | pr_err("can't add fou6 ops\n"); | ||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | ret = ip6_tnl_encap_add_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE); | ||
95 | if (ret < 0) { | ||
96 | pr_err("can't add gue6 ops\n"); | ||
97 | ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU); | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void ip6_tnl_encap_del_fou_ops(void) | ||
105 | { | ||
106 | ip6_tnl_encap_del_ops(&fou_ip6tun_ops, TUNNEL_ENCAP_FOU); | ||
107 | ip6_tnl_encap_del_ops(&gue_ip6tun_ops, TUNNEL_ENCAP_GUE); | ||
108 | } | ||
109 | |||
110 | #else | ||
111 | |||
112 | static int ip6_tnl_encap_add_fou_ops(void) | ||
113 | { | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | static void ip6_tnl_encap_del_fou_ops(void) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | #endif | ||
122 | |||
123 | static int __init fou6_init(void) | ||
124 | { | ||
125 | int ret; | ||
126 | |||
127 | ret = ip6_tnl_encap_add_fou_ops(); | ||
128 | |||
129 | return ret; | ||
130 | } | ||
131 | |||
132 | static void __exit fou6_fini(void) | ||
133 | { | ||
134 | ip6_tnl_encap_del_fou_ops(); | ||
135 | } | ||
136 | |||
137 | module_init(fou6_init); | ||
138 | module_exit(fou6_fini); | ||
139 | MODULE_AUTHOR("Tom Herbert <therbert@google.com>"); | ||
140 | MODULE_LICENSE("GPL"); | ||