1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
5 #include <linux/if_arp.h>
6 #include <linux/if_tunnel.h>
8 #include <linux/ip6_tunnel.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 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",
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");
35 #define HASH_KEY SD_ID128_MAKE(74,c4,de,12,f3,d9,41,34,bb,3d,c1,a4,42,93,50,87)
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
];
48 assert(link
->dhcp_lease
);
50 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &ipv4address
);
52 return log_link_debug_errno(link
, r
, "Failed to get DHCPv4 address: %m");
54 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, NULL
, NULL
);
56 return log_link_debug_errno(link
, r
, "Failed to get 6rd option: %m");
58 sz
= sizeof(uint8_t) * 2 + sizeof(struct in6_addr
) + sizeof(struct in_addr
);
59 buf
= newa(uint8_t, sz
);
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
));
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
);
81 ifname_alloc
= strdup(ifname
);
83 return log_oom_debug();
85 *ret
= TAKE_PTR(ifname_alloc
);
89 static int dhcp4_pd_create_6rd_tunnel_message(
91 sd_netlink_message
*m
,
92 const struct in_addr
*ipv4address
,
94 const struct in6_addr
*sixrd_prefix
,
95 uint8_t sixrd_prefixlen
) {
98 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, link
->dhcp4_6rd_tunnel_name
);
102 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
106 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "sit");
110 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, ipv4address
);
114 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, 64);
118 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_6RD_PREFIX
, sixrd_prefix
);
122 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, sixrd_prefixlen
);
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
);
132 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_RELAY_PREFIXLEN
, ipv4masklen
);
136 r
= sd_netlink_message_close_container(m
);
140 r
= sd_netlink_message_close_container(m
);
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
;
155 assert(link
->ifindex
> 0);
156 assert(link
->manager
);
157 assert(link
->dhcp_lease
);
158 assert(link
->dhcp4_6rd_tunnel_name
);
161 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &ipv4address
);
163 return log_link_debug_errno(link
, r
, "Failed to get DHCPv4 address: %m");
165 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, NULL
, NULL
);
167 return log_link_debug_errno(link
, r
, "Failed to get 6rd option: %m");
169 r
= sd_rtnl_message_new_link(link
->manager
->rtnl
, &m
, RTM_NEWLINK
, 0);
171 return log_link_debug_errno(link
, r
, "Failed to create netlink message: %m");
173 r
= dhcp4_pd_create_6rd_tunnel_message(link
, m
,
174 &ipv4address
, ipv4masklen
,
175 &sixrd_prefix
, sixrd_prefixlen
);
177 return log_link_debug_errno(link
, r
, "Failed to fill netlink message: %m");
179 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, m
, callback
,
180 link_netlink_destroy_callback
, link
);
182 return log_link_debug_errno(link
, r
, "Could not send netlink message: %m");
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_flag(m
, IFLA_IPTUN_COLLECT_METADATA
);
213 /* If external mode is enabled, then the following settings should not be appended. */
217 if (link
|| t
->assign_to_loopback
) {
218 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
223 r
= tunnel_get_local_address(t
, link
, &local
);
225 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
227 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &local
.in
);
231 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
235 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
239 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
244 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_TYPE
, t
->fou_encap_type
);
248 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
252 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
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
);
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.
266 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, t
->sixrd_prefixlen
);
271 if (t
->isatap
>= 0) {
274 SET_FLAG(flags
, SIT_ISATAP
, t
->isatap
);
276 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_FLAGS
, flags
);
285 static int netdev_gre_erspan_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
286 union in_addr_union local
;
297 switch (netdev
->kind
) {
298 case NETDEV_KIND_GRE
:
301 case NETDEV_KIND_ERSPAN
:
304 case NETDEV_KIND_GRETAP
:
308 assert_not_reached();
312 r
= sd_netlink_message_append_flag(m
, IFLA_GRE_COLLECT_METADATA
);
316 /* If external mode is enabled, then the following settings should not be appended. */
320 if (link
|| t
->assign_to_loopback
) {
321 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
326 if (netdev
->kind
== NETDEV_KIND_ERSPAN
) {
327 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_ERSPAN_VER
, t
->erspan_version
);
331 if (t
->erspan_version
== 1) {
332 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_ERSPAN_INDEX
, t
->erspan_index
);
336 } else if (t
->erspan_version
== 2) {
337 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_ERSPAN_DIR
, t
->erspan_direction
);
341 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ERSPAN_HWID
, t
->erspan_hwid
);
347 r
= tunnel_get_local_address(t
, link
, &local
);
349 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
351 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &local
.in
);
355 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
359 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
363 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
367 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
371 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_IGNORE_DF
, t
->ignore_df
);
376 ikey
= okey
= htobe32(t
->key
);
382 ikey
= htobe32(t
->ikey
);
387 okey
= htobe32(t
->okey
);
391 if (t
->gre_erspan_sequence
> 0) {
394 } else if (t
->gre_erspan_sequence
== 0) {
399 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_IKEY
, ikey
);
403 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_OKEY
, okey
);
407 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_IFLAGS
, iflags
);
411 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_OFLAGS
, oflags
);
416 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_TYPE
, t
->fou_encap_type
);
420 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
424 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
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;
442 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
445 t
= IP6GRETAP(netdev
);
448 r
= sd_netlink_message_append_flag(m
, IFLA_GRE_COLLECT_METADATA
);
452 /* If external mode is enabled, then the following settings should not be appended. */
456 if (link
|| t
->assign_to_loopback
) {
457 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
462 r
= tunnel_get_local_address(t
, link
, &local
);
464 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
466 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &local
.in6
);
470 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
474 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
478 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
479 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
484 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
489 ikey
= okey
= htobe32(t
->key
);
495 ikey
= htobe32(t
->ikey
);
500 okey
= htobe32(t
->okey
);
504 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_IKEY
, ikey
);
508 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_OKEY
, okey
);
512 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_IFLAGS
, iflags
);
516 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_OFLAGS
, oflags
);
523 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
527 union in_addr_union local
;
529 Tunnel
*t
= netdev
->kind
== NETDEV_KIND_VTI
? VTI(netdev
) : VTI6(netdev
);
532 if (link
|| t
->assign_to_loopback
) {
533 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
539 ikey
= okey
= htobe32(t
->key
);
541 ikey
= htobe32(t
->ikey
);
542 okey
= htobe32(t
->okey
);
545 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
549 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
553 r
= tunnel_get_local_address(t
, link
, &local
);
555 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
557 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_LOCAL
, t
->family
, &local
);
561 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_REMOTE
, t
->family
, &t
->remote
);
568 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
572 union in_addr_union local
;
574 Tunnel
*t
= IP6TNL(netdev
);
577 switch (t
->ip6tnl_mode
) {
578 case NETDEV_IP6_TNL_MODE_IP6IP6
:
579 proto
= IPPROTO_IPV6
;
581 case NETDEV_IP6_TNL_MODE_IPIP6
:
582 proto
= IPPROTO_IPIP
;
584 case NETDEV_IP6_TNL_MODE_ANYIP6
:
590 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
595 r
= sd_netlink_message_append_flag(m
, IFLA_IPTUN_COLLECT_METADATA
);
599 /* If external mode is enabled, then the following settings should not be appended. */
603 if (link
|| t
->assign_to_loopback
) {
604 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
609 r
= tunnel_get_local_address(t
, link
, &local
);
611 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
613 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &local
.in6
);
617 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
621 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
625 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
626 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
632 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
634 if (t
->allow_localremote
>= 0)
635 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
637 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
641 if (t
->encap_limit
!= 0) {
642 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
650 static int netdev_tunnel_is_ready_to_create(NetDev
*netdev
, Link
*link
) {
653 Tunnel
*t
= ASSERT_PTR(TUNNEL(netdev
));
658 return tunnel_get_local_address(t
, link
, NULL
) >= 0;
661 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
665 Tunnel
*t
= ASSERT_PTR(TUNNEL(netdev
));
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
);
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.");
676 /* tunnel with external mode does not require underlying interface. */
677 t
->independent
= true;
679 /* tunnel with external mode does not require any settings checked below. */
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
);
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
);
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
);
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
);
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
);
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
)
712 if (t
->assign_to_loopback
)
713 t
->independent
= true;
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
)));
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");
724 t
->pmtudisc
= !t
->ignore_df
;
728 static int unset_local(Tunnel
*t
) {
731 /* Unset the previous assignment. */
732 t
->local
= IN_ADDR_NULL
;
733 t
->local_type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
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
;
742 int config_parse_tunnel_local_address(
744 const char *filename
,
747 unsigned section_line
,
754 union in_addr_union buffer
= IN_ADDR_NULL
;
755 NetDevLocalAddressType type
;
756 Tunnel
*t
= ASSERT_PTR(userdata
);
763 if (isempty(rvalue
) || streq(rvalue
, "any"))
764 return unset_local(t
);
766 type
= netdev_local_address_type_from_string(rvalue
);
767 if (IN_SET(type
, NETDEV_LOCAL_ADDRESS_IPV4LL
, NETDEV_LOCAL_ADDRESS_DHCP4
))
769 else if (IN_SET(type
, NETDEV_LOCAL_ADDRESS_IPV6LL
, NETDEV_LOCAL_ADDRESS_DHCP6
, NETDEV_LOCAL_ADDRESS_SLAAC
))
772 type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
773 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
775 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
776 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
780 if (in_addr_is_null(f
, &buffer
))
781 return unset_local(t
);
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
);
792 t
->local_type
= type
;
796 static int unset_remote(Tunnel
*t
) {
799 /* Unset the previous assignment. */
800 t
->remote
= IN_ADDR_NULL
;
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
;
810 int config_parse_tunnel_remote_address(
812 const char *filename
,
815 unsigned section_line
,
822 union in_addr_union buffer
;
823 Tunnel
*t
= ASSERT_PTR(userdata
);
830 if (isempty(rvalue
) || streq(rvalue
, "any"))
831 return unset_remote(t
);
833 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
835 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
836 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
840 if (in_addr_is_null(f
, &buffer
))
841 return unset_remote(t
);
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
);
854 int config_parse_tunnel_key(
856 const char *filename
,
859 unsigned section_line
,
866 uint32_t *dest
= ASSERT_PTR(data
), k
;
867 union in_addr_union buffer
;
873 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
875 r
= safe_atou32(rvalue
, &k
);
877 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
878 "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
882 k
= be32toh(buffer
.in
.s_addr
);
888 int config_parse_ipv6_flowlabel(
890 const char *filename
,
893 unsigned section_line
,
900 Tunnel
*t
= ASSERT_PTR(userdata
);
907 if (streq(rvalue
, "inherit")) {
908 t
->ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
909 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
913 r
= config_parse_uint32_bounded(
914 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
919 t
->ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
920 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
925 int config_parse_encap_limit(
927 const char *filename
,
930 unsigned section_line
,
940 Tunnel
*t
= ASSERT_PTR(userdata
);
943 if (streq(rvalue
, "none")) {
945 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
949 r
= config_parse_uint8_bounded(
950 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
955 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
960 int config_parse_6rd_prefix(
962 const char *filename
,
965 unsigned section_line
,
972 Tunnel
*t
= userdata
;
973 union in_addr_union p
;
981 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &p
, &l
);
983 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue
);
987 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue
);
991 t
->sixrd_prefix
= p
.in6
;
992 t
->sixrd_prefixlen
= l
;
997 int config_parse_erspan_version(
999 const char *filename
,
1001 const char *section
,
1002 unsigned section_line
,
1013 uint8_t *v
= ASSERT_PTR(data
);
1015 if (isempty(rvalue
)) {
1016 *v
= 1; /* defaults to 1 */
1020 return config_parse_uint8_bounded(
1021 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
1026 int config_parse_erspan_index(
1028 const char *filename
,
1030 const char *section
,
1031 unsigned section_line
,
1042 uint32_t *v
= ASSERT_PTR(data
);
1044 if (isempty(rvalue
)) {
1045 *v
= 0; /* defaults to 0 */
1049 return config_parse_uint32_bounded(
1050 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
1051 0, 0x100000 - 1, true,
1055 int config_parse_erspan_direction(
1057 const char *filename
,
1059 const char *section
,
1060 unsigned section_line
,
1071 uint8_t *v
= ASSERT_PTR(data
);
1073 if (isempty(rvalue
) || streq(rvalue
, "ingress"))
1074 *v
= 0; /* defaults to ingress */
1075 else if (streq(rvalue
, "egress"))
1078 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1079 "Invalid erspan direction \"%s\", which must be \"ingress\" or \"egress\", ignoring.", rvalue
);
1084 int config_parse_erspan_hwid(
1086 const char *filename
,
1088 const char *section
,
1089 unsigned section_line
,
1100 uint16_t *v
= ASSERT_PTR(data
);
1102 if (isempty(rvalue
)) {
1103 *v
= 0; /* defaults to 0 */
1107 return config_parse_uint16_bounded(
1108 unit
, filename
, line
, section
, section_line
, lvalue
, rvalue
,
1113 static void netdev_tunnel_init(NetDev
*netdev
) {
1114 Tunnel
*t
= ASSERT_PTR(TUNNEL(netdev
));
1116 t
->local_type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
1118 t
->fou_encap_type
= NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
;
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;
1127 if (IN_SET(netdev
->kind
, NETDEV_KIND_IP6GRE
, NETDEV_KIND_IP6GRETAP
, NETDEV_KIND_IP6TNL
))
1128 t
->ttl
= DEFAULT_IPV6_TTL
;
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
,
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
,
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
,
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
,
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
,
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,
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
,
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,
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
,
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,