]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/tunnel.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / netdev / tunnel.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7951dea2 2
9aa5d8ba 3#include <netinet/in.h>
01234e1f 4#include <linux/fou.h>
9f0cf80d 5#include <linux/if_arp.h>
7951dea2 6#include <linux/if_tunnel.h>
9f0cf80d 7#include <linux/ip.h>
855ee1a1 8#include <linux/ip6_tunnel.h>
7951dea2 9
96d96ec4 10#include "af-list.h"
07630cea 11#include "conf-parser.h"
e49bad01 12#include "hexdecoct.h"
f5947a5e 13#include "missing_network.h"
3affe303 14#include "netlink-util.h"
e49bad01 15#include "networkd-manager.h"
6bedfcbb 16#include "parse-util.h"
e49bad01 17#include "siphash24.h"
8b43440b 18#include "string-table.h"
07630cea 19#include "string-util.h"
737f1405 20#include "tunnel.h"
7951dea2
SS
21#include "util.h"
22
a88f3913 23#define DEFAULT_IPV6_TTL 64
8e38570e 24#define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
3a4f3e42 25#define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
855ee1a1
SS
26
27static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
28 [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
73b23bea 29 [NETDEV_IP6_TNL_MODE_IPIP6] = "ipip6",
855ee1a1
SS
30 [NETDEV_IP6_TNL_MODE_ANYIP6] = "any",
31};
32
33DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
34DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
35
e49bad01
YW
36#define HASH_KEY SD_ID128_MAKE(74,c4,de,12,f3,d9,41,34,bb,3d,c1,a4,42,93,50,87)
37
38int dhcp4_pd_create_6rd_tunnel_name(Link *link, char **ret) {
39 _cleanup_free_ char *ifname_alloc = NULL;
40 uint8_t ipv4masklen, sixrd_prefixlen, *buf, *p;
41 struct in_addr ipv4address;
42 struct in6_addr sixrd_prefix;
43 char ifname[IFNAMSIZ];
44 uint64_t result;
45 size_t sz;
46 int r;
47
48 assert(link);
49 assert(link->dhcp_lease);
50
51 r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address);
52 if (r < 0)
53 return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m");
54
55 r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL);
56 if (r < 0)
57 return log_link_debug_errno(link, r, "Failed to get 6rd option: %m");
58
59 sz = sizeof(uint8_t) * 2 + sizeof(struct in6_addr) + sizeof(struct in_addr);
60 buf = newa(uint8_t, sz);
61 p = buf;
62 p = mempcpy(p, &ipv4masklen, sizeof(uint8_t));
63 p = mempcpy(p, &ipv4address, sizeof(struct in_addr));
64 p = mempcpy(p, &sixrd_prefixlen, sizeof(uint8_t));
65 p = mempcpy(p, &sixrd_prefix, sizeof(struct in6_addr));
66
67 result = siphash24(buf, sz, HASH_KEY.bytes);
68 memcpy(ifname, "6rd-", STRLEN("6rd-"));
69 ifname[STRLEN("6rd-") ] = urlsafe_base64char(result >> 54);
70 ifname[STRLEN("6rd-") + 1] = urlsafe_base64char(result >> 48);
71 ifname[STRLEN("6rd-") + 2] = urlsafe_base64char(result >> 42);
72 ifname[STRLEN("6rd-") + 3] = urlsafe_base64char(result >> 36);
73 ifname[STRLEN("6rd-") + 4] = urlsafe_base64char(result >> 30);
74 ifname[STRLEN("6rd-") + 5] = urlsafe_base64char(result >> 24);
75 ifname[STRLEN("6rd-") + 6] = urlsafe_base64char(result >> 18);
76 ifname[STRLEN("6rd-") + 7] = urlsafe_base64char(result >> 12);
77 ifname[STRLEN("6rd-") + 8] = urlsafe_base64char(result >> 6);
78 ifname[STRLEN("6rd-") + 9] = urlsafe_base64char(result);
79 ifname[STRLEN("6rd-") + 10] = '\0';
80 assert_cc(STRLEN("6rd-") + 10 <= IFNAMSIZ);
81
82 ifname_alloc = strdup(ifname);
83 if (!ifname_alloc)
84 return log_oom_debug();
85
86 *ret = TAKE_PTR(ifname_alloc);
87 return 0;
88}
89
f2b78e0e
ZJS
90static int dhcp4_pd_create_6rd_tunnel_message(
91 Link *link,
92 sd_netlink_message *m,
93 const struct in_addr *ipv4address,
94 uint8_t ipv4masklen,
95 const struct in6_addr *sixrd_prefix,
96 uint8_t sixrd_prefixlen) {
e49bad01
YW
97 int r;
98
e49bad01
YW
99 r = sd_netlink_message_append_string(m, IFLA_IFNAME, link->dhcp4_6rd_tunnel_name);
100 if (r < 0)
f2b78e0e 101 return r;
e49bad01
YW
102
103 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
104 if (r < 0)
f2b78e0e 105 return r;
e49bad01
YW
106
107 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "sit");
108 if (r < 0)
f2b78e0e 109 return r;
e49bad01 110
f2b78e0e 111 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, ipv4address);
e49bad01 112 if (r < 0)
f2b78e0e 113 return r;
e49bad01
YW
114
115 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, 64);
116 if (r < 0)
f2b78e0e 117 return r;
e49bad01 118
f2b78e0e 119 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, sixrd_prefix);
e49bad01 120 if (r < 0)
f2b78e0e 121 return r;
e49bad01
YW
122
123 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, sixrd_prefixlen);
124 if (r < 0)
f2b78e0e 125 return r;
e49bad01 126
f2b78e0e 127 struct in_addr relay_prefix = *ipv4address;
e49bad01
YW
128 (void) in4_addr_mask(&relay_prefix, ipv4masklen);
129 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_6RD_RELAY_PREFIX, relay_prefix.s_addr);
130 if (r < 0)
f2b78e0e 131 return r;
e49bad01
YW
132
133 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, ipv4masklen);
134 if (r < 0)
f2b78e0e 135 return r;
e49bad01
YW
136
137 r = sd_netlink_message_close_container(m);
138 if (r < 0)
f2b78e0e 139 return r;
e49bad01
YW
140
141 r = sd_netlink_message_close_container(m);
142 if (r < 0)
f2b78e0e
ZJS
143 return r;
144
145 return 0;
146}
147
148int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callback) {
149 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
150 uint8_t ipv4masklen, sixrd_prefixlen;
151 struct in_addr ipv4address;
152 struct in6_addr sixrd_prefix;
153 int r;
154
155 assert(link);
156 assert(link->ifindex > 0);
157 assert(link->manager);
158 assert(link->dhcp_lease);
159 assert(link->dhcp4_6rd_tunnel_name);
160 assert(callback);
161
162 r = sd_dhcp_lease_get_address(link->dhcp_lease, &ipv4address);
163 if (r < 0)
164 return log_link_debug_errno(link, r, "Failed to get DHCPv4 address: %m");
165
166 r = sd_dhcp_lease_get_6rd(link->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, NULL, NULL);
167 if (r < 0)
168 return log_link_debug_errno(link, r, "Failed to get 6rd option: %m");
169
170 r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, 0);
171 if (r < 0)
172 return log_link_debug_errno(link, r, "Failed to create netlink message: %m");
173
174 r = dhcp4_pd_create_6rd_tunnel_message(link, m,
175 &ipv4address, ipv4masklen,
176 &sixrd_prefix, sixrd_prefixlen);
177 if (r < 0)
178 return log_link_debug_errno(link, r, "Failed to fill netlink message: %m");
e49bad01
YW
179
180 r = netlink_call_async(link->manager->rtnl, NULL, m, callback,
181 link_netlink_destroy_callback, link);
182 if (r < 0)
f2b78e0e 183 return log_link_debug_errno(link, r, "Could not send netlink message: %m");
e49bad01
YW
184
185 link_ref(link);
186
187 return 0;
188}
189
2be25d75
YW
190static int tunnel_get_local_address(Tunnel *t, Link *link, union in_addr_union *ret) {
191 assert(t);
192
193 if (t->local_type < 0) {
194 if (ret)
195 *ret = t->local;
196 return 0;
197 }
198
199 return link_get_local_address(link, t->local_type, t->family, NULL, ret);
200}
201
9e64c1f8 202static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
2be25d75 203 union in_addr_union local;
9e64c1f8 204 Tunnel *t;
7951dea2
SS
205 int r;
206
3be1d7e0 207 assert(netdev);
fbe0139f 208 assert(m);
9e64c1f8
YW
209
210 if (netdev->kind == NETDEV_KIND_IPIP)
211 t = IPIP(netdev);
212 else
213 t = SIT(netdev);
214
aa9f1140 215 assert(t);
7951dea2 216
1ae308ab
YW
217 if (t->external) {
218 r = sd_netlink_message_append_flag(m, IFLA_IPTUN_COLLECT_METADATA);
219 if (r < 0)
220 return r;
221
222 /* If external mode is enabled, then the following settings should not be appended. */
223 return 0;
224 }
225
8c9c703c
YW
226 if (link || t->assign_to_loopback) {
227 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
4d7fa6de 228 if (r < 0)
5b80ecea 229 return r;
4d7fa6de 230 }
7951dea2 231
2be25d75
YW
232 r = tunnel_get_local_address(t, link, &local);
233 if (r < 0)
234 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
235
236 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &local.in);
5289f3ff 237 if (r < 0)
5b80ecea 238 return r;
7951dea2 239
1c4baffc 240 r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
5289f3ff 241 if (r < 0)
5b80ecea 242 return r;
7951dea2 243
1c4baffc 244 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
5289f3ff 245 if (r < 0)
5b80ecea 246 return r;
9ae70211 247
1c4baffc 248 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
5289f3ff 249 if (r < 0)
5b80ecea 250 return r;
9243e967 251
4799d932 252 if (t->fou_tunnel) {
53cb501a
SS
253 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_TYPE, t->fou_encap_type);
254 if (r < 0)
5b80ecea 255 return r;
53cb501a
SS
256
257 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_SPORT, htobe16(t->encap_src_port));
258 if (r < 0)
5b80ecea 259 return r;
53cb501a
SS
260
261 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_DPORT, htobe16(t->fou_destination_port));
262 if (r < 0)
5b80ecea 263 return r;
53cb501a
SS
264 }
265
9e64c1f8
YW
266 if (netdev->kind == NETDEV_KIND_SIT) {
267 if (t->sixrd_prefixlen > 0) {
268 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix);
269 if (r < 0)
5b80ecea 270 return r;
9e64c1f8
YW
271
272 /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
273 * expecting to receive the prefixlen as a u16.
274 */
275 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, t->sixrd_prefixlen);
276 if (r < 0)
5b80ecea 277 return r;
9e64c1f8 278 }
d067cab3 279
9e64c1f8
YW
280 if (t->isatap >= 0) {
281 uint16_t flags = 0;
918049ad 282
9e64c1f8 283 SET_FLAG(flags, SIT_ISATAP, t->isatap);
918049ad 284
9e64c1f8
YW
285 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags);
286 if (r < 0)
5b80ecea 287 return r;
9e64c1f8 288 }
918049ad
SS
289 }
290
5b80ecea 291 return 0;
abf446af
SS
292}
293
a8b9a65c 294static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
2be25d75 295 union in_addr_union local;
a8b9a65c
YW
296 uint32_t ikey = 0;
297 uint32_t okey = 0;
298 uint16_t iflags = 0;
299 uint16_t oflags = 0;
1af2536a 300 Tunnel *t;
8bb088c5
SS
301 int r;
302
3be1d7e0 303 assert(netdev);
a8b9a65c 304 assert(m);
1af2536a 305
a8b9a65c
YW
306 switch (netdev->kind) {
307 case NETDEV_KIND_GRE:
5289f3ff 308 t = GRE(netdev);
a8b9a65c
YW
309 break;
310 case NETDEV_KIND_ERSPAN:
311 t = ERSPAN(netdev);
312 break;
313 case NETDEV_KIND_GRETAP:
5289f3ff 314 t = GRETAP(netdev);
a8b9a65c
YW
315 break;
316 default:
04499a70 317 assert_not_reached();
a8b9a65c 318 }
1af2536a 319
aa9f1140 320 assert(t);
8bb088c5 321
1ae308ab
YW
322 if (t->external) {
323 r = sd_netlink_message_append_flag(m, IFLA_GRE_COLLECT_METADATA);
324 if (r < 0)
325 return r;
326
327 /* If external mode is enabled, then the following settings should not be appended. */
328 return 0;
329 }
330
8c9c703c
YW
331 if (link || t->assign_to_loopback) {
332 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
4d7fa6de 333 if (r < 0)
5b80ecea 334 return r;
4d7fa6de 335 }
8bb088c5 336
a8b9a65c 337 if (netdev->kind == NETDEV_KIND_ERSPAN) {
98406eda 338 r = sd_netlink_message_append_u8(m, IFLA_GRE_ERSPAN_VER, t->erspan_version);
a8b9a65c 339 if (r < 0)
5b80ecea 340 return r;
98406eda
YW
341
342 if (t->erspan_version == 1) {
343 r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
344 if (r < 0)
345 return r;
346
347 } else if (t->erspan_version == 2) {
348 r = sd_netlink_message_append_u8(m, IFLA_GRE_ERSPAN_DIR, t->erspan_direction);
349 if (r < 0)
350 return r;
351
352 r = sd_netlink_message_append_u16(m, IFLA_GRE_ERSPAN_HWID, t->erspan_hwid);
353 if (r < 0)
354 return r;
355 }
a8b9a65c
YW
356 }
357
2be25d75
YW
358 r = tunnel_get_local_address(t, link, &local);
359 if (r < 0)
360 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
361
362 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &local.in);
5289f3ff 363 if (r < 0)
5b80ecea 364 return r;
8bb088c5 365
1c4baffc 366 r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
5289f3ff 367 if (r < 0)
5b80ecea 368 return r;
8bb088c5 369
1c4baffc 370 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
5289f3ff 371 if (r < 0)
5b80ecea 372 return r;
8bb088c5 373
1c4baffc 374 r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
5289f3ff 375 if (r < 0)
5b80ecea 376 return r;
8bb088c5 377
1c4baffc 378 r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
5289f3ff 379 if (r < 0)
5b80ecea 380 return r;
9243e967 381
2266864b
SS
382 if (t->key != 0) {
383 ikey = okey = htobe32(t->key);
384 iflags |= GRE_KEY;
385 oflags |= GRE_KEY;
386 }
387
388 if (t->ikey != 0) {
389 ikey = htobe32(t->ikey);
390 iflags |= GRE_KEY;
391 }
392
393 if (t->okey != 0) {
394 okey = htobe32(t->okey);
395 oflags |= GRE_KEY;
396 }
397
a8b9a65c 398 if (t->gre_erspan_sequence > 0) {
2266864b
SS
399 iflags |= GRE_SEQ;
400 oflags |= GRE_SEQ;
a8b9a65c 401 } else if (t->gre_erspan_sequence == 0) {
2266864b
SS
402 iflags &= ~GRE_SEQ;
403 oflags &= ~GRE_SEQ;
404 }
405
406 r = sd_netlink_message_append_u32(m, IFLA_GRE_IKEY, ikey);
407 if (r < 0)
5b80ecea 408 return r;
2266864b
SS
409
410 r = sd_netlink_message_append_u32(m, IFLA_GRE_OKEY, okey);
411 if (r < 0)
5b80ecea 412 return r;
2266864b
SS
413
414 r = sd_netlink_message_append_u16(m, IFLA_GRE_IFLAGS, iflags);
415 if (r < 0)
5b80ecea 416 return r;
2266864b
SS
417
418 r = sd_netlink_message_append_u16(m, IFLA_GRE_OFLAGS, oflags);
419 if (r < 0)
5b80ecea 420 return r;
2266864b 421
4799d932
YW
422 if (t->fou_tunnel) {
423 r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_TYPE, t->fou_encap_type);
424 if (r < 0)
5b80ecea 425 return r;
4799d932
YW
426
427 r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_SPORT, htobe16(t->encap_src_port));
428 if (r < 0)
5b80ecea 429 return r;
4799d932
YW
430
431 r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_DPORT, htobe16(t->fou_destination_port));
432 if (r < 0)
5b80ecea 433 return r;
4799d932
YW
434 }
435
5b80ecea 436 return 0;
2266864b
SS
437}
438
1c4baffc 439static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
2be25d75 440 union in_addr_union local;
6ba0e7c8 441 uint32_t ikey = 0;
442 uint32_t okey = 0;
443 uint16_t iflags = 0;
444 uint16_t oflags = 0;
b16492f8
SS
445 Tunnel *t;
446 int r;
447
448 assert(netdev);
fbe0139f 449 assert(m);
b16492f8
SS
450
451 if (netdev->kind == NETDEV_KIND_IP6GRE)
5289f3ff 452 t = IP6GRE(netdev);
b16492f8 453 else
5289f3ff 454 t = IP6GRETAP(netdev);
b16492f8
SS
455
456 assert(t);
b16492f8 457
1ae308ab
YW
458 if (t->external) {
459 r = sd_netlink_message_append_flag(m, IFLA_GRE_COLLECT_METADATA);
460 if (r < 0)
461 return r;
462
463 /* If external mode is enabled, then the following settings should not be appended. */
464 return 0;
465 }
466
8c9c703c
YW
467 if (link || t->assign_to_loopback) {
468 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
4d7fa6de 469 if (r < 0)
5b80ecea 470 return r;
4d7fa6de 471 }
b16492f8 472
2be25d75
YW
473 r = tunnel_get_local_address(t, link, &local);
474 if (r < 0)
475 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
476
477 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &local.in6);
5289f3ff 478 if (r < 0)
5b80ecea 479 return r;
b16492f8 480
1c4baffc 481 r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
5289f3ff 482 if (r < 0)
5b80ecea 483 return r;
b16492f8 484
1c4baffc 485 r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
5289f3ff 486 if (r < 0)
5b80ecea 487 return r;
b16492f8 488
54a9d20c
SS
489 if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
490 r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel);
491 if (r < 0)
5b80ecea 492 return r;
54a9d20c
SS
493 }
494
495 r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags);
496 if (r < 0)
5b80ecea 497 return r;
54a9d20c 498
6ba0e7c8 499 if (t->key != 0) {
500 ikey = okey = htobe32(t->key);
501 iflags |= GRE_KEY;
502 oflags |= GRE_KEY;
503 }
504
505 if (t->ikey != 0) {
506 ikey = htobe32(t->ikey);
507 iflags |= GRE_KEY;
508 }
509
510 if (t->okey != 0) {
511 okey = htobe32(t->okey);
512 oflags |= GRE_KEY;
513 }
514
515 r = sd_netlink_message_append_u32(m, IFLA_GRE_IKEY, ikey);
516 if (r < 0)
5b80ecea 517 return r;
6ba0e7c8 518
519 r = sd_netlink_message_append_u32(m, IFLA_GRE_OKEY, okey);
520 if (r < 0)
5b80ecea 521 return r;
6ba0e7c8 522
523 r = sd_netlink_message_append_u16(m, IFLA_GRE_IFLAGS, iflags);
524 if (r < 0)
5b80ecea 525 return r;
6ba0e7c8 526
527 r = sd_netlink_message_append_u16(m, IFLA_GRE_OFLAGS, oflags);
528 if (r < 0)
5b80ecea 529 return r;
6ba0e7c8 530
5b80ecea 531 return 0;
b16492f8
SS
532}
533
3affe303 534static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
2be25d75 535 union in_addr_union local;
1d710029 536 uint32_t ikey, okey;
59f62519 537 Tunnel *t;
1d710029
SS
538 int r;
539
3affe303 540 assert(netdev);
1d710029 541 assert(m);
59f62519
SS
542
543 if (netdev->kind == NETDEV_KIND_VTI)
544 t = VTI(netdev);
545 else
546 t = VTI6(netdev);
547
1d710029 548 assert(t);
3affe303 549
8c9c703c
YW
550 if (link || t->assign_to_loopback) {
551 r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
3affe303 552 if (r < 0)
5b80ecea 553 return r;
3affe303 554 }
1d710029
SS
555
556 if (t->key != 0)
557 ikey = okey = htobe32(t->key);
558 else {
559 ikey = htobe32(t->ikey);
560 okey = htobe32(t->okey);
561 }
562
563 r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey);
564 if (r < 0)
5b80ecea 565 return r;
1d710029
SS
566
567 r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey);
568 if (r < 0)
5b80ecea 569 return r;
1d710029 570
2be25d75
YW
571 r = tunnel_get_local_address(t, link, &local);
572 if (r < 0)
573 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
574
575 r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &local);
9011ce77 576 if (r < 0)
5b80ecea 577 return r;
9011ce77 578
3affe303 579 r = netlink_message_append_in_addr_union(m, IFLA_VTI_REMOTE, t->family, &t->remote);
9011ce77 580 if (r < 0)
5b80ecea 581 return r;
9011ce77 582
5b80ecea 583 return 0;
9011ce77
SS
584}
585
1c4baffc 586static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
2be25d75 587 union in_addr_union local;
855ee1a1 588 uint8_t proto;
fbe0139f 589 Tunnel *t;
855ee1a1
SS
590 int r;
591
592 assert(netdev);
855ee1a1 593 assert(m);
fbe0139f
YW
594
595 t = IP6TNL(netdev);
596
855ee1a1 597 assert(t);
855ee1a1 598
1ae308ab
YW
599 switch (t->ip6tnl_mode) {
600 case NETDEV_IP6_TNL_MODE_IP6IP6:
601 proto = IPPROTO_IPV6;
602 break;
603 case NETDEV_IP6_TNL_MODE_IPIP6:
604 proto = IPPROTO_IPIP;
605 break;
606 case NETDEV_IP6_TNL_MODE_ANYIP6:
607 default:
608 proto = 0;
609 break;
610 }
611
612 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
613 if (r < 0)
614 return r;
615
616 if (t->external) {
617 r = sd_netlink_message_append_flag(m, IFLA_IPTUN_COLLECT_METADATA);
618 if (r < 0)
619 return r;
620
621 /* If external mode is enabled, then the following settings should not be appended. */
622 return 0;
623 }
624
8c9c703c
YW
625 if (link || t->assign_to_loopback) {
626 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
4d7fa6de 627 if (r < 0)
5b80ecea 628 return r;
4d7fa6de 629 }
855ee1a1 630
2be25d75
YW
631 r = tunnel_get_local_address(t, link, &local);
632 if (r < 0)
633 return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
634
635 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &local.in6);
5289f3ff 636 if (r < 0)
5b80ecea 637 return r;
855ee1a1 638
1c4baffc 639 r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
5289f3ff 640 if (r < 0)
5b80ecea 641 return r;
855ee1a1 642
1c4baffc 643 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
5289f3ff 644 if (r < 0)
5b80ecea 645 return r;
855ee1a1 646
407af9dd
SS
647 if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
648 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel);
649 if (r < 0)
5b80ecea 650 return r;
407af9dd
SS
651 }
652
a9b70f9d 653 if (t->copy_dscp)
ec2a3e3a
SS
654 t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
655
3f7cc080 656 if (t->allow_localremote >= 0)
3a4f3e42
SS
657 SET_FLAG(t->flags, IP6_TNL_F_ALLOW_LOCAL_REMOTE, t->allow_localremote);
658
acd8abb7
YW
659 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
660 if (r < 0)
661 return r;
662
6b1ed5e7 663 if (t->encap_limit != 0) {
b4828886
SS
664 r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit);
665 if (r < 0)
5b80ecea 666 return r;
b4828886
SS
667 }
668
5b80ecea 669 return 0;
855ee1a1
SS
670}
671
2be25d75
YW
672static int netdev_tunnel_is_ready_to_create(NetDev *netdev, Link *link) {
673 Tunnel *t;
674
675 assert(netdev);
2be25d75
YW
676
677 t = TUNNEL(netdev);
678
679 assert(t);
680
5d4a925a
YW
681 if (t->independent)
682 return true;
683
2be25d75
YW
684 return tunnel_get_local_address(t, link, NULL) >= 0;
685}
686
3be1d7e0 687static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
fbe0139f 688 Tunnel *t;
aa9f1140 689
7951dea2 690 assert(netdev);
3be1d7e0 691 assert(filename);
7951dea2 692
fbe0139f 693 t = TUNNEL(netdev);
aa9f1140
TG
694
695 assert(t);
696
1ae308ab
YW
697 if (netdev->kind == NETDEV_KIND_IP6TNL &&
698 t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID)
699 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
700 "ip6tnl without mode configured in %s. Ignoring", filename);
701
702 if (t->external) {
703 if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_VTI6))
704 log_netdev_debug(netdev, "vti/vti6 tunnel do not support external mode, ignoring.");
705 else {
706 /* tunnel with external mode does not require underlying interface. */
707 t->independent = true;
708
709 /* tunnel with external mode does not require any settings checked below. */
710 return 0;
711 }
712 }
713
dfc33655
YW
714 if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE) &&
715 !IN_SET(t->family, AF_UNSPEC, AF_INET))
716 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
717 "vti/ipip/sit/gre tunnel without a local/remote IPv4 address configured in %s. Ignoring", filename);
bb9683e0
YW
718
719 if (IN_SET(netdev->kind, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) &&
94876904 720 (t->family != AF_INET || !in_addr_is_set(t->family, &t->remote)))
bb9683e0
YW
721 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
722 "gretap/erspan tunnel without a remote IPv4 address configured in %s. Ignoring", filename);
6f3d4dec 723
dfc33655
YW
724 if ((IN_SET(netdev->kind, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL) && t->family != AF_INET6) ||
725 (netdev->kind == NETDEV_KIND_IP6GRE && !IN_SET(t->family, AF_UNSPEC, AF_INET6)))
726 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
727 "vti6/ip6tnl/ip6gre tunnel without a local/remote IPv6 address configured in %s. Ignoring", filename);
bb9683e0
YW
728
729 if (netdev->kind == NETDEV_KIND_IP6GRETAP &&
94876904 730 (t->family != AF_INET6 || !in_addr_is_set(t->family, &t->remote)))
bd930cbd 731 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
bb9683e0 732 "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename);
6f3d4dec 733
bd930cbd
YW
734 if (t->fou_tunnel && t->fou_destination_port <= 0)
735 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
736 "FooOverUDP missing port configured in %s. Ignoring", filename);
53cb501a 737
dfc33655
YW
738 /* netlink_message_append_in_addr_union() is used for vti/vti6. So, t->family cannot be AF_UNSPEC. */
739 if (netdev->kind == NETDEV_KIND_VTI)
740 t->family = AF_INET;
741
9e291330
YW
742 if (t->assign_to_loopback)
743 t->independent = true;
744
2be25d75
YW
745 if (t->independent && t->local_type >= 0)
746 return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
747 "The local address cannot be '%s' when Independent= or AssignToLoopback= is enabled, ignoring.",
748 strna(netdev_local_address_type_to_string(t->local_type)));
749
7951dea2
SS
750 return 0;
751}
6ef892fc 752
96d96ec4
YW
753static int unset_local(Tunnel *t) {
754 assert(t);
755
756 /* Unset the previous assignment. */
757 t->local = IN_ADDR_NULL;
758 t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
759
760 /* If the remote address is not specified, also clear the address family. */
761 if (!in_addr_is_set(t->family, &t->remote))
762 t->family = AF_UNSPEC;
763
764 return 0;
765}
766
2be25d75 767int config_parse_tunnel_local_address(
63481576
YW
768 const char *unit,
769 const char *filename,
770 unsigned line,
771 const char *section,
772 unsigned section_line,
773 const char *lvalue,
774 int ltype,
775 const char *rvalue,
776 void *data,
777 void *userdata) {
778
2be25d75
YW
779 union in_addr_union buffer = IN_ADDR_NULL;
780 NetDevLocalAddressType type;
99534007 781 Tunnel *t = ASSERT_PTR(userdata);
44e7b949 782 int r, f;
6ef892fc
TG
783
784 assert(filename);
785 assert(lvalue);
786 assert(rvalue);
2be25d75 787
96d96ec4
YW
788 if (isempty(rvalue) || streq(rvalue, "any"))
789 return unset_local(t);
2be25d75
YW
790
791 type = netdev_local_address_type_from_string(rvalue);
792 if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV4LL, NETDEV_LOCAL_ADDRESS_DHCP4))
793 f = AF_INET;
794 else if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV6LL, NETDEV_LOCAL_ADDRESS_DHCP6, NETDEV_LOCAL_ADDRESS_SLAAC))
795 f = AF_INET6;
796 else {
797 type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
798 r = in_addr_from_string_auto(rvalue, &f, &buffer);
799 if (r < 0) {
800 log_syntax(unit, LOG_WARNING, filename, line, r,
801 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue);
802 return 0;
803 }
96d96ec4
YW
804
805 if (in_addr_is_null(f, &buffer))
806 return unset_local(t);
2be25d75
YW
807 }
808
809 if (t->family != AF_UNSPEC && t->family != f) {
810 log_syntax(unit, LOG_WARNING, filename, line, 0,
811 "Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
812 return 0;
813 }
6ef892fc 814
2be25d75
YW
815 t->family = f;
816 t->local = buffer;
817 t->local_type = type;
818 return 0;
819}
820
96d96ec4
YW
821static int unset_remote(Tunnel *t) {
822 assert(t);
823
824 /* Unset the previous assignment. */
825 t->remote = IN_ADDR_NULL;
826
827 /* If the local address is not specified, also clear the address family. */
828 if (t->local_type == _NETDEV_LOCAL_ADDRESS_TYPE_INVALID &&
829 !in_addr_is_set(t->family, &t->local))
830 t->family = AF_UNSPEC;
831
832 return 0;
833}
834
2be25d75
YW
835int config_parse_tunnel_remote_address(
836 const char *unit,
837 const char *filename,
838 unsigned line,
839 const char *section,
840 unsigned section_line,
841 const char *lvalue,
842 int ltype,
843 const char *rvalue,
844 void *data,
845 void *userdata) {
846
847 union in_addr_union buffer;
99534007 848 Tunnel *t = ASSERT_PTR(userdata);
2be25d75
YW
849 int r, f;
850
851 assert(filename);
852 assert(lvalue);
853 assert(rvalue);
6e47dbbc 854
96d96ec4
YW
855 if (isempty(rvalue) || streq(rvalue, "any"))
856 return unset_remote(t);
6ef892fc 857
6e47dbbc
ZJS
858 r = in_addr_from_string_auto(rvalue, &f, &buffer);
859 if (r < 0) {
d96edb2c 860 log_syntax(unit, LOG_WARNING, filename, line, r,
6e47dbbc
ZJS
861 "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue);
862 return 0;
863 }
efd3c897 864
96d96ec4
YW
865 if (in_addr_is_null(f, &buffer))
866 return unset_remote(t);
867
6e47dbbc 868 if (t->family != AF_UNSPEC && t->family != f) {
d96edb2c 869 log_syntax(unit, LOG_WARNING, filename, line, 0,
2be25d75 870 "Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
6e47dbbc 871 return 0;
44e7b949
LP
872 }
873
874 t->family = f;
2be25d75 875 t->remote = buffer;
6ef892fc
TG
876 return 0;
877}
3be1d7e0 878
63481576
YW
879int config_parse_tunnel_key(
880 const char *unit,
881 const char *filename,
882 unsigned line,
883 const char *section,
884 unsigned section_line,
885 const char *lvalue,
886 int ltype,
887 const char *rvalue,
888 void *data,
889 void *userdata) {
890
396dfe0a 891 uint32_t *dest = ASSERT_PTR(data), k;
1d710029 892 union in_addr_union buffer;
1d710029
SS
893 int r;
894
895 assert(filename);
1d710029 896 assert(rvalue);
1d710029
SS
897
898 r = in_addr_from_string(AF_INET, rvalue, &buffer);
899 if (r < 0) {
900 r = safe_atou32(rvalue, &k);
901 if (r < 0) {
b98680b2
YW
902 log_syntax(unit, LOG_WARNING, filename, line, r,
903 "Failed to parse tunnel key ignoring assignment: %s", rvalue);
1d710029
SS
904 return 0;
905 }
906 } else
907 k = be32toh(buffer.in.s_addr);
908
396dfe0a 909 *dest = k;
1d710029
SS
910 return 0;
911}
912
63481576
YW
913int config_parse_ipv6_flowlabel(
914 const char* unit,
915 const char *filename,
916 unsigned line,
917 const char *section,
918 unsigned section_line,
919 const char *lvalue,
920 int ltype,
921 const char *rvalue,
922 void *data,
923 void *userdata) {
924
59c8bef0
YW
925 Tunnel *t = ASSERT_PTR(userdata);
926 int k, r;
407af9dd
SS
927
928 assert(filename);
407af9dd 929 assert(rvalue);
407af9dd 930
6870b415 931 if (streq(rvalue, "inherit")) {
59c8bef0 932 t->ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
407af9dd 933 t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
59c8bef0
YW
934 return 0;
935 }
12ca818f 936
59c8bef0
YW
937 r = safe_atoi(rvalue, &k);
938 if (r < 0) {
939 log_syntax(unit, LOG_WARNING, filename, line, r,
940 "Failed to parse tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue);
941 return 0;
942 }
943
944 if (k > 0xFFFFF) {
945 log_syntax(unit, LOG_WARNING, filename, line, 0,
946 "Invalid tunnel IPv6 flowlabel, ignoring assignment: %s", rvalue);
947 return 0;
407af9dd
SS
948 }
949
59c8bef0
YW
950 t->ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL;
951 t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
407af9dd
SS
952 return 0;
953}
954
63481576
YW
955int config_parse_encap_limit(
956 const char* unit,
957 const char *filename,
958 unsigned line,
959 const char *section,
960 unsigned section_line,
961 const char *lvalue,
962 int ltype,
963 const char *rvalue,
964 void *data,
965 void *userdata) {
966
a07e07cd
YW
967 Tunnel *t = ASSERT_PTR(userdata);
968 int k, r;
b4828886
SS
969
970 assert(filename);
b4828886
SS
971 assert(rvalue);
972
a07e07cd 973 if (streq(rvalue, "none")) {
b4828886 974 t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
a07e07cd
YW
975 t->encap_limit = 0;
976 return 0;
977 }
b4828886 978
a07e07cd
YW
979 r = safe_atoi(rvalue, &k);
980 if (r < 0) {
981 log_syntax(unit, LOG_WARNING, filename, line, r,
982 "Failed to parse Tunnel Encapsulation Limit option, ignoring assignment: %s", rvalue);
983 return 0;
984 }
985
986 if (k > 255 || k < 0) {
987 log_syntax(unit, LOG_WARNING, filename, line, 0,
988 "Invalid Tunnel Encapsulation value, ignoring assignment: %d", k);
989 return 0;
b4828886
SS
990 }
991
a07e07cd
YW
992 t->encap_limit = k;
993 t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
b4828886
SS
994 return 0;
995}
996
63481576
YW
997int config_parse_6rd_prefix(
998 const char* unit,
999 const char *filename,
1000 unsigned line,
1001 const char *section,
1002 unsigned section_line,
1003 const char *lvalue,
1004 int ltype,
1005 const char *rvalue,
1006 void *data,
1007 void *userdata) {
1008
d067cab3 1009 Tunnel *t = userdata;
63481576
YW
1010 union in_addr_union p;
1011 uint8_t l;
1012 int r;
d067cab3
DA
1013
1014 assert(filename);
1015 assert(lvalue);
1016 assert(rvalue);
1017
d067cab3
DA
1018 r = in_addr_prefix_from_string(rvalue, AF_INET6, &p, &l);
1019 if (r < 0) {
d96edb2c 1020 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue);
d067cab3
DA
1021 return 0;
1022 }
1023 if (l == 0) {
d96edb2c 1024 log_syntax(unit, LOG_WARNING, filename, line, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue);
d067cab3
DA
1025 return 0;
1026 }
1027
1028 t->sixrd_prefix = p.in6;
1029 t->sixrd_prefixlen = l;
1030
1031 return 0;
1032}
1033
98406eda
YW
1034int config_parse_erspan_version(
1035 const char* unit,
1036 const char *filename,
1037 unsigned line,
1038 const char *section,
1039 unsigned section_line,
1040 const char *lvalue,
1041 int ltype,
1042 const char *rvalue,
1043 void *data,
1044 void *userdata) {
1045
1046 uint8_t n, *v = ASSERT_PTR(data);
1047 int r;
1048
1049 assert(filename);
1050 assert(lvalue);
1051 assert(rvalue);
1052
1053 if (isempty(rvalue)) {
1054 *v = 1; /* defaults to 1 */
1055 return 0;
1056 }
1057
1058 r = safe_atou8(rvalue, &n);
1059 if (r < 0) {
1060 log_syntax(unit, LOG_WARNING, filename, line, r,
1061 "Failed to parse erspan version \"%s\", ignoring: %m", rvalue);
1062 return 0;
1063 }
1064 if (!IN_SET(n, 0, 1, 2)) {
1065 log_syntax(unit, LOG_WARNING, filename, line, 0,
1066 "Invalid erspan version \"%s\", which must be 0, 1 or 2, ignoring.", rvalue);
1067 return 0;
1068 }
1069
1070 *v = n;
1071 return 0;
1072}
1073
1074int config_parse_erspan_index(
1075 const char* unit,
1076 const char *filename,
1077 unsigned line,
1078 const char *section,
1079 unsigned section_line,
1080 const char *lvalue,
1081 int ltype,
1082 const char *rvalue,
1083 void *data,
1084 void *userdata) {
1085
1086 uint32_t n, *v = ASSERT_PTR(data);
1087 int r;
1088
1089 assert(filename);
1090 assert(lvalue);
1091 assert(rvalue);
1092
1093 if (isempty(rvalue)) {
1094 *v = 0; /* defaults to 0 */
1095 return 0;
1096 }
1097
1098 r = safe_atou32(rvalue, &n);
1099 if (r < 0) {
1100 log_syntax(unit, LOG_WARNING, filename, line, r,
1101 "Failed to parse erspan index \"%s\", ignoring: %m", rvalue);
1102 return 0;
1103 }
1104 if (n >= 0x100000) {
1105 log_syntax(unit, LOG_WARNING, filename, line, 0,
1106 "Invalid erspan index \"%s\", which must be less than 0x100000, ignoring.", rvalue);
1107 return 0;
1108 }
1109
1110 *v = n;
1111 return 0;
1112}
1113
1114int config_parse_erspan_direction(
1115 const char* unit,
1116 const char *filename,
1117 unsigned line,
1118 const char *section,
1119 unsigned section_line,
1120 const char *lvalue,
1121 int ltype,
1122 const char *rvalue,
1123 void *data,
1124 void *userdata) {
1125
1126 uint8_t *v = ASSERT_PTR(data);
1127
1128 assert(filename);
1129 assert(lvalue);
1130 assert(rvalue);
1131
1132 if (isempty(rvalue) || streq(rvalue, "ingress"))
1133 *v = 0; /* defaults to ingress */
1134 else if (streq(rvalue, "egress"))
1135 *v = 1;
1136 else
1137 log_syntax(unit, LOG_WARNING, filename, line, 0,
1138 "Invalid erspan direction \"%s\", which must be \"ingress\" or \"egress\", ignoring.", rvalue);
1139
1140 return 0;
1141}
1142
1143int config_parse_erspan_hwid(
1144 const char* unit,
1145 const char *filename,
1146 unsigned line,
1147 const char *section,
1148 unsigned section_line,
1149 const char *lvalue,
1150 int ltype,
1151 const char *rvalue,
1152 void *data,
1153 void *userdata) {
1154
1155 uint16_t n, *v = ASSERT_PTR(data);
1156 int r;
1157
1158 assert(filename);
1159 assert(lvalue);
1160 assert(rvalue);
1161
1162 if (isempty(rvalue)) {
1163 *v = 0; /* defaults to 0 */
1164 return 0;
1165 }
1166
1167 r = safe_atou16(rvalue, &n);
1168 if (r < 0) {
1169 log_syntax(unit, LOG_WARNING, filename, line, r,
1170 "Failed to parse erspan hwid \"%s\", ignoring: %m", rvalue);
1171 return 0;
1172 }
1173 if (n >= 64) {
1174 log_syntax(unit, LOG_WARNING, filename, line, 0,
1175 "Invalid erspan index \"%s\", which must be less than 64, ignoring.", rvalue);
1176 return 0;
1177 }
1178
1179 *v = n;
1180 return 0;
1181}
1182
a88f3913 1183static void netdev_tunnel_init(NetDev *netdev) {
a27a0ad6 1184 Tunnel *t;
aa9f1140 1185
a88f3913 1186 assert(netdev);
aa9f1140 1187
a88f3913 1188 t = TUNNEL(netdev);
aa9f1140 1189
aa9f1140
TG
1190 assert(t);
1191
2be25d75 1192 t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
aa9f1140 1193 t->pmtudisc = true;
a44956c9 1194 t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
918049ad 1195 t->isatap = -1;
a8b9a65c 1196 t->gre_erspan_sequence = -1;
855ee1a1
SS
1197 t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
1198 t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
407af9dd 1199 t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
3a4f3e42 1200 t->allow_localremote = -1;
98406eda 1201 t->erspan_version = 1;
a88f3913
YW
1202
1203 if (IN_SET(netdev->kind, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP, NETDEV_KIND_IP6TNL))
1204 t->ttl = DEFAULT_IPV6_TTL;
855ee1a1
SS
1205}
1206
3be1d7e0 1207const NetDevVTable ipip_vtable = {
aa9f1140 1208 .object_size = sizeof(Tunnel),
a88f3913 1209 .init = netdev_tunnel_init,
130b812f 1210 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
9e64c1f8 1211 .fill_message_create = netdev_ipip_sit_fill_message_create,
aa9f1140 1212 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1213 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
3be1d7e0 1214 .config_verify = netdev_tunnel_verify,
9f0cf80d 1215 .iftype = ARPHRD_TUNNEL,
3be1d7e0
TG
1216};
1217
1218const NetDevVTable sit_vtable = {
aa9f1140 1219 .object_size = sizeof(Tunnel),
a88f3913 1220 .init = netdev_tunnel_init,
130b812f 1221 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
9e64c1f8 1222 .fill_message_create = netdev_ipip_sit_fill_message_create,
aa9f1140 1223 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1224 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
3be1d7e0 1225 .config_verify = netdev_tunnel_verify,
9f0cf80d 1226 .iftype = ARPHRD_SIT,
3be1d7e0
TG
1227};
1228
1229const NetDevVTable vti_vtable = {
aa9f1140 1230 .object_size = sizeof(Tunnel),
a88f3913 1231 .init = netdev_tunnel_init,
130b812f 1232 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
aa9f1140
TG
1233 .fill_message_create = netdev_vti_fill_message_create,
1234 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1235 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
3be1d7e0 1236 .config_verify = netdev_tunnel_verify,
9f0cf80d 1237 .iftype = ARPHRD_TUNNEL,
3be1d7e0
TG
1238};
1239
9011ce77
SS
1240const NetDevVTable vti6_vtable = {
1241 .object_size = sizeof(Tunnel),
a88f3913 1242 .init = netdev_tunnel_init,
130b812f 1243 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
3affe303 1244 .fill_message_create = netdev_vti_fill_message_create,
9011ce77 1245 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1246 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
9011ce77 1247 .config_verify = netdev_tunnel_verify,
9f0cf80d 1248 .iftype = ARPHRD_TUNNEL6,
9011ce77
SS
1249};
1250
3be1d7e0 1251const NetDevVTable gre_vtable = {
aa9f1140 1252 .object_size = sizeof(Tunnel),
a88f3913 1253 .init = netdev_tunnel_init,
130b812f 1254 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
a8b9a65c 1255 .fill_message_create = netdev_gre_erspan_fill_message_create,
aa9f1140 1256 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1257 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
3be1d7e0 1258 .config_verify = netdev_tunnel_verify,
9f0cf80d 1259 .iftype = ARPHRD_IPGRE,
3be1d7e0 1260};
1af2536a
SS
1261
1262const NetDevVTable gretap_vtable = {
1263 .object_size = sizeof(Tunnel),
a88f3913 1264 .init = netdev_tunnel_init,
130b812f 1265 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
a8b9a65c 1266 .fill_message_create = netdev_gre_erspan_fill_message_create,
1af2536a 1267 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1268 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
1af2536a 1269 .config_verify = netdev_tunnel_verify,
9f0cf80d 1270 .iftype = ARPHRD_ETHER,
daf0f8ca 1271 .generate_mac = true,
1af2536a 1272};
855ee1a1 1273
b16492f8
SS
1274const NetDevVTable ip6gre_vtable = {
1275 .object_size = sizeof(Tunnel),
a88f3913 1276 .init = netdev_tunnel_init,
130b812f 1277 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
b16492f8
SS
1278 .fill_message_create = netdev_ip6gre_fill_message_create,
1279 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1280 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
b16492f8 1281 .config_verify = netdev_tunnel_verify,
9f0cf80d 1282 .iftype = ARPHRD_IP6GRE,
b16492f8
SS
1283};
1284
1285const NetDevVTable ip6gretap_vtable = {
1286 .object_size = sizeof(Tunnel),
a88f3913 1287 .init = netdev_tunnel_init,
130b812f 1288 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
b16492f8
SS
1289 .fill_message_create = netdev_ip6gre_fill_message_create,
1290 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1291 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
b16492f8 1292 .config_verify = netdev_tunnel_verify,
9f0cf80d 1293 .iftype = ARPHRD_ETHER,
daf0f8ca 1294 .generate_mac = true,
b16492f8
SS
1295};
1296
855ee1a1
SS
1297const NetDevVTable ip6tnl_vtable = {
1298 .object_size = sizeof(Tunnel),
a88f3913 1299 .init = netdev_tunnel_init,
130b812f 1300 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
855ee1a1
SS
1301 .fill_message_create = netdev_ip6tnl_fill_message_create,
1302 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1303 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
855ee1a1 1304 .config_verify = netdev_tunnel_verify,
9f0cf80d 1305 .iftype = ARPHRD_TUNNEL6,
855ee1a1 1306};
2266864b
SS
1307
1308const NetDevVTable erspan_vtable = {
1309 .object_size = sizeof(Tunnel),
a88f3913 1310 .init = netdev_tunnel_init,
130b812f 1311 .sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
a8b9a65c 1312 .fill_message_create = netdev_gre_erspan_fill_message_create,
9282f75b 1313 .create_type = NETDEV_CREATE_STACKED,
2be25d75 1314 .is_ready_to_create = netdev_tunnel_is_ready_to_create,
2266864b 1315 .config_verify = netdev_tunnel_verify,
9f0cf80d 1316 .iftype = ARPHRD_ETHER,
daf0f8ca 1317 .generate_mac = true,
2266864b 1318};