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 "networkd-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
);
57 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");
63 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
65 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
67 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
69 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
71 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
73 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
75 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
77 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
82 static int netdev_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
83 Tunnel
*t
= SIT(netdev
);
90 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
92 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
94 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
96 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
98 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
100 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
102 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
104 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
106 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
108 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
110 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
115 static int netdev_gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
121 if (netdev
->kind
== NETDEV_KIND_GRE
)
127 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
131 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
133 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
135 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in
);
137 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
139 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
141 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
143 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
145 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
147 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
149 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TOS attribute: %m");
151 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
153 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
158 static int netdev_ip6gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
164 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
167 t
= IP6GRETAP(netdev
);
170 assert(t
->family
== AF_INET6
);
174 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
176 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
178 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in6
);
180 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
182 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
184 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
186 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
188 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
190 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
191 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
193 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
196 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
198 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLAGS attribute: %m");
203 static int netdev_vti_fill_message_key(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
204 Tunnel
*t
= VTI(netdev
);
213 ikey
= okey
= htobe32(t
->key
);
215 ikey
= htobe32(t
->ikey
);
216 okey
= htobe32(t
->okey
);
219 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
221 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_IKEY attribute: %m");
223 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
225 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_OKEY attribute: %m");
230 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
231 Tunnel
*t
= VTI(netdev
);
238 assert(t
->family
== AF_INET
);
240 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
242 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
244 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
248 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in
);
250 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
252 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in
);
254 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
259 static int netdev_vti6_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
260 Tunnel
*t
= VTI6(netdev
);
267 assert(t
->family
== AF_INET6
);
269 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
271 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
);
297 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");
303 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in6
);
305 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
307 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
309 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
311 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
313 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
315 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
316 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
318 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
322 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
324 if (t
->encap_limit
!= IPV6_DEFAULT_TNL_ENCAP_LIMIT
) {
325 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
327 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
330 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
332 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
334 switch (t
->ip6tnl_mode
) {
335 case NETDEV_IP6_TNL_MODE_IP6IP6
:
336 proto
= IPPROTO_IPV6
;
338 case NETDEV_IP6_TNL_MODE_IPIP6
:
339 proto
= IPPROTO_IPIP
;
341 case NETDEV_IP6_TNL_MODE_ANYIP6
:
347 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
349 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_MODE attribute: %m");
354 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
360 switch (netdev
->kind
) {
361 case NETDEV_KIND_IPIP
:
364 case NETDEV_KIND_SIT
:
367 case NETDEV_KIND_GRE
:
370 case NETDEV_KIND_GRETAP
:
373 case NETDEV_KIND_IP6GRE
:
376 case NETDEV_KIND_IP6GRETAP
:
377 t
= IP6GRETAP(netdev
);
379 case NETDEV_KIND_VTI
:
382 case NETDEV_KIND_VTI6
:
385 case NETDEV_KIND_IP6TNL
:
389 assert_not_reached("Invalid tunnel kind");
394 if (t
->family
!= AF_INET
&& t
->family
!= AF_INET6
&& t
->family
!= 0) {
395 log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename
);
399 if (netdev
->kind
== NETDEV_KIND_IP6TNL
) {
400 if (t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
) {
401 log_warning("IP6 Tunnel without mode configured in %s. Ignoring", filename
);
409 int config_parse_tunnel_address(const char *unit
,
410 const char *filename
,
413 unsigned section_line
,
419 Tunnel
*t
= userdata
;
420 union in_addr_union
*addr
= data
, buffer
;
428 if (streq(rvalue
, "any")) {
433 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
435 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Tunnel address is invalid, ignoring assignment: %s", rvalue
);
439 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
440 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue
);
451 int config_parse_tunnel_key(const char *unit
,
452 const char *filename
,
455 unsigned section_line
,
461 union in_addr_union buffer
;
462 Tunnel
*t
= userdata
;
471 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
473 r
= safe_atou32(rvalue
, &k
);
475 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
479 k
= be32toh(buffer
.in
.s_addr
);
481 if (streq(lvalue
, "Key"))
483 else if (streq(lvalue
, "InputKey"))
491 int config_parse_ipv6_flowlabel(const char* unit
,
492 const char *filename
,
495 unsigned section_line
,
501 IPv6FlowLabel
*ipv6_flowlabel
= data
;
502 Tunnel
*t
= userdata
;
509 assert(ipv6_flowlabel
);
511 if (streq(rvalue
, "inherit")) {
512 *ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
513 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
515 r
= config_parse_int(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &k
, userdata
);
520 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue
);
522 *ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
523 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
530 int config_parse_encap_limit(const char* unit
,
531 const char *filename
,
534 unsigned section_line
,
540 Tunnel
*t
= userdata
;
548 if (streq(rvalue
, "none"))
549 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
551 r
= safe_atoi(rvalue
, &k
);
553 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue
);
557 if (k
> 255 || k
< 0)
558 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k
);
561 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
568 static void ipip_init(NetDev
*n
) {
575 t
->family
= AF_UNSPEC
;
578 static void sit_init(NetDev
*n
) {
585 t
->family
= AF_UNSPEC
;
588 static void vti_init(NetDev
*n
) {
593 if (n
->kind
== NETDEV_KIND_VTI
)
603 static void gre_init(NetDev
*n
) {
608 if (n
->kind
== NETDEV_KIND_GRE
)
616 t
->family
= AF_UNSPEC
;
619 static void ip6gre_init(NetDev
*n
) {
624 if (n
->kind
== NETDEV_KIND_IP6GRE
)
631 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
634 static void ip6tnl_init(NetDev
*n
) {
635 Tunnel
*t
= IP6TNL(n
);
640 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
641 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
642 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
643 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
646 const NetDevVTable ipip_vtable
= {
647 .object_size
= sizeof(Tunnel
),
649 .sections
= "Match\0NetDev\0Tunnel\0",
650 .fill_message_create
= netdev_ipip_fill_message_create
,
651 .create_type
= NETDEV_CREATE_STACKED
,
652 .config_verify
= netdev_tunnel_verify
,
655 const NetDevVTable sit_vtable
= {
656 .object_size
= sizeof(Tunnel
),
658 .sections
= "Match\0NetDev\0Tunnel\0",
659 .fill_message_create
= netdev_sit_fill_message_create
,
660 .create_type
= NETDEV_CREATE_STACKED
,
661 .config_verify
= netdev_tunnel_verify
,
664 const NetDevVTable vti_vtable
= {
665 .object_size
= sizeof(Tunnel
),
667 .sections
= "Match\0NetDev\0Tunnel\0",
668 .fill_message_create
= netdev_vti_fill_message_create
,
669 .create_type
= NETDEV_CREATE_STACKED
,
670 .config_verify
= netdev_tunnel_verify
,
673 const NetDevVTable vti6_vtable
= {
674 .object_size
= sizeof(Tunnel
),
676 .sections
= "Match\0NetDev\0Tunnel\0",
677 .fill_message_create
= netdev_vti6_fill_message_create
,
678 .create_type
= NETDEV_CREATE_STACKED
,
679 .config_verify
= netdev_tunnel_verify
,
682 const NetDevVTable gre_vtable
= {
683 .object_size
= sizeof(Tunnel
),
685 .sections
= "Match\0NetDev\0Tunnel\0",
686 .fill_message_create
= netdev_gre_fill_message_create
,
687 .create_type
= NETDEV_CREATE_STACKED
,
688 .config_verify
= netdev_tunnel_verify
,
691 const NetDevVTable gretap_vtable
= {
692 .object_size
= sizeof(Tunnel
),
694 .sections
= "Match\0NetDev\0Tunnel\0",
695 .fill_message_create
= netdev_gre_fill_message_create
,
696 .create_type
= NETDEV_CREATE_STACKED
,
697 .config_verify
= netdev_tunnel_verify
,
700 const NetDevVTable ip6gre_vtable
= {
701 .object_size
= sizeof(Tunnel
),
703 .sections
= "Match\0NetDev\0Tunnel\0",
704 .fill_message_create
= netdev_ip6gre_fill_message_create
,
705 .create_type
= NETDEV_CREATE_STACKED
,
706 .config_verify
= netdev_tunnel_verify
,
709 const NetDevVTable ip6gretap_vtable
= {
710 .object_size
= sizeof(Tunnel
),
712 .sections
= "Match\0NetDev\0Tunnel\0",
713 .fill_message_create
= netdev_ip6gre_fill_message_create
,
714 .create_type
= NETDEV_CREATE_STACKED
,
715 .config_verify
= netdev_tunnel_verify
,
718 const NetDevVTable ip6tnl_vtable
= {
719 .object_size
= sizeof(Tunnel
),
721 .sections
= "Match\0NetDev\0Tunnel\0",
722 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
723 .create_type
= NETDEV_CREATE_STACKED
,
724 .config_verify
= netdev_tunnel_verify
,