1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Susant Sahani
11 #include <linux/if_tunnel.h>
12 #include <linux/ip6_tunnel.h>
14 #include "sd-netlink.h"
16 #include "conf-parser.h"
18 #include "networkd-link.h"
19 #include "netdev/tunnel.h"
20 #include "parse-util.h"
21 #include "string-table.h"
22 #include "string-util.h"
25 #define DEFAULT_TNL_HOP_LIMIT 64
26 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
27 #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
29 static const char* const ip6tnl_mode_table
[_NETDEV_IP6_TNL_MODE_MAX
] = {
30 [NETDEV_IP6_TNL_MODE_IP6IP6
] = "ip6ip6",
31 [NETDEV_IP6_TNL_MODE_IPIP6
] = "ipip6",
32 [NETDEV_IP6_TNL_MODE_ANYIP6
] = "any",
35 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode
, Ip6TnlMode
);
36 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode
, ip6tnl_mode
, Ip6TnlMode
, "Failed to parse ip6 tunnel Mode");
38 static int netdev_ipip_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
39 Tunnel
*t
= IPIP(netdev
);
45 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
48 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
50 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
53 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
55 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
57 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
59 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
61 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
63 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
65 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
67 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
72 static int netdev_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
73 Tunnel
*t
= SIT(netdev
);
79 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
82 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
84 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
87 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
89 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
91 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
93 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
95 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
97 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
99 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
101 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
106 static int netdev_gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
112 if (netdev
->kind
== NETDEV_KIND_GRE
)
118 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
122 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
124 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
127 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in
);
129 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
131 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
133 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
135 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
137 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
139 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
141 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TOS attribute: %m");
143 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
145 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
150 static int netdev_ip6gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
156 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
159 t
= IP6GRETAP(netdev
);
162 assert(t
->family
== AF_INET6
);
166 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
168 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
171 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in6
);
173 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
175 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
177 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
179 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
181 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
183 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
184 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
186 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
189 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
191 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLAGS attribute: %m");
196 static int netdev_vti_fill_message_key(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
203 if (netdev
->kind
== NETDEV_KIND_VTI
)
211 ikey
= okey
= htobe32(t
->key
);
213 ikey
= htobe32(t
->ikey
);
214 okey
= htobe32(t
->okey
);
217 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
219 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_IKEY attribute: %m");
221 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
223 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_OKEY attribute: %m");
228 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
229 Tunnel
*t
= VTI(netdev
);
235 assert(t
->family
== AF_INET
);
238 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
240 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
243 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
247 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in
);
249 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
251 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in
);
253 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
258 static int netdev_vti6_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
259 Tunnel
*t
= VTI6(netdev
);
265 assert(t
->family
== AF_INET6
);
268 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
270 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
273 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
277 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in6
);
279 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
281 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in6
);
283 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
288 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
289 Tunnel
*t
= IP6TNL(netdev
);
296 assert(t
->family
== AF_INET6
);
299 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
301 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
304 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in6
);
306 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
308 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
310 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
312 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
314 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
316 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
317 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
319 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
323 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
325 if (t
->allow_localremote
!= -1)
326 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
328 if (t
->encap_limit
!= IPV6_DEFAULT_TNL_ENCAP_LIMIT
) {
329 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
331 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
334 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
336 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
338 switch (t
->ip6tnl_mode
) {
339 case NETDEV_IP6_TNL_MODE_IP6IP6
:
340 proto
= IPPROTO_IPV6
;
342 case NETDEV_IP6_TNL_MODE_IPIP6
:
343 proto
= IPPROTO_IPIP
;
345 case NETDEV_IP6_TNL_MODE_ANYIP6
:
351 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
353 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_MODE attribute: %m");
358 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
364 switch (netdev
->kind
) {
365 case NETDEV_KIND_IPIP
:
368 case NETDEV_KIND_SIT
:
371 case NETDEV_KIND_GRE
:
374 case NETDEV_KIND_GRETAP
:
377 case NETDEV_KIND_IP6GRE
:
380 case NETDEV_KIND_IP6GRETAP
:
381 t
= IP6GRETAP(netdev
);
383 case NETDEV_KIND_VTI
:
386 case NETDEV_KIND_VTI6
:
389 case NETDEV_KIND_IP6TNL
:
393 assert_not_reached("Invalid tunnel kind");
398 if (!IN_SET(t
->family
, AF_INET
, AF_INET6
, AF_UNSPEC
)) {
399 log_netdev_error(netdev
,
400 "Tunnel with invalid address family configured in %s. Ignoring", filename
);
404 if (netdev
->kind
== NETDEV_KIND_VTI
&&
405 (t
->family
!= AF_INET
|| in_addr_is_null(t
->family
, &t
->local
))) {
406 log_netdev_error(netdev
,
407 "vti tunnel without a local IPv4 address configured in %s. Ignoring", filename
);
411 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI6
, NETDEV_KIND_IP6TNL
, NETDEV_KIND_IP6GRE
) &&
412 (t
->family
!= AF_INET6
|| in_addr_is_null(t
->family
, &t
->local
))) {
413 log_netdev_error(netdev
,
414 "vti6/ip6tnl/ip6gre tunnel without a local IPv6 address configured in %s. Ignoring", filename
);
418 if (netdev
->kind
== NETDEV_KIND_IP6TNL
&&
419 t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
) {
420 log_netdev_error(netdev
,
421 "ip6tnl without mode configured in %s. Ignoring", filename
);
428 int config_parse_tunnel_address(const char *unit
,
429 const char *filename
,
432 unsigned section_line
,
438 Tunnel
*t
= userdata
;
439 union in_addr_union
*addr
= data
, buffer
;
447 /* This is used to parse addresses on both local and remote ends of the tunnel.
448 * Address families must match.
450 * "any" is a special value which means that the address is unspecified.
453 if (streq(rvalue
, "any")) {
454 *addr
= IN_ADDR_NULL
;
456 /* As a special case, if both the local and remote addresses are
457 * unspecified, also clear the address family.
459 if (t
->family
!= AF_UNSPEC
&&
460 in_addr_is_null(t
->family
, &t
->local
) &&
461 in_addr_is_null(t
->family
, &t
->remote
))
462 t
->family
= AF_UNSPEC
;
466 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
468 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
469 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
473 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
474 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
475 "Tunnel addresses incompatible, ignoring assignment: %s", rvalue
);
484 int config_parse_tunnel_key(const char *unit
,
485 const char *filename
,
488 unsigned section_line
,
494 union in_addr_union buffer
;
495 Tunnel
*t
= userdata
;
504 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
506 r
= safe_atou32(rvalue
, &k
);
508 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
512 k
= be32toh(buffer
.in
.s_addr
);
514 if (streq(lvalue
, "Key"))
516 else if (streq(lvalue
, "InputKey"))
524 int config_parse_ipv6_flowlabel(const char* unit
,
525 const char *filename
,
528 unsigned section_line
,
534 IPv6FlowLabel
*ipv6_flowlabel
= data
;
535 Tunnel
*t
= userdata
;
542 assert(ipv6_flowlabel
);
544 if (streq(rvalue
, "inherit")) {
545 *ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
546 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
548 r
= config_parse_int(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &k
, userdata
);
553 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue
);
555 *ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
556 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
563 int config_parse_encap_limit(const char* unit
,
564 const char *filename
,
567 unsigned section_line
,
573 Tunnel
*t
= userdata
;
581 if (streq(rvalue
, "none"))
582 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
584 r
= safe_atoi(rvalue
, &k
);
586 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue
);
590 if (k
> 255 || k
< 0)
591 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k
);
594 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
601 static void ipip_init(NetDev
*n
) {
610 static void sit_init(NetDev
*n
) {
619 static void vti_init(NetDev
*n
) {
624 if (n
->kind
== NETDEV_KIND_VTI
)
634 static void gre_init(NetDev
*n
) {
639 if (n
->kind
== NETDEV_KIND_GRE
)
649 static void ip6gre_init(NetDev
*n
) {
654 if (n
->kind
== NETDEV_KIND_IP6GRE
)
661 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
664 static void ip6tnl_init(NetDev
*n
) {
665 Tunnel
*t
= IP6TNL(n
);
670 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
671 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
672 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
673 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
674 t
->allow_localremote
= -1;
677 const NetDevVTable ipip_vtable
= {
678 .object_size
= sizeof(Tunnel
),
680 .sections
= "Match\0NetDev\0Tunnel\0",
681 .fill_message_create
= netdev_ipip_fill_message_create
,
682 .create_type
= NETDEV_CREATE_STACKED
,
683 .config_verify
= netdev_tunnel_verify
,
686 const NetDevVTable sit_vtable
= {
687 .object_size
= sizeof(Tunnel
),
689 .sections
= "Match\0NetDev\0Tunnel\0",
690 .fill_message_create
= netdev_sit_fill_message_create
,
691 .create_type
= NETDEV_CREATE_STACKED
,
692 .config_verify
= netdev_tunnel_verify
,
695 const NetDevVTable vti_vtable
= {
696 .object_size
= sizeof(Tunnel
),
698 .sections
= "Match\0NetDev\0Tunnel\0",
699 .fill_message_create
= netdev_vti_fill_message_create
,
700 .create_type
= NETDEV_CREATE_STACKED
,
701 .config_verify
= netdev_tunnel_verify
,
704 const NetDevVTable vti6_vtable
= {
705 .object_size
= sizeof(Tunnel
),
707 .sections
= "Match\0NetDev\0Tunnel\0",
708 .fill_message_create
= netdev_vti6_fill_message_create
,
709 .create_type
= NETDEV_CREATE_STACKED
,
710 .config_verify
= netdev_tunnel_verify
,
713 const NetDevVTable gre_vtable
= {
714 .object_size
= sizeof(Tunnel
),
716 .sections
= "Match\0NetDev\0Tunnel\0",
717 .fill_message_create
= netdev_gre_fill_message_create
,
718 .create_type
= NETDEV_CREATE_STACKED
,
719 .config_verify
= netdev_tunnel_verify
,
722 const NetDevVTable gretap_vtable
= {
723 .object_size
= sizeof(Tunnel
),
725 .sections
= "Match\0NetDev\0Tunnel\0",
726 .fill_message_create
= netdev_gre_fill_message_create
,
727 .create_type
= NETDEV_CREATE_STACKED
,
728 .config_verify
= netdev_tunnel_verify
,
731 const NetDevVTable ip6gre_vtable
= {
732 .object_size
= sizeof(Tunnel
),
734 .sections
= "Match\0NetDev\0Tunnel\0",
735 .fill_message_create
= netdev_ip6gre_fill_message_create
,
736 .create_type
= NETDEV_CREATE_STACKED
,
737 .config_verify
= netdev_tunnel_verify
,
740 const NetDevVTable ip6gretap_vtable
= {
741 .object_size
= sizeof(Tunnel
),
743 .sections
= "Match\0NetDev\0Tunnel\0",
744 .fill_message_create
= netdev_ip6gre_fill_message_create
,
745 .create_type
= NETDEV_CREATE_STACKED
,
746 .config_verify
= netdev_tunnel_verify
,
749 const NetDevVTable ip6tnl_vtable
= {
750 .object_size
= sizeof(Tunnel
),
752 .sections
= "Match\0NetDev\0Tunnel\0",
753 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
754 .create_type
= NETDEV_CREATE_STACKED
,
755 .config_verify
= netdev_tunnel_verify
,