]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev-tunnel.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / network / networkd-netdev-tunnel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Susant Sahani
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <arpa/inet.h>
23 #include <net/if.h>
24 #include <linux/ip.h>
25 #include <linux/if_tunnel.h>
26 #include <linux/ip6_tunnel.h>
27
28 #include "sd-netlink.h"
29
30 #include "conf-parser.h"
31 #include "missing.h"
32 #include "networkd-link.h"
33 #include "string-util.h"
34 #include "util.h"
35 #include "networkd-netdev-tunnel.h"
36
37 #define DEFAULT_TNL_HOP_LIMIT 64
38 #define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
39
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",
44 };
45
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");
48
49 static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
50 Tunnel *t = IPIP(netdev);
51 int r;
52
53 assert(netdev);
54 assert(link);
55 assert(m);
56 assert(t);
57 assert(t->family == AF_INET);
58
59 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
60 if (r < 0)
61 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
62
63 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
64 if (r < 0)
65 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
66
67 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
68 if (r < 0)
69 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
70
71 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
72 if (r < 0)
73 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
74
75 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
76 if (r < 0)
77 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
78
79 return r;
80 }
81
82 static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
83 Tunnel *t = SIT(netdev);
84 int r;
85
86 assert(netdev);
87 assert(link);
88 assert(m);
89 assert(t);
90 assert(t->family == AF_INET);
91
92 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
93 if (r < 0)
94 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
95
96 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
97 if (r < 0)
98 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
99
100 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
101 if (r < 0)
102 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
103
104 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
105 if (r < 0)
106 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
107
108 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
109 if (r < 0)
110 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
111
112 return r;
113 }
114
115 static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
116 Tunnel *t;
117 int r;
118
119 assert(netdev);
120
121 if (netdev->kind == NETDEV_KIND_GRE)
122 t = GRE(netdev);
123 else
124 t = GRETAP(netdev);
125
126 assert(t);
127 assert(t->family == AF_INET);
128 assert(link);
129 assert(m);
130
131 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
132 if (r < 0)
133 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
134
135 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
136 if (r < 0)
137 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
138
139 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
140 if (r < 0)
141 log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
142
143 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
144 if (r < 0)
145 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
146
147 r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
148 if (r < 0)
149 log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
150
151 r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
152 if (r < 0)
153 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
154
155 return r;
156 }
157
158 static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
159 Tunnel *t;
160 int r;
161
162 assert(netdev);
163
164 if (netdev->kind == NETDEV_KIND_IP6GRE)
165 t = IP6GRE(netdev);
166 else
167 t = IP6GRETAP(netdev);
168
169 assert(t);
170 assert(t->family == AF_INET6);
171 assert(link);
172 assert(m);
173
174 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
175 if (r < 0)
176 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
177
178 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
179 if (r < 0)
180 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
181
182 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
183 if (r < 0)
184 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
185
186 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
187 if (r < 0)
188 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
189
190 if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
191 r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel);
192 if (r < 0)
193 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
194 }
195
196 r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags);
197 if (r < 0)
198 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLAGS attribute: %m");
199
200 return r;
201 }
202
203 static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
204 Tunnel *t = VTI(netdev);
205 int r;
206
207 assert(netdev);
208 assert(link);
209 assert(m);
210 assert(t);
211 assert(t->family == AF_INET);
212
213 r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
214 if (r < 0)
215 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
216
217 r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
218 if (r < 0)
219 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
220
221 r = sd_netlink_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
222 if (r < 0)
223 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
224
225 return r;
226 }
227
228 static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
229 Tunnel *t = VTI6(netdev);
230 int r;
231
232 assert(netdev);
233 assert(link);
234 assert(m);
235 assert(t);
236 assert(t->family == AF_INET6);
237
238 r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
239 if (r < 0)
240 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
241
242 r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6);
243 if (r < 0)
244 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
245
246 r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_REMOTE, &t->remote.in6);
247 if (r < 0)
248 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
249
250 return r;
251 }
252
253 static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
254 Tunnel *t = IP6TNL(netdev);
255 uint8_t proto;
256 int r;
257
258 assert(netdev);
259 assert(link);
260 assert(m);
261 assert(t);
262 assert(t->family == AF_INET6);
263
264 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
265 if (r < 0)
266 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
267
268 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
269 if (r < 0)
270 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
271
272 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
273 if (r < 0)
274 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
275
276 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
277 if (r < 0)
278 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
279
280 if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
281 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel);
282 if (r < 0)
283 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
284 }
285
286 if (t->copy_dscp)
287 t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
288
289 if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) {
290 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit);
291 if (r < 0)
292 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
293 }
294
295 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
296 if (r < 0)
297 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
298
299 switch (t->ip6tnl_mode) {
300 case NETDEV_IP6_TNL_MODE_IP6IP6:
301 proto = IPPROTO_IPV6;
302 break;
303 case NETDEV_IP6_TNL_MODE_IPIP6:
304 proto = IPPROTO_IPIP;
305 break;
306 case NETDEV_IP6_TNL_MODE_ANYIP6:
307 default:
308 proto = 0;
309 break;
310 }
311
312 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
313 if (r < 0)
314 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_MODE attribute: %m");
315
316 return r;
317 }
318
319 static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
320 Tunnel *t = NULL;
321
322 assert(netdev);
323 assert(filename);
324
325 switch (netdev->kind) {
326 case NETDEV_KIND_IPIP:
327 t = IPIP(netdev);
328 break;
329 case NETDEV_KIND_SIT:
330 t = SIT(netdev);
331 break;
332 case NETDEV_KIND_GRE:
333 t = GRE(netdev);
334 break;
335 case NETDEV_KIND_GRETAP:
336 t = GRETAP(netdev);
337 break;
338 case NETDEV_KIND_IP6GRE:
339 t = IP6GRE(netdev);
340 break;
341 case NETDEV_KIND_IP6GRETAP:
342 t = IP6GRETAP(netdev);
343 break;
344 case NETDEV_KIND_VTI:
345 t = VTI(netdev);
346 break;
347 case NETDEV_KIND_VTI6:
348 t = VTI6(netdev);
349 break;
350 case NETDEV_KIND_IP6TNL:
351 t = IP6TNL(netdev);
352 break;
353 default:
354 assert_not_reached("Invalid tunnel kind");
355 }
356
357 assert(t);
358
359 if (t->remote.in.s_addr == INADDR_ANY) {
360 log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
361 return -EINVAL;
362 }
363
364 if (t->family != AF_INET && t->family != AF_INET6) {
365 log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
366 return -EINVAL;
367 }
368
369 if (netdev->kind == NETDEV_KIND_IP6TNL) {
370 if (t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) {
371 log_warning("IP6 Tunnel without mode configured in %s. Ignoring", filename);
372 return -EINVAL;
373 }
374 }
375
376 return 0;
377 }
378
379 int config_parse_tunnel_address(const char *unit,
380 const char *filename,
381 unsigned line,
382 const char *section,
383 unsigned section_line,
384 const char *lvalue,
385 int ltype,
386 const char *rvalue,
387 void *data,
388 void *userdata) {
389 Tunnel *t = userdata;
390 union in_addr_union *addr = data, buffer;
391 int r, f;
392
393 assert(filename);
394 assert(lvalue);
395 assert(rvalue);
396 assert(data);
397
398 r = in_addr_from_string_auto(rvalue, &f, &buffer);
399 if (r < 0) {
400 log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
401 return 0;
402 }
403
404 if (t->family != AF_UNSPEC && t->family != f) {
405 log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
406 return 0;
407 }
408
409 t->family = f;
410 *addr = buffer;
411
412 return 0;
413 }
414
415 int config_parse_ipv6_flowlabel(const char* unit,
416 const char *filename,
417 unsigned line,
418 const char *section,
419 unsigned section_line,
420 const char *lvalue,
421 int ltype,
422 const char *rvalue,
423 void *data,
424 void *userdata) {
425 IPv6FlowLabel *ipv6_flowlabel = data;
426 Tunnel *t = userdata;
427 int k = 0;
428 int r;
429
430 assert(filename);
431 assert(lvalue);
432 assert(rvalue);
433 assert(ipv6_flowlabel);
434
435 if (streq(rvalue, "inherit")) {
436 *ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
437 t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
438 } else {
439 r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata);
440 if (r < 0)
441 return r;
442
443 if (k > 0xFFFFF)
444 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
445 else {
446 *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL;
447 t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
448 }
449 }
450
451 return 0;
452 }
453
454 int config_parse_encap_limit(const char* unit,
455 const char *filename,
456 unsigned line,
457 const char *section,
458 unsigned section_line,
459 const char *lvalue,
460 int ltype,
461 const char *rvalue,
462 void *data,
463 void *userdata) {
464 Tunnel *t = userdata;
465 int k = 0;
466 int r;
467
468 assert(filename);
469 assert(lvalue);
470 assert(rvalue);
471
472 if (streq(rvalue, "none"))
473 t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
474 else {
475 r = safe_atoi(rvalue, &k);
476 if (r < 0) {
477 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
478 return 0;
479 }
480
481 if (k > 255 || k < 0)
482 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
483 else {
484 t->encap_limit = k;
485 t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
486 }
487 }
488
489 return 0;
490 }
491
492 static void ipip_init(NetDev *n) {
493 Tunnel *t = IPIP(n);
494
495 assert(n);
496 assert(t);
497
498 t->pmtudisc = true;
499 }
500
501 static void sit_init(NetDev *n) {
502 Tunnel *t = SIT(n);
503
504 assert(n);
505 assert(t);
506
507 t->pmtudisc = true;
508 }
509
510 static void vti_init(NetDev *n) {
511 Tunnel *t;
512
513 assert(n);
514
515 if (n->kind == NETDEV_KIND_VTI)
516 t = VTI(n);
517 else
518 t = VTI6(n);
519
520 assert(t);
521
522 t->pmtudisc = true;
523 }
524
525 static void gre_init(NetDev *n) {
526 Tunnel *t;
527
528 assert(n);
529
530 if (n->kind == NETDEV_KIND_GRE)
531 t = GRE(n);
532 else
533 t = GRETAP(n);
534
535 assert(t);
536
537 t->pmtudisc = true;
538 }
539
540 static void ip6gre_init(NetDev *n) {
541 Tunnel *t;
542
543 assert(n);
544
545 if (n->kind == NETDEV_KIND_IP6GRE)
546 t = IP6GRE(n);
547 else
548 t = IP6GRETAP(n);
549
550 assert(t);
551
552 t->ttl = DEFAULT_TNL_HOP_LIMIT;
553 }
554
555 static void ip6tnl_init(NetDev *n) {
556 Tunnel *t = IP6TNL(n);
557
558 assert(n);
559 assert(t);
560
561 t->ttl = DEFAULT_TNL_HOP_LIMIT;
562 t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
563 t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
564 t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
565 }
566
567 const NetDevVTable ipip_vtable = {
568 .object_size = sizeof(Tunnel),
569 .init = ipip_init,
570 .sections = "Match\0NetDev\0Tunnel\0",
571 .fill_message_create = netdev_ipip_fill_message_create,
572 .create_type = NETDEV_CREATE_STACKED,
573 .config_verify = netdev_tunnel_verify,
574 };
575
576 const NetDevVTable sit_vtable = {
577 .object_size = sizeof(Tunnel),
578 .init = sit_init,
579 .sections = "Match\0NetDev\0Tunnel\0",
580 .fill_message_create = netdev_sit_fill_message_create,
581 .create_type = NETDEV_CREATE_STACKED,
582 .config_verify = netdev_tunnel_verify,
583 };
584
585 const NetDevVTable vti_vtable = {
586 .object_size = sizeof(Tunnel),
587 .init = vti_init,
588 .sections = "Match\0NetDev\0Tunnel\0",
589 .fill_message_create = netdev_vti_fill_message_create,
590 .create_type = NETDEV_CREATE_STACKED,
591 .config_verify = netdev_tunnel_verify,
592 };
593
594 const NetDevVTable vti6_vtable = {
595 .object_size = sizeof(Tunnel),
596 .init = vti_init,
597 .sections = "Match\0NetDev\0Tunnel\0",
598 .fill_message_create = netdev_vti6_fill_message_create,
599 .create_type = NETDEV_CREATE_STACKED,
600 .config_verify = netdev_tunnel_verify,
601 };
602
603 const NetDevVTable gre_vtable = {
604 .object_size = sizeof(Tunnel),
605 .init = gre_init,
606 .sections = "Match\0NetDev\0Tunnel\0",
607 .fill_message_create = netdev_gre_fill_message_create,
608 .create_type = NETDEV_CREATE_STACKED,
609 .config_verify = netdev_tunnel_verify,
610 };
611
612 const NetDevVTable gretap_vtable = {
613 .object_size = sizeof(Tunnel),
614 .init = gre_init,
615 .sections = "Match\0NetDev\0Tunnel\0",
616 .fill_message_create = netdev_gre_fill_message_create,
617 .create_type = NETDEV_CREATE_STACKED,
618 .config_verify = netdev_tunnel_verify,
619 };
620
621 const NetDevVTable ip6gre_vtable = {
622 .object_size = sizeof(Tunnel),
623 .init = ip6gre_init,
624 .sections = "Match\0NetDev\0Tunnel\0",
625 .fill_message_create = netdev_ip6gre_fill_message_create,
626 .create_type = NETDEV_CREATE_STACKED,
627 .config_verify = netdev_tunnel_verify,
628 };
629
630 const NetDevVTable ip6gretap_vtable = {
631 .object_size = sizeof(Tunnel),
632 .init = ip6gre_init,
633 .sections = "Match\0NetDev\0Tunnel\0",
634 .fill_message_create = netdev_ip6gre_fill_message_create,
635 .create_type = NETDEV_CREATE_STACKED,
636 .config_verify = netdev_tunnel_verify,
637 };
638
639 const NetDevVTable ip6tnl_vtable = {
640 .object_size = sizeof(Tunnel),
641 .init = ip6tnl_init,
642 .sections = "Match\0NetDev\0Tunnel\0",
643 .fill_message_create = netdev_ip6tnl_fill_message_create,
644 .create_type = NETDEV_CREATE_STACKED,
645 .config_verify = netdev_tunnel_verify,
646 };