2 This file is part of systemd.
4 Copyright 2014 Susant Sahani
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <arpa/inet.h>
23 #include <linux/if_tunnel.h>
24 #include <linux/ip6_tunnel.h>
26 #include "sd-netlink.h"
28 #include "conf-parser.h"
30 #include "networkd-link.h"
31 #include "netdev/tunnel.h"
32 #include "parse-util.h"
33 #include "string-table.h"
34 #include "string-util.h"
37 #define DEFAULT_TNL_HOP_LIMIT 64
38 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
40 static const char* const ip6tnl_mode_table
[_NETDEV_IP6_TNL_MODE_MAX
] = {
41 [NETDEV_IP6_TNL_MODE_IP6IP6
] = "ip6ip6",
42 [NETDEV_IP6_TNL_MODE_IPIP6
] = "ipip6",
43 [NETDEV_IP6_TNL_MODE_ANYIP6
] = "any",
46 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode
, Ip6TnlMode
);
47 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode
, ip6tnl_mode
, Ip6TnlMode
, "Failed to parse ip6 tunnel Mode");
49 static int netdev_ipip_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
50 Tunnel
*t
= IPIP(netdev
);
56 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
59 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
61 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
65 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
67 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
69 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
71 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
73 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
75 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
77 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
79 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
84 static int netdev_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
85 Tunnel
*t
= SIT(netdev
);
91 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
94 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
96 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
);
249 assert(t
->family
== AF_INET
);
252 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
254 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
257 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
261 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in
);
263 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
265 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in
);
267 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
272 static int netdev_vti6_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
273 Tunnel
*t
= VTI6(netdev
);
279 assert(t
->family
== AF_INET6
);
282 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
284 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
287 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
291 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in6
);
293 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
295 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in6
);
297 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
302 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
303 Tunnel
*t
= IP6TNL(netdev
);
310 assert(t
->family
== AF_INET6
);
313 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
315 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
318 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in6
);
320 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
322 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
324 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
326 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
328 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
330 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
331 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
333 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
337 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
339 if (t
->encap_limit
!= IPV6_DEFAULT_TNL_ENCAP_LIMIT
) {
340 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
342 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
345 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
347 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
349 switch (t
->ip6tnl_mode
) {
350 case NETDEV_IP6_TNL_MODE_IP6IP6
:
351 proto
= IPPROTO_IPV6
;
353 case NETDEV_IP6_TNL_MODE_IPIP6
:
354 proto
= IPPROTO_IPIP
;
356 case NETDEV_IP6_TNL_MODE_ANYIP6
:
362 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
364 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_MODE attribute: %m");
369 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
375 switch (netdev
->kind
) {
376 case NETDEV_KIND_IPIP
:
379 case NETDEV_KIND_SIT
:
382 case NETDEV_KIND_GRE
:
385 case NETDEV_KIND_GRETAP
:
388 case NETDEV_KIND_IP6GRE
:
391 case NETDEV_KIND_IP6GRETAP
:
392 t
= IP6GRETAP(netdev
);
394 case NETDEV_KIND_VTI
:
397 case NETDEV_KIND_VTI6
:
400 case NETDEV_KIND_IP6TNL
:
404 assert_not_reached("Invalid tunnel kind");
409 if (!IN_SET(t
->family
, AF_INET
, AF_INET6
, AF_UNSPEC
)) {
410 log_netdev_error(netdev
,
411 "Tunnel with invalid address family configured in %s. Ignoring", filename
);
415 if (netdev
->kind
== NETDEV_KIND_VTI
&&
416 (t
->family
!= AF_INET
|| in_addr_is_null(t
->family
, &t
->local
))) {
417 log_netdev_error(netdev
,
418 "vti tunnel without a local IPv4 address configured in %s. Ignoring", filename
);
422 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI6
, NETDEV_KIND_IP6TNL
, NETDEV_KIND_IP6GRE
) &&
423 (t
->family
!= AF_INET6
|| in_addr_is_null(t
->family
, &t
->local
))) {
424 log_netdev_error(netdev
,
425 "vti6/ip6tnl/ip6gre tunnel without a local IPv6 address configured in %s. Ignoring", filename
);
429 if (netdev
->kind
== NETDEV_KIND_IP6TNL
&&
430 t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
) {
431 log_netdev_error(netdev
,
432 "ip6tnl without mode configured in %s. Ignoring", filename
);
439 int config_parse_tunnel_address(const char *unit
,
440 const char *filename
,
443 unsigned section_line
,
449 Tunnel
*t
= userdata
;
450 union in_addr_union
*addr
= data
, buffer
;
458 /* This is used to parse addresses on both local and remote ends of the tunnel.
459 * Address families must match.
461 * "any" is a special value which means that the address is unspecified.
464 if (streq(rvalue
, "any")) {
465 *addr
= IN_ADDR_NULL
;
467 /* As a special case, if both the local and remote addresses are
468 * unspecified, also clear the address family.
470 if (t
->family
!= AF_UNSPEC
&&
471 in_addr_is_null(t
->family
, &t
->local
) &&
472 in_addr_is_null(t
->family
, &t
->remote
))
473 t
->family
= AF_UNSPEC
;
477 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
479 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
480 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
484 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
485 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
486 "Tunnel addresses incompatible, ignoring assignment: %s", rvalue
);
495 int config_parse_tunnel_key(const char *unit
,
496 const char *filename
,
499 unsigned section_line
,
505 union in_addr_union buffer
;
506 Tunnel
*t
= userdata
;
515 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
517 r
= safe_atou32(rvalue
, &k
);
519 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
523 k
= be32toh(buffer
.in
.s_addr
);
525 if (streq(lvalue
, "Key"))
527 else if (streq(lvalue
, "InputKey"))
535 int config_parse_ipv6_flowlabel(const char* unit
,
536 const char *filename
,
539 unsigned section_line
,
545 IPv6FlowLabel
*ipv6_flowlabel
= data
;
546 Tunnel
*t
= userdata
;
553 assert(ipv6_flowlabel
);
555 if (streq(rvalue
, "inherit")) {
556 *ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
557 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
559 r
= config_parse_int(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &k
, userdata
);
564 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue
);
566 *ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
567 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
574 int config_parse_encap_limit(const char* unit
,
575 const char *filename
,
578 unsigned section_line
,
584 Tunnel
*t
= userdata
;
592 if (streq(rvalue
, "none"))
593 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
595 r
= safe_atoi(rvalue
, &k
);
597 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue
);
601 if (k
> 255 || k
< 0)
602 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k
);
605 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
612 static void ipip_init(NetDev
*n
) {
621 static void sit_init(NetDev
*n
) {
630 static void vti_init(NetDev
*n
) {
635 if (n
->kind
== NETDEV_KIND_VTI
)
645 static void gre_init(NetDev
*n
) {
650 if (n
->kind
== NETDEV_KIND_GRE
)
660 static void ip6gre_init(NetDev
*n
) {
665 if (n
->kind
== NETDEV_KIND_IP6GRE
)
672 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
675 static void ip6tnl_init(NetDev
*n
) {
676 Tunnel
*t
= IP6TNL(n
);
681 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
682 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
683 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
684 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
687 const NetDevVTable ipip_vtable
= {
688 .object_size
= sizeof(Tunnel
),
690 .sections
= "Match\0NetDev\0Tunnel\0",
691 .fill_message_create
= netdev_ipip_fill_message_create
,
692 .create_type
= NETDEV_CREATE_STACKED
,
693 .config_verify
= netdev_tunnel_verify
,
696 const NetDevVTable sit_vtable
= {
697 .object_size
= sizeof(Tunnel
),
699 .sections
= "Match\0NetDev\0Tunnel\0",
700 .fill_message_create
= netdev_sit_fill_message_create
,
701 .create_type
= NETDEV_CREATE_STACKED
,
702 .config_verify
= netdev_tunnel_verify
,
705 const NetDevVTable vti_vtable
= {
706 .object_size
= sizeof(Tunnel
),
708 .sections
= "Match\0NetDev\0Tunnel\0",
709 .fill_message_create
= netdev_vti_fill_message_create
,
710 .create_type
= NETDEV_CREATE_STACKED
,
711 .config_verify
= netdev_tunnel_verify
,
714 const NetDevVTable vti6_vtable
= {
715 .object_size
= sizeof(Tunnel
),
717 .sections
= "Match\0NetDev\0Tunnel\0",
718 .fill_message_create
= netdev_vti6_fill_message_create
,
719 .create_type
= NETDEV_CREATE_STACKED
,
720 .config_verify
= netdev_tunnel_verify
,
723 const NetDevVTable gre_vtable
= {
724 .object_size
= sizeof(Tunnel
),
726 .sections
= "Match\0NetDev\0Tunnel\0",
727 .fill_message_create
= netdev_gre_fill_message_create
,
728 .create_type
= NETDEV_CREATE_STACKED
,
729 .config_verify
= netdev_tunnel_verify
,
732 const NetDevVTable gretap_vtable
= {
733 .object_size
= sizeof(Tunnel
),
735 .sections
= "Match\0NetDev\0Tunnel\0",
736 .fill_message_create
= netdev_gre_fill_message_create
,
737 .create_type
= NETDEV_CREATE_STACKED
,
738 .config_verify
= netdev_tunnel_verify
,
741 const NetDevVTable ip6gre_vtable
= {
742 .object_size
= sizeof(Tunnel
),
744 .sections
= "Match\0NetDev\0Tunnel\0",
745 .fill_message_create
= netdev_ip6gre_fill_message_create
,
746 .create_type
= NETDEV_CREATE_STACKED
,
747 .config_verify
= netdev_tunnel_verify
,
750 const NetDevVTable ip6gretap_vtable
= {
751 .object_size
= sizeof(Tunnel
),
753 .sections
= "Match\0NetDev\0Tunnel\0",
754 .fill_message_create
= netdev_ip6gre_fill_message_create
,
755 .create_type
= NETDEV_CREATE_STACKED
,
756 .config_verify
= netdev_tunnel_verify
,
759 const NetDevVTable ip6tnl_vtable
= {
760 .object_size
= sizeof(Tunnel
),
762 .sections
= "Match\0NetDev\0Tunnel\0",
763 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
764 .create_type
= NETDEV_CREATE_STACKED
,
765 .config_verify
= netdev_tunnel_verify
,