1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include <linux/if_tunnel.h>
7 #include <linux/ip6_tunnel.h>
10 #include <linux/fou.h>
13 #include "sd-netlink.h"
15 #include "conf-parser.h"
17 #include "networkd-link.h"
18 #include "netdev/tunnel.h"
19 #include "parse-util.h"
20 #include "string-table.h"
21 #include "string-util.h"
24 #define DEFAULT_TNL_HOP_LIMIT 64
25 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
26 #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
28 static const char* const ip6tnl_mode_table
[_NETDEV_IP6_TNL_MODE_MAX
] = {
29 [NETDEV_IP6_TNL_MODE_IP6IP6
] = "ip6ip6",
30 [NETDEV_IP6_TNL_MODE_IPIP6
] = "ipip6",
31 [NETDEV_IP6_TNL_MODE_ANYIP6
] = "any",
34 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode
, Ip6TnlMode
);
35 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode
, ip6tnl_mode
, Ip6TnlMode
, "Failed to parse ip6 tunnel Mode");
37 static int netdev_ipip_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
38 Tunnel
*t
= IPIP(netdev
);
44 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
47 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
49 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
52 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
54 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
56 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
58 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
60 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
62 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
64 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
66 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
70 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_TYPE
, t
->fou_encap_type
);
72 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_TYPE attribute: %m");
74 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
76 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_SPORT attribute: %m");
78 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
80 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_DPORT attribute: %m");
86 static int netdev_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
87 Tunnel
*t
= SIT(netdev
);
93 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
96 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
98 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
101 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
103 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
105 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
107 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
109 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
111 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
113 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
115 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
117 if (t
->sixrd_prefixlen
> 0) {
118 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_6RD_PREFIX
, &t
->sixrd_prefix
);
120 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
121 /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
122 * expecting to receive the prefixlen as a u16.
124 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, t
->sixrd_prefixlen
);
126 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
132 static int netdev_gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
138 if (netdev
->kind
== NETDEV_KIND_GRE
)
144 assert(IN_SET(t
->family
, AF_INET
, AF_UNSPEC
));
148 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
150 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
153 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in
);
155 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
157 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
159 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
161 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
163 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
165 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
167 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TOS attribute: %m");
169 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
171 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
176 static int netdev_ip6gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
182 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
185 t
= IP6GRETAP(netdev
);
188 assert(t
->family
== AF_INET6
);
192 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
194 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
197 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in6
);
199 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
201 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
203 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
205 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
207 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
209 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
210 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
212 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
215 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
217 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLAGS attribute: %m");
222 static int netdev_vti_fill_message_key(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
229 if (netdev
->kind
== NETDEV_KIND_VTI
)
237 ikey
= okey
= htobe32(t
->key
);
239 ikey
= htobe32(t
->ikey
);
240 okey
= htobe32(t
->okey
);
243 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
245 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_IKEY attribute: %m");
247 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
249 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_OKEY attribute: %m");
254 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
255 Tunnel
*t
= VTI(netdev
);
261 assert(t
->family
== AF_INET
);
264 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
266 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
269 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
273 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_LOCAL
, &t
->local
.in
);
275 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
277 r
= sd_netlink_message_append_in_addr(m
, IFLA_VTI_REMOTE
, &t
->remote
.in
);
279 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
284 static int netdev_vti6_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
285 Tunnel
*t
= VTI6(netdev
);
291 assert(t
->family
== AF_INET6
);
294 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
296 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
299 r
= netdev_vti_fill_message_key(netdev
, link
, m
);
303 r
= sd_netlink_message_append_in6_addr(m
, IFLA_VTI_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_VTI_REMOTE
, &t
->remote
.in6
);
309 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
314 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
315 Tunnel
*t
= IP6TNL(netdev
);
322 assert(t
->family
== AF_INET6
);
325 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
327 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
330 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in6
);
332 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
334 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
336 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
338 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
340 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
342 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
343 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
345 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
349 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
351 if (t
->allow_localremote
!= -1)
352 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
354 if (t
->encap_limit
!= IPV6_DEFAULT_TNL_ENCAP_LIMIT
) {
355 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
357 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
360 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
362 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
364 switch (t
->ip6tnl_mode
) {
365 case NETDEV_IP6_TNL_MODE_IP6IP6
:
366 proto
= IPPROTO_IPV6
;
368 case NETDEV_IP6_TNL_MODE_IPIP6
:
369 proto
= IPPROTO_IPIP
;
371 case NETDEV_IP6_TNL_MODE_ANYIP6
:
377 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
379 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_MODE attribute: %m");
384 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
390 switch (netdev
->kind
) {
391 case NETDEV_KIND_IPIP
:
394 case NETDEV_KIND_SIT
:
397 case NETDEV_KIND_GRE
:
400 case NETDEV_KIND_GRETAP
:
403 case NETDEV_KIND_IP6GRE
:
406 case NETDEV_KIND_IP6GRETAP
:
407 t
= IP6GRETAP(netdev
);
409 case NETDEV_KIND_VTI
:
412 case NETDEV_KIND_VTI6
:
415 case NETDEV_KIND_IP6TNL
:
419 assert_not_reached("Invalid tunnel kind");
424 if (!IN_SET(t
->family
, AF_INET
, AF_INET6
, AF_UNSPEC
)) {
425 log_netdev_error(netdev
,
426 "Tunnel with invalid address family configured in %s. Ignoring", filename
);
430 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI
, NETDEV_KIND_IPIP
, NETDEV_KIND_SIT
, NETDEV_KIND_GRE
, NETDEV_KIND_GRETAP
) &&
431 (t
->family
!= AF_INET
|| in_addr_is_null(t
->family
, &t
->local
))) {
432 log_netdev_error(netdev
,
433 "vti/ipip/sit/gre/gretap tunnel without a local IPv4 address configured in %s. Ignoring", filename
);
437 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI6
, NETDEV_KIND_IP6TNL
, NETDEV_KIND_IP6GRE
, NETDEV_KIND_IP6GRETAP
) &&
438 (t
->family
!= AF_INET6
|| in_addr_is_null(t
->family
, &t
->local
))) {
439 log_netdev_error(netdev
,
440 "vti6/ip6tnl/ip6gre/ip6gretap tunnel without a local IPv6 address configured in %s. Ignoring", filename
);
444 if (netdev
->kind
== NETDEV_KIND_IP6TNL
&&
445 t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
) {
446 log_netdev_error(netdev
,
447 "ip6tnl without mode configured in %s. Ignoring", filename
);
451 if (t
->fou_tunnel
&& t
->fou_destination_port
<= 0) {
452 log_netdev_error(netdev
, "FooOverUDP missing port configured in %s. Ignoring", filename
);
459 int config_parse_tunnel_address(const char *unit
,
460 const char *filename
,
463 unsigned section_line
,
469 Tunnel
*t
= userdata
;
470 union in_addr_union
*addr
= data
, buffer
;
478 /* This is used to parse addresses on both local and remote ends of the tunnel.
479 * Address families must match.
481 * "any" is a special value which means that the address is unspecified.
484 if (streq(rvalue
, "any")) {
485 *addr
= IN_ADDR_NULL
;
487 /* As a special case, if both the local and remote addresses are
488 * unspecified, also clear the address family.
490 if (t
->family
!= AF_UNSPEC
&&
491 in_addr_is_null(t
->family
, &t
->local
) &&
492 in_addr_is_null(t
->family
, &t
->remote
))
493 t
->family
= AF_UNSPEC
;
497 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
499 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
500 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
504 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
505 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
506 "Tunnel addresses incompatible, ignoring assignment: %s", rvalue
);
515 int config_parse_tunnel_key(const char *unit
,
516 const char *filename
,
519 unsigned section_line
,
525 union in_addr_union buffer
;
526 Tunnel
*t
= userdata
;
535 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
537 r
= safe_atou32(rvalue
, &k
);
539 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
543 k
= be32toh(buffer
.in
.s_addr
);
545 if (streq(lvalue
, "Key"))
547 else if (streq(lvalue
, "InputKey"))
555 int config_parse_ipv6_flowlabel(const char* unit
,
556 const char *filename
,
559 unsigned section_line
,
565 IPv6FlowLabel
*ipv6_flowlabel
= data
;
566 Tunnel
*t
= userdata
;
573 assert(ipv6_flowlabel
);
575 if (streq(rvalue
, "inherit")) {
576 *ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
577 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
579 r
= config_parse_int(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &k
, userdata
);
584 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue
);
586 *ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
587 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
594 int config_parse_encap_limit(const char* unit
,
595 const char *filename
,
598 unsigned section_line
,
604 Tunnel
*t
= userdata
;
612 if (streq(rvalue
, "none"))
613 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
615 r
= safe_atoi(rvalue
, &k
);
617 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue
);
621 if (k
> 255 || k
< 0)
622 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k
);
625 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
632 int config_parse_6rd_prefix(const char* unit
,
633 const char *filename
,
636 unsigned section_line
,
642 Tunnel
*t
= userdata
;
648 union in_addr_union p
;
652 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &p
, &l
);
654 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue
);
658 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue
);
662 t
->sixrd_prefix
= p
.in6
;
663 t
->sixrd_prefixlen
= l
;
668 static void ipip_init(NetDev
*n
) {
675 t
->fou_encap_type
= FOU_ENCAP_DIRECT
;
678 static void sit_init(NetDev
*n
) {
687 static void vti_init(NetDev
*n
) {
692 if (n
->kind
== NETDEV_KIND_VTI
)
702 static void gre_init(NetDev
*n
) {
707 if (n
->kind
== NETDEV_KIND_GRE
)
717 static void ip6gre_init(NetDev
*n
) {
722 if (n
->kind
== NETDEV_KIND_IP6GRE
)
729 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
732 static void ip6tnl_init(NetDev
*n
) {
733 Tunnel
*t
= IP6TNL(n
);
738 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
739 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
740 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
741 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
742 t
->allow_localremote
= -1;
745 const NetDevVTable ipip_vtable
= {
746 .object_size
= sizeof(Tunnel
),
748 .sections
= "Match\0NetDev\0Tunnel\0",
749 .fill_message_create
= netdev_ipip_fill_message_create
,
750 .create_type
= NETDEV_CREATE_STACKED
,
751 .config_verify
= netdev_tunnel_verify
,
754 const NetDevVTable sit_vtable
= {
755 .object_size
= sizeof(Tunnel
),
757 .sections
= "Match\0NetDev\0Tunnel\0",
758 .fill_message_create
= netdev_sit_fill_message_create
,
759 .create_type
= NETDEV_CREATE_STACKED
,
760 .config_verify
= netdev_tunnel_verify
,
763 const NetDevVTable vti_vtable
= {
764 .object_size
= sizeof(Tunnel
),
766 .sections
= "Match\0NetDev\0Tunnel\0",
767 .fill_message_create
= netdev_vti_fill_message_create
,
768 .create_type
= NETDEV_CREATE_STACKED
,
769 .config_verify
= netdev_tunnel_verify
,
772 const NetDevVTable vti6_vtable
= {
773 .object_size
= sizeof(Tunnel
),
775 .sections
= "Match\0NetDev\0Tunnel\0",
776 .fill_message_create
= netdev_vti6_fill_message_create
,
777 .create_type
= NETDEV_CREATE_STACKED
,
778 .config_verify
= netdev_tunnel_verify
,
781 const NetDevVTable gre_vtable
= {
782 .object_size
= sizeof(Tunnel
),
784 .sections
= "Match\0NetDev\0Tunnel\0",
785 .fill_message_create
= netdev_gre_fill_message_create
,
786 .create_type
= NETDEV_CREATE_STACKED
,
787 .config_verify
= netdev_tunnel_verify
,
790 const NetDevVTable gretap_vtable
= {
791 .object_size
= sizeof(Tunnel
),
793 .sections
= "Match\0NetDev\0Tunnel\0",
794 .fill_message_create
= netdev_gre_fill_message_create
,
795 .create_type
= NETDEV_CREATE_STACKED
,
796 .config_verify
= netdev_tunnel_verify
,
799 const NetDevVTable ip6gre_vtable
= {
800 .object_size
= sizeof(Tunnel
),
802 .sections
= "Match\0NetDev\0Tunnel\0",
803 .fill_message_create
= netdev_ip6gre_fill_message_create
,
804 .create_type
= NETDEV_CREATE_STACKED
,
805 .config_verify
= netdev_tunnel_verify
,
808 const NetDevVTable ip6gretap_vtable
= {
809 .object_size
= sizeof(Tunnel
),
811 .sections
= "Match\0NetDev\0Tunnel\0",
812 .fill_message_create
= netdev_ip6gre_fill_message_create
,
813 .create_type
= NETDEV_CREATE_STACKED
,
814 .config_verify
= netdev_tunnel_verify
,
817 const NetDevVTable ip6tnl_vtable
= {
818 .object_size
= sizeof(Tunnel
),
820 .sections
= "Match\0NetDev\0Tunnel\0",
821 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
822 .create_type
= NETDEV_CREATE_STACKED
,
823 .config_verify
= netdev_tunnel_verify
,