]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/nspawn/nspawn-network.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / nspawn / nspawn-network.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
9a2a5625
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2015 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <linux/veth.h>
22#include <net/if.h>
fe993888 23#include <sys/file.h>
9a2a5625 24
b4bbcaa9 25#include "libudev.h"
9a2a5625
LP
26#include "sd-id128.h"
27#include "sd-netlink.h"
9a2a5625 28
b5efdb8a 29#include "alloc-util.h"
9a2a5625 30#include "ether-addr-util.h"
22b28dfd 31#include "lockfile-util.h"
9a2a5625 32#include "netlink-util.h"
cf0fbc49 33#include "nspawn-network.h"
07630cea 34#include "siphash24.h"
ef76dff2
LP
35#include "socket-util.h"
36#include "stat-util.h"
07630cea 37#include "string-util.h"
9a2a5625 38#include "udev-util.h"
07630cea 39#include "util.h"
9a2a5625
LP
40
41#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
42#define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
f6d6bad1
LP
43#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
44#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
9a2a5625
LP
45#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
46
22b28dfd
LP
47static int remove_one_link(sd_netlink *rtnl, const char *name) {
48 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
49 int r;
50
51 if (isempty(name))
52 return 0;
53
54 r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
55 if (r < 0)
56 return log_error_errno(r, "Failed to allocate netlink message: %m");
57
58 r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
59 if (r < 0)
60 return log_error_errno(r, "Failed to add netlink interface name: %m");
61
62 r = sd_netlink_call(rtnl, m, 0, NULL);
63 if (r == -ENODEV) /* Already gone */
64 return 0;
65 if (r < 0)
66 return log_error_errno(r, "Failed to remove interface %s: %m", name);
67
68 return 1;
69}
70
9a2a5625
LP
71static int generate_mac(
72 const char *machine_name,
73 struct ether_addr *mac,
74 sd_id128_t hash_key,
75 uint64_t idx) {
76
dbe81cbd 77 uint64_t result;
9a2a5625
LP
78 size_t l, sz;
79 uint8_t *v, *i;
80 int r;
81
82 l = strlen(machine_name);
83 sz = sizeof(sd_id128_t) + l;
84 if (idx > 0)
85 sz += sizeof(idx);
86
87 v = alloca(sz);
88
89 /* fetch some persistent data unique to the host */
90 r = sd_id128_get_machine((sd_id128_t*) v);
91 if (r < 0)
92 return r;
93
94 /* combine with some data unique (on this host) to this
95 * container instance */
96 i = mempcpy(v + sizeof(sd_id128_t), machine_name, l);
97 if (idx > 0) {
98 idx = htole64(idx);
99 memcpy(i, &idx, sizeof(idx));
100 }
101
102 /* Let's hash the host machine ID plus the container name. We
103 * use a fixed, but originally randomly created hash key here. */
933f9cae 104 result = htole64(siphash24(v, sz, hash_key.bytes));
9a2a5625
LP
105
106 assert_cc(ETH_ALEN <= sizeof(result));
dbe81cbd 107 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
9a2a5625
LP
108
109 /* see eth_random_addr in the kernel */
110 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
111 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
112
113 return 0;
114}
115
f6d6bad1
LP
116static int add_veth(
117 sd_netlink *rtnl,
118 pid_t pid,
119 const char *ifname_host,
120 const struct ether_addr *mac_host,
121 const char *ifname_container,
122 const struct ether_addr *mac_container) {
9a2a5625 123
4afd3348 124 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
f6d6bad1 125 int r;
9a2a5625 126
f6d6bad1
LP
127 assert(rtnl);
128 assert(ifname_host);
129 assert(mac_host);
130 assert(ifname_container);
131 assert(mac_container);
9a2a5625
LP
132
133 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
134 if (r < 0)
135 return log_error_errno(r, "Failed to allocate netlink message: %m");
136
f6d6bad1 137 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host);
9a2a5625
LP
138 if (r < 0)
139 return log_error_errno(r, "Failed to add netlink interface name: %m");
140
f6d6bad1 141 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host);
9a2a5625
LP
142 if (r < 0)
143 return log_error_errno(r, "Failed to add netlink MAC address: %m");
144
145 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
146 if (r < 0)
147 return log_error_errno(r, "Failed to open netlink container: %m");
148
149 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
150 if (r < 0)
151 return log_error_errno(r, "Failed to open netlink container: %m");
152
153 r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
154 if (r < 0)
155 return log_error_errno(r, "Failed to open netlink container: %m");
156
f6d6bad1 157 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container);
9a2a5625
LP
158 if (r < 0)
159 return log_error_errno(r, "Failed to add netlink interface name: %m");
160
f6d6bad1 161 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container);
9a2a5625
LP
162 if (r < 0)
163 return log_error_errno(r, "Failed to add netlink MAC address: %m");
164
165 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
166 if (r < 0)
167 return log_error_errno(r, "Failed to add netlink namespace field: %m");
168
169 r = sd_netlink_message_close_container(m);
170 if (r < 0)
171 return log_error_errno(r, "Failed to close netlink container: %m");
172
173 r = sd_netlink_message_close_container(m);
174 if (r < 0)
175 return log_error_errno(r, "Failed to close netlink container: %m");
176
177 r = sd_netlink_message_close_container(m);
178 if (r < 0)
179 return log_error_errno(r, "Failed to close netlink container: %m");
180
181 r = sd_netlink_call(rtnl, m, 0, NULL);
182 if (r < 0)
f6d6bad1
LP
183 return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
184
185 return 0;
186}
187
188int setup_veth(const char *machine_name,
189 pid_t pid,
190 char iface_name[IFNAMSIZ],
191 bool bridge) {
192
4afd3348 193 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
f6d6bad1
LP
194 struct ether_addr mac_host, mac_container;
195 int r, i;
196
197 assert(machine_name);
198 assert(pid > 0);
199 assert(iface_name);
200
201 /* Use two different interface name prefixes depending whether
202 * we are in bridge mode or not. */
203 snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
204 bridge ? "vb" : "ve", machine_name);
205
206 r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
207 if (r < 0)
208 return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
209
210 r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
211 if (r < 0)
212 return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
213
214 r = sd_netlink_open(&rtnl);
215 if (r < 0)
216 return log_error_errno(r, "Failed to connect to netlink: %m");
217
218 r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container);
219 if (r < 0)
220 return r;
9a2a5625
LP
221
222 i = (int) if_nametoindex(iface_name);
223 if (i <= 0)
224 return log_error_errno(errno, "Failed to resolve interface %s: %m", iface_name);
225
226 return i;
227}
228
f6d6bad1
LP
229int setup_veth_extra(
230 const char *machine_name,
231 pid_t pid,
232 char **pairs) {
233
4afd3348 234 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
f6d6bad1
LP
235 uint64_t idx = 0;
236 char **a, **b;
237 int r;
238
239 assert(machine_name);
240 assert(pid > 0);
241
242 if (strv_isempty(pairs))
243 return 0;
244
245 r = sd_netlink_open(&rtnl);
246 if (r < 0)
247 return log_error_errno(r, "Failed to connect to netlink: %m");
248
249 STRV_FOREACH_PAIR(a, b, pairs) {
250 struct ether_addr mac_host, mac_container;
251
252 r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
253 if (r < 0)
254 return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
255
256 r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx);
257 if (r < 0)
258 return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
259
260 r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container);
261 if (r < 0)
262 return r;
263
313cefa1 264 idx++;
f6d6bad1
LP
265 }
266
267 return 0;
268}
269
22b28dfd 270static int join_bridge(sd_netlink *rtnl, const char *veth_name, const char *bridge_name) {
4afd3348 271 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
9a2a5625
LP
272 int r, bridge_ifi;
273
22b28dfd 274 assert(rtnl);
9a2a5625
LP
275 assert(veth_name);
276 assert(bridge_name);
277
278 bridge_ifi = (int) if_nametoindex(bridge_name);
279 if (bridge_ifi <= 0)
22b28dfd 280 return -errno;
9a2a5625
LP
281
282 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
283 if (r < 0)
22b28dfd 284 return r;
9a2a5625
LP
285
286 r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
287 if (r < 0)
22b28dfd 288 return r;
9a2a5625
LP
289
290 r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
291 if (r < 0)
22b28dfd 292 return r;
9a2a5625
LP
293
294 r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
295 if (r < 0)
22b28dfd 296 return r;
9a2a5625
LP
297
298 r = sd_netlink_call(rtnl, m, 0, NULL);
299 if (r < 0)
22b28dfd 300 return r;
9a2a5625
LP
301
302 return bridge_ifi;
303}
304
22b28dfd
LP
305static int create_bridge(sd_netlink *rtnl, const char *bridge_name) {
306 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
307 int r;
308
309 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
310 if (r < 0)
311 return r;
312
313 r = sd_netlink_message_append_string(m, IFLA_IFNAME, bridge_name);
314 if (r < 0)
315 return r;
316
317 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
318 if (r < 0)
319 return r;
320
321 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "bridge");
322 if (r < 0)
323 return r;
324
325 r = sd_netlink_message_close_container(m);
326 if (r < 0)
327 return r;
328
329 r = sd_netlink_message_close_container(m);
330 if (r < 0)
331 return r;
332
333 r = sd_netlink_call(rtnl, m, 0, NULL);
334 if (r < 0)
335 return r;
336
337 return 0;
338}
339
340int setup_bridge(const char *veth_name, const char *bridge_name, bool create) {
341 _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT;
342 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
343 int r, bridge_ifi;
344 unsigned n = 0;
345
346 assert(veth_name);
347 assert(bridge_name);
348
349 r = sd_netlink_open(&rtnl);
350 if (r < 0)
351 return log_error_errno(r, "Failed to connect to netlink: %m");
352
353 if (create) {
354 /* We take a system-wide lock here, so that we can safely check whether there's still a member in the
6dd6a9c4 355 * bridge before removing it, without risking interference from other nspawn instances. */
22b28dfd
LP
356
357 r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
358 if (r < 0)
359 return log_error_errno(r, "Failed to take network zone lock: %m");
360 }
361
362 for (;;) {
363 bridge_ifi = join_bridge(rtnl, veth_name, bridge_name);
364 if (bridge_ifi >= 0)
365 return bridge_ifi;
366 if (bridge_ifi != -ENODEV || !create || n > 10)
367 return log_error_errno(bridge_ifi, "Failed to add interface %s to bridge %s: %m", veth_name, bridge_name);
368
369 /* Count attempts, so that we don't enter an endless loop here. */
370 n++;
371
372 /* The bridge doesn't exist yet. Let's create it */
373 r = create_bridge(rtnl, bridge_name);
374 if (r < 0)
375 return log_error_errno(r, "Failed to create bridge interface %s: %m", bridge_name);
376
377 /* Try again, now that the bridge exists */
378 }
379}
380
381int remove_bridge(const char *bridge_name) {
382 _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT;
383 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
384 const char *path;
385 int r;
386
387 /* Removes the specified bridge, but only if it is currently empty */
388
389 if (isempty(bridge_name))
390 return 0;
391
392 r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
393 if (r < 0)
394 return log_error_errno(r, "Failed to take network zone lock: %m");
395
396 path = strjoina("/sys/class/net/", bridge_name, "/brif");
397
398 r = dir_is_empty(path);
399 if (r == -ENOENT) /* Already gone? */
400 return 0;
401 if (r < 0)
402 return log_error_errno(r, "Can't detect if bridge %s is empty: %m", bridge_name);
403 if (r == 0) /* Still populated, leave it around */
404 return 0;
405
406 r = sd_netlink_open(&rtnl);
407 if (r < 0)
408 return log_error_errno(r, "Failed to connect to netlink: %m");
409
410 return remove_one_link(rtnl, bridge_name);
411}
412
9a2a5625
LP
413static int parse_interface(struct udev *udev, const char *name) {
414 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
415 char ifi_str[2 + DECIMAL_STR_MAX(int)];
416 int ifi;
417
418 ifi = (int) if_nametoindex(name);
419 if (ifi <= 0)
420 return log_error_errno(errno, "Failed to resolve interface %s: %m", name);
421
422 sprintf(ifi_str, "n%i", ifi);
423 d = udev_device_new_from_device_id(udev, ifi_str);
424 if (!d)
425 return log_error_errno(errno, "Failed to get udev device for interface %s: %m", name);
426
427 if (udev_device_get_is_initialized(d) <= 0) {
428 log_error("Network interface %s is not initialized yet.", name);
429 return -EBUSY;
430 }
431
432 return ifi;
433}
434
435int move_network_interfaces(pid_t pid, char **ifaces) {
436 _cleanup_udev_unref_ struct udev *udev = NULL;
4afd3348 437 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
9a2a5625
LP
438 char **i;
439 int r;
440
441 if (strv_isempty(ifaces))
442 return 0;
443
444 r = sd_netlink_open(&rtnl);
445 if (r < 0)
446 return log_error_errno(r, "Failed to connect to netlink: %m");
447
448 udev = udev_new();
449 if (!udev) {
450 log_error("Failed to connect to udev.");
451 return -ENOMEM;
452 }
453
454 STRV_FOREACH(i, ifaces) {
4afd3348 455 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
9a2a5625
LP
456 int ifi;
457
458 ifi = parse_interface(udev, *i);
459 if (ifi < 0)
460 return ifi;
461
462 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, ifi);
463 if (r < 0)
464 return log_error_errno(r, "Failed to allocate netlink message: %m");
465
466 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
467 if (r < 0)
468 return log_error_errno(r, "Failed to append namespace PID to netlink message: %m");
469
470 r = sd_netlink_call(rtnl, m, 0, NULL);
471 if (r < 0)
472 return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
473 }
474
475 return 0;
476}
477
478int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
479 _cleanup_udev_unref_ struct udev *udev = NULL;
4afd3348 480 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
9a2a5625
LP
481 unsigned idx = 0;
482 char **i;
483 int r;
484
485 if (strv_isempty(ifaces))
486 return 0;
487
488 r = sd_netlink_open(&rtnl);
489 if (r < 0)
490 return log_error_errno(r, "Failed to connect to netlink: %m");
491
492 udev = udev_new();
493 if (!udev) {
494 log_error("Failed to connect to udev.");
495 return -ENOMEM;
496 }
497
498 STRV_FOREACH(i, ifaces) {
4afd3348 499 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
9a2a5625
LP
500 _cleanup_free_ char *n = NULL;
501 struct ether_addr mac;
502 int ifi;
503
504 ifi = parse_interface(udev, *i);
505 if (ifi < 0)
506 return ifi;
507
508 r = generate_mac(machine_name, &mac, MACVLAN_HASH_KEY, idx++);
509 if (r < 0)
510 return log_error_errno(r, "Failed to create MACVLAN MAC address: %m");
511
512 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
513 if (r < 0)
514 return log_error_errno(r, "Failed to allocate netlink message: %m");
515
516 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
517 if (r < 0)
518 return log_error_errno(r, "Failed to add netlink interface index: %m");
519
520 n = strappend("mv-", *i);
521 if (!n)
522 return log_oom();
523
524 strshorten(n, IFNAMSIZ-1);
525
526 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
527 if (r < 0)
528 return log_error_errno(r, "Failed to add netlink interface name: %m");
529
530 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
531 if (r < 0)
532 return log_error_errno(r, "Failed to add netlink MAC address: %m");
533
534 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
535 if (r < 0)
536 return log_error_errno(r, "Failed to add netlink namespace field: %m");
537
538 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
539 if (r < 0)
540 return log_error_errno(r, "Failed to open netlink container: %m");
541
542 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
543 if (r < 0)
544 return log_error_errno(r, "Failed to open netlink container: %m");
545
546 r = sd_netlink_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
547 if (r < 0)
548 return log_error_errno(r, "Failed to append macvlan mode: %m");
549
550 r = sd_netlink_message_close_container(m);
551 if (r < 0)
552 return log_error_errno(r, "Failed to close netlink container: %m");
553
554 r = sd_netlink_message_close_container(m);
555 if (r < 0)
556 return log_error_errno(r, "Failed to close netlink container: %m");
557
558 r = sd_netlink_call(rtnl, m, 0, NULL);
559 if (r < 0)
560 return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
561 }
562
563 return 0;
564}
565
566int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
567 _cleanup_udev_unref_ struct udev *udev = NULL;
4afd3348 568 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
9a2a5625
LP
569 char **i;
570 int r;
571
572 if (strv_isempty(ifaces))
573 return 0;
574
575 r = sd_netlink_open(&rtnl);
576 if (r < 0)
577 return log_error_errno(r, "Failed to connect to netlink: %m");
578
579 udev = udev_new();
580 if (!udev) {
581 log_error("Failed to connect to udev.");
582 return -ENOMEM;
583 }
584
585 STRV_FOREACH(i, ifaces) {
4afd3348 586 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
9a2a5625
LP
587 _cleanup_free_ char *n = NULL;
588 int ifi;
589
590 ifi = parse_interface(udev, *i);
591 if (ifi < 0)
592 return ifi;
593
594 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
595 if (r < 0)
596 return log_error_errno(r, "Failed to allocate netlink message: %m");
597
598 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
599 if (r < 0)
600 return log_error_errno(r, "Failed to add netlink interface index: %m");
601
602 n = strappend("iv-", *i);
603 if (!n)
604 return log_oom();
605
606 strshorten(n, IFNAMSIZ-1);
607
608 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
609 if (r < 0)
610 return log_error_errno(r, "Failed to add netlink interface name: %m");
611
612 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid);
613 if (r < 0)
614 return log_error_errno(r, "Failed to add netlink namespace field: %m");
615
616 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
617 if (r < 0)
618 return log_error_errno(r, "Failed to open netlink container: %m");
619
620 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
621 if (r < 0)
622 return log_error_errno(r, "Failed to open netlink container: %m");
623
624 r = sd_netlink_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
625 if (r < 0)
626 return log_error_errno(r, "Failed to add ipvlan mode: %m");
627
628 r = sd_netlink_message_close_container(m);
629 if (r < 0)
630 return log_error_errno(r, "Failed to close netlink container: %m");
631
632 r = sd_netlink_message_close_container(m);
633 if (r < 0)
634 return log_error_errno(r, "Failed to close netlink container: %m");
635
636 r = sd_netlink_call(rtnl, m, 0, NULL);
637 if (r < 0)
638 return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
639 }
640
641 return 0;
642}
f6d6bad1
LP
643
644int veth_extra_parse(char ***l, const char *p) {
645 _cleanup_free_ char *a = NULL, *b = NULL;
646 int r;
647
648 r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
649 if (r < 0)
650 return r;
ef76dff2 651 if (r == 0 || !ifname_valid(a))
f6d6bad1
LP
652 return -EINVAL;
653
654 r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
655 if (r < 0)
656 return r;
ef76dff2 657 if (r == 0 || !ifname_valid(b)) {
f6d6bad1
LP
658 free(b);
659 b = strdup(a);
660 if (!b)
661 return -ENOMEM;
662 }
663
664 if (p)
665 return -EINVAL;
666
667 r = strv_push_pair(l, a, b);
668 if (r < 0)
669 return -ENOMEM;
670
671 a = b = NULL;
672 return 0;
673}
ef3b2aa7 674
ef3b2aa7
LP
675int remove_veth_links(const char *primary, char **pairs) {
676 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
677 char **a, **b;
678 int r;
679
680 /* In some cases the kernel might pin the veth links between host and container even after the namespace
681 * died. Hence, let's better remove them explicitly too. */
682
683 if (isempty(primary) && strv_isempty(pairs))
684 return 0;
685
686 r = sd_netlink_open(&rtnl);
687 if (r < 0)
688 return log_error_errno(r, "Failed to connect to netlink: %m");
689
22b28dfd 690 remove_one_link(rtnl, primary);
ef3b2aa7
LP
691
692 STRV_FOREACH_PAIR(a, b, pairs)
22b28dfd 693 remove_one_link(rtnl, *a);
ef3b2aa7
LP
694
695 return 0;
696}