1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2014 Susant Sahani
9 #include <linux/if_tunnel.h>
10 #include <linux/ip6_tunnel.h>
12 #include "sd-netlink.h"
14 #include "conf-parser.h"
16 #include "networkd-link.h"
17 #include "netdev/tunnel.h"
18 #include "parse-util.h"
19 #include "string-table.h"
20 #include "string-util.h"
23 #define DEFAULT_TNL_HOP_LIMIT 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 static int netdev_ipip_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
37 Tunnel
*t
= IPIP(netdev
);
43 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
46 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
48 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
51 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
53 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
55 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
57 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
59 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
61 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
63 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
65 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
70 static int netdev_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
71 Tunnel
*t
= SIT(netdev
);
77 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
80 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
82 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
85 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
87 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
89 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
91 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
93 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
95 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
97 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
99 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
104 static int netdev_gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
110 if (netdev
->kind
== NETDEV_KIND_GRE
)
116 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
120 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
122 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
125 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in
);
127 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
129 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
131 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
133 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
135 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
137 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
139 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TOS attribute: %m");
141 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
143 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
148 static int netdev_ip6gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
154 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
157 t
= IP6GRETAP(netdev
);
160 assert(t
->family
== AF_INET6
);
164 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
166 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
169 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in6
);
171 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
173 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
175 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
177 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
179 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
181 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
182 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
184 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
187 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
189 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLAGS attribute: %m");
194 static int netdev_vti_fill_message_key(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
201 if (netdev
->kind
== NETDEV_KIND_VTI
)
209 ikey
= okey
= htobe32(t
->key
);
211 ikey
= htobe32(t
->ikey
);
212 okey
= htobe32(t
->okey
);
215 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
217 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_IKEY attribute: %m");
219 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
221 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_OKEY attribute: %m");
226 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
227 Tunnel
*t
= VTI(netdev
);
233 assert(t
->family
== AF_INET
);
236 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
238 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
241 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
245 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in
);
247 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
249 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in
);
251 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
256 static int netdev_vti6_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
257 Tunnel
*t
= VTI6(netdev
);
263 assert(t
->family
== AF_INET6
);
266 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
268 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
271 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
275 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in6
);
277 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
279 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in6
);
281 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
286 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
287 Tunnel
*t
= IP6TNL(netdev
);
294 assert(t
->family
== AF_INET6
);
297 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
299 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
302 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in6
);
304 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
306 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
308 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
310 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
312 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
314 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
315 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
317 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
321 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
323 if (t
->allow_localremote
!= -1)
324 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
326 if (t
->encap_limit
!= IPV6_DEFAULT_TNL_ENCAP_LIMIT
) {
327 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
329 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
332 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
334 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
336 switch (t
->ip6tnl_mode
) {
337 case NETDEV_IP6_TNL_MODE_IP6IP6
:
338 proto
= IPPROTO_IPV6
;
340 case NETDEV_IP6_TNL_MODE_IPIP6
:
341 proto
= IPPROTO_IPIP
;
343 case NETDEV_IP6_TNL_MODE_ANYIP6
:
349 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
351 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_MODE attribute: %m");
356 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
362 switch (netdev
->kind
) {
363 case NETDEV_KIND_IPIP
:
366 case NETDEV_KIND_SIT
:
369 case NETDEV_KIND_GRE
:
372 case NETDEV_KIND_GRETAP
:
375 case NETDEV_KIND_IP6GRE
:
378 case NETDEV_KIND_IP6GRETAP
:
379 t
= IP6GRETAP(netdev
);
381 case NETDEV_KIND_VTI
:
384 case NETDEV_KIND_VTI6
:
387 case NETDEV_KIND_IP6TNL
:
391 assert_not_reached("Invalid tunnel kind");
396 if (!IN_SET(t
->family
, AF_INET
, AF_INET6
, AF_UNSPEC
)) {
397 log_netdev_error(netdev
,
398 "Tunnel with invalid address family configured in %s. Ignoring", filename
);
402 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI
, NETDEV_KIND_IPIP
, NETDEV_KIND_GRE
, NETDEV_KIND_GRETAP
) &&
403 (t
->family
!= AF_INET
|| in_addr_is_null(t
->family
, &t
->local
))) {
404 log_netdev_error(netdev
,
405 "vti/ipip/gre/gretap tunnel without a local IPv4 address configured in %s. Ignoring", filename
);
409 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI6
, NETDEV_KIND_IP6TNL
, NETDEV_KIND_IP6GRE
) &&
410 (t
->family
!= AF_INET6
|| in_addr_is_null(t
->family
, &t
->local
))) {
411 log_netdev_error(netdev
,
412 "vti6/ip6tnl/ip6gre tunnel without a local IPv6 address configured in %s. Ignoring", filename
);
416 if (netdev
->kind
== NETDEV_KIND_IP6TNL
&&
417 t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
) {
418 log_netdev_error(netdev
,
419 "ip6tnl without mode configured in %s. Ignoring", filename
);
426 int config_parse_tunnel_address(const char *unit
,
427 const char *filename
,
430 unsigned section_line
,
436 Tunnel
*t
= userdata
;
437 union in_addr_union
*addr
= data
, buffer
;
445 /* This is used to parse addresses on both local and remote ends of the tunnel.
446 * Address families must match.
448 * "any" is a special value which means that the address is unspecified.
451 if (streq(rvalue
, "any")) {
452 *addr
= IN_ADDR_NULL
;
454 /* As a special case, if both the local and remote addresses are
455 * unspecified, also clear the address family.
457 if (t
->family
!= AF_UNSPEC
&&
458 in_addr_is_null(t
->family
, &t
->local
) &&
459 in_addr_is_null(t
->family
, &t
->remote
))
460 t
->family
= AF_UNSPEC
;
464 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
466 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
467 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
471 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
472 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
473 "Tunnel addresses incompatible, ignoring assignment: %s", rvalue
);
482 int config_parse_tunnel_key(const char *unit
,
483 const char *filename
,
486 unsigned section_line
,
492 union in_addr_union buffer
;
493 Tunnel
*t
= userdata
;
502 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
504 r
= safe_atou32(rvalue
, &k
);
506 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
510 k
= be32toh(buffer
.in
.s_addr
);
512 if (streq(lvalue
, "Key"))
514 else if (streq(lvalue
, "InputKey"))
522 int config_parse_ipv6_flowlabel(const char* unit
,
523 const char *filename
,
526 unsigned section_line
,
532 IPv6FlowLabel
*ipv6_flowlabel
= data
;
533 Tunnel
*t
= userdata
;
540 assert(ipv6_flowlabel
);
542 if (streq(rvalue
, "inherit")) {
543 *ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
544 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
546 r
= config_parse_int(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &k
, userdata
);
551 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue
);
553 *ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
554 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
561 int config_parse_encap_limit(const char* unit
,
562 const char *filename
,
565 unsigned section_line
,
571 Tunnel
*t
= userdata
;
579 if (streq(rvalue
, "none"))
580 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
582 r
= safe_atoi(rvalue
, &k
);
584 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue
);
588 if (k
> 255 || k
< 0)
589 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k
);
592 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
599 static void ipip_init(NetDev
*n
) {
608 static void sit_init(NetDev
*n
) {
617 static void vti_init(NetDev
*n
) {
622 if (n
->kind
== NETDEV_KIND_VTI
)
632 static void gre_init(NetDev
*n
) {
637 if (n
->kind
== NETDEV_KIND_GRE
)
647 static void ip6gre_init(NetDev
*n
) {
652 if (n
->kind
== NETDEV_KIND_IP6GRE
)
659 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
662 static void ip6tnl_init(NetDev
*n
) {
663 Tunnel
*t
= IP6TNL(n
);
668 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
669 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
670 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
671 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
672 t
->allow_localremote
= -1;
675 const NetDevVTable ipip_vtable
= {
676 .object_size
= sizeof(Tunnel
),
678 .sections
= "Match\0NetDev\0Tunnel\0",
679 .fill_message_create
= netdev_ipip_fill_message_create
,
680 .create_type
= NETDEV_CREATE_STACKED
,
681 .config_verify
= netdev_tunnel_verify
,
684 const NetDevVTable sit_vtable
= {
685 .object_size
= sizeof(Tunnel
),
687 .sections
= "Match\0NetDev\0Tunnel\0",
688 .fill_message_create
= netdev_sit_fill_message_create
,
689 .create_type
= NETDEV_CREATE_STACKED
,
690 .config_verify
= netdev_tunnel_verify
,
693 const NetDevVTable vti_vtable
= {
694 .object_size
= sizeof(Tunnel
),
696 .sections
= "Match\0NetDev\0Tunnel\0",
697 .fill_message_create
= netdev_vti_fill_message_create
,
698 .create_type
= NETDEV_CREATE_STACKED
,
699 .config_verify
= netdev_tunnel_verify
,
702 const NetDevVTable vti6_vtable
= {
703 .object_size
= sizeof(Tunnel
),
705 .sections
= "Match\0NetDev\0Tunnel\0",
706 .fill_message_create
= netdev_vti6_fill_message_create
,
707 .create_type
= NETDEV_CREATE_STACKED
,
708 .config_verify
= netdev_tunnel_verify
,
711 const NetDevVTable gre_vtable
= {
712 .object_size
= sizeof(Tunnel
),
714 .sections
= "Match\0NetDev\0Tunnel\0",
715 .fill_message_create
= netdev_gre_fill_message_create
,
716 .create_type
= NETDEV_CREATE_STACKED
,
717 .config_verify
= netdev_tunnel_verify
,
720 const NetDevVTable gretap_vtable
= {
721 .object_size
= sizeof(Tunnel
),
723 .sections
= "Match\0NetDev\0Tunnel\0",
724 .fill_message_create
= netdev_gre_fill_message_create
,
725 .create_type
= NETDEV_CREATE_STACKED
,
726 .config_verify
= netdev_tunnel_verify
,
729 const NetDevVTable ip6gre_vtable
= {
730 .object_size
= sizeof(Tunnel
),
732 .sections
= "Match\0NetDev\0Tunnel\0",
733 .fill_message_create
= netdev_ip6gre_fill_message_create
,
734 .create_type
= NETDEV_CREATE_STACKED
,
735 .config_verify
= netdev_tunnel_verify
,
738 const NetDevVTable ip6gretap_vtable
= {
739 .object_size
= sizeof(Tunnel
),
741 .sections
= "Match\0NetDev\0Tunnel\0",
742 .fill_message_create
= netdev_ip6gre_fill_message_create
,
743 .create_type
= NETDEV_CREATE_STACKED
,
744 .config_verify
= netdev_tunnel_verify
,
747 const NetDevVTable ip6tnl_vtable
= {
748 .object_size
= sizeof(Tunnel
),
750 .sections
= "Match\0NetDev\0Tunnel\0",
751 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
752 .create_type
= NETDEV_CREATE_STACKED
,
753 .config_verify
= netdev_tunnel_verify
,