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"
23 #define DEFAULT_IPV6_TTL 64
24 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
25 #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
27 static const char* const ip6tnl_mode_table
[_NETDEV_IP6_TNL_MODE_MAX
] = {
28 [NETDEV_IP6_TNL_MODE_IP6IP6
] = "ip6ip6",
29 [NETDEV_IP6_TNL_MODE_IPIP6
] = "ipip6",
30 [NETDEV_IP6_TNL_MODE_ANYIP6
] = "any",
33 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode
, Ip6TnlMode
);
34 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode
, ip6tnl_mode
, Ip6TnlMode
, "Failed to parse ip6 tunnel Mode");
36 #define HASH_KEY SD_ID128_MAKE(74,c4,de,12,f3,d9,41,34,bb,3d,c1,a4,42,93,50,87)
38 int dhcp4_pd_create_6rd_tunnel_name(Link
*link
, char **ret
) {
39 _cleanup_free_
char *ifname_alloc
= NULL
;
40 uint8_t ipv4masklen
, sixrd_prefixlen
, *buf
, *p
;
41 struct in_addr ipv4address
;
42 struct in6_addr sixrd_prefix
;
43 char ifname
[IFNAMSIZ
];
49 assert(link
->dhcp_lease
);
51 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &ipv4address
);
53 return log_link_debug_errno(link
, r
, "Failed to get DHCPv4 address: %m");
55 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, NULL
, NULL
);
57 return log_link_debug_errno(link
, r
, "Failed to get 6rd option: %m");
59 sz
= sizeof(uint8_t) * 2 + sizeof(struct in6_addr
) + sizeof(struct in_addr
);
60 buf
= newa(uint8_t, sz
);
62 p
= mempcpy(p
, &ipv4masklen
, sizeof(uint8_t));
63 p
= mempcpy(p
, &ipv4address
, sizeof(struct in_addr
));
64 p
= mempcpy(p
, &sixrd_prefixlen
, sizeof(uint8_t));
65 p
= mempcpy(p
, &sixrd_prefix
, sizeof(struct in6_addr
));
67 result
= siphash24(buf
, sz
, HASH_KEY
.bytes
);
68 memcpy(ifname
, "6rd-", STRLEN("6rd-"));
69 ifname
[STRLEN("6rd-") ] = urlsafe_base64char(result
>> 54);
70 ifname
[STRLEN("6rd-") + 1] = urlsafe_base64char(result
>> 48);
71 ifname
[STRLEN("6rd-") + 2] = urlsafe_base64char(result
>> 42);
72 ifname
[STRLEN("6rd-") + 3] = urlsafe_base64char(result
>> 36);
73 ifname
[STRLEN("6rd-") + 4] = urlsafe_base64char(result
>> 30);
74 ifname
[STRLEN("6rd-") + 5] = urlsafe_base64char(result
>> 24);
75 ifname
[STRLEN("6rd-") + 6] = urlsafe_base64char(result
>> 18);
76 ifname
[STRLEN("6rd-") + 7] = urlsafe_base64char(result
>> 12);
77 ifname
[STRLEN("6rd-") + 8] = urlsafe_base64char(result
>> 6);
78 ifname
[STRLEN("6rd-") + 9] = urlsafe_base64char(result
);
79 ifname
[STRLEN("6rd-") + 10] = '\0';
80 assert_cc(STRLEN("6rd-") + 10 <= IFNAMSIZ
);
82 ifname_alloc
= strdup(ifname
);
84 return log_oom_debug();
86 *ret
= TAKE_PTR(ifname_alloc
);
90 static int dhcp4_pd_create_6rd_tunnel_message(
92 sd_netlink_message
*m
,
93 const struct in_addr
*ipv4address
,
95 const struct in6_addr
*sixrd_prefix
,
96 uint8_t sixrd_prefixlen
) {
99 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, link
->dhcp4_6rd_tunnel_name
);
103 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
107 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "sit");
111 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, ipv4address
);
115 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, 64);
119 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_6RD_PREFIX
, sixrd_prefix
);
123 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, sixrd_prefixlen
);
127 struct in_addr relay_prefix
= *ipv4address
;
128 (void) in4_addr_mask(&relay_prefix
, ipv4masklen
);
129 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_6RD_RELAY_PREFIX
, relay_prefix
.s_addr
);
133 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_RELAY_PREFIXLEN
, ipv4masklen
);
137 r
= sd_netlink_message_close_container(m
);
141 r
= sd_netlink_message_close_container(m
);
148 int dhcp4_pd_create_6rd_tunnel(Link
*link
, link_netlink_message_handler_t callback
) {
149 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
150 uint8_t ipv4masklen
, sixrd_prefixlen
;
151 struct in_addr ipv4address
;
152 struct in6_addr sixrd_prefix
;
156 assert(link
->ifindex
> 0);
157 assert(link
->manager
);
158 assert(link
->dhcp_lease
);
159 assert(link
->dhcp4_6rd_tunnel_name
);
162 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &ipv4address
);
164 return log_link_debug_errno(link
, r
, "Failed to get DHCPv4 address: %m");
166 r
= sd_dhcp_lease_get_6rd(link
->dhcp_lease
, &ipv4masklen
, &sixrd_prefixlen
, &sixrd_prefix
, NULL
, NULL
);
168 return log_link_debug_errno(link
, r
, "Failed to get 6rd option: %m");
170 r
= sd_rtnl_message_new_link(link
->manager
->rtnl
, &m
, RTM_NEWLINK
, 0);
172 return log_link_debug_errno(link
, r
, "Failed to create netlink message: %m");
174 r
= dhcp4_pd_create_6rd_tunnel_message(link
, m
,
175 &ipv4address
, ipv4masklen
,
176 &sixrd_prefix
, sixrd_prefixlen
);
178 return log_link_debug_errno(link
, r
, "Failed to fill netlink message: %m");
180 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, m
, callback
,
181 link_netlink_destroy_callback
, link
);
183 return log_link_debug_errno(link
, r
, "Could not send netlink message: %m");
190 static int tunnel_get_local_address(Tunnel
*t
, Link
*link
, union in_addr_union
*ret
) {
193 if (t
->local_type
< 0) {
199 return link_get_local_address(link
, t
->local_type
, t
->family
, NULL
, ret
);
202 static int netdev_ipip_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
203 union in_addr_union local
;
210 if (netdev
->kind
== NETDEV_KIND_IPIP
)
218 r
= sd_netlink_message_append_flag(m
, IFLA_IPTUN_COLLECT_METADATA
);
222 /* If external mode is enabled, then the following settings should not be appended. */
226 if (link
|| t
->assign_to_loopback
) {
227 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
232 r
= tunnel_get_local_address(t
, link
, &local
);
234 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
236 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &local
.in
);
240 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
244 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
248 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
253 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_TYPE
, t
->fou_encap_type
);
257 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
261 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
266 if (netdev
->kind
== NETDEV_KIND_SIT
) {
267 if (t
->sixrd_prefixlen
> 0) {
268 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_6RD_PREFIX
, &t
->sixrd_prefix
);
272 /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
273 * expecting to receive the prefixlen as a u16.
275 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, t
->sixrd_prefixlen
);
280 if (t
->isatap
>= 0) {
283 SET_FLAG(flags
, SIT_ISATAP
, t
->isatap
);
285 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_FLAGS
, flags
);
294 static int netdev_gre_erspan_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
295 union in_addr_union local
;
306 switch (netdev
->kind
) {
307 case NETDEV_KIND_GRE
:
310 case NETDEV_KIND_ERSPAN
:
313 case NETDEV_KIND_GRETAP
:
317 assert_not_reached();
323 r
= sd_netlink_message_append_flag(m
, IFLA_GRE_COLLECT_METADATA
);
327 /* If external mode is enabled, then the following settings should not be appended. */
331 if (link
|| t
->assign_to_loopback
) {
332 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
337 if (netdev
->kind
== NETDEV_KIND_ERSPAN
) {
338 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_ERSPAN_VER
, t
->erspan_version
);
342 if (t
->erspan_version
== 1) {
343 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_ERSPAN_INDEX
, t
->erspan_index
);
347 } else if (t
->erspan_version
== 2) {
348 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_ERSPAN_DIR
, t
->erspan_direction
);
352 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ERSPAN_HWID
, t
->erspan_hwid
);
358 r
= tunnel_get_local_address(t
, link
, &local
);
360 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
362 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &local
.in
);
366 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
370 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
374 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
378 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
383 ikey
= okey
= htobe32(t
->key
);
389 ikey
= htobe32(t
->ikey
);
394 okey
= htobe32(t
->okey
);
398 if (t
->gre_erspan_sequence
> 0) {
401 } else if (t
->gre_erspan_sequence
== 0) {
406 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_IKEY
, ikey
);
410 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_OKEY
, okey
);
414 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_IFLAGS
, iflags
);
418 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_OFLAGS
, oflags
);
423 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_TYPE
, t
->fou_encap_type
);
427 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
431 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
439 static int netdev_ip6gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
440 union in_addr_union local
;
451 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
454 t
= IP6GRETAP(netdev
);
459 r
= sd_netlink_message_append_flag(m
, IFLA_GRE_COLLECT_METADATA
);
463 /* If external mode is enabled, then the following settings should not be appended. */
467 if (link
|| t
->assign_to_loopback
) {
468 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
473 r
= tunnel_get_local_address(t
, link
, &local
);
475 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
477 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &local
.in6
);
481 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
485 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
489 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
490 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
495 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
500 ikey
= okey
= htobe32(t
->key
);
506 ikey
= htobe32(t
->ikey
);
511 okey
= htobe32(t
->okey
);
515 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_IKEY
, ikey
);
519 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_OKEY
, okey
);
523 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_IFLAGS
, iflags
);
527 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_OFLAGS
, oflags
);
534 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
535 union in_addr_union local
;
543 if (netdev
->kind
== NETDEV_KIND_VTI
)
550 if (link
|| t
->assign_to_loopback
) {
551 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
557 ikey
= okey
= htobe32(t
->key
);
559 ikey
= htobe32(t
->ikey
);
560 okey
= htobe32(t
->okey
);
563 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
567 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
571 r
= tunnel_get_local_address(t
, link
, &local
);
573 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
575 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_LOCAL
, t
->family
, &local
);
579 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_REMOTE
, t
->family
, &t
->remote
);
586 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
587 union in_addr_union local
;
599 switch (t
->ip6tnl_mode
) {
600 case NETDEV_IP6_TNL_MODE_IP6IP6
:
601 proto
= IPPROTO_IPV6
;
603 case NETDEV_IP6_TNL_MODE_IPIP6
:
604 proto
= IPPROTO_IPIP
;
606 case NETDEV_IP6_TNL_MODE_ANYIP6
:
612 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
617 r
= sd_netlink_message_append_flag(m
, IFLA_IPTUN_COLLECT_METADATA
);
621 /* If external mode is enabled, then the following settings should not be appended. */
625 if (link
|| t
->assign_to_loopback
) {
626 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
? link
->ifindex
: LOOPBACK_IFINDEX
);
631 r
= tunnel_get_local_address(t
, link
, &local
);
633 return log_netdev_error_errno(netdev
, r
, "Could not find local address: %m");
635 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &local
.in6
);
639 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
643 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
647 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
648 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
654 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
656 if (t
->allow_localremote
>= 0)
657 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
659 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
663 if (t
->encap_limit
!= 0) {
664 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
672 static int netdev_tunnel_is_ready_to_create(NetDev
*netdev
, Link
*link
) {
684 return tunnel_get_local_address(t
, link
, NULL
) >= 0;
687 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
697 if (netdev
->kind
== NETDEV_KIND_IP6TNL
&&
698 t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
)
699 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
700 "ip6tnl without mode configured in %s. Ignoring", filename
);
703 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI
, NETDEV_KIND_VTI6
))
704 log_netdev_debug(netdev
, "vti/vti6 tunnel do not support external mode, ignoring.");
706 /* tunnel with external mode does not require underlying interface. */
707 t
->independent
= true;
709 /* tunnel with external mode does not require any settings checked below. */
714 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI
, NETDEV_KIND_IPIP
, NETDEV_KIND_SIT
, NETDEV_KIND_GRE
) &&
715 !IN_SET(t
->family
, AF_UNSPEC
, AF_INET
))
716 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
717 "vti/ipip/sit/gre tunnel without a local/remote IPv4 address configured in %s. Ignoring", filename
);
719 if (IN_SET(netdev
->kind
, NETDEV_KIND_GRETAP
, NETDEV_KIND_ERSPAN
) &&
720 (t
->family
!= AF_INET
|| !in_addr_is_set(t
->family
, &t
->remote
)))
721 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
722 "gretap/erspan tunnel without a remote IPv4 address configured in %s. Ignoring", filename
);
724 if ((IN_SET(netdev
->kind
, NETDEV_KIND_VTI6
, NETDEV_KIND_IP6TNL
) && t
->family
!= AF_INET6
) ||
725 (netdev
->kind
== NETDEV_KIND_IP6GRE
&& !IN_SET(t
->family
, AF_UNSPEC
, AF_INET6
)))
726 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
727 "vti6/ip6tnl/ip6gre tunnel without a local/remote IPv6 address configured in %s. Ignoring", filename
);
729 if (netdev
->kind
== NETDEV_KIND_IP6GRETAP
&&
730 (t
->family
!= AF_INET6
|| !in_addr_is_set(t
->family
, &t
->remote
)))
731 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
732 "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename
);
734 if (t
->fou_tunnel
&& t
->fou_destination_port
<= 0)
735 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
736 "FooOverUDP missing port configured in %s. Ignoring", filename
);
738 /* netlink_message_append_in_addr_union() is used for vti/vti6. So, t->family cannot be AF_UNSPEC. */
739 if (netdev
->kind
== NETDEV_KIND_VTI
)
742 if (t
->assign_to_loopback
)
743 t
->independent
= true;
745 if (t
->independent
&& t
->local_type
>= 0)
746 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
747 "The local address cannot be '%s' when Independent= or AssignToLoopback= is enabled, ignoring.",
748 strna(netdev_local_address_type_to_string(t
->local_type
)));
753 static int unset_local(Tunnel
*t
) {
756 /* Unset the previous assignment. */
757 t
->local
= IN_ADDR_NULL
;
758 t
->local_type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
760 /* If the remote address is not specified, also clear the address family. */
761 if (!in_addr_is_set(t
->family
, &t
->remote
))
762 t
->family
= AF_UNSPEC
;
767 int config_parse_tunnel_local_address(
769 const char *filename
,
772 unsigned section_line
,
779 union in_addr_union buffer
= IN_ADDR_NULL
;
780 NetDevLocalAddressType type
;
781 Tunnel
*t
= ASSERT_PTR(userdata
);
788 if (isempty(rvalue
) || streq(rvalue
, "any"))
789 return unset_local(t
);
791 type
= netdev_local_address_type_from_string(rvalue
);
792 if (IN_SET(type
, NETDEV_LOCAL_ADDRESS_IPV4LL
, NETDEV_LOCAL_ADDRESS_DHCP4
))
794 else if (IN_SET(type
, NETDEV_LOCAL_ADDRESS_IPV6LL
, NETDEV_LOCAL_ADDRESS_DHCP6
, NETDEV_LOCAL_ADDRESS_SLAAC
))
797 type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
798 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
800 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
801 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
805 if (in_addr_is_null(f
, &buffer
))
806 return unset_local(t
);
809 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
810 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
811 "Address family does not match the previous assignment, ignoring assignment: %s", rvalue
);
817 t
->local_type
= type
;
821 static int unset_remote(Tunnel
*t
) {
824 /* Unset the previous assignment. */
825 t
->remote
= IN_ADDR_NULL
;
827 /* If the local address is not specified, also clear the address family. */
828 if (t
->local_type
== _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
&&
829 !in_addr_is_set(t
->family
, &t
->local
))
830 t
->family
= AF_UNSPEC
;
835 int config_parse_tunnel_remote_address(
837 const char *filename
,
840 unsigned section_line
,
847 union in_addr_union buffer
;
848 Tunnel
*t
= ASSERT_PTR(userdata
);
855 if (isempty(rvalue
) || streq(rvalue
, "any"))
856 return unset_remote(t
);
858 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
860 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
861 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
865 if (in_addr_is_null(f
, &buffer
))
866 return unset_remote(t
);
868 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
869 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
870 "Address family does not match the previous assignment, ignoring assignment: %s", rvalue
);
879 int config_parse_tunnel_key(
881 const char *filename
,
884 unsigned section_line
,
891 uint32_t *dest
= ASSERT_PTR(data
), k
;
892 union in_addr_union buffer
;
898 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
900 r
= safe_atou32(rvalue
, &k
);
902 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
903 "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
907 k
= be32toh(buffer
.in
.s_addr
);
913 int config_parse_ipv6_flowlabel(
915 const char *filename
,
918 unsigned section_line
,
925 Tunnel
*t
= ASSERT_PTR(userdata
);
931 if (streq(rvalue
, "inherit")) {
932 t
->ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
933 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
937 r
= safe_atoi(rvalue
, &k
);
939 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
940 "Failed to parse tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue
);
945 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
946 "Invalid tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue
);
950 t
->ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
951 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
955 int config_parse_encap_limit(
957 const char *filename
,
960 unsigned section_line
,
967 Tunnel
*t
= ASSERT_PTR(userdata
);
973 if (streq(rvalue
, "none")) {
974 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
979 r
= safe_atoi(rvalue
, &k
);
981 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
982 "Failed to parse Tunnel Encapsulation Limit option, ignoring assignment: %s", rvalue
);
986 if (k
> 255 || k
< 0) {
987 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
988 "Invalid Tunnel Encapsulation value, ignoring assignment: %d", k
);
993 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
997 int config_parse_6rd_prefix(
999 const char *filename
,
1001 const char *section
,
1002 unsigned section_line
,
1009 Tunnel
*t
= userdata
;
1010 union in_addr_union p
;
1018 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &p
, &l
);
1020 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue
);
1024 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue
);
1028 t
->sixrd_prefix
= p
.in6
;
1029 t
->sixrd_prefixlen
= l
;
1034 int config_parse_erspan_version(
1036 const char *filename
,
1038 const char *section
,
1039 unsigned section_line
,
1046 uint8_t n
, *v
= ASSERT_PTR(data
);
1053 if (isempty(rvalue
)) {
1054 *v
= 1; /* defaults to 1 */
1058 r
= safe_atou8(rvalue
, &n
);
1060 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1061 "Failed to parse erspan version \"%s\", ignoring: %m", rvalue
);
1064 if (!IN_SET(n
, 0, 1, 2)) {
1065 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1066 "Invalid erspan version \"%s\", which must be 0, 1 or 2, ignoring.", rvalue
);
1074 int config_parse_erspan_index(
1076 const char *filename
,
1078 const char *section
,
1079 unsigned section_line
,
1086 uint32_t n
, *v
= ASSERT_PTR(data
);
1093 if (isempty(rvalue
)) {
1094 *v
= 0; /* defaults to 0 */
1098 r
= safe_atou32(rvalue
, &n
);
1100 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1101 "Failed to parse erspan index \"%s\", ignoring: %m", rvalue
);
1104 if (n
>= 0x100000) {
1105 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1106 "Invalid erspan index \"%s\", which must be less than 0x100000, ignoring.", rvalue
);
1114 int config_parse_erspan_direction(
1116 const char *filename
,
1118 const char *section
,
1119 unsigned section_line
,
1126 uint8_t *v
= ASSERT_PTR(data
);
1132 if (isempty(rvalue
) || streq(rvalue
, "ingress"))
1133 *v
= 0; /* defaults to ingress */
1134 else if (streq(rvalue
, "egress"))
1137 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1138 "Invalid erspan direction \"%s\", which must be \"ingress\" or \"egress\", ignoring.", rvalue
);
1143 int config_parse_erspan_hwid(
1145 const char *filename
,
1147 const char *section
,
1148 unsigned section_line
,
1155 uint16_t n
, *v
= ASSERT_PTR(data
);
1162 if (isempty(rvalue
)) {
1163 *v
= 0; /* defaults to 0 */
1167 r
= safe_atou16(rvalue
, &n
);
1169 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1170 "Failed to parse erspan hwid \"%s\", ignoring: %m", rvalue
);
1174 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
1175 "Invalid erspan index \"%s\", which must be less than 64, ignoring.", rvalue
);
1183 static void netdev_tunnel_init(NetDev
*netdev
) {
1192 t
->local_type
= _NETDEV_LOCAL_ADDRESS_TYPE_INVALID
;
1194 t
->fou_encap_type
= NETDEV_FOO_OVER_UDP_ENCAP_DIRECT
;
1196 t
->gre_erspan_sequence
= -1;
1197 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
1198 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
1199 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
1200 t
->allow_localremote
= -1;
1201 t
->erspan_version
= 1;
1203 if (IN_SET(netdev
->kind
, NETDEV_KIND_IP6GRE
, NETDEV_KIND_IP6GRETAP
, NETDEV_KIND_IP6TNL
))
1204 t
->ttl
= DEFAULT_IPV6_TTL
;
1207 const NetDevVTable ipip_vtable
= {
1208 .object_size
= sizeof(Tunnel
),
1209 .init
= netdev_tunnel_init
,
1210 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1211 .fill_message_create
= netdev_ipip_sit_fill_message_create
,
1212 .create_type
= NETDEV_CREATE_STACKED
,
1213 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1214 .config_verify
= netdev_tunnel_verify
,
1215 .iftype
= ARPHRD_TUNNEL
,
1218 const NetDevVTable sit_vtable
= {
1219 .object_size
= sizeof(Tunnel
),
1220 .init
= netdev_tunnel_init
,
1221 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1222 .fill_message_create
= netdev_ipip_sit_fill_message_create
,
1223 .create_type
= NETDEV_CREATE_STACKED
,
1224 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1225 .config_verify
= netdev_tunnel_verify
,
1226 .iftype
= ARPHRD_SIT
,
1229 const NetDevVTable vti_vtable
= {
1230 .object_size
= sizeof(Tunnel
),
1231 .init
= netdev_tunnel_init
,
1232 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1233 .fill_message_create
= netdev_vti_fill_message_create
,
1234 .create_type
= NETDEV_CREATE_STACKED
,
1235 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1236 .config_verify
= netdev_tunnel_verify
,
1237 .iftype
= ARPHRD_TUNNEL
,
1240 const NetDevVTable vti6_vtable
= {
1241 .object_size
= sizeof(Tunnel
),
1242 .init
= netdev_tunnel_init
,
1243 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1244 .fill_message_create
= netdev_vti_fill_message_create
,
1245 .create_type
= NETDEV_CREATE_STACKED
,
1246 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1247 .config_verify
= netdev_tunnel_verify
,
1248 .iftype
= ARPHRD_TUNNEL6
,
1251 const NetDevVTable gre_vtable
= {
1252 .object_size
= sizeof(Tunnel
),
1253 .init
= netdev_tunnel_init
,
1254 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1255 .fill_message_create
= netdev_gre_erspan_fill_message_create
,
1256 .create_type
= NETDEV_CREATE_STACKED
,
1257 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1258 .config_verify
= netdev_tunnel_verify
,
1259 .iftype
= ARPHRD_IPGRE
,
1262 const NetDevVTable gretap_vtable
= {
1263 .object_size
= sizeof(Tunnel
),
1264 .init
= netdev_tunnel_init
,
1265 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1266 .fill_message_create
= netdev_gre_erspan_fill_message_create
,
1267 .create_type
= NETDEV_CREATE_STACKED
,
1268 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1269 .config_verify
= netdev_tunnel_verify
,
1270 .iftype
= ARPHRD_ETHER
,
1271 .generate_mac
= true,
1274 const NetDevVTable ip6gre_vtable
= {
1275 .object_size
= sizeof(Tunnel
),
1276 .init
= netdev_tunnel_init
,
1277 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1278 .fill_message_create
= netdev_ip6gre_fill_message_create
,
1279 .create_type
= NETDEV_CREATE_STACKED
,
1280 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1281 .config_verify
= netdev_tunnel_verify
,
1282 .iftype
= ARPHRD_IP6GRE
,
1285 const NetDevVTable ip6gretap_vtable
= {
1286 .object_size
= sizeof(Tunnel
),
1287 .init
= netdev_tunnel_init
,
1288 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1289 .fill_message_create
= netdev_ip6gre_fill_message_create
,
1290 .create_type
= NETDEV_CREATE_STACKED
,
1291 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1292 .config_verify
= netdev_tunnel_verify
,
1293 .iftype
= ARPHRD_ETHER
,
1294 .generate_mac
= true,
1297 const NetDevVTable ip6tnl_vtable
= {
1298 .object_size
= sizeof(Tunnel
),
1299 .init
= netdev_tunnel_init
,
1300 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1301 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
1302 .create_type
= NETDEV_CREATE_STACKED
,
1303 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1304 .config_verify
= netdev_tunnel_verify
,
1305 .iftype
= ARPHRD_TUNNEL6
,
1308 const NetDevVTable erspan_vtable
= {
1309 .object_size
= sizeof(Tunnel
),
1310 .init
= netdev_tunnel_init
,
1311 .sections
= NETDEV_COMMON_SECTIONS
"Tunnel\0",
1312 .fill_message_create
= netdev_gre_erspan_fill_message_create
,
1313 .create_type
= NETDEV_CREATE_STACKED
,
1314 .is_ready_to_create
= netdev_tunnel_is_ready_to_create
,
1315 .config_verify
= netdev_tunnel_verify
,
1316 .iftype
= ARPHRD_ETHER
,
1317 .generate_mac
= true,