Branch data 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 [ + + + + ]: 40 : 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 : : };
|