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