aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2019-03-29 16:16:28 -0400
committerSteffen Klassert <steffen.klassert@secunet.com>2019-04-08 03:14:55 -0400
commitb3284df1c86f7ac078dcb8fb250fe3d6437e740c (patch)
tree116d8518d917cc43bf0e3954b8aafa16db93e5c6
parent7613b92b1ae37141704948b77e8762c5de896510 (diff)
xfrm: remove input2 indirection from xfrm_mode
No external dependencies on any module, place this in the core. Increase is about 1800 byte for xfrm_input.o. The beet helpers get added to internal header, as they can be reused from xfrm_output.c in the next patch (kernel contains several copies of them in the xfrm{4,6}_mode_beet.c files). Before: text data bss dec filename 5578 176 2364 8118 net/xfrm/xfrm_input.o 1180 64 0 1244 net/ipv4/xfrm4_mode_beet.o 171 40 0 211 net/ipv4/xfrm4_mode_transport.o 1163 40 0 1203 net/ipv4/xfrm4_mode_tunnel.o 1083 52 0 1135 net/ipv6/xfrm6_mode_beet.o 172 40 0 212 net/ipv6/xfrm6_mode_ro.o 172 40 0 212 net/ipv6/xfrm6_mode_transport.o 1056 40 0 1096 net/ipv6/xfrm6_mode_tunnel.o After: text data bss dec filename 7373 200 2364 9937 net/xfrm/xfrm_input.o 587 44 0 631 net/ipv4/xfrm4_mode_beet.o 171 32 0 203 net/ipv4/xfrm4_mode_transport.o 649 32 0 681 net/ipv4/xfrm4_mode_tunnel.o 625 44 0 669 net/ipv6/xfrm6_mode_beet.o 172 32 0 204 net/ipv6/xfrm6_mode_ro.o 172 32 0 204 net/ipv6/xfrm6_mode_transport.o 599 32 0 631 net/ipv6/xfrm6_mode_tunnel.o v2: pass inner_mode to xfrm_inner_mode_encap_remove to fix AF_UNSPEC selector breakage (bisected by Benedict Wong) Signed-off-by: Florian Westphal <fw@strlen.de> Reviewed-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r--include/net/xfrm.h13
-rw-r--r--net/ipv4/xfrm4_mode_beet.c47
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c39
-rw-r--r--net/ipv6/xfrm6_mode_beet.c27
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c46
-rw-r--r--net/xfrm/xfrm_inout.h38
-rw-r--r--net/xfrm/xfrm_input.c185
7 files changed, 222 insertions, 173 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index de103a6d1ef8..bdda545cf740 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -424,19 +424,6 @@ int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned
424 424
425struct xfrm_mode { 425struct xfrm_mode {
426 /* 426 /*
427 * Remove encapsulation header.
428 *
429 * The IP header will be moved over the top of the encapsulation
430 * header.
431 *
432 * On entry, the transport header shall point to where the IP header
433 * should be and the network header shall be set to where the IP
434 * header currently is. skb->data shall point to the start of the
435 * payload.
436 */
437 int (*input2)(struct xfrm_state *x, struct sk_buff *skb);
438
439 /*
440 * Add encapsulation header. 427 * Add encapsulation header.
441 * 428 *
442 * On exit, the transport header will be set to the start of the 429 * On exit, the transport header will be set to the start of the
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index f02cc8237d54..500960172933 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -80,54 +80,7 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
80 return 0; 80 return 0;
81} 81}
82 82
83static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
84{
85 struct iphdr *iph;
86 int optlen = 0;
87 int err = -EINVAL;
88
89 if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
90 struct ip_beet_phdr *ph;
91 int phlen;
92
93 if (!pskb_may_pull(skb, sizeof(*ph)))
94 goto out;
95
96 ph = (struct ip_beet_phdr *)skb->data;
97
98 phlen = sizeof(*ph) + ph->padlen;
99 optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
100 if (optlen < 0 || optlen & 3 || optlen > 250)
101 goto out;
102
103 XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
104
105 if (!pskb_may_pull(skb, phlen))
106 goto out;
107 __skb_pull(skb, phlen);
108 }
109
110 skb_push(skb, sizeof(*iph));
111 skb_reset_network_header(skb);
112 skb_mac_header_rebuild(skb);
113
114 xfrm4_beet_make_header(skb);
115
116 iph = ip_hdr(skb);
117
118 iph->ihl += optlen / 4;
119 iph->tot_len = htons(skb->len);
120 iph->daddr = x->sel.daddr.a4;
121 iph->saddr = x->sel.saddr.a4;
122 iph->check = 0;
123 iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
124 err = 0;
125out:
126 return err;
127}
128
129static struct xfrm_mode xfrm4_beet_mode = { 83static struct xfrm_mode xfrm4_beet_mode = {
130 .input2 = xfrm4_beet_input,
131 .output2 = xfrm4_beet_output, 84 .output2 = xfrm4_beet_output,
132 .owner = THIS_MODULE, 85 .owner = THIS_MODULE,
133 .encap = XFRM_MODE_BEET, 86 .encap = XFRM_MODE_BEET,
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index b5d4ba41758e..31645319aaeb 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -15,14 +15,6 @@
15#include <net/ip.h> 15#include <net/ip.h>
16#include <net/xfrm.h> 16#include <net/xfrm.h>
17 17
18static inline void ipip_ecn_decapsulate(struct sk_buff *skb)
19{
20 struct iphdr *inner_iph = ipip_hdr(skb);
21
22 if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
23 IP_ECN_set_ce(inner_iph);
24}
25
26/* Add encapsulation header. 18/* Add encapsulation header.
27 * 19 *
28 * The top IP header will be constructed per RFC 2401. 20 * The top IP header will be constructed per RFC 2401.
@@ -71,38 +63,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
71 return 0; 63 return 0;
72} 64}
73 65
74static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
75{
76 int err = -EINVAL;
77
78 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
79 goto out;
80
81 if (!pskb_may_pull(skb, sizeof(struct iphdr)))
82 goto out;
83
84 err = skb_unclone(skb, GFP_ATOMIC);
85 if (err)
86 goto out;
87
88 if (x->props.flags & XFRM_STATE_DECAP_DSCP)
89 ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb));
90 if (!(x->props.flags & XFRM_STATE_NOECN))
91 ipip_ecn_decapsulate(skb);
92
93 skb_reset_network_header(skb);
94 skb_mac_header_rebuild(skb);
95 if (skb->mac_len)
96 eth_hdr(skb)->h_proto = skb->protocol;
97
98 err = 0;
99
100out:
101 return err;
102}
103
104static struct xfrm_mode xfrm4_tunnel_mode = { 66static struct xfrm_mode xfrm4_tunnel_mode = {
105 .input2 = xfrm4_mode_tunnel_input,
106 .output2 = xfrm4_mode_tunnel_output, 67 .output2 = xfrm4_mode_tunnel_output,
107 .owner = THIS_MODULE, 68 .owner = THIS_MODULE,
108 .encap = XFRM_MODE_TUNNEL, 69 .encap = XFRM_MODE_TUNNEL,
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index 6f35e24f0077..a0537b4f62f8 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -76,34 +76,7 @@ static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
76 top_iph->daddr = *(struct in6_addr *)&x->id.daddr; 76 top_iph->daddr = *(struct in6_addr *)&x->id.daddr;
77 return 0; 77 return 0;
78} 78}
79
80static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
81{
82 struct ipv6hdr *ip6h;
83 int size = sizeof(struct ipv6hdr);
84 int err;
85
86 err = skb_cow_head(skb, size + skb->mac_len);
87 if (err)
88 goto out;
89
90 __skb_push(skb, size);
91 skb_reset_network_header(skb);
92 skb_mac_header_rebuild(skb);
93
94 xfrm6_beet_make_header(skb);
95
96 ip6h = ipv6_hdr(skb);
97 ip6h->payload_len = htons(skb->len - size);
98 ip6h->daddr = x->sel.daddr.in6;
99 ip6h->saddr = x->sel.saddr.in6;
100 err = 0;
101out:
102 return err;
103}
104
105static struct xfrm_mode xfrm6_beet_mode = { 79static struct xfrm_mode xfrm6_beet_mode = {
106 .input2 = xfrm6_beet_input,
107 .output2 = xfrm6_beet_output, 80 .output2 = xfrm6_beet_output,
108 .owner = THIS_MODULE, 81 .owner = THIS_MODULE,
109 .encap = XFRM_MODE_BEET, 82 .encap = XFRM_MODE_BEET,
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 8e23a2fba617..79c57decb472 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -18,14 +18,6 @@
18#include <net/ipv6.h> 18#include <net/ipv6.h>
19#include <net/xfrm.h> 19#include <net/xfrm.h>
20 20
21static inline void ipip6_ecn_decapsulate(struct sk_buff *skb)
22{
23 struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
24
25 if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
26 IP6_ECN_set_ce(skb, inner_iph);
27}
28
29/* Add encapsulation header. 21/* Add encapsulation header.
30 * 22 *
31 * The top IP header will be constructed per RFC 2401. 23 * The top IP header will be constructed per RFC 2401.
@@ -65,45 +57,7 @@ static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
65 return 0; 57 return 0;
66} 58}
67 59
68#define for_each_input_rcu(head, handler) \
69 for (handler = rcu_dereference(head); \
70 handler != NULL; \
71 handler = rcu_dereference(handler->next))
72
73
74static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
75{
76 int err = -EINVAL;
77
78 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
79 goto out;
80 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
81 goto out;
82
83 err = skb_unclone(skb, GFP_ATOMIC);
84 if (err)
85 goto out;
86
87 if (x->props.flags & XFRM_STATE_DECAP_DSCP)
88 ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)),
89 ipipv6_hdr(skb));
90 if (!(x->props.flags & XFRM_STATE_NOECN))
91 ipip6_ecn_decapsulate(skb);
92
93 skb_reset_network_header(skb);
94 skb_mac_header_rebuild(skb);
95 if (skb->mac_len)
96 eth_hdr(skb)->h_proto = skb->protocol;
97
98 err = 0;
99
100out:
101 return err;
102}
103
104
105static struct xfrm_mode xfrm6_tunnel_mode = { 60static struct xfrm_mode xfrm6_tunnel_mode = {
106 .input2 = xfrm6_mode_tunnel_input,
107 .output2 = xfrm6_mode_tunnel_output, 61 .output2 = xfrm6_mode_tunnel_output,
108 .owner = THIS_MODULE, 62 .owner = THIS_MODULE,
109 .encap = XFRM_MODE_TUNNEL, 63 .encap = XFRM_MODE_TUNNEL,
diff --git a/net/xfrm/xfrm_inout.h b/net/xfrm/xfrm_inout.h
new file mode 100644
index 000000000000..c7b0318938e2
--- /dev/null
+++ b/net/xfrm/xfrm_inout.h
@@ -0,0 +1,38 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#include <linux/ipv6.h>
3#include <net/dsfield.h>
4#include <net/xfrm.h>
5
6#ifndef XFRM_INOUT_H
7#define XFRM_INOUT_H 1
8
9static inline void xfrm6_beet_make_header(struct sk_buff *skb)
10{
11 struct ipv6hdr *iph = ipv6_hdr(skb);
12
13 iph->version = 6;
14
15 memcpy(iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
16 sizeof(iph->flow_lbl));
17 iph->nexthdr = XFRM_MODE_SKB_CB(skb)->protocol;
18
19 ipv6_change_dsfield(iph, 0, XFRM_MODE_SKB_CB(skb)->tos);
20 iph->hop_limit = XFRM_MODE_SKB_CB(skb)->ttl;
21}
22
23static inline void xfrm4_beet_make_header(struct sk_buff *skb)
24{
25 struct iphdr *iph = ip_hdr(skb);
26
27 iph->ihl = 5;
28 iph->version = 4;
29
30 iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol;
31 iph->tos = XFRM_MODE_SKB_CB(skb)->tos;
32
33 iph->id = XFRM_MODE_SKB_CB(skb)->id;
34 iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off;
35 iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl;
36}
37
38#endif
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 0edf3fb73585..e0fd9561ffe5 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -21,6 +21,8 @@
21#include <net/ip_tunnels.h> 21#include <net/ip_tunnels.h>
22#include <net/ip6_tunnel.h> 22#include <net/ip6_tunnel.h>
23 23
24#include "xfrm_inout.h"
25
24struct xfrm_trans_tasklet { 26struct xfrm_trans_tasklet {
25 struct tasklet_struct tasklet; 27 struct tasklet_struct tasklet;
26 struct sk_buff_head queue; 28 struct sk_buff_head queue;
@@ -166,6 +168,187 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
166} 168}
167EXPORT_SYMBOL(xfrm_parse_spi); 169EXPORT_SYMBOL(xfrm_parse_spi);
168 170
171static int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
172{
173 struct iphdr *iph;
174 int optlen = 0;
175 int err = -EINVAL;
176
177 if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
178 struct ip_beet_phdr *ph;
179 int phlen;
180
181 if (!pskb_may_pull(skb, sizeof(*ph)))
182 goto out;
183
184 ph = (struct ip_beet_phdr *)skb->data;
185
186 phlen = sizeof(*ph) + ph->padlen;
187 optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen);
188 if (optlen < 0 || optlen & 3 || optlen > 250)
189 goto out;
190
191 XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr;
192
193 if (!pskb_may_pull(skb, phlen))
194 goto out;
195 __skb_pull(skb, phlen);
196 }
197
198 skb_push(skb, sizeof(*iph));
199 skb_reset_network_header(skb);
200 skb_mac_header_rebuild(skb);
201
202 xfrm4_beet_make_header(skb);
203
204 iph = ip_hdr(skb);
205
206 iph->ihl += optlen / 4;
207 iph->tot_len = htons(skb->len);
208 iph->daddr = x->sel.daddr.a4;
209 iph->saddr = x->sel.saddr.a4;
210 iph->check = 0;
211 iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl);
212 err = 0;
213out:
214 return err;
215}
216
217static void ipip_ecn_decapsulate(struct sk_buff *skb)
218{
219 struct iphdr *inner_iph = ipip_hdr(skb);
220
221 if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
222 IP_ECN_set_ce(inner_iph);
223}
224
225static int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
226{
227 int err = -EINVAL;
228
229 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
230 goto out;
231
232 if (!pskb_may_pull(skb, sizeof(struct iphdr)))
233 goto out;
234
235 err = skb_unclone(skb, GFP_ATOMIC);
236 if (err)
237 goto out;
238
239 if (x->props.flags & XFRM_STATE_DECAP_DSCP)
240 ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb));
241 if (!(x->props.flags & XFRM_STATE_NOECN))
242 ipip_ecn_decapsulate(skb);
243
244 skb_reset_network_header(skb);
245 skb_mac_header_rebuild(skb);
246 if (skb->mac_len)
247 eth_hdr(skb)->h_proto = skb->protocol;
248
249 err = 0;
250
251out:
252 return err;
253}
254
255static void ipip6_ecn_decapsulate(struct sk_buff *skb)
256{
257 struct ipv6hdr *inner_iph = ipipv6_hdr(skb);
258
259 if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos))
260 IP6_ECN_set_ce(skb, inner_iph);
261}
262
263static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
264{
265 int err = -EINVAL;
266
267 if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
268 goto out;
269 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
270 goto out;
271
272 err = skb_unclone(skb, GFP_ATOMIC);
273 if (err)
274 goto out;
275
276 if (x->props.flags & XFRM_STATE_DECAP_DSCP)
277 ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)),
278 ipipv6_hdr(skb));
279 if (!(x->props.flags & XFRM_STATE_NOECN))
280 ipip6_ecn_decapsulate(skb);
281
282 skb_reset_network_header(skb);
283 skb_mac_header_rebuild(skb);
284 if (skb->mac_len)
285 eth_hdr(skb)->h_proto = skb->protocol;
286
287 err = 0;
288
289out:
290 return err;
291}
292
293static int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
294{
295 struct ipv6hdr *ip6h;
296 int size = sizeof(struct ipv6hdr);
297 int err;
298
299 err = skb_cow_head(skb, size + skb->mac_len);
300 if (err)
301 goto out;
302
303 __skb_push(skb, size);
304 skb_reset_network_header(skb);
305 skb_mac_header_rebuild(skb);
306
307 xfrm6_beet_make_header(skb);
308
309 ip6h = ipv6_hdr(skb);
310 ip6h->payload_len = htons(skb->len - size);
311 ip6h->daddr = x->sel.daddr.in6;
312 ip6h->saddr = x->sel.saddr.in6;
313 err = 0;
314out:
315 return err;
316}
317
318/* Remove encapsulation header.
319 *
320 * The IP header will be moved over the top of the encapsulation
321 * header.
322 *
323 * On entry, the transport header shall point to where the IP header
324 * should be and the network header shall be set to where the IP
325 * header currently is. skb->data shall point to the start of the
326 * payload.
327 */
328static int
329xfrm_inner_mode_encap_remove(struct xfrm_state *x,
330 const struct xfrm_mode *inner_mode,
331 struct sk_buff *skb)
332{
333 switch (inner_mode->encap) {
334 case XFRM_MODE_BEET:
335 if (inner_mode->family == AF_INET)
336 return xfrm4_remove_beet_encap(x, skb);
337 if (inner_mode->family == AF_INET6)
338 return xfrm6_remove_beet_encap(x, skb);
339 break;
340 case XFRM_MODE_TUNNEL:
341 if (inner_mode->family == AF_INET)
342 return xfrm4_remove_tunnel_encap(x, skb);
343 if (inner_mode->family == AF_INET6)
344 return xfrm6_remove_tunnel_encap(x, skb);
345 break;
346 }
347
348 WARN_ON_ONCE(1);
349 return -EOPNOTSUPP;
350}
351
169static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) 352static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
170{ 353{
171 struct xfrm_mode *inner_mode = x->inner_mode; 354 struct xfrm_mode *inner_mode = x->inner_mode;
@@ -182,7 +365,7 @@ static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
182 } 365 }
183 366
184 skb->protocol = inner_mode->afinfo->eth_proto; 367 skb->protocol = inner_mode->afinfo->eth_proto;
185 return inner_mode->input2(x, skb); 368 return xfrm_inner_mode_encap_remove(x, inner_mode, skb);
186} 369}
187 370
188/* Remove encapsulation header. 371/* Remove encapsulation header.