1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Susant Sahani
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <arpa/inet.h>
24 #include <linux/if_tunnel.h>
25 #include <linux/ip6_tunnel.h>
27 #include "sd-netlink.h"
29 #include "conf-parser.h"
31 #include "networkd-link.h"
32 #include "netdev/tunnel.h"
33 #include "parse-util.h"
34 #include "string-table.h"
35 #include "string-util.h"
38 #define DEFAULT_TNL_HOP_LIMIT 64
39 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
40 #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
42 static const char* const ip6tnl_mode_table
[_NETDEV_IP6_TNL_MODE_MAX
] = {
43 [NETDEV_IP6_TNL_MODE_IP6IP6
] = "ip6ip6",
44 [NETDEV_IP6_TNL_MODE_IPIP6
] = "ipip6",
45 [NETDEV_IP6_TNL_MODE_ANYIP6
] = "any",
48 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode
, Ip6TnlMode
);
49 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode
, ip6tnl_mode
, Ip6TnlMode
, "Failed to parse ip6 tunnel Mode");
51 static int netdev_ipip_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
52 Tunnel
*t
= IPIP(netdev
);
58 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
61 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
63 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
66 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
68 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
70 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
72 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
74 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
76 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
78 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
80 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
85 static int netdev_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
86 Tunnel
*t
= SIT(netdev
);
92 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
95 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
97 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
100 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
102 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
104 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
106 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
108 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
110 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
112 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
114 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
119 static int netdev_gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
125 if (netdev
->kind
== NETDEV_KIND_GRE
)
131 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
135 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
137 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
140 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in
);
142 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
144 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
146 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
148 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
150 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
152 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
154 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TOS attribute: %m");
156 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
158 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
163 static int netdev_ip6gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
169 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
172 t
= IP6GRETAP(netdev
);
175 assert(t
->family
== AF_INET6
);
179 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
181 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
184 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in6
);
186 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
188 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
190 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
192 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
194 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
196 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
197 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
199 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
202 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
204 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLAGS attribute: %m");
209 static int netdev_vti_fill_message_key(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
216 if (netdev
->kind
== NETDEV_KIND_VTI
)
224 ikey
= okey
= htobe32(t
->key
);
226 ikey
= htobe32(t
->ikey
);
227 okey
= htobe32(t
->okey
);
230 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
232 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_IKEY attribute: %m");
234 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
236 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_OKEY attribute: %m");
241 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
242 Tunnel
*t
= VTI(netdev
);
248 assert(t
->family
== AF_INET
);
251 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
253 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
256 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
260 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in
);
262 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
264 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in
);
266 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
271 static int netdev_vti6_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
272 Tunnel
*t
= VTI6(netdev
);
278 assert(t
->family
== AF_INET6
);
281 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
283 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
286 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
290 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in6
);
292 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
294 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in6
);
296 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
301 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
302 Tunnel
*t
= IP6TNL(netdev
);
309 assert(t
->family
== AF_INET6
);
312 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
314 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
317 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in6
);
319 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
321 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
323 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
325 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
327 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
329 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
330 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
332 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
336 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
338 if (t
->allow_localremote
!= -1)
339 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
341 if (t
->encap_limit
!= IPV6_DEFAULT_TNL_ENCAP_LIMIT
) {
342 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
344 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
347 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
349 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
351 switch (t
->ip6tnl_mode
) {
352 case NETDEV_IP6_TNL_MODE_IP6IP6
:
353 proto
= IPPROTO_IPV6
;
355 case NETDEV_IP6_TNL_MODE_IPIP6
:
356 proto
= IPPROTO_IPIP
;
358 case NETDEV_IP6_TNL_MODE_ANYIP6
:
364 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
366 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_MODE attribute: %m");
371 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
377 switch (netdev
->kind
) {
378 case NETDEV_KIND_IPIP
:
381 case NETDEV_KIND_SIT
:
384 case NETDEV_KIND_GRE
:
387 case NETDEV_KIND_GRETAP
:
390 case NETDEV_KIND_IP6GRE
:
393 case NETDEV_KIND_IP6GRETAP
:
394 t
= IP6GRETAP(netdev
);
396 case NETDEV_KIND_VTI
:
399 case NETDEV_KIND_VTI6
:
402 case NETDEV_KIND_IP6TNL
:
406 assert_not_reached("Invalid tunnel kind");
411 if (!IN_SET(t
->family
, AF_INET
, AF_INET6
, AF_UNSPEC
)) {
412 log_netdev_error(netdev
,
413 "Tunnel with invalid address family configured in %s. Ignoring", filename
);
417 if (netdev
->kind
== NETDEV_KIND_VTI
&&
418 (t
->family
!= AF_INET
|| in_addr_is_null(t
->family
, &t
->local
))) {
419 log_netdev_error(netdev
,
420 "vti tunnel without a local IPv4 address configured in %s. Ignoring", filename
);
424 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI6
, NETDEV_KIND_IP6TNL
, NETDEV_KIND_IP6GRE
) &&
425 (t
->family
!= AF_INET6
|| in_addr_is_null(t
->family
, &t
->local
))) {
426 log_netdev_error(netdev
,
427 "vti6/ip6tnl/ip6gre tunnel without a local IPv6 address configured in %s. Ignoring", filename
);
431 if (netdev
->kind
== NETDEV_KIND_IP6TNL
&&
432 t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
) {
433 log_netdev_error(netdev
,
434 "ip6tnl without mode configured in %s. Ignoring", filename
);
441 int config_parse_tunnel_address(const char *unit
,
442 const char *filename
,
445 unsigned section_line
,
451 Tunnel
*t
= userdata
;
452 union in_addr_union
*addr
= data
, buffer
;
460 /* This is used to parse addresses on both local and remote ends of the tunnel.
461 * Address families must match.
463 * "any" is a special value which means that the address is unspecified.
466 if (streq(rvalue
, "any")) {
467 *addr
= IN_ADDR_NULL
;
469 /* As a special case, if both the local and remote addresses are
470 * unspecified, also clear the address family.
472 if (t
->family
!= AF_UNSPEC
&&
473 in_addr_is_null(t
->family
, &t
->local
) &&
474 in_addr_is_null(t
->family
, &t
->remote
))
475 t
->family
= AF_UNSPEC
;
479 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
481 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
482 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
486 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
487 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
488 "Tunnel addresses incompatible, ignoring assignment: %s", rvalue
);
497 int config_parse_tunnel_key(const char *unit
,
498 const char *filename
,
501 unsigned section_line
,
507 union in_addr_union buffer
;
508 Tunnel
*t
= userdata
;
517 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
519 r
= safe_atou32(rvalue
, &k
);
521 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
525 k
= be32toh(buffer
.in
.s_addr
);
527 if (streq(lvalue
, "Key"))
529 else if (streq(lvalue
, "InputKey"))
537 int config_parse_ipv6_flowlabel(const char* unit
,
538 const char *filename
,
541 unsigned section_line
,
547 IPv6FlowLabel
*ipv6_flowlabel
= data
;
548 Tunnel
*t
= userdata
;
555 assert(ipv6_flowlabel
);
557 if (streq(rvalue
, "inherit")) {
558 *ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
559 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
561 r
= config_parse_int(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &k
, userdata
);
566 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue
);
568 *ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
569 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
576 int config_parse_encap_limit(const char* unit
,
577 const char *filename
,
580 unsigned section_line
,
586 Tunnel
*t
= userdata
;
594 if (streq(rvalue
, "none"))
595 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
597 r
= safe_atoi(rvalue
, &k
);
599 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue
);
603 if (k
> 255 || k
< 0)
604 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k
);
607 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
614 static void ipip_init(NetDev
*n
) {
623 static void sit_init(NetDev
*n
) {
632 static void vti_init(NetDev
*n
) {
637 if (n
->kind
== NETDEV_KIND_VTI
)
647 static void gre_init(NetDev
*n
) {
652 if (n
->kind
== NETDEV_KIND_GRE
)
662 static void ip6gre_init(NetDev
*n
) {
667 if (n
->kind
== NETDEV_KIND_IP6GRE
)
674 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
677 static void ip6tnl_init(NetDev
*n
) {
678 Tunnel
*t
= IP6TNL(n
);
683 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
684 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
685 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
686 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
687 t
->allow_localremote
= -1;
690 const NetDevVTable ipip_vtable
= {
691 .object_size
= sizeof(Tunnel
),
693 .sections
= "Match\0NetDev\0Tunnel\0",
694 .fill_message_create
= netdev_ipip_fill_message_create
,
695 .create_type
= NETDEV_CREATE_STACKED
,
696 .config_verify
= netdev_tunnel_verify
,
699 const NetDevVTable sit_vtable
= {
700 .object_size
= sizeof(Tunnel
),
702 .sections
= "Match\0NetDev\0Tunnel\0",
703 .fill_message_create
= netdev_sit_fill_message_create
,
704 .create_type
= NETDEV_CREATE_STACKED
,
705 .config_verify
= netdev_tunnel_verify
,
708 const NetDevVTable vti_vtable
= {
709 .object_size
= sizeof(Tunnel
),
711 .sections
= "Match\0NetDev\0Tunnel\0",
712 .fill_message_create
= netdev_vti_fill_message_create
,
713 .create_type
= NETDEV_CREATE_STACKED
,
714 .config_verify
= netdev_tunnel_verify
,
717 const NetDevVTable vti6_vtable
= {
718 .object_size
= sizeof(Tunnel
),
720 .sections
= "Match\0NetDev\0Tunnel\0",
721 .fill_message_create
= netdev_vti6_fill_message_create
,
722 .create_type
= NETDEV_CREATE_STACKED
,
723 .config_verify
= netdev_tunnel_verify
,
726 const NetDevVTable gre_vtable
= {
727 .object_size
= sizeof(Tunnel
),
729 .sections
= "Match\0NetDev\0Tunnel\0",
730 .fill_message_create
= netdev_gre_fill_message_create
,
731 .create_type
= NETDEV_CREATE_STACKED
,
732 .config_verify
= netdev_tunnel_verify
,
735 const NetDevVTable gretap_vtable
= {
736 .object_size
= sizeof(Tunnel
),
738 .sections
= "Match\0NetDev\0Tunnel\0",
739 .fill_message_create
= netdev_gre_fill_message_create
,
740 .create_type
= NETDEV_CREATE_STACKED
,
741 .config_verify
= netdev_tunnel_verify
,
744 const NetDevVTable ip6gre_vtable
= {
745 .object_size
= sizeof(Tunnel
),
747 .sections
= "Match\0NetDev\0Tunnel\0",
748 .fill_message_create
= netdev_ip6gre_fill_message_create
,
749 .create_type
= NETDEV_CREATE_STACKED
,
750 .config_verify
= netdev_tunnel_verify
,
753 const NetDevVTable ip6gretap_vtable
= {
754 .object_size
= sizeof(Tunnel
),
756 .sections
= "Match\0NetDev\0Tunnel\0",
757 .fill_message_create
= netdev_ip6gre_fill_message_create
,
758 .create_type
= NETDEV_CREATE_STACKED
,
759 .config_verify
= netdev_tunnel_verify
,
762 const NetDevVTable ip6tnl_vtable
= {
763 .object_size
= sizeof(Tunnel
),
765 .sections
= "Match\0NetDev\0Tunnel\0",
766 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
767 .create_type
= NETDEV_CREATE_STACKED
,
768 .config_verify
= netdev_tunnel_verify
,