]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/nspawn/nspawn-network.c
io.systemd.Unit.List fix context/runtime split (#38172)
[thirdparty/systemd.git] / src / nspawn / nspawn-network.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <linux/if.h>
4#include <linux/nl80211.h>
5#include <linux/veth.h>
6#include <net/if.h>
7#include <sys/file.h>
8#include <sys/mount.h>
9#include <unistd.h>
10
11#include "sd-device.h"
12#include "sd-id128.h"
13#include "sd-netlink.h"
14
15#include "alloc-util.h"
16#include "device-private.h"
17#include "device-util.h"
18#include "ether-addr-util.h"
19#include "extract-word.h"
20#include "fd-util.h"
21#include "lock-util.h"
22#include "mkdir.h"
23#include "mount-util.h"
24#include "namespace-util.h"
25#include "netif-util.h"
26#include "netlink-util.h"
27#include "nspawn-network.h"
28#include "pidref.h"
29#include "process-util.h"
30#include "socket-util.h"
31#include "stat-util.h"
32#include "string-util.h"
33#include "strv.h"
34#include "udev-util.h"
35
36#define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
37#define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
38#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)
39#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)
40#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
41
42static int remove_one_link(sd_netlink *rtnl, const char *name) {
43 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
44 int r;
45
46 if (isempty(name))
47 return 0;
48
49 r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
50 if (r < 0)
51 return log_error_errno(r, "Failed to allocate netlink message: %m");
52
53 r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
54 if (r < 0)
55 return log_error_errno(r, "Failed to add netlink interface name: %m");
56
57 r = sd_netlink_call(rtnl, m, 0, NULL);
58 if (r == -ENODEV) /* Already gone */
59 return 0;
60 if (r < 0)
61 return log_error_errno(r, "Failed to remove interface %s: %m", name);
62
63 return 1;
64}
65
66static int set_alternative_ifname(sd_netlink *rtnl, const char *ifname, const char *altifname) {
67 int r;
68
69 assert(rtnl);
70 assert(ifname);
71
72 if (!altifname)
73 return 0;
74
75 if (strlen(altifname) >= ALTIFNAMSIZ)
76 return log_warning_errno(SYNTHETIC_ERRNO(ERANGE),
77 "Alternative interface name '%s' for '%s' is too long, ignoring",
78 altifname, ifname);
79
80 r = rtnl_set_link_alternative_names_by_ifname(&rtnl, ifname, STRV_MAKE(altifname));
81 if (r < 0)
82 return log_warning_errno(r,
83 "Failed to set alternative interface name '%s' to '%s', ignoring: %m",
84 altifname, ifname);
85
86 return 0;
87}
88
89static int add_veth(
90 sd_netlink *rtnl,
91 const PidRef *pid,
92 const char *ifname_host,
93 const char *altifname_host,
94 const struct ether_addr *mac_host,
95 const char *ifname_container,
96 const struct ether_addr *mac_container) {
97
98 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
99 int r;
100
101 assert(rtnl);
102 assert(pidref_is_set(pid));
103 assert(ifname_host);
104 assert(mac_host);
105 assert(ifname_container);
106 assert(mac_container);
107
108 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
109 if (r < 0)
110 return log_error_errno(r, "Failed to allocate netlink message: %m");
111
112 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host);
113 if (r < 0)
114 return log_error_errno(r, "Failed to add netlink interface name: %m");
115
116 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host);
117 if (r < 0)
118 return log_error_errno(r, "Failed to add netlink MAC address: %m");
119
120 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
121 if (r < 0)
122 return log_error_errno(r, "Failed to open netlink container: %m");
123
124 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth");
125 if (r < 0)
126 return log_error_errno(r, "Failed to open netlink container: %m");
127
128 r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
129 if (r < 0)
130 return log_error_errno(r, "Failed to open netlink container: %m");
131
132 r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container);
133 if (r < 0)
134 return log_error_errno(r, "Failed to add netlink interface name: %m");
135
136 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container);
137 if (r < 0)
138 return log_error_errno(r, "Failed to add netlink MAC address: %m");
139
140 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid->pid);
141 if (r < 0)
142 return log_error_errno(r, "Failed to add netlink namespace field: %m");
143
144 r = sd_netlink_message_close_container(m);
145 if (r < 0)
146 return log_error_errno(r, "Failed to close netlink container: %m");
147
148 r = sd_netlink_message_close_container(m);
149 if (r < 0)
150 return log_error_errno(r, "Failed to close netlink container: %m");
151
152 r = sd_netlink_message_close_container(m);
153 if (r < 0)
154 return log_error_errno(r, "Failed to close netlink container: %m");
155
156 r = sd_netlink_call(rtnl, m, 0, NULL);
157 if (r < 0)
158 return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container);
159
160 (void) set_alternative_ifname(rtnl, ifname_host, altifname_host);
161
162 return 0;
163}
164
165int setup_veth(const char *machine_name,
166 const PidRef *pid,
167 char iface_name[IFNAMSIZ],
168 bool bridge,
169 const struct ether_addr *provided_mac) {
170
171 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
172 struct ether_addr mac_host, mac_container;
173 unsigned u;
174 char *n, *a = NULL;
175 int r;
176
177 assert(machine_name);
178 assert(pidref_is_set(pid));
179 assert(iface_name);
180
181 /* Use two different interface name prefixes depending whether
182 * we are in bridge mode or not. */
183 n = strjoina(bridge ? "vb-" : "ve-", machine_name);
184 r = net_shorten_ifname(n, /* check_naming_scheme= */ true);
185 if (r > 0)
186 a = strjoina(bridge ? "vb-" : "ve-", machine_name);
187
188 if (ether_addr_is_null(provided_mac)){
189 r = net_generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
190 if (r < 0)
191 return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m");
192 } else
193 mac_container = *provided_mac;
194
195 r = net_generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0);
196 if (r < 0)
197 return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
198
199 r = sd_netlink_open(&rtnl);
200 if (r < 0)
201 return log_error_errno(r, "Failed to connect to netlink: %m");
202
203 r = add_veth(rtnl, pid, n, a, &mac_host, "host0", &mac_container);
204 if (r < 0)
205 return r;
206
207 u = if_nametoindex(n); /* We don't need to use rtnl_resolve_ifname() here because the
208 * name we assigned is always the main name. */
209 if (u == 0)
210 return log_error_errno(errno, "Failed to resolve interface %s: %m", n);
211
212 strcpy(iface_name, n);
213 return (int) u;
214}
215
216int setup_veth_extra(
217 const char *machine_name,
218 const PidRef *pid,
219 char **pairs) {
220
221 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
222 uint64_t idx = 0;
223 int r;
224
225 assert(machine_name);
226 assert(pidref_is_set(pid));
227
228 if (strv_isempty(pairs))
229 return 0;
230
231 r = sd_netlink_open(&rtnl);
232 if (r < 0)
233 return log_error_errno(r, "Failed to connect to netlink: %m");
234
235 STRV_FOREACH_PAIR(a, b, pairs) {
236 struct ether_addr mac_host, mac_container;
237
238 r = net_generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
239 if (r < 0)
240 return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m");
241
242 r = net_generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx);
243 if (r < 0)
244 return log_error_errno(r, "Failed to generate predictable MAC address for host side of extra veth link: %m");
245
246 r = add_veth(rtnl, pid, *a, NULL, &mac_host, *b, &mac_container);
247 if (r < 0)
248 return r;
249
250 idx++;
251 }
252
253 return 0;
254}
255
256static int join_bridge(sd_netlink *rtnl, const char *veth_name, const char *bridge_name) {
257 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
258 int r, bridge_ifi;
259
260 assert(rtnl);
261 assert(veth_name);
262 assert(bridge_name);
263
264 bridge_ifi = rtnl_resolve_interface(&rtnl, bridge_name);
265 if (bridge_ifi < 0)
266 return bridge_ifi;
267
268 r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
269 if (r < 0)
270 return r;
271
272 r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
273 if (r < 0)
274 return r;
275
276 r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
277 if (r < 0)
278 return r;
279
280 r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
281 if (r < 0)
282 return r;
283
284 r = sd_netlink_call(rtnl, m, 0, NULL);
285 if (r < 0)
286 return r;
287
288 return bridge_ifi;
289}
290
291static int create_bridge(sd_netlink *rtnl, const char *bridge_name) {
292 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
293 int r;
294
295 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
296 if (r < 0)
297 return r;
298
299 r = sd_netlink_message_append_string(m, IFLA_IFNAME, bridge_name);
300 if (r < 0)
301 return r;
302
303 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
304 if (r < 0)
305 return r;
306
307 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "bridge");
308 if (r < 0)
309 return r;
310
311 r = sd_netlink_message_close_container(m);
312 if (r < 0)
313 return r;
314
315 r = sd_netlink_message_close_container(m);
316 if (r < 0)
317 return r;
318
319 r = sd_netlink_call(rtnl, m, 0, NULL);
320 if (r < 0)
321 return r;
322
323 return 0;
324}
325
326int setup_bridge(const char *veth_name, const char *bridge_name, bool create) {
327 _cleanup_(release_lock_file) LockFile bridge_lock = LOCK_FILE_INIT;
328 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
329 int r, bridge_ifi;
330 unsigned n = 0;
331
332 assert(veth_name);
333 assert(bridge_name);
334
335 r = sd_netlink_open(&rtnl);
336 if (r < 0)
337 return log_error_errno(r, "Failed to connect to netlink: %m");
338
339 if (create) {
340 /* We take a system-wide lock here, so that we can safely check whether there's still a member in the
341 * bridge before removing it, without risking interference from other nspawn instances. */
342
343 r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
344 if (r < 0)
345 return log_error_errno(r, "Failed to take network zone lock: %m");
346 }
347
348 for (;;) {
349 bridge_ifi = join_bridge(rtnl, veth_name, bridge_name);
350 if (bridge_ifi >= 0)
351 return bridge_ifi;
352 if (bridge_ifi != -ENODEV || !create || n > 10)
353 return log_error_errno(bridge_ifi, "Failed to add interface %s to bridge %s: %m", veth_name, bridge_name);
354
355 /* Count attempts, so that we don't enter an endless loop here. */
356 n++;
357
358 /* The bridge doesn't exist yet. Let's create it */
359 r = create_bridge(rtnl, bridge_name);
360 if (r < 0)
361 return log_error_errno(r, "Failed to create bridge interface %s: %m", bridge_name);
362
363 /* Try again, now that the bridge exists */
364 }
365}
366
367int remove_bridge(const char *bridge_name) {
368 _cleanup_(release_lock_file) LockFile bridge_lock = LOCK_FILE_INIT;
369 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
370 const char *path;
371 int r;
372
373 /* Removes the specified bridge, but only if it is currently empty */
374
375 if (isempty(bridge_name))
376 return 0;
377
378 r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
379 if (r < 0)
380 return log_error_errno(r, "Failed to take network zone lock: %m");
381
382 path = strjoina("/sys/class/net/", bridge_name, "/brif");
383
384 r = dir_is_empty(path, /* ignore_hidden_or_backup= */ false);
385 if (r == -ENOENT) /* Already gone? */
386 return 0;
387 if (r < 0)
388 return log_error_errno(r, "Can't detect if bridge %s is empty: %m", bridge_name);
389 if (r == 0) /* Still populated, leave it around */
390 return 0;
391
392 r = sd_netlink_open(&rtnl);
393 if (r < 0)
394 return log_error_errno(r, "Failed to connect to netlink: %m");
395
396 return remove_one_link(rtnl, bridge_name);
397}
398
399static int test_network_interface_initialized(const char *name) {
400 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
401 int r;
402
403 if (!udev_available())
404 return 0;
405
406 /* udev should be around. */
407
408 r = sd_device_new_from_ifname(&d, name);
409 if (r < 0)
410 return log_error_errno(r, "Failed to get device %s: %m", name);
411
412 r = device_is_processed(d);
413 if (r < 0)
414 return log_error_errno(r, "Failed to determine whether interface %s is initialized: %m", name);
415 if (r == 0)
416 return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Network interface %s is not initialized yet.", name);
417
418 r = device_is_renaming(d);
419 if (r < 0)
420 return log_error_errno(r, "Failed to determine the interface %s is being renamed: %m", name);
421 if (r > 0)
422 return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Interface %s is being renamed.", name);
423
424 return 0;
425}
426
427int test_network_interfaces_initialized(char **iface_pairs) {
428 int r;
429 STRV_FOREACH_PAIR(a, b, iface_pairs) {
430 r = test_network_interface_initialized(*a);
431 if (r < 0)
432 return r;
433 }
434 return 0;
435}
436
437int resolve_network_interface_names(char **iface_pairs) {
438 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
439 int r;
440
441 /* Due to a bug in kernel fixed by 8e15aee621618a3ee3abecaf1fd8c1428098b7ef (v6.6, backported to
442 * 6.1.60 and 6.5.9), an interface with alternative names cannot be resolved by the alternative name
443 * if the interface is moved to another network namespace. Hence, we need to adjust the provided
444 * names before moving interfaces to container namespace. */
445
446 STRV_FOREACH_PAIR(from, to, iface_pairs) {
447 _cleanup_free_ char *name = NULL;
448 _cleanup_strv_free_ char **altnames = NULL;
449
450 r = rtnl_resolve_ifname_full(&rtnl, _RESOLVE_IFNAME_ALL, *from, &name, &altnames);
451 if (r < 0)
452 return r;
453
454 /* Always use the resolved name for 'from'. */
455 free_and_replace(*from, name);
456
457 /* If the name 'to' is assigned as an alternative name, we cannot rename the interface.
458 * Hence, use the assigned interface name (including the alternative names) as is, and
459 * use the resolved name for 'to'. */
460 if (strv_contains(altnames, *to)) {
461 r = free_and_strdup_warn(to, *from);
462 if (r < 0)
463 return r;
464 }
465 }
466 return 0;
467}
468
469static int netns_child_begin(int netns_fd, int *ret_original_netns_fd) {
470 _cleanup_close_ int original_netns_fd = -EBADF;
471 int r;
472
473 assert(netns_fd >= 0);
474
475 if (ret_original_netns_fd) {
476 original_netns_fd = namespace_open_by_type(NAMESPACE_NET);
477 if (original_netns_fd < 0)
478 return log_error_errno(original_netns_fd, "Failed to open original network namespace: %m");
479 }
480
481 r = namespace_enter(/* pidns_fd = */ -EBADF,
482 /* mntns_fd = */ -EBADF,
483 netns_fd,
484 /* userns_fd = */ -EBADF,
485 /* root_fd = */ -EBADF);
486 if (r < 0)
487 return log_error_errno(r, "Failed to enter child network namespace: %m");
488
489 r = umount_recursive("/sys/", /* flags = */ 0);
490 if (r < 0)
491 log_debug_errno(r, "Failed to unmount directories below /sys/, ignoring: %m");
492
493 (void) mkdir_p("/sys/", 0755);
494
495 /* Populate new sysfs instance associated with the client netns, to make sd_device usable. */
496 r = mount_nofollow_verbose(LOG_ERR, "sysfs", "/sys/", "sysfs",
497 MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, /* options = */ NULL);
498 if (r < 0)
499 return log_error_errno(r, "Failed to mount sysfs on /sys/: %m");
500
501 /* udev_avaliable() might be called previously and the result may be cached.
502 * Now, we (re-)mount sysfs. Hence, we need to reset the cache. */
503 reset_cached_udev_availability();
504
505 if (ret_original_netns_fd)
506 *ret_original_netns_fd = TAKE_FD(original_netns_fd);
507
508 return 0;
509}
510
511static int netns_fork_and_wait(int netns_fd, int *ret_original_netns_fd) {
512 int r;
513
514 assert(netns_fd >= 0);
515
516 r = safe_fork("(sd-netns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL);
517 if (r < 0)
518 return log_error_errno(r, "Failed to fork process (sd-netns): %m");
519 if (r == 0) {
520 if (netns_child_begin(netns_fd, ret_original_netns_fd) < 0)
521 _exit(EXIT_FAILURE);
522
523 return 0;
524 }
525
526 if (ret_original_netns_fd)
527 *ret_original_netns_fd = -EBADF;
528
529 return 1;
530}
531
532static int move_wlan_interface_impl(sd_netlink **genl, int netns_fd, sd_device *dev) {
533 _cleanup_(sd_netlink_unrefp) sd_netlink *our_genl = NULL;
534 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
535 int r;
536
537 assert(netns_fd >= 0);
538 assert(dev);
539
540 if (!genl)
541 genl = &our_genl;
542 if (!*genl) {
543 r = sd_genl_socket_open(genl);
544 if (r < 0)
545 return log_error_errno(r, "Failed to connect to generic netlink: %m");
546 }
547
548 r = sd_genl_message_new(*genl, NL80211_GENL_NAME, NL80211_CMD_SET_WIPHY_NETNS, &m);
549 if (r < 0)
550 return log_device_error_errno(dev, r, "Failed to allocate netlink message: %m");
551
552 uint32_t phy_index;
553 r = device_get_sysattr_u32(dev, "phy80211/index", &phy_index);
554 if (r < 0)
555 return log_device_error_errno(dev, r, "Failed to get phy index: %m");
556
557 r = sd_netlink_message_append_u32(m, NL80211_ATTR_WIPHY, phy_index);
558 if (r < 0)
559 return log_device_error_errno(dev, r, "Failed to append phy index to netlink message: %m");
560
561 r = sd_netlink_message_append_u32(m, NL80211_ATTR_NETNS_FD, netns_fd);
562 if (r < 0)
563 return log_device_error_errno(dev, r, "Failed to append namespace fd to netlink message: %m");
564
565 r = sd_netlink_call(*genl, m, 0, NULL);
566 if (r < 0)
567 return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m");
568
569 return 0;
570}
571
572static int move_wlan_interface_one(
573 sd_netlink **rtnl,
574 sd_netlink **genl,
575 int *temp_netns_fd,
576 int netns_fd,
577 sd_device *dev,
578 const char *name) {
579
580 int r;
581
582 assert(rtnl);
583 assert(genl);
584 assert(temp_netns_fd);
585 assert(netns_fd >= 0);
586 assert(dev);
587
588 if (!name)
589 return move_wlan_interface_impl(genl, netns_fd, dev);
590
591 /* The command NL80211_CMD_SET_WIPHY_NETNS takes phy instead of network interface, and does not take
592 * an interface name in the passed network namespace. Hence, we need to move the phy and interface to
593 * a temporary network namespace, rename the interface in it, and move them to the requested netns. */
594
595 if (*temp_netns_fd < 0) {
596 r = netns_acquire();
597 if (r < 0)
598 return log_error_errno(r, "Failed to acquire new network namespace: %m");
599 *temp_netns_fd = r;
600 }
601
602 r = move_wlan_interface_impl(genl, *temp_netns_fd, dev);
603 if (r < 0)
604 return r;
605
606 const char *sysname;
607 r = sd_device_get_sysname(dev, &sysname);
608 if (r < 0)
609 return log_device_error_errno(dev, r, "Failed to get interface name: %m");
610
611 r = netns_fork_and_wait(*temp_netns_fd, NULL);
612 if (r < 0)
613 return log_error_errno(r, "Failed to fork process (nspawn-rename-wlan): %m");
614 if (r == 0) {
615 _cleanup_(sd_device_unrefp) sd_device *temp_dev = NULL;
616
617 r = rtnl_rename_link(NULL, sysname, name);
618 if (r < 0) {
619 log_error_errno(r, "Failed to rename network interface '%s' to '%s': %m", sysname, name);
620 goto finalize;
621 }
622
623 r = sd_device_new_from_ifname(&temp_dev, name);
624 if (r < 0) {
625 log_error_errno(r, "Failed to acquire device '%s': %m", name);
626 goto finalize;
627 }
628
629 r = move_wlan_interface_impl(NULL, netns_fd, temp_dev);
630
631 finalize:
632 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
633 }
634
635 return 0;
636}
637
638static int move_network_interface_one(sd_netlink **rtnl, int netns_fd, sd_device *dev, const char *name) {
639 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
640 int r;
641
642 assert(rtnl);
643 assert(netns_fd >= 0);
644 assert(dev);
645
646 if (!*rtnl) {
647 r = sd_netlink_open(rtnl);
648 if (r < 0)
649 return log_error_errno(r, "Failed to connect to rtnetlink: %m");
650 }
651
652 int ifindex;
653 r = sd_device_get_ifindex(dev, &ifindex);
654 if (r < 0)
655 return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
656
657 r = sd_rtnl_message_new_link(*rtnl, &m, RTM_SETLINK, ifindex);
658 if (r < 0)
659 return log_device_error_errno(dev, r, "Failed to allocate netlink message: %m");
660
661 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_FD, netns_fd);
662 if (r < 0)
663 return log_device_error_errno(dev, r, "Failed to append namespace fd to netlink message: %m");
664
665 if (name) {
666 r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
667 if (r < 0)
668 return log_device_error_errno(dev, r, "Failed to add netlink interface name: %m");
669 }
670
671 r = sd_netlink_call(*rtnl, m, 0, NULL);
672 if (r < 0)
673 return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m");
674
675 return 0;
676}
677
678int move_network_interfaces(int netns_fd, char **iface_pairs) {
679 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL, *genl = NULL;
680 _cleanup_close_ int temp_netns_fd = -EBADF;
681 int r;
682
683 assert(netns_fd >= 0);
684
685 if (strv_isempty(iface_pairs))
686 return 0;
687
688 STRV_FOREACH_PAIR(from, to, iface_pairs) {
689 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
690 const char *name;
691
692 name = streq(*from, *to) ? NULL : *to;
693
694 r = sd_device_new_from_ifname(&dev, *from);
695 if (r < 0)
696 return log_error_errno(r, "Unknown interface name %s: %m", *from);
697
698 if (device_is_devtype(dev, "wlan"))
699 r = move_wlan_interface_one(&rtnl, &genl, &temp_netns_fd, netns_fd, dev, name);
700 else
701 r = move_network_interface_one(&rtnl, netns_fd, dev, name);
702 if (r < 0)
703 return r;
704 }
705
706 return 0;
707}
708
709int move_back_network_interfaces(int child_netns_fd, char **interface_pairs) {
710 _cleanup_close_ int parent_netns_fd = -EBADF;
711 int r;
712
713 assert(child_netns_fd >= 0);
714
715 if (strv_isempty(interface_pairs))
716 return 0;
717
718 r = netns_fork_and_wait(child_netns_fd, &parent_netns_fd);
719 if (r < 0)
720 return r;
721 if (r == 0) {
722 /* Reverse network interfaces pair list so that interfaces get their initial name back.
723 * This is about ensuring interfaces get their old name back when being moved back. */
724 interface_pairs = strv_reverse(interface_pairs);
725
726 r = move_network_interfaces(parent_netns_fd, interface_pairs);
727 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
728 }
729
730 return 0;
731}
732
733int setup_macvlan(const char *machine_name, const PidRef *pid, char **iface_pairs) {
734 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
735 unsigned idx = 0;
736 int r;
737
738 assert(pidref_is_set(pid));
739
740 if (strv_isempty(iface_pairs))
741 return 0;
742
743 r = sd_netlink_open(&rtnl);
744 if (r < 0)
745 return log_error_errno(r, "Failed to connect to netlink: %m");
746
747 STRV_FOREACH_PAIR(i, b, iface_pairs) {
748 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
749 _cleanup_free_ char *n = NULL;
750 int shortened, ifi;
751 struct ether_addr mac;
752
753 ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
754 if (ifi < 0)
755 return ifi;
756
757 r = net_generate_mac(machine_name, &mac, MACVLAN_HASH_KEY, idx++);
758 if (r < 0)
759 return log_error_errno(r, "Failed to create MACVLAN MAC address: %m");
760
761 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
762 if (r < 0)
763 return log_error_errno(r, "Failed to allocate netlink message: %m");
764
765 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
766 if (r < 0)
767 return log_error_errno(r, "Failed to add netlink interface index: %m");
768
769 n = strdup(*b);
770 if (!n)
771 return log_oom();
772
773 shortened = net_shorten_ifname(n, /* check_naming_scheme= */ true);
774
775 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
776 if (r < 0)
777 return log_error_errno(r, "Failed to add netlink interface name: %m");
778
779 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac);
780 if (r < 0)
781 return log_error_errno(r, "Failed to add netlink MAC address: %m");
782
783 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid->pid);
784 if (r < 0)
785 return log_error_errno(r, "Failed to add netlink namespace field: %m");
786
787 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
788 if (r < 0)
789 return log_error_errno(r, "Failed to open netlink container: %m");
790
791 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "macvlan");
792 if (r < 0)
793 return log_error_errno(r, "Failed to open netlink container: %m");
794
795 r = sd_netlink_message_append_u32(m, IFLA_MACVLAN_MODE, MACVLAN_MODE_BRIDGE);
796 if (r < 0)
797 return log_error_errno(r, "Failed to append macvlan mode: %m");
798
799 r = sd_netlink_message_close_container(m);
800 if (r < 0)
801 return log_error_errno(r, "Failed to close netlink container: %m");
802
803 r = sd_netlink_message_close_container(m);
804 if (r < 0)
805 return log_error_errno(r, "Failed to close netlink container: %m");
806
807 r = sd_netlink_call(rtnl, m, 0, NULL);
808 if (r < 0)
809 return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
810
811 if (shortened > 0)
812 (void) set_alternative_ifname(rtnl, n, *b);
813 }
814
815 return 0;
816}
817
818static int remove_macvlan_impl(char **interface_pairs) {
819 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
820 int r;
821
822 assert(interface_pairs);
823
824 r = sd_netlink_open(&rtnl);
825 if (r < 0)
826 return log_error_errno(r, "Failed to connect to netlink: %m");
827
828 STRV_FOREACH_PAIR(a, b, interface_pairs) {
829 _cleanup_free_ char *n = NULL;
830
831 n = strdup(*b);
832 if (!n)
833 return log_oom();
834
835 (void) net_shorten_ifname(n, /* check_naming_scheme= */ true);
836
837 r = remove_one_link(rtnl, n);
838 if (r < 0)
839 log_warning_errno(r, "Failed to remove macvlan interface %s, ignoring: %m", n);
840 }
841
842 return 0;
843}
844
845int remove_macvlan(int child_netns_fd, char **interface_pairs) {
846 _cleanup_close_ int parent_netns_fd = -EBADF;
847 int r;
848
849 /* In some cases the kernel might pin the macvlan links on the container even after the namespace
850 * died. Hence, let's better remove them explicitly too. See issue #680. */
851
852 assert(child_netns_fd >= 0);
853
854 if (strv_isempty(interface_pairs))
855 return 0;
856
857 r = netns_fork_and_wait(child_netns_fd, &parent_netns_fd);
858 if (r < 0)
859 return r;
860 if (r == 0) {
861 r = remove_macvlan_impl(interface_pairs);
862 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
863 }
864
865 return 0;
866}
867
868int setup_ipvlan(const char *machine_name, const PidRef *pid, char **iface_pairs) {
869 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
870 int r;
871
872 assert(pidref_is_set(pid));
873
874 if (strv_isempty(iface_pairs))
875 return 0;
876
877 r = sd_netlink_open(&rtnl);
878 if (r < 0)
879 return log_error_errno(r, "Failed to connect to netlink: %m");
880
881 STRV_FOREACH_PAIR(i, b, iface_pairs) {
882 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
883 _cleanup_free_ char *n = NULL;
884 int shortened, ifi ;
885
886 ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
887 if (ifi < 0)
888 return ifi;
889
890 r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
891 if (r < 0)
892 return log_error_errno(r, "Failed to allocate netlink message: %m");
893
894 r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
895 if (r < 0)
896 return log_error_errno(r, "Failed to add netlink interface index: %m");
897
898 n = strdup(*b);
899 if (!n)
900 return log_oom();
901
902 shortened = net_shorten_ifname(n, /* check_naming_scheme= */ true);
903
904 r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
905 if (r < 0)
906 return log_error_errno(r, "Failed to add netlink interface name: %m");
907
908 r = sd_netlink_message_append_u32(m, IFLA_NET_NS_PID, pid->pid);
909 if (r < 0)
910 return log_error_errno(r, "Failed to add netlink namespace field: %m");
911
912 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
913 if (r < 0)
914 return log_error_errno(r, "Failed to open netlink container: %m");
915
916 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "ipvlan");
917 if (r < 0)
918 return log_error_errno(r, "Failed to open netlink container: %m");
919
920 r = sd_netlink_message_append_u16(m, IFLA_IPVLAN_MODE, IPVLAN_MODE_L2);
921 if (r < 0)
922 return log_error_errno(r, "Failed to add ipvlan mode: %m");
923
924 r = sd_netlink_message_close_container(m);
925 if (r < 0)
926 return log_error_errno(r, "Failed to close netlink container: %m");
927
928 r = sd_netlink_message_close_container(m);
929 if (r < 0)
930 return log_error_errno(r, "Failed to close netlink container: %m");
931
932 r = sd_netlink_call(rtnl, m, 0, NULL);
933 if (r < 0)
934 return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
935
936 if (shortened > 0)
937 (void) set_alternative_ifname(rtnl, n, *b);
938 }
939
940 return 0;
941}
942
943int veth_extra_parse(char ***l, const char *p) {
944 _cleanup_free_ char *a = NULL, *b = NULL;
945 int r;
946
947 r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
948 if (r < 0)
949 return r;
950 if (r == 0 || !ifname_valid(a))
951 return -EINVAL;
952
953 r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
954 if (r < 0)
955 return r;
956 if (r == 0 || !ifname_valid(b)) {
957 r = free_and_strdup(&b, a);
958 if (r < 0)
959 return r;
960 }
961
962 if (p)
963 return -EINVAL;
964
965 r = strv_push_pair(l, a, b);
966 if (r < 0)
967 return -ENOMEM;
968
969 a = b = NULL;
970 return 0;
971}
972
973int remove_veth_links(const char *primary, char **pairs) {
974 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
975 int r;
976
977 /* In some cases the kernel might pin the veth links between host and container even after the namespace
978 * died. Hence, let's better remove them explicitly too. */
979
980 if (isempty(primary) && strv_isempty(pairs))
981 return 0;
982
983 r = sd_netlink_open(&rtnl);
984 if (r < 0)
985 return log_error_errno(r, "Failed to connect to netlink: %m");
986
987 remove_one_link(rtnl, primary);
988
989 STRV_FOREACH_PAIR(a, b, pairs)
990 remove_one_link(rtnl, *a);
991
992 return 0;
993}
994
995static int network_iface_pair_parse(const char* iftype, char ***l, const char *p, const char* ifprefix) {
996 int r;
997
998 for (;;) {
999 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
1000 const char *interface;
1001
1002 r = extract_first_word(&p, &word, NULL, 0);
1003 if (r < 0)
1004 return log_error_errno(r, "Failed to parse interface name: %m");
1005 if (r == 0)
1006 break;
1007
1008 interface = word;
1009 r = extract_first_word(&interface, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1010 if (r < 0)
1011 return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype);
1012 if (r == 0)
1013 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1014 "Short read while reading %s parameter: %m", iftype);
1015 if (!ifname_valid(a))
1016 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1017 "%s, interface name not valid: %s", iftype, a);
1018
1019 /* Here, we only check the validity of the specified second name. If it is not specified,
1020 * the copied or prefixed name should be already valid, except for its length. If it is too
1021 * long, then it will be shortened later. */
1022 if (!isempty(interface)) {
1023 if (!ifname_valid(interface))
1024 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1025 "%s, interface name not valid: %s", iftype, interface);
1026
1027 b = strdup(interface);
1028 } else if (ifprefix)
1029 b = strjoin(ifprefix, a);
1030 else
1031 b = strdup(a);
1032 if (!b)
1033 return log_oom();
1034
1035 r = strv_consume_pair(l, TAKE_PTR(a), TAKE_PTR(b));
1036 if (r < 0)
1037 return log_oom();
1038 }
1039
1040 return 0;
1041}
1042
1043int interface_pair_parse(char ***l, const char *p) {
1044 return network_iface_pair_parse("Network interface", l, p, NULL);
1045}
1046
1047int macvlan_pair_parse(char ***l, const char *p) {
1048 return network_iface_pair_parse("MACVLAN network interface", l, p, "mv-");
1049}
1050
1051int ipvlan_pair_parse(char ***l, const char *p) {
1052 return network_iface_pair_parse("IPVLAN network interface", l, p, "iv-");
1053}