Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <netinet/in.h>
4 : #include <linux/fou.h>
5 : #include <linux/ip.h>
6 : #include <linux/if_tunnel.h>
7 : #include <linux/ip6_tunnel.h>
8 :
9 : #include "sd-netlink.h"
10 :
11 : #include "conf-parser.h"
12 : #include "missing.h"
13 : #include "netlink-util.h"
14 : #include "networkd-link.h"
15 : #include "netdev/tunnel.h"
16 : #include "parse-util.h"
17 : #include "string-table.h"
18 : #include "string-util.h"
19 : #include "util.h"
20 :
21 : #define DEFAULT_TNL_HOP_LIMIT 64
22 : #define IP6_FLOWINFO_FLOWLABEL htobe32(0x000FFFFF)
23 : #define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0x40
24 :
25 : static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
26 : [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6",
27 : [NETDEV_IP6_TNL_MODE_IPIP6] = "ipip6",
28 : [NETDEV_IP6_TNL_MODE_ANYIP6] = "any",
29 : };
30 :
31 10 : DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
32 0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
33 :
34 0 : static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
35 : Tunnel *t;
36 : int r;
37 :
38 0 : assert(netdev);
39 :
40 0 : if (netdev->kind == NETDEV_KIND_IPIP)
41 0 : t = IPIP(netdev);
42 : else
43 0 : t = SIT(netdev);
44 :
45 0 : assert(m);
46 0 : assert(t);
47 :
48 0 : if (link || t->assign_to_loopback) {
49 0 : r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
50 0 : if (r < 0)
51 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
52 : }
53 :
54 0 : r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
55 0 : if (r < 0)
56 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
57 :
58 0 : r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
59 0 : if (r < 0)
60 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
61 :
62 0 : r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
63 0 : if (r < 0)
64 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
65 :
66 0 : r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
67 0 : if (r < 0)
68 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
69 :
70 0 : if (t->fou_tunnel) {
71 0 : r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_TYPE, t->fou_encap_type);
72 0 : if (r < 0)
73 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_TYPE attribute: %m");
74 :
75 0 : r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_SPORT, htobe16(t->encap_src_port));
76 0 : if (r < 0)
77 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_SPORT attribute: %m");
78 :
79 0 : r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_DPORT, htobe16(t->fou_destination_port));
80 0 : if (r < 0)
81 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_DPORT attribute: %m");
82 : }
83 :
84 0 : if (netdev->kind == NETDEV_KIND_SIT) {
85 0 : if (t->sixrd_prefixlen > 0) {
86 0 : r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix);
87 0 : if (r < 0)
88 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
89 :
90 : /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
91 : * expecting to receive the prefixlen as a u16.
92 : */
93 0 : r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, t->sixrd_prefixlen);
94 0 : if (r < 0)
95 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
96 : }
97 :
98 0 : if (t->isatap >= 0) {
99 0 : uint16_t flags = 0;
100 :
101 0 : SET_FLAG(flags, SIT_ISATAP, t->isatap);
102 :
103 0 : r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags);
104 0 : if (r < 0)
105 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
106 : }
107 : }
108 :
109 0 : return r;
110 : }
111 :
112 0 : static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
113 0 : uint32_t ikey = 0;
114 0 : uint32_t okey = 0;
115 0 : uint16_t iflags = 0;
116 0 : uint16_t oflags = 0;
117 : Tunnel *t;
118 : int r;
119 :
120 0 : assert(netdev);
121 0 : assert(m);
122 :
123 0 : switch (netdev->kind) {
124 0 : case NETDEV_KIND_GRE:
125 0 : t = GRE(netdev);
126 0 : break;
127 0 : case NETDEV_KIND_ERSPAN:
128 0 : t = ERSPAN(netdev);
129 0 : break;
130 0 : case NETDEV_KIND_GRETAP:
131 0 : t = GRETAP(netdev);
132 0 : break;
133 0 : default:
134 0 : assert_not_reached("invalid netdev kind");
135 : }
136 :
137 0 : assert(t);
138 :
139 0 : if (link || t->assign_to_loopback) {
140 0 : r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
141 0 : if (r < 0)
142 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
143 : }
144 :
145 0 : if (netdev->kind == NETDEV_KIND_ERSPAN) {
146 0 : r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
147 0 : if (r < 0)
148 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
149 : }
150 :
151 0 : r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
152 0 : if (r < 0)
153 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
154 :
155 0 : r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
156 0 : if (r < 0)
157 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
158 :
159 0 : r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
160 0 : if (r < 0)
161 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
162 :
163 0 : r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
164 0 : if (r < 0)
165 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
166 :
167 0 : r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
168 0 : if (r < 0)
169 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
170 :
171 0 : if (t->key != 0) {
172 0 : ikey = okey = htobe32(t->key);
173 0 : iflags |= GRE_KEY;
174 0 : oflags |= GRE_KEY;
175 : }
176 :
177 0 : if (t->ikey != 0) {
178 0 : ikey = htobe32(t->ikey);
179 0 : iflags |= GRE_KEY;
180 : }
181 :
182 0 : if (t->okey != 0) {
183 0 : okey = htobe32(t->okey);
184 0 : oflags |= GRE_KEY;
185 : }
186 :
187 0 : if (t->gre_erspan_sequence > 0) {
188 0 : iflags |= GRE_SEQ;
189 0 : oflags |= GRE_SEQ;
190 0 : } else if (t->gre_erspan_sequence == 0) {
191 0 : iflags &= ~GRE_SEQ;
192 0 : oflags &= ~GRE_SEQ;
193 : }
194 :
195 0 : r = sd_netlink_message_append_u32(m, IFLA_GRE_IKEY, ikey);
196 0 : if (r < 0)
197 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_IKEY attribute: %m");
198 :
199 0 : r = sd_netlink_message_append_u32(m, IFLA_GRE_OKEY, okey);
200 0 : if (r < 0)
201 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_OKEY attribute: %m");
202 :
203 0 : r = sd_netlink_message_append_u16(m, IFLA_GRE_IFLAGS, iflags);
204 0 : if (r < 0)
205 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_IFLAGS attribute: %m");
206 :
207 0 : r = sd_netlink_message_append_u16(m, IFLA_GRE_OFLAGS, oflags);
208 0 : if (r < 0)
209 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_OFLAGS, attribute: %m");
210 :
211 0 : if (t->fou_tunnel) {
212 0 : r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_TYPE, t->fou_encap_type);
213 0 : if (r < 0)
214 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_TYPE attribute: %m");
215 :
216 0 : r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_SPORT, htobe16(t->encap_src_port));
217 0 : if (r < 0)
218 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_SPORT attribute: %m");
219 :
220 0 : r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_DPORT, htobe16(t->fou_destination_port));
221 0 : if (r < 0)
222 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_DPORT attribute: %m");
223 : }
224 :
225 0 : return r;
226 : }
227 :
228 0 : static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
229 : Tunnel *t;
230 : int r;
231 :
232 0 : assert(netdev);
233 :
234 0 : if (netdev->kind == NETDEV_KIND_IP6GRE)
235 0 : t = IP6GRE(netdev);
236 : else
237 0 : t = IP6GRETAP(netdev);
238 :
239 0 : assert(t);
240 0 : assert(m);
241 :
242 0 : if (link || t->assign_to_loopback) {
243 0 : r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
244 0 : if (r < 0)
245 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
246 : }
247 :
248 0 : r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
249 0 : if (r < 0)
250 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
251 :
252 0 : r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_REMOTE, &t->remote.in6);
253 0 : if (r < 0)
254 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
255 :
256 0 : r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
257 0 : if (r < 0)
258 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m");
259 :
260 0 : if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
261 0 : r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel);
262 0 : if (r < 0)
263 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLOWINFO attribute: %m");
264 : }
265 :
266 0 : r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags);
267 0 : if (r < 0)
268 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLAGS attribute: %m");
269 :
270 0 : return r;
271 : }
272 :
273 0 : static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
274 : uint32_t ikey, okey;
275 : Tunnel *t;
276 : int r;
277 :
278 0 : assert(netdev);
279 0 : assert(m);
280 :
281 0 : if (netdev->kind == NETDEV_KIND_VTI)
282 0 : t = VTI(netdev);
283 : else
284 0 : t = VTI6(netdev);
285 :
286 0 : assert(t);
287 :
288 0 : if (link || t->assign_to_loopback) {
289 0 : r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
290 0 : if (r < 0)
291 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LINK attribute: %m");
292 : }
293 :
294 0 : if (t->key != 0)
295 0 : ikey = okey = htobe32(t->key);
296 : else {
297 0 : ikey = htobe32(t->ikey);
298 0 : okey = htobe32(t->okey);
299 : }
300 :
301 0 : r = sd_netlink_message_append_u32(m, IFLA_VTI_IKEY, ikey);
302 0 : if (r < 0)
303 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_IKEY attribute: %m");
304 :
305 0 : r = sd_netlink_message_append_u32(m, IFLA_VTI_OKEY, okey);
306 0 : if (r < 0)
307 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m");
308 :
309 0 : r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &t->local);
310 0 : if (r < 0)
311 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LOCAL attribute: %m");
312 :
313 0 : r = netlink_message_append_in_addr_union(m, IFLA_VTI_REMOTE, t->family, &t->remote);
314 0 : if (r < 0)
315 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_REMOTE attribute: %m");
316 :
317 0 : return r;
318 : }
319 :
320 0 : static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
321 0 : Tunnel *t = IP6TNL(netdev);
322 : uint8_t proto;
323 : int r;
324 :
325 0 : assert(netdev);
326 0 : assert(m);
327 0 : assert(t);
328 :
329 0 : if (link || t->assign_to_loopback) {
330 0 : r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link ? link->ifindex : LOOPBACK_IFINDEX);
331 0 : if (r < 0)
332 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
333 : }
334 :
335 0 : r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
336 0 : if (r < 0)
337 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
338 :
339 0 : r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in6);
340 0 : if (r < 0)
341 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
342 :
343 0 : r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
344 0 : if (r < 0)
345 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
346 :
347 0 : if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) {
348 0 : r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel);
349 0 : if (r < 0)
350 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m");
351 : }
352 :
353 0 : if (t->copy_dscp)
354 0 : t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
355 :
356 0 : if (t->allow_localremote >= 0)
357 0 : SET_FLAG(t->flags, IP6_TNL_F_ALLOW_LOCAL_REMOTE, t->allow_localremote);
358 :
359 0 : if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) {
360 0 : r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit);
361 0 : if (r < 0)
362 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m");
363 : }
364 :
365 0 : r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags);
366 0 : if (r < 0)
367 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
368 :
369 0 : switch (t->ip6tnl_mode) {
370 0 : case NETDEV_IP6_TNL_MODE_IP6IP6:
371 0 : proto = IPPROTO_IPV6;
372 0 : break;
373 0 : case NETDEV_IP6_TNL_MODE_IPIP6:
374 0 : proto = IPPROTO_IPIP;
375 0 : break;
376 0 : case NETDEV_IP6_TNL_MODE_ANYIP6:
377 : default:
378 0 : proto = 0;
379 0 : break;
380 : }
381 :
382 0 : r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
383 0 : if (r < 0)
384 0 : return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PROTO attribute: %m");
385 :
386 0 : return r;
387 : }
388 :
389 0 : static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
390 0 : Tunnel *t = NULL;
391 :
392 0 : assert(netdev);
393 0 : assert(filename);
394 :
395 0 : switch (netdev->kind) {
396 0 : case NETDEV_KIND_IPIP:
397 0 : t = IPIP(netdev);
398 0 : break;
399 0 : case NETDEV_KIND_SIT:
400 0 : t = SIT(netdev);
401 0 : break;
402 0 : case NETDEV_KIND_GRE:
403 0 : t = GRE(netdev);
404 0 : break;
405 0 : case NETDEV_KIND_GRETAP:
406 0 : t = GRETAP(netdev);
407 0 : break;
408 0 : case NETDEV_KIND_IP6GRE:
409 0 : t = IP6GRE(netdev);
410 0 : break;
411 0 : case NETDEV_KIND_IP6GRETAP:
412 0 : t = IP6GRETAP(netdev);
413 0 : break;
414 0 : case NETDEV_KIND_VTI:
415 0 : t = VTI(netdev);
416 0 : break;
417 0 : case NETDEV_KIND_VTI6:
418 0 : t = VTI6(netdev);
419 0 : break;
420 0 : case NETDEV_KIND_IP6TNL:
421 0 : t = IP6TNL(netdev);
422 0 : break;
423 0 : case NETDEV_KIND_ERSPAN:
424 0 : t = ERSPAN(netdev);
425 0 : break;
426 0 : default:
427 0 : assert_not_reached("Invalid tunnel kind");
428 : }
429 :
430 0 : assert(t);
431 :
432 0 : if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE) &&
433 0 : !IN_SET(t->family, AF_UNSPEC, AF_INET))
434 0 : return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
435 : "vti/ipip/sit/gre tunnel without a local/remote IPv4 address configured in %s. Ignoring", filename);
436 :
437 0 : if (IN_SET(netdev->kind, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) &&
438 0 : (t->family != AF_INET || in_addr_is_null(t->family, &t->remote)))
439 0 : return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
440 : "gretap/erspan tunnel without a remote IPv4 address configured in %s. Ignoring", filename);
441 :
442 0 : if ((IN_SET(netdev->kind, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL) && t->family != AF_INET6) ||
443 0 : (netdev->kind == NETDEV_KIND_IP6GRE && !IN_SET(t->family, AF_UNSPEC, AF_INET6)))
444 0 : return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
445 : "vti6/ip6tnl/ip6gre tunnel without a local/remote IPv6 address configured in %s. Ignoring", filename);
446 :
447 0 : if (netdev->kind == NETDEV_KIND_IP6GRETAP &&
448 0 : (t->family != AF_INET6 || in_addr_is_null(t->family, &t->remote)))
449 0 : return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
450 : "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename);
451 :
452 0 : if (netdev->kind == NETDEV_KIND_IP6TNL &&
453 0 : t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID)
454 0 : return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
455 : "ip6tnl without mode configured in %s. Ignoring", filename);
456 :
457 0 : if (t->fou_tunnel && t->fou_destination_port <= 0)
458 0 : return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
459 : "FooOverUDP missing port configured in %s. Ignoring", filename);
460 :
461 0 : if (netdev->kind == NETDEV_KIND_ERSPAN && (t->erspan_index >= (1 << 20) || t->erspan_index == 0))
462 0 : return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Invalid erspan index %d. Ignoring", t->erspan_index);
463 :
464 : /* netlink_message_append_in_addr_union() is used for vti/vti6. So, t->family cannot be AF_UNSPEC. */
465 0 : if (netdev->kind == NETDEV_KIND_VTI)
466 0 : t->family = AF_INET;
467 :
468 0 : return 0;
469 : }
470 :
471 0 : int config_parse_tunnel_address(const char *unit,
472 : const char *filename,
473 : unsigned line,
474 : const char *section,
475 : unsigned section_line,
476 : const char *lvalue,
477 : int ltype,
478 : const char *rvalue,
479 : void *data,
480 : void *userdata) {
481 0 : Tunnel *t = userdata;
482 0 : union in_addr_union *addr = data, buffer;
483 : int r, f;
484 :
485 0 : assert(filename);
486 0 : assert(lvalue);
487 0 : assert(rvalue);
488 0 : assert(data);
489 :
490 : /* This is used to parse addresses on both local and remote ends of the tunnel.
491 : * Address families must match.
492 : *
493 : * "any" is a special value which means that the address is unspecified.
494 : */
495 :
496 0 : if (streq(rvalue, "any")) {
497 0 : *addr = IN_ADDR_NULL;
498 :
499 : /* As a special case, if both the local and remote addresses are
500 : * unspecified, also clear the address family.
501 : */
502 0 : if (t->family != AF_UNSPEC &&
503 0 : in_addr_is_null(t->family, &t->local) != 0 &&
504 0 : in_addr_is_null(t->family, &t->remote) != 0)
505 0 : t->family = AF_UNSPEC;
506 0 : return 0;
507 : }
508 :
509 0 : r = in_addr_from_string_auto(rvalue, &f, &buffer);
510 0 : if (r < 0) {
511 0 : log_syntax(unit, LOG_ERR, filename, line, r,
512 : "Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue);
513 0 : return 0;
514 : }
515 :
516 0 : if (t->family != AF_UNSPEC && t->family != f) {
517 0 : log_syntax(unit, LOG_ERR, filename, line, 0,
518 : "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
519 0 : return 0;
520 : }
521 :
522 0 : t->family = f;
523 0 : *addr = buffer;
524 0 : return 0;
525 : }
526 :
527 0 : int config_parse_tunnel_key(const char *unit,
528 : const char *filename,
529 : unsigned line,
530 : const char *section,
531 : unsigned section_line,
532 : const char *lvalue,
533 : int ltype,
534 : const char *rvalue,
535 : void *data,
536 : void *userdata) {
537 : union in_addr_union buffer;
538 0 : Tunnel *t = userdata;
539 : uint32_t k;
540 : int r;
541 :
542 0 : assert(filename);
543 0 : assert(lvalue);
544 0 : assert(rvalue);
545 0 : assert(data);
546 :
547 0 : r = in_addr_from_string(AF_INET, rvalue, &buffer);
548 0 : if (r < 0) {
549 0 : r = safe_atou32(rvalue, &k);
550 0 : if (r < 0) {
551 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue);
552 0 : return 0;
553 : }
554 : } else
555 0 : k = be32toh(buffer.in.s_addr);
556 :
557 0 : if (streq(lvalue, "Key"))
558 0 : t->key = k;
559 0 : else if (streq(lvalue, "InputKey"))
560 0 : t->ikey = k;
561 : else
562 0 : t->okey = k;
563 :
564 0 : return 0;
565 : }
566 :
567 0 : int config_parse_ipv6_flowlabel(const char* unit,
568 : const char *filename,
569 : unsigned line,
570 : const char *section,
571 : unsigned section_line,
572 : const char *lvalue,
573 : int ltype,
574 : const char *rvalue,
575 : void *data,
576 : void *userdata) {
577 0 : IPv6FlowLabel *ipv6_flowlabel = data;
578 0 : Tunnel *t = userdata;
579 0 : int k = 0;
580 : int r;
581 :
582 0 : assert(filename);
583 0 : assert(lvalue);
584 0 : assert(rvalue);
585 0 : assert(ipv6_flowlabel);
586 :
587 0 : if (streq(rvalue, "inherit")) {
588 0 : *ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL;
589 0 : t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
590 : } else {
591 0 : r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata);
592 0 : if (r < 0)
593 0 : return r;
594 :
595 0 : if (k > 0xFFFFF)
596 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
597 : else {
598 0 : *ipv6_flowlabel = htobe32(k) & IP6_FLOWINFO_FLOWLABEL;
599 0 : t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
600 : }
601 : }
602 :
603 0 : return 0;
604 : }
605 :
606 0 : int config_parse_encap_limit(const char* unit,
607 : const char *filename,
608 : unsigned line,
609 : const char *section,
610 : unsigned section_line,
611 : const char *lvalue,
612 : int ltype,
613 : const char *rvalue,
614 : void *data,
615 : void *userdata) {
616 0 : Tunnel *t = userdata;
617 0 : int k = 0;
618 : int r;
619 :
620 0 : assert(filename);
621 0 : assert(lvalue);
622 0 : assert(rvalue);
623 :
624 0 : if (streq(rvalue, "none"))
625 0 : t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
626 : else {
627 0 : r = safe_atoi(rvalue, &k);
628 0 : if (r < 0) {
629 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
630 0 : return 0;
631 : }
632 :
633 0 : if (k > 255 || k < 0)
634 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
635 : else {
636 0 : t->encap_limit = k;
637 0 : t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
638 : }
639 : }
640 :
641 0 : return 0;
642 : }
643 :
644 0 : int config_parse_6rd_prefix(const char* unit,
645 : const char *filename,
646 : unsigned line,
647 : const char *section,
648 : unsigned section_line,
649 : const char *lvalue,
650 : int ltype,
651 : const char *rvalue,
652 : void *data,
653 : void *userdata) {
654 0 : Tunnel *t = userdata;
655 :
656 0 : assert(filename);
657 0 : assert(lvalue);
658 0 : assert(rvalue);
659 :
660 : union in_addr_union p;
661 : uint8_t l;
662 : int r;
663 :
664 0 : r = in_addr_prefix_from_string(rvalue, AF_INET6, &p, &l);
665 0 : if (r < 0) {
666 0 : log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse 6rd prefix \"%s\", ignoring: %m", rvalue);
667 0 : return 0;
668 : }
669 0 : if (l == 0) {
670 0 : log_syntax(unit, LOG_ERR, filename, line, 0, "6rd prefix length of \"%s\" must be greater than zero, ignoring", rvalue);
671 0 : return 0;
672 : }
673 :
674 0 : t->sixrd_prefix = p.in6;
675 0 : t->sixrd_prefixlen = l;
676 :
677 0 : return 0;
678 : }
679 :
680 0 : static void ipip_sit_init(NetDev *n) {
681 : Tunnel *t;
682 :
683 0 : assert(n);
684 :
685 0 : switch (n->kind) {
686 0 : case NETDEV_KIND_IPIP:
687 0 : t = IPIP(n);
688 0 : break;
689 0 : case NETDEV_KIND_SIT:
690 0 : t = SIT(n);
691 0 : break;
692 0 : default:
693 0 : assert_not_reached("invalid netdev kind");
694 : }
695 :
696 0 : assert(t);
697 :
698 0 : t->pmtudisc = true;
699 0 : t->fou_encap_type = FOU_ENCAP_DIRECT;
700 0 : t->isatap = -1;
701 0 : }
702 :
703 0 : static void vti_init(NetDev *n) {
704 : Tunnel *t;
705 :
706 0 : assert(n);
707 :
708 0 : if (n->kind == NETDEV_KIND_VTI)
709 0 : t = VTI(n);
710 : else
711 0 : t = VTI6(n);
712 :
713 0 : assert(t);
714 :
715 0 : t->pmtudisc = true;
716 0 : }
717 :
718 0 : static void gre_erspan_init(NetDev *n) {
719 : Tunnel *t;
720 :
721 0 : assert(n);
722 :
723 0 : switch (n->kind) {
724 0 : case NETDEV_KIND_GRE:
725 0 : t = GRE(n);
726 0 : break;
727 0 : case NETDEV_KIND_ERSPAN:
728 0 : t = ERSPAN(n);
729 0 : break;
730 0 : case NETDEV_KIND_GRETAP:
731 0 : t = GRETAP(n);
732 0 : break;
733 0 : default:
734 0 : assert_not_reached("invalid netdev kind");
735 : }
736 :
737 0 : assert(t);
738 :
739 0 : t->pmtudisc = true;
740 0 : t->gre_erspan_sequence = -1;
741 0 : t->fou_encap_type = FOU_ENCAP_DIRECT;
742 0 : }
743 :
744 0 : static void ip6gre_init(NetDev *n) {
745 : Tunnel *t;
746 :
747 0 : assert(n);
748 :
749 0 : if (n->kind == NETDEV_KIND_IP6GRE)
750 0 : t = IP6GRE(n);
751 : else
752 0 : t = IP6GRETAP(n);
753 :
754 0 : assert(t);
755 :
756 0 : t->ttl = DEFAULT_TNL_HOP_LIMIT;
757 0 : }
758 :
759 0 : static void ip6tnl_init(NetDev *n) {
760 0 : Tunnel *t = IP6TNL(n);
761 :
762 0 : assert(n);
763 0 : assert(t);
764 :
765 0 : t->ttl = DEFAULT_TNL_HOP_LIMIT;
766 0 : t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
767 0 : t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID;
768 0 : t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID;
769 0 : t->allow_localremote = -1;
770 0 : }
771 :
772 : const NetDevVTable ipip_vtable = {
773 : .object_size = sizeof(Tunnel),
774 : .init = ipip_sit_init,
775 : .sections = "Match\0NetDev\0Tunnel\0",
776 : .fill_message_create = netdev_ipip_sit_fill_message_create,
777 : .create_type = NETDEV_CREATE_STACKED,
778 : .config_verify = netdev_tunnel_verify,
779 : .generate_mac = true,
780 : };
781 :
782 : const NetDevVTable sit_vtable = {
783 : .object_size = sizeof(Tunnel),
784 : .init = ipip_sit_init,
785 : .sections = "Match\0NetDev\0Tunnel\0",
786 : .fill_message_create = netdev_ipip_sit_fill_message_create,
787 : .create_type = NETDEV_CREATE_STACKED,
788 : .config_verify = netdev_tunnel_verify,
789 : .generate_mac = true,
790 : };
791 :
792 : const NetDevVTable vti_vtable = {
793 : .object_size = sizeof(Tunnel),
794 : .init = vti_init,
795 : .sections = "Match\0NetDev\0Tunnel\0",
796 : .fill_message_create = netdev_vti_fill_message_create,
797 : .create_type = NETDEV_CREATE_STACKED,
798 : .config_verify = netdev_tunnel_verify,
799 : .generate_mac = true,
800 : };
801 :
802 : const NetDevVTable vti6_vtable = {
803 : .object_size = sizeof(Tunnel),
804 : .init = vti_init,
805 : .sections = "Match\0NetDev\0Tunnel\0",
806 : .fill_message_create = netdev_vti_fill_message_create,
807 : .create_type = NETDEV_CREATE_STACKED,
808 : .config_verify = netdev_tunnel_verify,
809 : .generate_mac = true,
810 : };
811 :
812 : const NetDevVTable gre_vtable = {
813 : .object_size = sizeof(Tunnel),
814 : .init = gre_erspan_init,
815 : .sections = "Match\0NetDev\0Tunnel\0",
816 : .fill_message_create = netdev_gre_erspan_fill_message_create,
817 : .create_type = NETDEV_CREATE_STACKED,
818 : .config_verify = netdev_tunnel_verify,
819 : .generate_mac = true,
820 : };
821 :
822 : const NetDevVTable gretap_vtable = {
823 : .object_size = sizeof(Tunnel),
824 : .init = gre_erspan_init,
825 : .sections = "Match\0NetDev\0Tunnel\0",
826 : .fill_message_create = netdev_gre_erspan_fill_message_create,
827 : .create_type = NETDEV_CREATE_STACKED,
828 : .config_verify = netdev_tunnel_verify,
829 : .generate_mac = true,
830 : };
831 :
832 : const NetDevVTable ip6gre_vtable = {
833 : .object_size = sizeof(Tunnel),
834 : .init = ip6gre_init,
835 : .sections = "Match\0NetDev\0Tunnel\0",
836 : .fill_message_create = netdev_ip6gre_fill_message_create,
837 : .create_type = NETDEV_CREATE_STACKED,
838 : .config_verify = netdev_tunnel_verify,
839 : .generate_mac = true,
840 : };
841 :
842 : const NetDevVTable ip6gretap_vtable = {
843 : .object_size = sizeof(Tunnel),
844 : .init = ip6gre_init,
845 : .sections = "Match\0NetDev\0Tunnel\0",
846 : .fill_message_create = netdev_ip6gre_fill_message_create,
847 : .create_type = NETDEV_CREATE_STACKED,
848 : .config_verify = netdev_tunnel_verify,
849 : .generate_mac = true,
850 : };
851 :
852 : const NetDevVTable ip6tnl_vtable = {
853 : .object_size = sizeof(Tunnel),
854 : .init = ip6tnl_init,
855 : .sections = "Match\0NetDev\0Tunnel\0",
856 : .fill_message_create = netdev_ip6tnl_fill_message_create,
857 : .create_type = NETDEV_CREATE_STACKED,
858 : .config_verify = netdev_tunnel_verify,
859 : .generate_mac = true,
860 : };
861 :
862 : const NetDevVTable erspan_vtable = {
863 : .object_size = sizeof(Tunnel),
864 : .init = gre_erspan_init,
865 : .sections = "Match\0NetDev\0Tunnel\0",
866 : .fill_message_create = netdev_gre_erspan_fill_message_create,
867 : .create_type = NETDEV_CREATE_STACKED,
868 : .config_verify = netdev_tunnel_verify,
869 : .generate_mac = true,
870 : };
|