]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/netdev/tunnel.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / netdev / tunnel.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/in.h>
4 #include <linux/fou.h>
5 #include <linux/if_arp.h>
6 #include <linux/if_tunnel.h>
7 #include <linux/ip.h>
8 #include <linux/ip6_tunnel.h>
9
10 #include "af-list.h"
11 #include "conf-parser.h"
12 #include "hexdecoct.h"
13 #include "missing_network.h"
14 #include "netlink-util.h"
15 #include "networkd-manager.h"
16 #include "parse-util.h"
17 #include "siphash24.h"
18 #include "string-table.h"
19 #include "string-util.h"
20 #include "tunnel.h"
21 #include "util.h"
22
23 #define DEFAULT_IPV6_TTL 64
24 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
25 #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
26
27 static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
28 [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
29 [NETDEV_IP6_TNL_MODE_IPIP6] = "ipip6",
30 [NETDEV_IP6_TNL_MODE_ANYIP6] = "any",
31 };
32
33 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
34 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
35
36 #define HASH_KEY SD_ID128_MAKE(74,c4,de,12,f3,d9,41,34,bb,3d,c1,a4,42,93,50,87)
37
38 int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret) {
39 _cleanup_free_ char *ifname_alloc = NULL;
40 uint8_t ipv4masklen, sixrd_prefixlen, *buf, *p;
41 struct in_addr ipv4address;
42 struct in6_addr sixrd_prefix;
43 char ifname[IFNAMSIZ];
44 uint64_t result;
45 size_t sz;
46 int r;
47
48 assert(link);
49 assert(link->dhcp_lease);
50
51 r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address);
52 if (r < 0)
53 return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m");
54
55 r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL);
56 if (r < 0)
57 return log_link_debug_errno(link, r, "Failed to get 6rd option: %m");
58
59 sz = sizeof(uint8_t) * 2 + sizeof(struct in6_addr) + sizeof(struct in_addr);
60 buf = newa(uint8_t, sz);
61 p = buf;
62 p = mempcpy(p, &ipv4masklen, sizeof(uint8_t));
63 p = mempcpy(p, &ipv4address, sizeof(struct in_addr));
64 p = mempcpy(p, &sixrd_prefixlen, sizeof(uint8_t));
65 p = mempcpy(p, &sixrd_prefix, sizeof(struct in6_addr));
66
67 result = siphash24(buf, sz, HASH_KEY.bytes);
68 memcpy(ifname, "6rd-", STRLEN("6rd-"));
69 ifname[STRLEN("6rd-") ] = urlsafe_base64char(result >> 54);
70 ifname[STRLEN("6rd-") + 1] = urlsafe_base64char(result >> 48);
71 ifname[STRLEN("6rd-") + 2] = urlsafe_base64char(result >> 42);
72 ifname[STRLEN("6rd-") + 3] = urlsafe_base64char(result >> 36);
73 ifname[STRLEN("6rd-") + 4] = urlsafe_base64char(result >> 30);
74 ifname[STRLEN("6rd-") + 5] = urlsafe_base64char(result >> 24);
75 ifname[STRLEN("6rd-") + 6] = urlsafe_base64char(result >> 18);
76 ifname[STRLEN("6rd-") + 7] = urlsafe_base64char(result >> 12);
77 ifname[STRLEN("6rd-") + 8] = urlsafe_base64char(result >> 6);
78 ifname[STRLEN("6rd-") + 9] = urlsafe_base64char(result);
79 ifname[STRLEN("6rd-") + 10] = '\0';
80 assert_cc(STRLEN("6rd-") + 10 <= IFNAMSIZ);
81
82 ifname_alloc = strdup(ifname);
83 if (!ifname_alloc)
84 return log_oom_debug();
85
86 *ret = TAKE_PTR(ifname_alloc);
87 return 0;
88 }
89
90 static int dhcp4_pd_create_6rd_tunnel_message(
91 Link *link,
92 sd_netlink_message *m,
93 const struct in_addr *ipv4address,
94 uint8_t ipv4masklen,
95 const struct in6_addr *sixrd_prefix,
96 uint8_t sixrd_prefixlen) {
97 int r;
98
99 r = sd_netlink_message_append_string(m, IFLA_IFNAME, link->dhcp4_6rd_tunnel_name);
100 if (r < 0)
101 return r;
102
103 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
104 if (r < 0)
105 return r;
106
107 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "sit");
108 if (r < 0)
109 return r;
110
111 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, ipv4address);
112 if (r < 0)
113 return r;
114
115 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, 64);
116 if (r < 0)
117 return r;
118
119 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, sixrd_prefix);
120 if (r < 0)
121 return r;
122
123 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, sixrd_prefixlen);
124 if (r < 0)
125 return r;
126
127 struct in_addr relay_prefix = *ipv4address;
128 (void) in4_addr_mask(&relay_prefix, ipv4masklen);
129 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_6RD_RELAY_PREFIX, relay_prefix.s_addr);
130 if (r < 0)
131 return r;
132
133 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, ipv4masklen);
134 if (r < 0)
135 return r;
136
137 r = sd_netlink_message_close_container(m);
138 if (r < 0)
139 return r;
140
141 r = sd_netlink_message_close_container(m);
142 if (r < 0)
143 return r;
144
145 return 0;
146 }
147
148 int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callback) {
149 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
150 uint8_t ipv4masklen, sixrd_prefixlen;
151 struct in_addr ipv4address;
152 struct in6_addr sixrd_prefix;
153 int r;
154
155 assert(link);
156 assert(link->ifindex > 0);
157 assert(link->manager);
158 assert(link->dhcp_lease);
159 assert(link->dhcp4_6rd_tunnel_name);
160 assert(callback);
161
162 r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address);
163 if (r < 0)
164 return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m");
165
166 r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL);
167 if (r < 0)
168 return log_link_debug_errno(link, r, "Failed to get 6rd option: %m");
169
170 r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, 0);
171 if (r < 0)
172 return log_link_debug_errno(link, r, "Failed to create netlink message: %m");
173
174 r = dhcp4_pd_create_6rd_tunnel_message(link, m,
175 &ipv4address, ipv4masklen,
176 &sixrd_prefix, sixrd_prefixlen);
177 if (r < 0)
178 return log_link_debug_errno(link, r, "Failed to fill netlink message: %m");
179
180 r = netlink_call_async(link->manager->rtnl, NULL, m, callback,
181 link_netlink_destroy_callback, link);
182 if (r < 0)
183 return log_link_debug_errno(link, r, "Could not send netlink message: %m");
184
185 link_ref(link);
186
187 return 0;
188 }
189
190 static int tunnel_get_local_address(Tunnel *t, Link *link, union in_addr_union *ret) {
191 assert(t);
192
193 if (t->local_type < 0) {
194 if (ret)
195 *ret = t->local;
196 return 0;
197 }
198
199 return link_get_local_address(link, t->local_type, t->family, NULL, ret);
200 }
201
202 static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
203 union in_addr_union local;
204 Tunnel *t;
205 int r;
206
207 assert(netdev);
208 assert(m);
209
210 if (netdev->kind == NETDEV_KIND_IPIP)
211 t = IPIP(netdev);
212 else
213 t = SIT(netdev);
214
215 assert(t);
216
217 if (t->external) {
218 r = sd_netlink_message_append_flag(m, IFLA_IPTUN_COLLECT_METADATA);
219 if (r < 0)
220 return r;
221
222 /* If external mode is enabled, then the following settings should not be appended. */
223 return 0;
224 }
225
226 if (link || t->assign_to_loopback) {
227 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
228 if (r < 0)
229 return r;
230 }
231
232 r = tunnel_get_local_address(t, link, &local);
233 if (r < 0)
234 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
235
236 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &local.in);
237 if (r < 0)
238 return r;
239
240 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
241 if (r < 0)
242 return r;
243
244 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
245 if (r < 0)
246 return r;
247
248 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
249 if (r < 0)
250 return r;
251
252 if (t->fou_tunnel) {
253 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_TYPE, t->fou_encap_type);
254 if (r < 0)
255 return r;
256
257 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_SPORT, htobe16(t->encap_src_port));
258 if (r < 0)
259 return r;
260
261 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_DPORT, htobe16(t->fou_destination_port));
262 if (r < 0)
263 return r;
264 }
265
266 if (netdev->kind == NETDEV_KIND_SIT) {
267 if (t->sixrd_prefixlen > 0) {
268 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix);
269 if (r < 0)
270 return r;
271
272 /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
273 * expecting to receive the prefixlen as a u16.
274 */
275 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, t->sixrd_prefixlen);
276 if (r < 0)
277 return r;
278 }
279
280 if (t->isatap >= 0) {
281 uint16_t flags = 0;
282
283 SET_FLAG(flags, SIT_ISATAP, t->isatap);
284
285 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags);
286 if (r < 0)
287 return r;
288 }
289 }
290
291 return 0;
292 }
293
294 static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
295 union in_addr_union local;
296 uint32_t ikey = 0;
297 uint32_t okey = 0;
298 uint16_t iflags = 0;
299 uint16_t oflags = 0;
300 Tunnel *t;
301 int r;
302
303 assert(netdev);
304 assert(m);
305
306 switch (netdev->kind) {
307 case NETDEV_KIND_GRE:
308 t = GRE(netdev);
309 break;
310 case NETDEV_KIND_ERSPAN:
311 t = ERSPAN(netdev);
312 break;
313 case NETDEV_KIND_GRETAP:
314 t = GRETAP(netdev);
315 break;
316 default:
317 assert_not_reached();
318 }
319
320 assert(t);
321
322 if (t->external) {
323 r = sd_netlink_message_append_flag(m, IFLA_GRE_COLLECT_METADATA);
324 if (r < 0)
325 return r;
326
327 /* If external mode is enabled, then the following settings should not be appended. */
328 return 0;
329 }
330
331 if (link || t->assign_to_loopback) {
332 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
333 if (r < 0)
334 return r;
335 }
336
337 if (netdev->kind == NETDEV_KIND_ERSPAN) {
338 r = sd_netlink_message_append_u8(m, IFLA_GRE_ERSPAN_VER, t->erspan_version);
339 if (r < 0)
340 return r;
341
342 if (t->erspan_version == 1) {
343 r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
344 if (r < 0)
345 return r;
346
347 } else if (t->erspan_version == 2) {
348 r = sd_netlink_message_append_u8(m, IFLA_GRE_ERSPAN_DIR, t->erspan_direction);
349 if (r < 0)
350 return r;
351
352 r = sd_netlink_message_append_u16(m, IFLA_GRE_ERSPAN_HWID, t->erspan_hwid);
353 if (r < 0)
354 return r;
355 }
356 }
357
358 r = tunnel_get_local_address(t, link, &local);
359 if (r < 0)
360 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
361
362 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &local.in);
363 if (r < 0)
364 return r;
365
366 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
367 if (r < 0)
368 return r;
369
370 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
371 if (r < 0)
372 return r;
373
374 r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
375 if (r < 0)
376 return r;
377
378 r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
379 if (r < 0)
380 return r;
381
382 if (t->key != 0) {
383 ikey = okey = htobe32(t->key);
384 iflags |= GRE_KEY;
385 oflags |= GRE_KEY;
386 }
387
388 if (t->ikey != 0) {
389 ikey = htobe32(t->ikey);
390 iflags |= GRE_KEY;
391 }
392
393 if (t->okey != 0) {
394 okey = htobe32(t->okey);
395 oflags |= GRE_KEY;
396 }
397
398 if (t->gre_erspan_sequence > 0) {
399 iflags |= GRE_SEQ;
400 oflags |= GRE_SEQ;
401 } else if (t->gre_erspan_sequence == 0) {
402 iflags &= ~GRE_SEQ;
403 oflags &= ~GRE_SEQ;
404 }
405
406 r = sd_netlink_message_append_u32(m, IFLA_GRE_IKEY, ikey);
407 if (r < 0)
408 return r;
409
410 r = sd_netlink_message_append_u32(m, IFLA_GRE_OKEY, okey);
411 if (r < 0)
412 return r;
413
414 r = sd_netlink_message_append_u16(m, IFLA_GRE_IFLAGS, iflags);
415 if (r < 0)
416 return r;
417
418 r = sd_netlink_message_append_u16(m, IFLA_GRE_OFLAGS, oflags);
419 if (r < 0)
420 return r;
421
422 if (t->fou_tunnel) {
423 r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_TYPE, t->fou_encap_type);
424 if (r < 0)
425 return r;
426
427 r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_SPORT, htobe16(t->encap_src_port));
428 if (r < 0)
429 return r;
430
431 r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_DPORT, htobe16(t->fou_destination_port));
432 if (r < 0)
433 return r;
434 }
435
436 return 0;
437 }
438
439 static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
440 union in_addr_union local;
441 uint32_t ikey = 0;
442 uint32_t okey = 0;
443 uint16_t iflags = 0;
444 uint16_t oflags = 0;
445 Tunnel *t;
446 int r;
447
448 assert(netdev);
449 assert(m);
450
451 if (netdev->kind == NETDEV_KIND_IP6GRE)
452 t = IP6GRE(netdev);
453 else
454 t = IP6GRETAP(netdev);
455
456 assert(t);
457
458 if (t->external) {
459 r = sd_netlink_message_append_flag(m, IFLA_GRE_COLLECT_METADATA);
460 if (r < 0)
461 return r;
462
463 /* If external mode is enabled, then the following settings should not be appended. */
464 return 0;
465 }
466
467 if (link || t->assign_to_loopback) {
468 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
469 if (r < 0)
470 return r;
471 }
472
473 r = tunnel_get_local_address(t, link, &local);
474 if (r < 0)
475 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
476
477 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &local.in6);
478 if (r < 0)
479 return r;
480
481 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
482 if (r < 0)
483 return r;
484
485 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
486 if (r < 0)
487 return r;
488
489 if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
490 r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel);
491 if (r < 0)
492 return r;
493 }
494
495 r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags);
496 if (r < 0)
497 return r;
498
499 if (t->key != 0) {
500 ikey = okey = htobe32(t->key);
501 iflags |= GRE_KEY;
502 oflags |= GRE_KEY;
503 }
504
505 if (t->ikey != 0) {
506 ikey = htobe32(t->ikey);
507 iflags |= GRE_KEY;
508 }
509
510 if (t->okey != 0) {
511 okey = htobe32(t->okey);
512 oflags |= GRE_KEY;
513 }
514
515 r = sd_netlink_message_append_u32(m, IFLA_GRE_IKEY, ikey);
516 if (r < 0)
517 return r;
518
519 r = sd_netlink_message_append_u32(m, IFLA_GRE_OKEY, okey);
520 if (r < 0)
521 return r;
522
523 r = sd_netlink_message_append_u16(m, IFLA_GRE_IFLAGS, iflags);
524 if (r < 0)
525 return r;
526
527 r = sd_netlink_message_append_u16(m, IFLA_GRE_OFLAGS, oflags);
528 if (r < 0)
529 return r;
530
531 return 0;
532 }
533
534 static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
535 union in_addr_union local;
536 uint32_t ikey, okey;
537 Tunnel *t;
538 int r;
539
540 assert(netdev);
541 assert(m);
542
543 if (netdev->kind == NETDEV_KIND_VTI)
544 t = VTI(netdev);
545 else
546 t = VTI6(netdev);
547
548 assert(t);
549
550 if (link || t->assign_to_loopback) {
551 r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
552 if (r < 0)
553 return r;
554 }
555
556 if (t->key != 0)
557 ikey = okey = htobe32(t->key);
558 else {
559 ikey = htobe32(t->ikey);
560 okey = htobe32(t->okey);
561 }
562
563 r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey);
564 if (r < 0)
565 return r;
566
567 r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey);
568 if (r < 0)
569 return r;
570
571 r = tunnel_get_local_address(t, link, &local);
572 if (r < 0)
573 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
574
575 r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &local);
576 if (r < 0)
577 return r;
578
579 r = netlink_message_append_in_addr_union(m, IFLA_VTI_REMOTE, t->family, &t->remote);
580 if (r < 0)
581 return r;
582
583 return 0;
584 }
585
586 static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
587 union in_addr_union local;
588 uint8_t proto;
589 Tunnel *t;
590 int r;
591
592 assert(netdev);
593 assert(m);
594
595 t = IP6TNL(netdev);
596
597 assert(t);
598
599 switch (t->ip6tnl_mode) {
600 case NETDEV_IP6_TNL_MODE_IP6IP6:
601 proto = IPPROTO_IPV6;
602 break;
603 case NETDEV_IP6_TNL_MODE_IPIP6:
604 proto = IPPROTO_IPIP;
605 break;
606 case NETDEV_IP6_TNL_MODE_ANYIP6:
607 default:
608 proto = 0;
609 break;
610 }
611
612 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
613 if (r < 0)
614 return r;
615
616 if (t->external) {
617 r = sd_netlink_message_append_flag(m, IFLA_IPTUN_COLLECT_METADATA);
618 if (r < 0)
619 return r;
620
621 /* If external mode is enabled, then the following settings should not be appended. */
622 return 0;
623 }
624
625 if (link || t->assign_to_loopback) {
626 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
627 if (r < 0)
628 return r;
629 }
630
631 r = tunnel_get_local_address(t, link, &local);
632 if (r < 0)
633 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
634
635 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &local.in6);
636 if (r < 0)
637 return r;
638
639 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
640 if (r < 0)
641 return r;
642
643 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
644 if (r < 0)
645 return r;
646
647 if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
648 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel);
649 if (r < 0)
650 return r;
651 }
652
653 if (t->copy_dscp)
654 t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
655
656 if (t->allow_localremote >= 0)
657 SET_FLAG(t->flags, IP6_TNL_F_ALLOW_LOCAL_REMOTE, t->allow_localremote);
658
659 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
660 if (r < 0)
661 return r;
662
663 if (t->encap_limit != 0) {
664 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit);
665 if (r < 0)
666 return r;
667 }
668
669 return 0;
670 }
671
672 static int netdev_tunnel_is_ready_to_create(NetDev *netdev, Link *link) {
673 Tunnel *t;
674
675 assert(netdev);
676
677 t = TUNNEL(netdev);
678
679 assert(t);
680
681 if (t->independent)
682 return true;
683
684 return tunnel_get_local_address(t, link, NULL) >= 0;
685 }
686
687 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
688 Tunnel *t;
689
690 assert(netdev);
691 assert(filename);
692
693 t = TUNNEL(netdev);
694
695 assert(t);
696
697 if (netdev->kind == NETDEV_KIND_IP6TNL &&
698 t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID)
699 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
700 "ip6tnl without mode configured in %s. Ignoring", filename);
701
702 if (t->external) {
703 if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_VTI6))
704 log_netdev_debug(netdev, "vti/vti6 tunnel do not support external mode, ignoring.");
705 else {
706 /* tunnel with external mode does not require underlying interface. */
707 t->independent = true;
708
709 /* tunnel with external mode does not require any settings checked below. */
710 return 0;
711 }
712 }
713
714 if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE) &&
715 !IN_SET(t->family, AF_UNSPEC, AF_INET))
716 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
717 "vti/ipip/sit/gre tunnel without a local/remote IPv4 address configured in %s. Ignoring", filename);
718
719 if (IN_SET(netdev->kind, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) &&
720 (t->family != AF_INET || !in_addr_is_set(t->family, &t->remote)))
721 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
722 "gretap/erspan tunnel without a remote IPv4 address configured in %s. Ignoring", filename);
723
724 if ((IN_SET(netdev->kind, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL) && t->family != AF_INET6) ||
725 (netdev->kind == NETDEV_KIND_IP6GRE && !IN_SET(t->family, AF_UNSPEC, AF_INET6)))
726 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
727 "vti6/ip6tnl/ip6gre tunnel without a local/remote IPv6 address configured in %s. Ignoring", filename);
728
729 if (netdev->kind == NETDEV_KIND_IP6GRETAP &&
730 (t->family != AF_INET6 || !in_addr_is_set(t->family, &t->remote)))
731 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
732 "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename);
733
734 if (t->fou_tunnel && t->fou_destination_port <= 0)
735 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
736 "FooOverUDP missing port configured in %s. Ignoring", filename);
737
738 /* netlink_message_append_in_addr_union() is used for vti/vti6. So, t->family cannot be AF_UNSPEC. */
739 if (netdev->kind == NETDEV_KIND_VTI)
740 t->family = AF_INET;
741
742 if (t->assign_to_loopback)
743 t->independent = true;
744
745 if (t->independent && t->local_type >= 0)
746 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
747 "The local address cannot be '%s' when Independent= or AssignToLoopback= is enabled, ignoring.",
748 strna(netdev_local_address_type_to_string(t->local_type)));
749
750 return 0;
751 }
752
753 static int unset_local(Tunnel *t) {
754 assert(t);
755
756 /* Unset the previous assignment. */
757 t->local = IN_ADDR_NULL;
758 t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
759
760 /* If the remote address is not specified, also clear the address family. */
761 if (!in_addr_is_set(t->family, &t->remote))
762 t->family = AF_UNSPEC;
763
764 return 0;
765 }
766
767 int config_parse_tunnel_local_address(
768 const char *unit,
769 const char *filename,
770 unsigned line,
771 const char *section,
772 unsigned section_line,
773 const char *lvalue,
774 int ltype,
775 const char *rvalue,
776 void *data,
777 void *userdata) {
778
779 union in_addr_union buffer = IN_ADDR_NULL;
780 NetDevLocalAddressType type;
781 Tunnel *t = ASSERT_PTR(userdata);
782 int r, f;
783
784 assert(filename);
785 assert(lvalue);
786 assert(rvalue);
787
788 if (isempty(rvalue) || streq(rvalue, "any"))
789 return unset_local(t);
790
791 type = netdev_local_address_type_from_string(rvalue);
792 if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV4LL, NETDEV_LOCAL_ADDRESS_DHCP4))
793 f = AF_INET;
794 else if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV6LL, NETDEV_LOCAL_ADDRESS_DHCP6, NETDEV_LOCAL_ADDRESS_SLAAC))
795 f = AF_INET6;
796 else {
797 type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
798 r = in_addr_from_string_auto(rvalue, &f, &buffer);
799 if (r < 0) {
800 log_syntax(unit, LOG_WARNING, filename, line, r,
801 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue);
802 return 0;
803 }
804
805 if (in_addr_is_null(f, &buffer))
806 return unset_local(t);
807 }
808
809 if (t->family != AF_UNSPEC && t->family != f) {
810 log_syntax(unit, LOG_WARNING, filename, line, 0,
811 "Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
812 return 0;
813 }
814
815 t->family = f;
816 t->local = buffer;
817 t->local_type = type;
818 return 0;
819 }
820
821 static int unset_remote(Tunnel *t) {
822 assert(t);
823
824 /* Unset the previous assignment. */
825 t->remote = IN_ADDR_NULL;
826
827 /* If the local address is not specified, also clear the address family. */
828 if (t->local_type == _NETDEV_LOCAL_ADDRESS_TYPE_INVALID &&
829 !in_addr_is_set(t->family, &t->local))
830 t->family = AF_UNSPEC;
831
832 return 0;
833 }
834
835 int config_parse_tunnel_remote_address(
836 const char *unit,
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
846
847 union in_addr_union buffer;
848 Tunnel *t = ASSERT_PTR(userdata);
849 int r, f;
850
851 assert(filename);
852 assert(lvalue);
853 assert(rvalue);
854
855 if (isempty(rvalue) || streq(rvalue, "any"))
856 return unset_remote(t);
857
858 r = in_addr_from_string_auto(rvalue, &f, &buffer);
859 if (r < 0) {
860 log_syntax(unit, LOG_WARNING, filename, line, r,
861 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue);
862 return 0;
863 }
864
865 if (in_addr_is_null(f, &buffer))
866 return unset_remote(t);
867
868 if (t->family != AF_UNSPEC && t->family != f) {
869 log_syntax(unit, LOG_WARNING, filename, line, 0,
870 "Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
871 return 0;
872 }
873
874 t->family = f;
875 t->remote = buffer;
876 return 0;
877 }
878
879 int config_parse_tunnel_key(
880 const char *unit,
881 const char *filename,
882 unsigned line,
883 const char *section,
884 unsigned section_line,
885 const char *lvalue,
886 int ltype,
887 const char *rvalue,
888 void *data,
889 void *userdata) {
890
891 uint32_t *dest = ASSERT_PTR(data), k;
892 union in_addr_union buffer;
893 int r;
894
895 assert(filename);
896 assert(rvalue);
897
898 r = in_addr_from_string(AF_INET, rvalue, &buffer);
899 if (r < 0) {
900 r = safe_atou32(rvalue, &k);
901 if (r < 0) {
902 log_syntax(unit, LOG_WARNING, filename, line, r,
903 "Failed to parse tunnel key ignoring assignment: %s", rvalue);
904 return 0;
905 }
906 } else
907 k = be32toh(buffer.in.s_addr);
908
909 *dest = k;
910 return 0;
911 }
912
913 int config_parse_ipv6_flowlabel(
914 const char* unit,
915 const char *filename,
916 unsigned line,
917 const char *section,
918 unsigned section_line,
919 const char *lvalue,
920 int ltype,
921 const char *rvalue,
922 void *data,
923 void *userdata) {
924
925 Tunnel *t = ASSERT_PTR(userdata);
926 int k, r;
927
928 assert(filename);
929 assert(rvalue);
930
931 if (streq(rvalue, "inherit")) {
932 t->ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
933 t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
934 return 0;
935 }
936
937 r = safe_atoi(rvalue, &k);
938 if (r < 0) {
939 log_syntax(unit, LOG_WARNING, filename, line, r,
940 "Failed to parse tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue);
941 return 0;
942 }
943
944 if (k > 0xFFFFF) {
945 log_syntax(unit, LOG_WARNING, filename, line, 0,
946 "Invalid tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue);
947 return 0;
948 }
949
950 t->ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL;
951 t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
952 return 0;
953 }
954
955 int config_parse_encap_limit(
956 const char* unit,
957 const char *filename,
958 unsigned line,
959 const char *section,
960 unsigned section_line,
961 const char *lvalue,
962 int ltype,
963 const char *rvalue,
964 void *data,
965 void *userdata) {
966
967 Tunnel *t = ASSERT_PTR(userdata);
968 int k, r;
969
970 assert(filename);
971 assert(rvalue);
972
973 if (streq(rvalue, "none")) {
974 t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
975 t->encap_limit = 0;
976 return 0;
977 }
978
979 r = safe_atoi(rvalue, &k);
980 if (r < 0) {
981 log_syntax(unit, LOG_WARNING, filename, line, r,
982 "Failed to parse Tunnel Encapsulation Limit option, ignoring assignment: %s", rvalue);
983 return 0;
984 }
985
986 if (k > 255 || k < 0) {
987 log_syntax(unit, LOG_WARNING, filename, line, 0,
988 "Invalid Tunnel Encapsulation value, ignoring assignment: %d", k);
989 return 0;
990 }
991
992 t->encap_limit = k;
993 t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
994 return 0;
995 }
996
997 int config_parse_6rd_prefix(
998 const char* unit,
999 const char *filename,
1000 unsigned line,
1001 const char *section,
1002 unsigned section_line,
1003 const char *lvalue,
1004 int ltype,
1005 const char *rvalue,
1006 void *data,
1007 void *userdata) {
1008
1009 Tunnel *t = userdata;
1010 union in_addr_union p;
1011 uint8_t l;
1012 int r;
1013
1014 assert(filename);
1015 assert(lvalue);
1016 assert(rvalue);
1017
1018 r = in_addr_prefix_from_string(rvalue, AF_INET6, &p, &l);
1019 if (r < 0) {
1020 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue);
1021 return 0;
1022 }
1023 if (l == 0) {
1024 log_syntax(unit, LOG_WARNING, filename, line, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue);
1025 return 0;
1026 }
1027
1028 t->sixrd_prefix = p.in6;
1029 t->sixrd_prefixlen = l;
1030
1031 return 0;
1032 }
1033
1034 int config_parse_erspan_version(
1035 const char* unit,
1036 const char *filename,
1037 unsigned line,
1038 const char *section,
1039 unsigned section_line,
1040 const char *lvalue,
1041 int ltype,
1042 const char *rvalue,
1043 void *data,
1044 void *userdata) {
1045
1046 uint8_t n, *v = ASSERT_PTR(data);
1047 int r;
1048
1049 assert(filename);
1050 assert(lvalue);
1051 assert(rvalue);
1052
1053 if (isempty(rvalue)) {
1054 *v = 1; /* defaults to 1 */
1055 return 0;
1056 }
1057
1058 r = safe_atou8(rvalue, &n);
1059 if (r < 0) {
1060 log_syntax(unit, LOG_WARNING, filename, line, r,
1061 "Failed to parse erspan version \"%s\", ignoring: %m", rvalue);
1062 return 0;
1063 }
1064 if (!IN_SET(n, 0, 1, 2)) {
1065 log_syntax(unit, LOG_WARNING, filename, line, 0,
1066 "Invalid erspan version \"%s\", which must be 0, 1 or 2, ignoring.", rvalue);
1067 return 0;
1068 }
1069
1070 *v = n;
1071 return 0;
1072 }
1073
1074 int config_parse_erspan_index(
1075 const char* unit,
1076 const char *filename,
1077 unsigned line,
1078 const char *section,
1079 unsigned section_line,
1080 const char *lvalue,
1081 int ltype,
1082 const char *rvalue,
1083 void *data,
1084 void *userdata) {
1085
1086 uint32_t n, *v = ASSERT_PTR(data);
1087 int r;
1088
1089 assert(filename);
1090 assert(lvalue);
1091 assert(rvalue);
1092
1093 if (isempty(rvalue)) {
1094 *v = 0; /* defaults to 0 */
1095 return 0;
1096 }
1097
1098 r = safe_atou32(rvalue, &n);
1099 if (r < 0) {
1100 log_syntax(unit, LOG_WARNING, filename, line, r,
1101 "Failed to parse erspan index \"%s\", ignoring: %m", rvalue);
1102 return 0;
1103 }
1104 if (n >= 0x100000) {
1105 log_syntax(unit, LOG_WARNING, filename, line, 0,
1106 "Invalid erspan index \"%s\", which must be less than 0x100000, ignoring.", rvalue);
1107 return 0;
1108 }
1109
1110 *v = n;
1111 return 0;
1112 }
1113
1114 int config_parse_erspan_direction(
1115 const char* unit,
1116 const char *filename,
1117 unsigned line,
1118 const char *section,
1119 unsigned section_line,
1120 const char *lvalue,
1121 int ltype,
1122 const char *rvalue,
1123 void *data,
1124 void *userdata) {
1125
1126 uint8_t *v = ASSERT_PTR(data);
1127
1128 assert(filename);
1129 assert(lvalue);
1130 assert(rvalue);
1131
1132 if (isempty(rvalue) || streq(rvalue, "ingress"))
1133 *v = 0; /* defaults to ingress */
1134 else if (streq(rvalue, "egress"))
1135 *v = 1;
1136 else
1137 log_syntax(unit, LOG_WARNING, filename, line, 0,
1138 "Invalid erspan direction \"%s\", which must be \"ingress\" or \"egress\", ignoring.", rvalue);
1139
1140 return 0;
1141 }
1142
1143 int config_parse_erspan_hwid(
1144 const char* unit,
1145 const char *filename,
1146 unsigned line,
1147 const char *section,
1148 unsigned section_line,
1149 const char *lvalue,
1150 int ltype,
1151 const char *rvalue,
1152 void *data,
1153 void *userdata) {
1154
1155 uint16_t n, *v = ASSERT_PTR(data);
1156 int r;
1157
1158 assert(filename);
1159 assert(lvalue);
1160 assert(rvalue);
1161
1162 if (isempty(rvalue)) {
1163 *v = 0; /* defaults to 0 */
1164 return 0;
1165 }
1166
1167 r = safe_atou16(rvalue, &n);
1168 if (r < 0) {
1169 log_syntax(unit, LOG_WARNING, filename, line, r,
1170 "Failed to parse erspan hwid \"%s\", ignoring: %m", rvalue);
1171 return 0;
1172 }
1173 if (n >= 64) {
1174 log_syntax(unit, LOG_WARNING, filename, line, 0,
1175 "Invalid erspan index \"%s\", which must be less than 64, ignoring.", rvalue);
1176 return 0;
1177 }
1178
1179 *v = n;
1180 return 0;
1181 }
1182
1183 static void netdev_tunnel_init(NetDev *netdev) {
1184 Tunnel *t;
1185
1186 assert(netdev);
1187
1188 t = TUNNEL(netdev);
1189
1190 assert(t);
1191
1192 t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
1193 t->pmtudisc = true;
1194 t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
1195 t->isatap = -1;
1196 t->gre_erspan_sequence = -1;
1197 t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
1198 t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
1199 t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
1200 t->allow_localremote = -1;
1201 t->erspan_version = 1;
1202
1203 if (IN_SET(netdev->kind, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP, NETDEV_KIND_IP6TNL))
1204 t->ttl = DEFAULT_IPV6_TTL;
1205 }
1206
1207 const NetDevVTable ipip_vtable = {
1208 .object_size = sizeof(Tunnel),
1209 .init = netdev_tunnel_init,
1210 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1211 .fill_message_create = netdev_ipip_sit_fill_message_create,
1212 .create_type = NETDEV_CREATE_STACKED,
1213 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1214 .config_verify = netdev_tunnel_verify,
1215 .iftype = ARPHRD_TUNNEL,
1216 };
1217
1218 const NetDevVTable sit_vtable = {
1219 .object_size = sizeof(Tunnel),
1220 .init = netdev_tunnel_init,
1221 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1222 .fill_message_create = netdev_ipip_sit_fill_message_create,
1223 .create_type = NETDEV_CREATE_STACKED,
1224 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1225 .config_verify = netdev_tunnel_verify,
1226 .iftype = ARPHRD_SIT,
1227 };
1228
1229 const NetDevVTable vti_vtable = {
1230 .object_size = sizeof(Tunnel),
1231 .init = netdev_tunnel_init,
1232 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1233 .fill_message_create = netdev_vti_fill_message_create,
1234 .create_type = NETDEV_CREATE_STACKED,
1235 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1236 .config_verify = netdev_tunnel_verify,
1237 .iftype = ARPHRD_TUNNEL,
1238 };
1239
1240 const NetDevVTable vti6_vtable = {
1241 .object_size = sizeof(Tunnel),
1242 .init = netdev_tunnel_init,
1243 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1244 .fill_message_create = netdev_vti_fill_message_create,
1245 .create_type = NETDEV_CREATE_STACKED,
1246 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1247 .config_verify = netdev_tunnel_verify,
1248 .iftype = ARPHRD_TUNNEL6,
1249 };
1250
1251 const NetDevVTable gre_vtable = {
1252 .object_size = sizeof(Tunnel),
1253 .init = netdev_tunnel_init,
1254 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1255 .fill_message_create = netdev_gre_erspan_fill_message_create,
1256 .create_type = NETDEV_CREATE_STACKED,
1257 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1258 .config_verify = netdev_tunnel_verify,
1259 .iftype = ARPHRD_IPGRE,
1260 };
1261
1262 const NetDevVTable gretap_vtable = {
1263 .object_size = sizeof(Tunnel),
1264 .init = netdev_tunnel_init,
1265 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1266 .fill_message_create = netdev_gre_erspan_fill_message_create,
1267 .create_type = NETDEV_CREATE_STACKED,
1268 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1269 .config_verify = netdev_tunnel_verify,
1270 .iftype = ARPHRD_ETHER,
1271 .generate_mac = true,
1272 };
1273
1274 const NetDevVTable ip6gre_vtable = {
1275 .object_size = sizeof(Tunnel),
1276 .init = netdev_tunnel_init,
1277 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1278 .fill_message_create = netdev_ip6gre_fill_message_create,
1279 .create_type = NETDEV_CREATE_STACKED,
1280 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1281 .config_verify = netdev_tunnel_verify,
1282 .iftype = ARPHRD_IP6GRE,
1283 };
1284
1285 const NetDevVTable ip6gretap_vtable = {
1286 .object_size = sizeof(Tunnel),
1287 .init = netdev_tunnel_init,
1288 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1289 .fill_message_create = netdev_ip6gre_fill_message_create,
1290 .create_type = NETDEV_CREATE_STACKED,
1291 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1292 .config_verify = netdev_tunnel_verify,
1293 .iftype = ARPHRD_ETHER,
1294 .generate_mac = true,
1295 };
1296
1297 const NetDevVTable ip6tnl_vtable = {
1298 .object_size = sizeof(Tunnel),
1299 .init = netdev_tunnel_init,
1300 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1301 .fill_message_create = netdev_ip6tnl_fill_message_create,
1302 .create_type = NETDEV_CREATE_STACKED,
1303 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1304 .config_verify = netdev_tunnel_verify,
1305 .iftype = ARPHRD_TUNNEL6,
1306 };
1307
1308 const NetDevVTable erspan_vtable = {
1309 .object_size = sizeof(Tunnel),
1310 .init = netdev_tunnel_init,
1311 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
1312 .fill_message_create = netdev_gre_erspan_fill_message_create,
1313 .create_type = NETDEV_CREATE_STACKED,
1314 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1315 .config_verify = netdev_tunnel_verify,
1316 .iftype = ARPHRD_ETHER,
1317 .generate_mac = true,
1318 };