]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev-tunnel.c
Merge pull request #154 from dmedri/master
[thirdparty/systemd.git] / src / network / networkd-netdev-tunnel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Susant Sahani
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <arpa/inet.h>
23 #include <net/if.h>
24 #include <linux/ip.h>
25 #include <linux/if_tunnel.h>
26 #include <linux/ip6_tunnel.h>
27
28 #include "sd-netlink.h"
29 #include "networkd-netdev-tunnel.h"
30 #include "networkd-link.h"
31 #include "util.h"
32 #include "missing.h"
33 #include "conf-parser.h"
34
35 #define DEFAULT_TNL_HOP_LIMIT 64
36
37 static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
38 [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
39 [NETDEV_IP6_TNL_MODE_IPIP6] = "ipip6",
40 [NETDEV_IP6_TNL_MODE_ANYIP6] = "any",
41 };
42
43 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
44 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
45
46 static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
47 Tunnel *t = IPIP(netdev);
48 int r;
49
50 assert(netdev);
51 assert(link);
52 assert(m);
53 assert(t);
54 assert(t->family == AF_INET);
55
56 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
57 if (r < 0)
58 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
59
60 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
61 if (r < 0)
62 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
63
64 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
65 if (r < 0)
66 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
67
68 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
69 if (r < 0)
70 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
71
72 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
73 if (r < 0)
74 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
75
76 return r;
77 }
78
79 static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
80 Tunnel *t = SIT(netdev);
81 int r;
82
83 assert(netdev);
84 assert(link);
85 assert(m);
86 assert(t);
87 assert(t->family == AF_INET);
88
89 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
90 if (r < 0)
91 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
92
93 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
94 if (r < 0)
95 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
96
97 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
98 if (r < 0)
99 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
100
101 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
102 if (r < 0)
103 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
104
105 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
106 if (r < 0)
107 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
108
109 return r;
110 }
111
112 static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
113 Tunnel *t;
114 int r;
115
116 assert(netdev);
117
118 if (netdev->kind == NETDEV_KIND_GRE)
119 t = GRE(netdev);
120 else
121 t = GRETAP(netdev);
122
123 assert(t);
124 assert(t->family == AF_INET);
125 assert(link);
126 assert(m);
127
128 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
129 if (r < 0)
130 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
131
132 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
133 if (r < 0)
134 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
135
136 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
137 if (r < 0)
138 log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
139
140 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
141 if (r < 0)
142 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
143
144 r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
145 if (r < 0)
146 log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
147
148 r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
149 if (r < 0)
150 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
151
152 return r;
153 }
154
155 static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
156 Tunnel *t;
157 int r;
158
159 assert(netdev);
160
161 if (netdev->kind == NETDEV_KIND_IP6GRE)
162 t = IP6GRE(netdev);
163 else
164 t = IP6GRETAP(netdev);
165
166 assert(t);
167 assert(t->family == AF_INET6);
168 assert(link);
169 assert(m);
170
171 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
172 if (r < 0)
173 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
174
175 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
176 if (r < 0)
177 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
178
179 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
180 if (r < 0)
181 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
182
183 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
184 if (r < 0)
185 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
186
187 return r;
188 }
189
190 static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
191 Tunnel *t = VTI(netdev);
192 int r;
193
194 assert(netdev);
195 assert(link);
196 assert(m);
197 assert(t);
198 assert(t->family == AF_INET);
199
200 r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
201 if (r < 0)
202 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
203
204 r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
205 if (r < 0)
206 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
207
208 r = sd_netlink_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
209 if (r < 0)
210 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
211
212 return r;
213 }
214
215 static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
216 Tunnel *t = VTI6(netdev);
217 int r;
218
219 assert(netdev);
220 assert(link);
221 assert(m);
222 assert(t);
223 assert(t->family == AF_INET6);
224
225 r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
226 if (r < 0)
227 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
228
229 r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6);
230 if (r < 0)
231 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
232
233 r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_REMOTE, &t->remote.in6);
234 if (r < 0)
235 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
236
237 return r;
238 }
239
240 static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
241 Tunnel *t = IP6TNL(netdev);
242 uint8_t proto;
243 int r;
244
245 assert(netdev);
246 assert(link);
247 assert(m);
248 assert(t);
249 assert(t->family == AF_INET6);
250
251 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
252 if (r < 0)
253 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
254
255 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
256 if (r < 0)
257 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
258
259 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
260 if (r < 0)
261 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
262
263 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
264 if (r < 0)
265 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
266
267 switch (t->ip6tnl_mode) {
268 case NETDEV_IP6_TNL_MODE_IP6IP6:
269 proto = IPPROTO_IPV6;
270 break;
271 case NETDEV_IP6_TNL_MODE_IPIP6:
272 proto = IPPROTO_IPIP;
273 break;
274 case NETDEV_IP6_TNL_MODE_ANYIP6:
275 default:
276 proto = 0;
277 break;
278 }
279
280 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
281 if (r < 0)
282 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_MODE attribute: %m");
283
284 return r;
285 }
286
287 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
288 Tunnel *t = NULL;
289
290 assert(netdev);
291 assert(filename);
292
293 switch (netdev->kind) {
294 case NETDEV_KIND_IPIP:
295 t = IPIP(netdev);
296 break;
297 case NETDEV_KIND_SIT:
298 t = SIT(netdev);
299 break;
300 case NETDEV_KIND_GRE:
301 t = GRE(netdev);
302 break;
303 case NETDEV_KIND_GRETAP:
304 t = GRETAP(netdev);
305 break;
306 case NETDEV_KIND_IP6GRE:
307 t = IP6GRE(netdev);
308 break;
309 case NETDEV_KIND_IP6GRETAP:
310 t = IP6GRETAP(netdev);
311 break;
312 case NETDEV_KIND_VTI:
313 t = VTI(netdev);
314 break;
315 case NETDEV_KIND_VTI6:
316 t = VTI6(netdev);
317 break;
318 case NETDEV_KIND_IP6TNL:
319 t = IP6TNL(netdev);
320 break;
321 default:
322 assert_not_reached("Invalid tunnel kind");
323 }
324
325 assert(t);
326
327 if (t->remote.in.s_addr == INADDR_ANY) {
328 log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
329 return -EINVAL;
330 }
331
332 if (t->family != AF_INET && t->family != AF_INET6) {
333 log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
334 return -EINVAL;
335 }
336
337 if (netdev->kind == NETDEV_KIND_IP6TNL) {
338 if (t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) {
339 log_warning("IP6 Tunnel without mode configured in %s. Ignoring", filename);
340 return -EINVAL;
341 }
342 }
343
344 return 0;
345 }
346
347 int config_parse_tunnel_address(const char *unit,
348 const char *filename,
349 unsigned line,
350 const char *section,
351 unsigned section_line,
352 const char *lvalue,
353 int ltype,
354 const char *rvalue,
355 void *data,
356 void *userdata) {
357 Tunnel *t = userdata;
358 union in_addr_union *addr = data, buffer;
359 int r, f;
360
361 assert(filename);
362 assert(lvalue);
363 assert(rvalue);
364 assert(data);
365
366 r = in_addr_from_string_auto(rvalue, &f, &buffer);
367 if (r < 0) {
368 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
369 return 0;
370 }
371
372 if (t->family != AF_UNSPEC && t->family != f) {
373 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
374 return 0;
375 }
376
377 t->family = f;
378 *addr = buffer;
379
380 return 0;
381 }
382
383 static void ipip_init(NetDev *n) {
384 Tunnel *t = IPIP(n);
385
386 assert(n);
387 assert(t);
388
389 t->pmtudisc = true;
390 }
391
392 static void sit_init(NetDev *n) {
393 Tunnel *t = SIT(n);
394
395 assert(n);
396 assert(t);
397
398 t->pmtudisc = true;
399 }
400
401 static void vti_init(NetDev *n) {
402 Tunnel *t;
403
404 assert(n);
405
406 if (n->kind == NETDEV_KIND_VTI)
407 t = VTI(n);
408 else
409 t = VTI6(n);
410
411 assert(t);
412
413 t->pmtudisc = true;
414 }
415
416 static void gre_init(NetDev *n) {
417 Tunnel *t;
418
419 assert(n);
420
421 if (n->kind == NETDEV_KIND_GRE)
422 t = GRE(n);
423 else
424 t = GRETAP(n);
425
426 assert(t);
427
428 t->pmtudisc = true;
429 }
430
431 static void ip6gre_init(NetDev *n) {
432 Tunnel *t;
433
434 assert(n);
435
436 if (n->kind == NETDEV_KIND_IP6GRE)
437 t = IP6GRE(n);
438 else
439 t = IP6GRETAP(n);
440
441 assert(t);
442
443 t->ttl = DEFAULT_TNL_HOP_LIMIT;
444 }
445
446 static void ip6tnl_init(NetDev *n) {
447 Tunnel *t = IP6TNL(n);
448
449 assert(n);
450 assert(t);
451
452 t->ttl = DEFAULT_TNL_HOP_LIMIT;
453 t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
454 t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
455 }
456
457 const NetDevVTable ipip_vtable = {
458 .object_size = sizeof(Tunnel),
459 .init = ipip_init,
460 .sections = "Match\0NetDev\0Tunnel\0",
461 .fill_message_create = netdev_ipip_fill_message_create,
462 .create_type = NETDEV_CREATE_STACKED,
463 .config_verify = netdev_tunnel_verify,
464 };
465
466 const NetDevVTable sit_vtable = {
467 .object_size = sizeof(Tunnel),
468 .init = sit_init,
469 .sections = "Match\0NetDev\0Tunnel\0",
470 .fill_message_create = netdev_sit_fill_message_create,
471 .create_type = NETDEV_CREATE_STACKED,
472 .config_verify = netdev_tunnel_verify,
473 };
474
475 const NetDevVTable vti_vtable = {
476 .object_size = sizeof(Tunnel),
477 .init = vti_init,
478 .sections = "Match\0NetDev\0Tunnel\0",
479 .fill_message_create = netdev_vti_fill_message_create,
480 .create_type = NETDEV_CREATE_STACKED,
481 .config_verify = netdev_tunnel_verify,
482 };
483
484 const NetDevVTable vti6_vtable = {
485 .object_size = sizeof(Tunnel),
486 .init = vti_init,
487 .sections = "Match\0NetDev\0Tunnel\0",
488 .fill_message_create = netdev_vti6_fill_message_create,
489 .create_type = NETDEV_CREATE_STACKED,
490 .config_verify = netdev_tunnel_verify,
491 };
492
493 const NetDevVTable gre_vtable = {
494 .object_size = sizeof(Tunnel),
495 .init = gre_init,
496 .sections = "Match\0NetDev\0Tunnel\0",
497 .fill_message_create = netdev_gre_fill_message_create,
498 .create_type = NETDEV_CREATE_STACKED,
499 .config_verify = netdev_tunnel_verify,
500 };
501
502 const NetDevVTable gretap_vtable = {
503 .object_size = sizeof(Tunnel),
504 .init = gre_init,
505 .sections = "Match\0NetDev\0Tunnel\0",
506 .fill_message_create = netdev_gre_fill_message_create,
507 .create_type = NETDEV_CREATE_STACKED,
508 .config_verify = netdev_tunnel_verify,
509 };
510
511 const NetDevVTable ip6gre_vtable = {
512 .object_size = sizeof(Tunnel),
513 .init = ip6gre_init,
514 .sections = "Match\0NetDev\0Tunnel\0",
515 .fill_message_create = netdev_ip6gre_fill_message_create,
516 .create_type = NETDEV_CREATE_STACKED,
517 .config_verify = netdev_tunnel_verify,
518 };
519
520 const NetDevVTable ip6gretap_vtable = {
521 .object_size = sizeof(Tunnel),
522 .init = ip6gre_init,
523 .sections = "Match\0NetDev\0Tunnel\0",
524 .fill_message_create = netdev_ip6gre_fill_message_create,
525 .create_type = NETDEV_CREATE_STACKED,
526 .config_verify = netdev_tunnel_verify,
527 };
528
529 const NetDevVTable ip6tnl_vtable = {
530 .object_size = sizeof(Tunnel),
531 .init = ip6tnl_init,
532 .sections = "Match\0NetDev\0Tunnel\0",
533 .fill_message_create = netdev_ip6tnl_fill_message_create,
534 .create_type = NETDEV_CREATE_STACKED,
535 .config_verify = netdev_tunnel_verify,
536 };