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