1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/if_arp.h>
4 #include <linux/if_tunnel.h>
5 #include <linux/ip6_tunnel.h>
6 #include <netinet/in.h>
8 #include "sd-netlink.h"
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"
22 #define DEFAULT_IPV6_TTL 64
23 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
24 #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
26 #define HASH_KEY SD_ID128_MAKE(74,c4,de,12,f3,d9,41,34,bb,3d,c1,a4,42,93,50,87)
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
,
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",
44 DEFINE_STRING_TABLE_LOOKUP(tunnel_mode
, TunnelMode
);
45 DEFINE_CONFIG_PARSE_ENUM(config_parse_tunnel_mode
, tunnel_mode
, TunnelMode
);
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
];
58 assert(link
->dhcp_lease
);
60 if (link
->dhcp4_6rd_tunnel_name
)
61 return 0; /* Already set. Do not change even if the 6rd option is changed. */
63 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &ipv4address
);
67 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, NULL
, NULL
);
71 sz
= sizeof(uint8_t) * 2 + sizeof(struct in6_addr
) + sizeof(struct in_addr
);
72 buf
= newa(uint8_t, sz
);
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
));
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
);
94 ifname_alloc
= strdup(ifname
);
98 link
->dhcp4_6rd_tunnel_name
= TAKE_PTR(ifname_alloc
);
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
;
111 assert(link
->manager
);
112 assert(link
->manager
->rtnl
);
113 assert(link
->dhcp_lease
);
116 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &ipv4address
);
120 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, NULL
, NULL
);
124 r
= dhcp4_pd_create_6rd_tunnel_name(link
);
128 (void) link_get_by_name(link
->manager
, link
->dhcp4_6rd_tunnel_name
, &sit
);
130 r
= sd_rtnl_message_new_link(link
->manager
->rtnl
, &m
, RTM_NEWLINK
, sit
? sit
->ifindex
: 0);
134 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, link
->dhcp4_6rd_tunnel_name
);
138 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
142 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "sit");
146 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &ipv4address
);
150 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, 64);
154 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_6RD_PREFIX
, &sixrd_prefix
);
158 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, sixrd_prefixlen
);
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
);
168 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_RELAY_PREFIXLEN
, ipv4masklen
);
172 r
= sd_netlink_message_close_container(m
);
176 r
= sd_netlink_message_close_container(m
);
180 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, m
, callback
,
181 link_netlink_destroy_callback
, link
);
189 static int tunnel_get_local_address(Tunnel
*t
, Link
*link
, union in_addr_union
*ret
) {
192 if (t
->local_type
< 0) {
198 return link_get_local_address(link
, t
->local_type
, t
->family
, NULL
, ret
);
201 static int netdev_ipip_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
204 union in_addr_union local
;
205 Tunnel
*t
= ASSERT_PTR(netdev
)->kind
== NETDEV_KIND_IPIP
? IPIP(netdev
) : SIT(netdev
);
209 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, tunnel_mode_to_proto
[t
->mode
]);
215 r
= sd_netlink_message_append_flag(m
, IFLA_IPTUN_COLLECT_METADATA
);
219 /* If external mode is enabled, then the following settings should not be appended. */
223 if (link
|| t
->assign_to_loopback
) {
224 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
229 r
= tunnel_get_local_address(t
, link
, &local
);
231 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
233 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &local
.in
);
237 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
241 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
245 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
250 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_TYPE
, t
->fou_encap_type
);
254 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
258 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
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
);
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.
272 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, t
->sixrd_prefixlen
);
277 if (t
->isatap
>= 0) {
280 SET_FLAG(flags
, SIT_ISATAP
, t
->isatap
);
282 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_FLAGS
, flags
);
291 static int netdev_gre_erspan_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
292 union in_addr_union local
;
303 switch (netdev
->kind
) {
304 case NETDEV_KIND_GRE
:
307 case NETDEV_KIND_ERSPAN
:
310 case NETDEV_KIND_GRETAP
:
314 assert_not_reached();
318 r
= sd_netlink_message_append_flag(m
, IFLA_GRE_COLLECT_METADATA
);
322 /* If external mode is enabled, then the following settings should not be appended. */
326 if (link
|| t
->assign_to_loopback
) {
327 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
332 if (netdev
->kind
== NETDEV_KIND_ERSPAN
) {
333 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_ERSPAN_VER
, t
->erspan_version
);
337 if (t
->erspan_version
== 1) {
338 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_ERSPAN_INDEX
, t
->erspan_index
);
342 } else if (t
->erspan_version
== 2) {
343 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_ERSPAN_DIR
, t
->erspan_direction
);
347 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ERSPAN_HWID
, t
->erspan_hwid
);
353 r
= tunnel_get_local_address(t
, link
, &local
);
355 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
357 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &local
.in
);
361 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
365 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
369 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
373 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
377 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_IGNORE_DF
, t
->ignore_df
);
382 ikey
= okey
= htobe32(t
->key
);
388 ikey
= htobe32(t
->ikey
);
393 okey
= htobe32(t
->okey
);
397 if (t
->gre_erspan_sequence
> 0) {
400 } else if (t
->gre_erspan_sequence
== 0) {
405 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_IKEY
, ikey
);
409 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_OKEY
, okey
);
413 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_IFLAGS
, iflags
);
417 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_OFLAGS
, oflags
);
422 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_TYPE
, t
->fou_encap_type
);
426 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
430 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
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;
448 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
451 t
= IP6GRETAP(netdev
);
454 r
= sd_netlink_message_append_flag(m
, IFLA_GRE_COLLECT_METADATA
);
458 /* If external mode is enabled, then the following settings should not be appended. */
462 if (link
|| t
->assign_to_loopback
) {
463 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
468 r
= tunnel_get_local_address(t
, link
, &local
);
470 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
472 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &local
.in6
);
476 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
480 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
484 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
485 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
490 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
495 ikey
= okey
= htobe32(t
->key
);
501 ikey
= htobe32(t
->ikey
);
506 okey
= htobe32(t
->okey
);
510 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_IKEY
, ikey
);
514 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_OKEY
, okey
);
518 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_IFLAGS
, iflags
);
522 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_OFLAGS
, oflags
);
529 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
533 union in_addr_union local
;
535 Tunnel
*t
= netdev
->kind
== NETDEV_KIND_VTI
? VTI(netdev
) : VTI6(netdev
);
538 if (link
|| t
->assign_to_loopback
) {
539 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
545 ikey
= okey
= htobe32(t
->key
);
547 ikey
= htobe32(t
->ikey
);
548 okey
= htobe32(t
->okey
);
551 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
555 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
559 r
= tunnel_get_local_address(t
, link
, &local
);
561 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
563 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_LOCAL
, t
->family
, &local
);
567 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_REMOTE
, t
->family
, &t
->remote
);
574 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
578 union in_addr_union local
;
579 Tunnel
*t
= IP6TNL(netdev
);
583 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, tunnel_mode_to_proto
[t
->mode
]);
589 r
= sd_netlink_message_append_flag(m
, IFLA_IPTUN_COLLECT_METADATA
);
593 /* If external mode is enabled, then the following settings should not be appended. */
597 if (link
|| t
->assign_to_loopback
) {
598 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
603 r
= tunnel_get_local_address(t
, link
, &local
);
605 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
607 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &local
.in6
);
611 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
615 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
619 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
620 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
626 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
628 if (t
->allow_localremote
>= 0)
629 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
631 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
635 if (t
->encap_limit
!= 0) {
636 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
644 static int netdev_tunnel_is_ready_to_create(NetDev
*netdev
, Link
*link
) {
647 Tunnel
*t
= ASSERT_PTR(TUNNEL(netdev
));
652 return tunnel_get_local_address(t
, link
, NULL
) >= 0;
655 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
659 Tunnel
*t
= ASSERT_PTR(TUNNEL(netdev
));
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.");
665 /* tunnel with external mode does not require underlying interface. */
666 t
->independent
= true;
668 /* tunnel with external mode does not require any settings checked below. */
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
);
679 t
->family
= AF_INET
; /* For netlink_message_append_in_addr_union(). */
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(). */
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
);
694 if (t
->assign_to_loopback
)
695 t
->independent
= true;
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
)));
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");
706 t
->pmtudisc
= !t
->ignore_df
;
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
));
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
));
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
));
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
));
738 static bool tunnel_needs_reconfigure(NetDev
*netdev
, NetDevLocalAddressType type
) {
739 assert(type
>= 0 && type
< _NETDEV_LOCAL_ADDRESS_TYPE_MAX
);
741 Tunnel
*t
= ASSERT_PTR(TUNNEL(netdev
));
743 return t
->local_type
== type
;
746 static int unset_local(Tunnel
*t
) {
749 /* Unset the previous assignment. */
750 t
->local
= IN_ADDR_NULL
;
751 t
->local_type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
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
;
760 int config_parse_tunnel_local_address(
762 const char *filename
,
765 unsigned section_line
,
772 union in_addr_union buffer
= IN_ADDR_NULL
;
773 NetDevLocalAddressType type
;
774 Tunnel
*t
= ASSERT_PTR(userdata
);
781 if (isempty(rvalue
) || streq(rvalue
, "any"))
782 return unset_local(t
);
784 type
= netdev_local_address_type_from_string(rvalue
);
785 if (IN_SET(type
, NETDEV_LOCAL_ADDRESS_IPV4LL
, NETDEV_LOCAL_ADDRESS_DHCP4
))
787 else if (IN_SET(type
, NETDEV_LOCAL_ADDRESS_IPV6LL
, NETDEV_LOCAL_ADDRESS_DHCP6
, NETDEV_LOCAL_ADDRESS_SLAAC
))
790 type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
791 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
793 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
794 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
798 if (in_addr_is_null(f
, &buffer
))
799 return unset_local(t
);
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
);
810 t
->local_type
= type
;
814 static int unset_remote(Tunnel
*t
) {
817 /* Unset the previous assignment. */
818 t
->remote
= IN_ADDR_NULL
;
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
;
828 int config_parse_tunnel_remote_address(
830 const char *filename
,
833 unsigned section_line
,
840 union in_addr_union buffer
;
841 Tunnel
*t
= ASSERT_PTR(userdata
);
848 if (isempty(rvalue
) || streq(rvalue
, "any"))
849 return unset_remote(t
);
851 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
853 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
854 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
858 if (in_addr_is_null(f
, &buffer
))
859 return unset_remote(t
);
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
);
872 int config_parse_tunnel_key(
874 const char *filename
,
877 unsigned section_line
,
884 uint32_t *dest
= ASSERT_PTR(data
), k
;
885 union in_addr_union buffer
;
891 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
893 r
= safe_atou32(rvalue
, &k
);
895 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
896 "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
900 k
= be32toh(buffer
.in
.s_addr
);
906 int config_parse_ipv6_flowlabel(
908 const char *filename
,
911 unsigned section_line
,
918 Tunnel
*t
= ASSERT_PTR(userdata
);
925 if (streq(rvalue
, "inherit")) {
926 t
->ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
927 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
931 r
= config_parse_uint32_bounded(
932 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
937 t
->ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
938 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
943 int config_parse_encap_limit(
945 const char *filename
,
948 unsigned section_line
,
958 Tunnel
*t
= ASSERT_PTR(userdata
);
961 if (streq(rvalue
, "none")) {
963 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
967 r
= config_parse_uint8_bounded(
968 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
973 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
978 int config_parse_6rd_prefix(
980 const char *filename
,
983 unsigned section_line
,
990 Tunnel
*t
= userdata
;
991 union in_addr_union p
;
999 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &p
, &l
);
1001 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue
);
1005 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue
);
1009 t
->sixrd_prefix
= p
.in6
;
1010 t
->sixrd_prefixlen
= l
;
1015 int config_parse_erspan_version(
1017 const char *filename
,
1019 const char *section
,
1020 unsigned section_line
,
1031 uint8_t *v
= ASSERT_PTR(data
);
1033 if (isempty(rvalue
)) {
1034 *v
= 1; /* defaults to 1 */
1038 return config_parse_uint8_bounded(
1039 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
1044 int config_parse_erspan_index(
1046 const char *filename
,
1048 const char *section
,
1049 unsigned section_line
,
1060 uint32_t *v
= ASSERT_PTR(data
);
1062 if (isempty(rvalue
)) {
1063 *v
= 0; /* defaults to 0 */
1067 return config_parse_uint32_bounded(
1068 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
1069 0, 0x100000 - 1, true,
1073 int config_parse_erspan_direction(
1075 const char *filename
,
1077 const char *section
,
1078 unsigned section_line
,
1089 uint8_t *v
= ASSERT_PTR(data
);
1091 if (isempty(rvalue
) || streq(rvalue
, "ingress"))
1092 *v
= 0; /* defaults to ingress */
1093 else if (streq(rvalue
, "egress"))
1096 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1097 "Invalid erspan direction \"%s\", which must be \"ingress\" or \"egress\", ignoring.", rvalue
);
1102 int config_parse_erspan_hwid(
1104 const char *filename
,
1106 const char *section
,
1107 unsigned section_line
,
1118 uint16_t *v
= ASSERT_PTR(data
);
1120 if (isempty(rvalue
)) {
1121 *v
= 0; /* defaults to 0 */
1125 return config_parse_uint16_bounded(
1126 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
1131 static void netdev_tunnel_init(NetDev
*netdev
) {
1132 Tunnel
*t
= ASSERT_PTR(TUNNEL(netdev
));
1134 t
->local_type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
1136 t
->fou_encap_type
= NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
;
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;
1145 if (IN_SET(netdev
->kind
, NETDEV_KIND_IP6GRE
, NETDEV_KIND_IP6GRETAP
, NETDEV_KIND_IP6TNL
))
1146 t
->ttl
= DEFAULT_IPV6_TTL
;
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
));
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
,
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
,
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
,
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
,
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
,
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,
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
,
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,
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
,
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,