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 "netlink-util.h"
18 #include "networkd-link.h"
19 #include "netdev/tunnel.h"
20 #include "parse-util.h"
21 #include "string-table.h"
22 #include "string-util.h"
25 #define DEFAULT_TNL_HOP_LIMIT 64
26 #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
27 #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
29 static const char* const ip6tnl_mode_table
[_NETDEV_IP6_TNL_MODE_MAX
] = {
30 [NETDEV_IP6_TNL_MODE_IP6IP6
] = "ip6ip6",
31 [NETDEV_IP6_TNL_MODE_IPIP6
] = "ipip6",
32 [NETDEV_IP6_TNL_MODE_ANYIP6
] = "any",
35 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode
, Ip6TnlMode
);
36 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode
, ip6tnl_mode
, Ip6TnlMode
, "Failed to parse ip6 tunnel Mode");
38 static int netdev_ipip_sit_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
44 if (netdev
->kind
== NETDEV_KIND_IPIP
)
51 assert(t
->family
== AF_INET
);
54 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
56 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
59 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in
);
61 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
63 r
= sd_netlink_message_append_in_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in
);
65 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
67 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
69 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
71 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PMTUDISC
, t
->pmtudisc
);
73 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
75 if (netdev
->kind
== NETDEV_KIND_IPIP
&& t
->fou_tunnel
) {
76 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_TYPE
, t
->fou_encap_type
);
78 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_TYPE attribute: %m");
80 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_SPORT
, htobe16(t
->encap_src_port
));
82 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_SPORT attribute: %m");
84 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_ENCAP_DPORT
, htobe16(t
->fou_destination_port
));
86 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_DPORT attribute: %m");
89 if (netdev
->kind
== NETDEV_KIND_SIT
) {
90 if (t
->sixrd_prefixlen
> 0) {
91 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_6RD_PREFIX
, &t
->sixrd_prefix
);
93 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
95 /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
96 * expecting to receive the prefixlen as a u16.
98 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_6RD_PREFIXLEN
, t
->sixrd_prefixlen
);
100 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
103 if (t
->isatap
>= 0) {
106 SET_FLAG(flags
, SIT_ISATAP
, t
->isatap
);
108 r
= sd_netlink_message_append_u16(m
, IFLA_IPTUN_FLAGS
, flags
);
110 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
117 static int netdev_gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
123 if (netdev
->kind
== NETDEV_KIND_GRE
)
129 assert(t
->family
== AF_INET
);
133 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
135 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
138 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in
);
140 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
142 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
144 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
146 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
148 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
150 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TOS
, t
->tos
);
152 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TOS attribute: %m");
154 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_PMTUDISC
, t
->pmtudisc
);
156 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
161 static int netdev_erspan_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
174 assert(t
->family
== AF_INET
);
177 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_ERSPAN_INDEX
, t
->erspan_index
);
179 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
182 ikey
= okey
= htobe32(t
->key
);
188 ikey
= htobe32(t
->ikey
);
193 okey
= htobe32(t
->okey
);
197 if (t
->erspan_sequence
> 0) {
200 } else if (t
->erspan_sequence
== 0) {
205 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_IKEY
, ikey
);
207 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_IKEY attribute: %m");
209 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_OKEY
, okey
);
211 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_OKEY attribute: %m");
213 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_IFLAGS
, iflags
);
215 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_IFLAGS attribute: %m");
217 r
= sd_netlink_message_append_u16(m
, IFLA_GRE_OFLAGS
, oflags
);
219 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_OFLAGS, attribute: %m");
221 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in
);
223 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
225 r
= sd_netlink_message_append_in_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in
);
227 log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
232 static int netdev_ip6gre_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
238 if (netdev
->kind
== NETDEV_KIND_IP6GRE
)
241 t
= IP6GRETAP(netdev
);
244 assert(t
->family
== AF_INET6
);
248 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_LINK
, link
->ifindex
);
250 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LINK attribute: %m");
253 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_LOCAL
, &t
->local
.in6
);
255 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_LOCAL attribute: %m");
257 r
= sd_netlink_message_append_in6_addr(m
, IFLA_GRE_REMOTE
, &t
->remote
.in6
);
259 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_REMOTE attribute: %m");
261 r
= sd_netlink_message_append_u8(m
, IFLA_GRE_TTL
, t
->ttl
);
263 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_TTL attribute: %m");
265 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
266 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLOWINFO
, t
->ipv6_flowlabel
);
268 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
271 r
= sd_netlink_message_append_u32(m
, IFLA_GRE_FLAGS
, t
->flags
);
273 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_GRE_FLAGS attribute: %m");
278 static int netdev_vti_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
286 if (netdev
->kind
== NETDEV_KIND_VTI
)
292 assert((netdev
->kind
== NETDEV_KIND_VTI
&& t
->family
== AF_INET
) ||
293 (netdev
->kind
== NETDEV_KIND_VTI6
&& t
->family
== AF_INET6
));
296 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_LINK
, link
->ifindex
);
298 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_LINK attribute: %m");
302 ikey
= okey
= htobe32(t
->key
);
304 ikey
= htobe32(t
->ikey
);
305 okey
= htobe32(t
->okey
);
308 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_IKEY
, ikey
);
310 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_IKEY attribute: %m");
312 r
= sd_netlink_message_append_u32(m
, IFLA_VTI_OKEY
, okey
);
314 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_OKEY attribute: %m");
316 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_LOCAL
, t
->family
, &t
->local
);
318 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_LOCAL attribute: %m");
320 r
= netlink_message_append_in_addr_union(m
, IFLA_VTI_REMOTE
, t
->family
, &t
->remote
);
322 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_VTI_REMOTE attribute: %m");
327 static int netdev_ip6tnl_fill_message_create(NetDev
*netdev
, Link
*link
, sd_netlink_message
*m
) {
328 Tunnel
*t
= IP6TNL(netdev
);
335 assert(t
->family
== AF_INET6
);
338 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_LINK
, link
->ifindex
);
340 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LINK attribute: %m");
343 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_LOCAL
, &t
->local
.in6
);
345 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
347 r
= sd_netlink_message_append_in6_addr(m
, IFLA_IPTUN_REMOTE
, &t
->remote
.in6
);
349 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
351 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_TTL
, t
->ttl
);
353 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_TTL attribute: %m");
355 if (t
->ipv6_flowlabel
!= _NETDEV_IPV6_FLOWLABEL_INVALID
) {
356 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLOWINFO
, t
->ipv6_flowlabel
);
358 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
362 t
->flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
364 if (t
->allow_localremote
>= 0)
365 SET_FLAG(t
->flags
, IP6_TNL_F_ALLOW_LOCAL_REMOTE
, t
->allow_localremote
);
367 if (t
->encap_limit
!= IPV6_DEFAULT_TNL_ENCAP_LIMIT
) {
368 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_ENCAP_LIMIT
, t
->encap_limit
);
370 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
373 r
= sd_netlink_message_append_u32(m
, IFLA_IPTUN_FLAGS
, t
->flags
);
375 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
377 switch (t
->ip6tnl_mode
) {
378 case NETDEV_IP6_TNL_MODE_IP6IP6
:
379 proto
= IPPROTO_IPV6
;
381 case NETDEV_IP6_TNL_MODE_IPIP6
:
382 proto
= IPPROTO_IPIP
;
384 case NETDEV_IP6_TNL_MODE_ANYIP6
:
390 r
= sd_netlink_message_append_u8(m
, IFLA_IPTUN_PROTO
, proto
);
392 return log_netdev_error_errno(netdev
, r
, "Could not append IFLA_IPTUN_PROTO attribute: %m");
397 static int netdev_tunnel_verify(NetDev
*netdev
, const char *filename
) {
403 switch (netdev
->kind
) {
404 case NETDEV_KIND_IPIP
:
407 case NETDEV_KIND_SIT
:
410 case NETDEV_KIND_GRE
:
413 case NETDEV_KIND_GRETAP
:
416 case NETDEV_KIND_IP6GRE
:
419 case NETDEV_KIND_IP6GRETAP
:
420 t
= IP6GRETAP(netdev
);
422 case NETDEV_KIND_VTI
:
425 case NETDEV_KIND_VTI6
:
428 case NETDEV_KIND_IP6TNL
:
431 case NETDEV_KIND_ERSPAN
:
435 assert_not_reached("Invalid tunnel kind");
440 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI
, NETDEV_KIND_IPIP
, NETDEV_KIND_SIT
, NETDEV_KIND_GRE
, NETDEV_KIND_GRETAP
, NETDEV_KIND_ERSPAN
) &&
441 (t
->family
!= AF_INET
|| in_addr_is_null(t
->family
, &t
->local
)))
442 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
443 "vti/ipip/sit/gre/gretap/erspan tunnel without a local IPv4 address configured in %s. Ignoring", filename
);
445 if (IN_SET(netdev
->kind
, NETDEV_KIND_VTI6
, NETDEV_KIND_IP6TNL
, NETDEV_KIND_IP6GRE
, NETDEV_KIND_IP6GRETAP
) &&
446 (t
->family
!= AF_INET6
|| in_addr_is_null(t
->family
, &t
->local
)))
447 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
448 "vti6/ip6tnl/ip6gre/ip6gretap tunnel without a local IPv6 address configured in %s. Ignoring", filename
);
450 if (netdev
->kind
== NETDEV_KIND_IP6TNL
&&
451 t
->ip6tnl_mode
== _NETDEV_IP6_TNL_MODE_INVALID
)
452 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
453 "ip6tnl without mode configured in %s. Ignoring", filename
);
455 if (t
->fou_tunnel
&& t
->fou_destination_port
<= 0)
456 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
457 "FooOverUDP missing port configured in %s. Ignoring", filename
);
459 if (netdev
->kind
== NETDEV_KIND_ERSPAN
&& (t
->erspan_index
>= (1 << 20) || t
->erspan_index
== 0))
460 return log_netdev_error_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
), "Invalid erspan index %d. Ignoring", t
->erspan_index
);
465 int config_parse_tunnel_address(const char *unit
,
466 const char *filename
,
469 unsigned section_line
,
475 Tunnel
*t
= userdata
;
476 union in_addr_union
*addr
= data
, buffer
;
484 /* This is used to parse addresses on both local and remote ends of the tunnel.
485 * Address families must match.
487 * "any" is a special value which means that the address is unspecified.
490 if (streq(rvalue
, "any")) {
491 *addr
= IN_ADDR_NULL
;
493 /* As a special case, if both the local and remote addresses are
494 * unspecified, also clear the address family.
496 if (t
->family
!= AF_UNSPEC
&&
497 in_addr_is_null(t
->family
, &t
->local
) != 0 &&
498 in_addr_is_null(t
->family
, &t
->remote
) != 0)
499 t
->family
= AF_UNSPEC
;
503 r
= in_addr_from_string_auto(rvalue
, &f
, &buffer
);
505 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
506 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue
);
510 if (t
->family
!= AF_UNSPEC
&& t
->family
!= f
) {
511 log_syntax(unit
, LOG_ERR
, filename
, line
, 0,
512 "Tunnel addresses incompatible, ignoring assignment: %s", rvalue
);
521 int config_parse_tunnel_key(const char *unit
,
522 const char *filename
,
525 unsigned section_line
,
531 union in_addr_union buffer
;
532 Tunnel
*t
= userdata
;
541 r
= in_addr_from_string(AF_INET
, rvalue
, &buffer
);
543 r
= safe_atou32(rvalue
, &k
);
545 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue
);
549 k
= be32toh(buffer
.in
.s_addr
);
551 if (streq(lvalue
, "Key"))
553 else if (streq(lvalue
, "InputKey"))
561 int config_parse_ipv6_flowlabel(const char* unit
,
562 const char *filename
,
565 unsigned section_line
,
571 IPv6FlowLabel
*ipv6_flowlabel
= data
;
572 Tunnel
*t
= userdata
;
579 assert(ipv6_flowlabel
);
581 if (streq(rvalue
, "inherit")) {
582 *ipv6_flowlabel
= IP6_FLOWINFO_FLOWLABEL
;
583 t
->flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
585 r
= config_parse_int(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &k
, userdata
);
590 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue
);
592 *ipv6_flowlabel
= htobe32(k
) & IP6_FLOWINFO_FLOWLABEL
;
593 t
->flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
600 int config_parse_encap_limit(const char* unit
,
601 const char *filename
,
604 unsigned section_line
,
610 Tunnel
*t
= userdata
;
618 if (streq(rvalue
, "none"))
619 t
->flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
621 r
= safe_atoi(rvalue
, &k
);
623 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue
);
627 if (k
> 255 || k
< 0)
628 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k
);
631 t
->flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
638 int config_parse_6rd_prefix(const char* unit
,
639 const char *filename
,
642 unsigned section_line
,
648 Tunnel
*t
= userdata
;
654 union in_addr_union p
;
658 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &p
, &l
);
660 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue
);
664 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue
);
668 t
->sixrd_prefix
= p
.in6
;
669 t
->sixrd_prefixlen
= l
;
674 static void ipip_init(NetDev
*n
) {
681 t
->fou_encap_type
= FOU_ENCAP_DIRECT
;
684 static void sit_init(NetDev
*n
) {
694 static void vti_init(NetDev
*n
) {
699 if (n
->kind
== NETDEV_KIND_VTI
)
709 static void gre_init(NetDev
*n
) {
714 if (n
->kind
== NETDEV_KIND_GRE
)
724 static void ip6gre_init(NetDev
*n
) {
729 if (n
->kind
== NETDEV_KIND_IP6GRE
)
736 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
739 static void erspan_init(NetDev
*n
) {
748 t
->erspan_sequence
= -1;
751 static void ip6tnl_init(NetDev
*n
) {
752 Tunnel
*t
= IP6TNL(n
);
757 t
->ttl
= DEFAULT_TNL_HOP_LIMIT
;
758 t
->encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
759 t
->ip6tnl_mode
= _NETDEV_IP6_TNL_MODE_INVALID
;
760 t
->ipv6_flowlabel
= _NETDEV_IPV6_FLOWLABEL_INVALID
;
761 t
->allow_localremote
= -1;
764 const NetDevVTable ipip_vtable
= {
765 .object_size
= sizeof(Tunnel
),
767 .sections
= "Match\0NetDev\0Tunnel\0",
768 .fill_message_create
= netdev_ipip_sit_fill_message_create
,
769 .create_type
= NETDEV_CREATE_STACKED
,
770 .config_verify
= netdev_tunnel_verify
,
773 const NetDevVTable sit_vtable
= {
774 .object_size
= sizeof(Tunnel
),
776 .sections
= "Match\0NetDev\0Tunnel\0",
777 .fill_message_create
= netdev_ipip_sit_fill_message_create
,
778 .create_type
= NETDEV_CREATE_STACKED
,
779 .config_verify
= netdev_tunnel_verify
,
782 const NetDevVTable vti_vtable
= {
783 .object_size
= sizeof(Tunnel
),
785 .sections
= "Match\0NetDev\0Tunnel\0",
786 .fill_message_create
= netdev_vti_fill_message_create
,
787 .create_type
= NETDEV_CREATE_STACKED
,
788 .config_verify
= netdev_tunnel_verify
,
791 const NetDevVTable vti6_vtable
= {
792 .object_size
= sizeof(Tunnel
),
794 .sections
= "Match\0NetDev\0Tunnel\0",
795 .fill_message_create
= netdev_vti_fill_message_create
,
796 .create_type
= NETDEV_CREATE_STACKED
,
797 .config_verify
= netdev_tunnel_verify
,
800 const NetDevVTable gre_vtable
= {
801 .object_size
= sizeof(Tunnel
),
803 .sections
= "Match\0NetDev\0Tunnel\0",
804 .fill_message_create
= netdev_gre_fill_message_create
,
805 .create_type
= NETDEV_CREATE_STACKED
,
806 .config_verify
= netdev_tunnel_verify
,
809 const NetDevVTable gretap_vtable
= {
810 .object_size
= sizeof(Tunnel
),
812 .sections
= "Match\0NetDev\0Tunnel\0",
813 .fill_message_create
= netdev_gre_fill_message_create
,
814 .create_type
= NETDEV_CREATE_STACKED
,
815 .config_verify
= netdev_tunnel_verify
,
818 const NetDevVTable ip6gre_vtable
= {
819 .object_size
= sizeof(Tunnel
),
821 .sections
= "Match\0NetDev\0Tunnel\0",
822 .fill_message_create
= netdev_ip6gre_fill_message_create
,
823 .create_type
= NETDEV_CREATE_STACKED
,
824 .config_verify
= netdev_tunnel_verify
,
827 const NetDevVTable ip6gretap_vtable
= {
828 .object_size
= sizeof(Tunnel
),
830 .sections
= "Match\0NetDev\0Tunnel\0",
831 .fill_message_create
= netdev_ip6gre_fill_message_create
,
832 .create_type
= NETDEV_CREATE_STACKED
,
833 .config_verify
= netdev_tunnel_verify
,
836 const NetDevVTable ip6tnl_vtable
= {
837 .object_size
= sizeof(Tunnel
),
839 .sections
= "Match\0NetDev\0Tunnel\0",
840 .fill_message_create
= netdev_ip6tnl_fill_message_create
,
841 .create_type
= NETDEV_CREATE_STACKED
,
842 .config_verify
= netdev_tunnel_verify
,
845 const NetDevVTable erspan_vtable
= {
846 .object_size
= sizeof(Tunnel
),
848 .sections
= "Match\0NetDev\0Tunnel\0",
849 .fill_message_create
= netdev_erspan_fill_message_create
,
850 .create_type
= NETDEV_CREATE_INDEPENDENT
,
851 .config_verify
= netdev_tunnel_verify
,