• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15986406979

30 Jun 2025 05:03PM UTC coverage: 72.045% (-0.09%) from 72.13%
15986406979

push

github

bluca
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options

ephemeral/ephemeral-import are described as possible '--mutable' options but
not present in the list. Note, "systemd-sysext --help" lists them correctly.

300514 of 417119 relevant lines covered (72.05%)

708586.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.76
/src/nspawn/nspawn-network.c
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

42
static int remove_one_link(sd_netlink *rtnl, const char *name) {
27✔
43
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
27✔
44
        int r;
27✔
45

46
        if (isempty(name))
54✔
47
                return 0;
48

49
        r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
27✔
50
        if (r < 0)
27✔
51
                return log_error_errno(r, "Failed to allocate netlink message: %m");
×
52

53
        r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
27✔
54
        if (r < 0)
27✔
55
                return log_error_errno(r, "Failed to add netlink interface name: %m");
×
56

57
        r = sd_netlink_call(rtnl, m, 0, NULL);
27✔
58
        if (r == -ENODEV) /* Already gone */
27✔
59
                return 0;
60
        if (r < 0)
6✔
61
                return log_error_errno(r, "Failed to remove interface %s: %m", name);
×
62

63
        return 1;
64
}
65

66
static int set_alternative_ifname(sd_netlink *rtnl, const char *ifname, const char *altifname) {
40✔
67
        int r;
40✔
68

69
        assert(rtnl);
40✔
70
        assert(ifname);
40✔
71

72
        if (!altifname)
40✔
73
                return 0;
40✔
74

75
        if (strlen(altifname) >= ALTIFNAMSIZ)
23✔
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));
23✔
81
        if (r < 0)
23✔
82
                return log_warning_errno(r,
8✔
83
                                         "Failed to set alternative interface name '%s' to '%s', ignoring: %m",
84
                                         altifname, ifname);
85

86
        return 0;
87
}
88

89
static int add_veth(
32✔
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;
32✔
99
        int r;
32✔
100

101
        assert(rtnl);
32✔
102
        assert(pidref_is_set(pid));
32✔
103
        assert(ifname_host);
32✔
104
        assert(mac_host);
32✔
105
        assert(ifname_container);
32✔
106
        assert(mac_container);
32✔
107

108
        r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
32✔
109
        if (r < 0)
32✔
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);
32✔
113
        if (r < 0)
32✔
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);
32✔
117
        if (r < 0)
32✔
118
                return log_error_errno(r, "Failed to add netlink MAC address: %m");
×
119

120
        r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
32✔
121
        if (r < 0)
32✔
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");
32✔
125
        if (r < 0)
32✔
126
                return log_error_errno(r, "Failed to open netlink container: %m");
×
127

128
        r = sd_netlink_message_open_container(m, VETH_INFO_PEER);
32✔
129
        if (r < 0)
32✔
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);
32✔
133
        if (r < 0)
32✔
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);
32✔
137
        if (r < 0)
32✔
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);
32✔
141
        if (r < 0)
32✔
142
                return log_error_errno(r, "Failed to add netlink namespace field: %m");
×
143

144
        r = sd_netlink_message_close_container(m);
32✔
145
        if (r < 0)
32✔
146
                return log_error_errno(r, "Failed to close netlink container: %m");
×
147

148
        r = sd_netlink_message_close_container(m);
32✔
149
        if (r < 0)
32✔
150
                return log_error_errno(r, "Failed to close netlink container: %m");
×
151

152
        r = sd_netlink_message_close_container(m);
32✔
153
        if (r < 0)
32✔
154
                return log_error_errno(r, "Failed to close netlink container: %m");
×
155

156
        r = sd_netlink_call(rtnl, m, 0, NULL);
32✔
157
        if (r < 0)
32✔
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);
32✔
161

162
        return 0;
163
}
164

165
int setup_veth(const char *machine_name,
24✔
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;
24✔
172
        struct ether_addr mac_host, mac_container;
24✔
173
        unsigned u;
24✔
174
        char *n, *a = NULL;
24✔
175
        int r;
24✔
176

177
        assert(machine_name);
24✔
178
        assert(pidref_is_set(pid));
24✔
179
        assert(iface_name);
24✔
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);
140✔
184
        r = net_shorten_ifname(n, /* check_naming_scheme= */ true);
24✔
185
        if (r > 0)
24✔
186
                a = strjoina(bridge ? "vb-" : "ve-", machine_name);
75✔
187

188
        if (ether_addr_is_null(provided_mac)){
24✔
189
                r = net_generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
24✔
190
                if (r < 0)
24✔
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);
24✔
196
        if (r < 0)
24✔
197
                return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m");
×
198

199
        r = sd_netlink_open(&rtnl);
24✔
200
        if (r < 0)
24✔
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);
24✔
204
        if (r < 0)
24✔
205
                return r;
206

207
        u = if_nametoindex(n); /* We don't need to use rtnl_resolve_ifname() here because the
24✔
208
                                * name we assigned is always the main name. */
209
        if (u == 0)
24✔
210
                return log_error_errno(errno, "Failed to resolve interface %s: %m", n);
×
211

212
        strcpy(iface_name, n);
24✔
213
        return (int) u;
24✔
214
}
215

216
int setup_veth_extra(
54✔
217
                const char *machine_name,
218
                const PidRef *pid,
219
                char **pairs) {
220

221
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
54✔
222
        uint64_t idx = 0;
54✔
223
        int r;
54✔
224

225
        assert(machine_name);
54✔
226
        assert(pidref_is_set(pid));
54✔
227

228
        if (strv_isempty(pairs))
58✔
229
                return 0;
230

231
        r = sd_netlink_open(&rtnl);
4✔
232
        if (r < 0)
4✔
233
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
234

235
        STRV_FOREACH_PAIR(a, b, pairs) {
12✔
236
                struct ether_addr mac_host, mac_container;
8✔
237

238
                r = net_generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx);
8✔
239
                if (r < 0)
8✔
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);
8✔
243
                if (r < 0)
8✔
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);
8✔
247
                if (r < 0)
8✔
248
                        return r;
249

250
                idx++;
8✔
251
        }
252

253
        return 0;
254
}
255

256
static int join_bridge(sd_netlink *rtnl, const char *veth_name, const char *bridge_name) {
8✔
257
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
8✔
258
        int r, bridge_ifi;
8✔
259

260
        assert(rtnl);
8✔
261
        assert(veth_name);
8✔
262
        assert(bridge_name);
8✔
263

264
        bridge_ifi = rtnl_resolve_interface(&rtnl, bridge_name);
8✔
265
        if (bridge_ifi < 0)
8✔
266
                return bridge_ifi;
267

268
        r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
4✔
269
        if (r < 0)
4✔
270
                return r;
271

272
        r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
4✔
273
        if (r < 0)
4✔
274
                return r;
275

276
        r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
4✔
277
        if (r < 0)
4✔
278
                return r;
279

280
        r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
4✔
281
        if (r < 0)
4✔
282
                return r;
283

284
        r = sd_netlink_call(rtnl, m, 0, NULL);
4✔
285
        if (r < 0)
4✔
286
                return r;
×
287

288
        return bridge_ifi;
289
}
290

291
static int create_bridge(sd_netlink *rtnl, const char *bridge_name) {
4✔
292
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
4✔
293
        int r;
4✔
294

295
        r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
4✔
296
        if (r < 0)
4✔
297
                return r;
298

299
        r = sd_netlink_message_append_string(m, IFLA_IFNAME, bridge_name);
4✔
300
        if (r < 0)
4✔
301
                return r;
302

303
        r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
4✔
304
        if (r < 0)
4✔
305
                return r;
306

307
        r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "bridge");
4✔
308
        if (r < 0)
4✔
309
                return r;
310

311
        r = sd_netlink_message_close_container(m);
4✔
312
        if (r < 0)
4✔
313
                return r;
314

315
        r = sd_netlink_message_close_container(m);
4✔
316
        if (r < 0)
4✔
317
                return r;
318

319
        r = sd_netlink_call(rtnl, m, 0, NULL);
4✔
320
        if (r < 0)
4✔
321
                return r;
×
322

323
        return 0;
324
}
325

326
int setup_bridge(const char *veth_name, const char *bridge_name, bool create) {
4✔
327
        _cleanup_(release_lock_file) LockFile bridge_lock = LOCK_FILE_INIT;
×
328
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
4✔
329
        int r, bridge_ifi;
4✔
330
        unsigned n = 0;
4✔
331

332
        assert(veth_name);
4✔
333
        assert(bridge_name);
4✔
334

335
        r = sd_netlink_open(&rtnl);
4✔
336
        if (r < 0)
4✔
337
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
338

339
        if (create) {
4✔
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);
4✔
344
                if (r < 0)
4✔
345
                        return log_error_errno(r, "Failed to take network zone lock: %m");
×
346
        }
347

348
        for (;;) {
8✔
349
                bridge_ifi = join_bridge(rtnl, veth_name, bridge_name);
8✔
350
                if (bridge_ifi >= 0)
8✔
351
                        return bridge_ifi;
352
                if (bridge_ifi != -ENODEV || !create || n > 10)
4✔
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++;
4✔
357

358
                /* The bridge doesn't exist yet. Let's create it */
359
                r = create_bridge(rtnl, bridge_name);
4✔
360
                if (r < 0)
4✔
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

367
int remove_bridge(const char *bridge_name) {
350✔
368
        _cleanup_(release_lock_file) LockFile bridge_lock = LOCK_FILE_INIT;
×
369
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
350✔
370
        const char *path;
350✔
371
        int r;
350✔
372

373
        /* Removes the specified bridge, but only if it is currently empty */
374

375
        if (isempty(bridge_name))
357✔
376
                return 0;
377

378
        r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
7✔
379
        if (r < 0)
7✔
380
                return log_error_errno(r, "Failed to take network zone lock: %m");
×
381

382
        path = strjoina("/sys/class/net/", bridge_name, "/brif");
49✔
383

384
        r = dir_is_empty(path, /* ignore_hidden_or_backup= */ false);
7✔
385
        if (r == -ENOENT) /* Already gone? */
7✔
386
                return 0;
387
        if (r < 0)
1✔
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 */
1✔
390
                return 0;
391

392
        r = sd_netlink_open(&rtnl);
1✔
393
        if (r < 0)
1✔
394
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
395

396
        return remove_one_link(rtnl, bridge_name);
1✔
397
}
398

399
static int test_network_interface_initialized(const char *name) {
79✔
400
        _cleanup_(sd_device_unrefp) sd_device *d = NULL;
79✔
401
        int r;
79✔
402

403
        if (!udev_available())
79✔
404
                return 0;
405

406
        /* udev should be around. */
407

408
        r = sd_device_new_from_ifname(&d, name);
79✔
409
        if (r < 0)
79✔
410
                return log_error_errno(r, "Failed to get device %s: %m", name);
2✔
411

412
        r = device_is_processed(d);
77✔
413
        if (r < 0)
77✔
414
                return log_error_errno(r, "Failed to determine whether interface %s is initialized: %m", name);
×
415
        if (r == 0)
77✔
416
                return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Network interface %s is not initialized yet.", name);
×
417

418
        r = device_is_renaming(d);
77✔
419
        if (r < 0)
77✔
420
                return log_error_errno(r, "Failed to determine the interface %s is being renamed: %m", name);
×
421
        if (r > 0)
77✔
422
                return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Interface %s is being renamed.", name);
×
423

424
        return 0;
425
}
426

427
int test_network_interfaces_initialized(char **iface_pairs) {
1,208✔
428
        int r;
1,208✔
429
        STRV_FOREACH_PAIR(a, b, iface_pairs) {
1,285✔
430
                r = test_network_interface_initialized(*a);
79✔
431
                if (r < 0)
79✔
432
                        return r;
433
        }
434
        return 0;
435
}
436

437
int resolve_network_interface_names(char **iface_pairs) {
404✔
438
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
404✔
439
        int r;
404✔
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) {
439✔
447
                _cleanup_free_ char *name = NULL;
36✔
448
                _cleanup_strv_free_ char **altnames = NULL;
36✔
449

450
                r = rtnl_resolve_ifname_full(&rtnl, _RESOLVE_IFNAME_ALL, *from, &name, &altnames);
36✔
451
                if (r < 0)
36✔
452
                        return r;
453

454
                /* Always use the resolved name for 'from'. */
455
                free_and_replace(*from, name);
35✔
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)) {
35✔
461
                        r = free_and_strdup_warn(to, *from);
7✔
462
                        if (r < 0)
7✔
463
                                return r;
464
                }
465
        }
466
        return 0;
467
}
468

469
static int netns_child_begin(int netns_fd, int *ret_original_netns_fd) {
5✔
470
        _cleanup_close_ int original_netns_fd = -EBADF;
5✔
471
        int r;
5✔
472

473
        assert(netns_fd >= 0);
5✔
474

475
        if (ret_original_netns_fd) {
5✔
476
                original_netns_fd = namespace_open_by_type(NAMESPACE_NET);
3✔
477
                if (original_netns_fd < 0)
3✔
478
                        return log_error_errno(original_netns_fd, "Failed to open original network namespace: %m");
×
479
        }
480

481
        r = namespace_enter(/* pidns_fd = */ -EBADF,
5✔
482
                            /* mntns_fd = */ -EBADF,
483
                            netns_fd,
484
                            /* userns_fd = */ -EBADF,
485
                            /* root_fd = */ -EBADF);
486
        if (r < 0)
5✔
487
                return log_error_errno(r, "Failed to enter child network namespace: %m");
×
488

489
        r = umount_recursive("/sys/", /* flags = */ 0);
5✔
490
        if (r < 0)
5✔
491
                log_debug_errno(r, "Failed to unmount directories below /sys/, ignoring: %m");
×
492

493
        (void) mkdir_p("/sys/", 0755);
5✔
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",
5✔
497
                                   MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, /* options = */ NULL);
498
        if (r < 0)
5✔
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();
5✔
504

505
        if (ret_original_netns_fd)
5✔
506
                *ret_original_netns_fd = TAKE_FD(original_netns_fd);
3✔
507

508
        return 0;
509
}
510

511
static int netns_fork_and_wait(int netns_fd, int *ret_original_netns_fd) {
13✔
512
        int r;
13✔
513

514
        assert(netns_fd >= 0);
13✔
515

516
        r = safe_fork("(sd-netns)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE, NULL);
13✔
517
        if (r < 0)
13✔
518
                return log_error_errno(r, "Failed to fork process (sd-netns): %m");
×
519
        if (r == 0) {
13✔
520
                if (netns_child_begin(netns_fd, ret_original_netns_fd) < 0)
5✔
521
                        _exit(EXIT_FAILURE);
×
522

523
                return 0;
524
        }
525

526
        if (ret_original_netns_fd)
8✔
527
                *ret_original_netns_fd = -EBADF;
3✔
528

529
        return 1;
530
}
531

532
static int move_wlan_interface_impl(sd_netlink **genl, int netns_fd, sd_device *dev) {
15✔
533
        _cleanup_(sd_netlink_unrefp) sd_netlink *our_genl = NULL;
15✔
534
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
15✔
535
        int r;
15✔
536

537
        assert(netns_fd >= 0);
15✔
538
        assert(dev);
15✔
539

540
        if (!genl)
15✔
541
                genl = &our_genl;
2✔
542
        if (!*genl) {
15✔
543
                r = sd_genl_socket_open(genl);
9✔
544
                if (r < 0)
9✔
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);
15✔
549
        if (r < 0)
15✔
550
                return log_device_error_errno(dev, r, "Failed to allocate netlink message: %m");
×
551

552
        uint32_t phy_index;
15✔
553
        r = device_get_sysattr_u32(dev, "phy80211/index", &phy_index);
15✔
554
        if (r < 0)
15✔
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);
15✔
558
        if (r < 0)
15✔
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);
15✔
562
        if (r < 0)
15✔
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);
15✔
566
        if (r < 0)
15✔
567
                return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m");
×
568

569
        return 0;
570
}
571

572
static int move_wlan_interface_one(
13✔
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;
13✔
581

582
        assert(rtnl);
13✔
583
        assert(genl);
13✔
584
        assert(temp_netns_fd);
13✔
585
        assert(netns_fd >= 0);
13✔
586
        assert(dev);
13✔
587

588
        if (!name)
13✔
589
                return move_wlan_interface_impl(genl, netns_fd, dev);
11✔
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) {
7✔
596
                r = netns_acquire();
7✔
597
                if (r < 0)
7✔
598
                        return log_error_errno(r, "Failed to acquire new network namespace: %m");
×
599
                *temp_netns_fd = r;
7✔
600
        }
601

602
        r = move_wlan_interface_impl(genl, *temp_netns_fd, dev);
7✔
603
        if (r < 0)
7✔
604
                return r;
605

606
        const char *sysname;
7✔
607
        r = sd_device_get_sysname(dev, &sysname);
7✔
608
        if (r < 0)
7✔
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);
7✔
612
        if (r < 0)
7✔
613
                return log_error_errno(r, "Failed to fork process (nspawn-rename-wlan): %m");
×
614
        if (r == 0) {
7✔
615
                _cleanup_(sd_device_unrefp) sd_device *temp_dev = NULL;
2✔
616

617
                r = rtnl_rename_link(NULL, sysname, name);
2✔
618
                if (r < 0) {
2✔
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);
2✔
624
                if (r < 0) {
2✔
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);
2✔
630

631
        finalize:
2✔
632
                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
2✔
633
        }
634

635
        return 0;
636
}
637

638
static int move_network_interface_one(sd_netlink **rtnl, int netns_fd, sd_device *dev, const char *name) {
18✔
639
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
18✔
640
        int r;
18✔
641

642
        assert(rtnl);
18✔
643
        assert(netns_fd >= 0);
18✔
644
        assert(dev);
18✔
645

646
        if (!*rtnl) {
18✔
647
                r = sd_netlink_open(rtnl);
6✔
648
                if (r < 0)
6✔
649
                        return log_error_errno(r, "Failed to connect to rtnetlink: %m");
×
650
        }
651

652
        int ifindex;
18✔
653
        r = sd_device_get_ifindex(dev, &ifindex);
18✔
654
        if (r < 0)
18✔
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);
18✔
658
        if (r < 0)
18✔
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);
18✔
662
        if (r < 0)
18✔
663
                return log_device_error_errno(dev, r, "Failed to append namespace fd to netlink message: %m");
×
664

665
        if (name) {
18✔
666
                r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
6✔
667
                if (r < 0)
6✔
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);
18✔
672
        if (r < 0)
18✔
673
                return log_device_error_errno(dev, r, "Failed to move interface to namespace: %m");
×
674

675
        return 0;
676
}
677

678
int move_network_interfaces(int netns_fd, char **iface_pairs) {
57✔
679
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL, *genl = NULL;
60✔
680
        _cleanup_close_ int temp_netns_fd = -EBADF;
55✔
681
        int r;
57✔
682

683
        assert(netns_fd >= 0);
57✔
684

685
        if (strv_isempty(iface_pairs))
62✔
686
                return 0;
687

688
        STRV_FOREACH_PAIR(from, to, iface_pairs) {
36✔
689
                _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
29✔
690
                const char *name;
31✔
691

692
                name = streq(*from, *to) ? NULL : *to;
31✔
693

694
                r = sd_device_new_from_ifname(&dev, *from);
31✔
695
                if (r < 0)
31✔
696
                        return log_error_errno(r, "Unknown interface name %s: %m", *from);
×
697

698
                if (device_is_devtype(dev, "wlan"))
31✔
699
                        r = move_wlan_interface_one(&rtnl, &genl, &temp_netns_fd, netns_fd, dev, name);
13✔
700
                else
701
                        r = move_network_interface_one(&rtnl, netns_fd, dev, name);
18✔
702
                if (r < 0)
29✔
703
                        return r;
704
        }
705

706
        return 0;
707
}
708

709
int move_back_network_interfaces(int child_netns_fd, char **interface_pairs) {
47✔
710
        _cleanup_close_ int parent_netns_fd = -EBADF;
45✔
711
        int r;
47✔
712

713
        assert(child_netns_fd >= 0);
47✔
714

715
        if (strv_isempty(interface_pairs))
49✔
716
                return 0;
717

718
        r = netns_fork_and_wait(child_netns_fd, &parent_netns_fd);
4✔
719
        if (r < 0)
4✔
720
                return r;
721
        if (r == 0) {
4✔
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);
2✔
725

726
                r = move_network_interfaces(parent_netns_fd, interface_pairs);
2✔
727
                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
1✔
728
        }
729

730
        return 0;
731
}
732

733
int setup_macvlan(const char *machine_name, const PidRef *pid, char **iface_pairs) {
54✔
734
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
54✔
735
        unsigned idx = 0;
54✔
736
        int r;
54✔
737

738
        assert(pidref_is_set(pid));
54✔
739

740
        if (strv_isempty(iface_pairs))
58✔
741
                return 0;
742

743
        r = sd_netlink_open(&rtnl);
4✔
744
        if (r < 0)
4✔
745
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
746

747
        STRV_FOREACH_PAIR(i, b, iface_pairs) {
16✔
748
                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
12✔
749
                _cleanup_free_ char *n = NULL;
12✔
750
                int shortened, ifi;
12✔
751
                struct ether_addr mac;
12✔
752

753
                ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
12✔
754
                if (ifi < 0)
12✔
755
                        return ifi;
756

757
                r = net_generate_mac(machine_name, &mac, MACVLAN_HASH_KEY, idx++);
12✔
758
                if (r < 0)
12✔
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);
12✔
762
                if (r < 0)
12✔
763
                        return log_error_errno(r, "Failed to allocate netlink message: %m");
×
764

765
                r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
12✔
766
                if (r < 0)
12✔
767
                        return log_error_errno(r, "Failed to add netlink interface index: %m");
×
768

769
                n = strdup(*b);
12✔
770
                if (!n)
12✔
771
                        return log_oom();
×
772

773
                shortened = net_shorten_ifname(n, /* check_naming_scheme= */ true);
12✔
774

775
                r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
12✔
776
                if (r < 0)
12✔
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);
12✔
780
                if (r < 0)
12✔
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);
12✔
784
                if (r < 0)
12✔
785
                        return log_error_errno(r, "Failed to add netlink namespace field: %m");
×
786

787
                r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
12✔
788
                if (r < 0)
12✔
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");
12✔
792
                if (r < 0)
12✔
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);
12✔
796
                if (r < 0)
12✔
797
                        return log_error_errno(r, "Failed to append macvlan mode: %m");
×
798

799
                r = sd_netlink_message_close_container(m);
12✔
800
                if (r < 0)
12✔
801
                        return log_error_errno(r, "Failed to close netlink container: %m");
×
802

803
                r = sd_netlink_message_close_container(m);
12✔
804
                if (r < 0)
12✔
805
                        return log_error_errno(r, "Failed to close netlink container: %m");
×
806

807
                r = sd_netlink_call(rtnl, m, 0, NULL);
12✔
808
                if (r < 0)
12✔
809
                        return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
×
810

811
                if (shortened > 0)
12✔
812
                        (void) set_alternative_ifname(rtnl, n, *b);
4✔
813
        }
814

815
        return 0;
816
}
817

818
static int remove_macvlan_impl(char **interface_pairs) {
1✔
819
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
1✔
820
        int r;
1✔
821

822
        assert(interface_pairs);
1✔
823

824
        r = sd_netlink_open(&rtnl);
1✔
825
        if (r < 0)
1✔
826
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
827

828
        STRV_FOREACH_PAIR(a, b, interface_pairs) {
4✔
829
                _cleanup_free_ char *n = NULL;
3✔
830

831
                n = strdup(*b);
3✔
832
                if (!n)
3✔
833
                        return log_oom();
×
834

835
                (void) net_shorten_ifname(n, /* check_naming_scheme= */ true);
3✔
836

837
                r = remove_one_link(rtnl, n);
3✔
838
                if (r < 0)
3✔
839
                        log_warning_errno(r, "Failed to remove macvlan interface %s, ignoring: %m", n);
3✔
840
        }
841

842
        return 0;
843
}
844

845
int remove_macvlan(int child_netns_fd, char **interface_pairs) {
45✔
846
        _cleanup_close_ int parent_netns_fd = -EBADF;
44✔
847
        int r;
45✔
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);
45✔
853

854
        if (strv_isempty(interface_pairs))
46✔
855
                return 0;
856

857
        r = netns_fork_and_wait(child_netns_fd, &parent_netns_fd);
2✔
858
        if (r < 0)
2✔
859
                return r;
860
        if (r == 0) {
2✔
861
                r = remove_macvlan_impl(interface_pairs);
1✔
862
                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
1✔
863
        }
864

865
        return 0;
866
}
867

868
int setup_ipvlan(const char *machine_name, const PidRef *pid, char **iface_pairs) {
54✔
869
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
54✔
870
        int r;
54✔
871

872
        assert(pidref_is_set(pid));
54✔
873

874
        if (strv_isempty(iface_pairs))
58✔
875
                return 0;
876

877
        r = sd_netlink_open(&rtnl);
4✔
878
        if (r < 0)
4✔
879
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
880

881
        STRV_FOREACH_PAIR(i, b, iface_pairs) {
16✔
882
                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
12✔
883
                _cleanup_free_ char *n = NULL;
12✔
884
                int shortened, ifi ;
12✔
885

886
                ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
12✔
887
                if (ifi < 0)
12✔
888
                        return ifi;
889

890
                r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
12✔
891
                if (r < 0)
12✔
892
                        return log_error_errno(r, "Failed to allocate netlink message: %m");
×
893

894
                r = sd_netlink_message_append_u32(m, IFLA_LINK, ifi);
12✔
895
                if (r < 0)
12✔
896
                        return log_error_errno(r, "Failed to add netlink interface index: %m");
×
897

898
                n = strdup(*b);
12✔
899
                if (!n)
12✔
900
                        return log_oom();
×
901

902
                shortened = net_shorten_ifname(n, /* check_naming_scheme= */ true);
12✔
903

904
                r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
12✔
905
                if (r < 0)
12✔
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);
12✔
909
                if (r < 0)
12✔
910
                        return log_error_errno(r, "Failed to add netlink namespace field: %m");
×
911

912
                r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
12✔
913
                if (r < 0)
12✔
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");
12✔
917
                if (r < 0)
12✔
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);
12✔
921
                if (r < 0)
12✔
922
                        return log_error_errno(r, "Failed to add ipvlan mode: %m");
×
923

924
                r = sd_netlink_message_close_container(m);
12✔
925
                if (r < 0)
12✔
926
                        return log_error_errno(r, "Failed to close netlink container: %m");
×
927

928
                r = sd_netlink_message_close_container(m);
12✔
929
                if (r < 0)
12✔
930
                        return log_error_errno(r, "Failed to close netlink container: %m");
×
931

932
                r = sd_netlink_call(rtnl, m, 0, NULL);
12✔
933
                if (r < 0)
12✔
934
                        return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
×
935

936
                if (shortened > 0)
12✔
937
                        (void) set_alternative_ifname(rtnl, n, *b);
4✔
938
        }
939

940
        return 0;
941
}
942

943
int veth_extra_parse(char ***l, const char *p) {
28✔
944
        _cleanup_free_ char *a = NULL, *b = NULL;
28✔
945
        int r;
28✔
946

947
        r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
28✔
948
        if (r < 0)
28✔
949
                return r;
950
        if (r == 0 || !ifname_valid(a))
28✔
951
                return -EINVAL;
952

953
        r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
27✔
954
        if (r < 0)
27✔
955
                return r;
956
        if (r == 0 || !ifname_valid(b)) {
27✔
957
                r = free_and_strdup(&b, a);
20✔
958
                if (r < 0)
20✔
959
                        return r;
960
        }
961

962
        if (p)
27✔
963
                return -EINVAL;
964

965
        r = strv_push_pair(l, a, b);
27✔
966
        if (r < 0)
27✔
967
                return -ENOMEM;
968

969
        a = b = NULL;
27✔
970
        return 0;
27✔
971
}
972

973
int remove_veth_links(const char *primary, char **pairs) {
44✔
974
        _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
44✔
975
        int r;
44✔
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))
88✔
981
                return 0;
982

983
        r = sd_netlink_open(&rtnl);
21✔
984
        if (r < 0)
21✔
985
                return log_error_errno(r, "Failed to connect to netlink: %m");
×
986

987
        remove_one_link(rtnl, primary);
21✔
988

989
        STRV_FOREACH_PAIR(a, b, pairs)
23✔
990
                remove_one_link(rtnl, *a);
2✔
991

992
        return 0;
993
}
994

995
static int network_iface_pair_parse(const char* iftype, char ***l, const char *p, const char* ifprefix) {
45✔
996
        int r;
143✔
997

998
        for (;;) {
98✔
999
                _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
143✔
1000
                const char *interface;
143✔
1001

1002
                r = extract_first_word(&p, &word, NULL, 0);
143✔
1003
                if (r < 0)
143✔
1004
                        return log_error_errno(r, "Failed to parse interface name: %m");
×
1005
                if (r == 0)
143✔
1006
                        break;
1007

1008
                interface = word;
101✔
1009
                r = extract_first_word(&interface, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
101✔
1010
                if (r < 0)
101✔
1011
                        return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype);
×
1012
                if (r == 0)
101✔
1013
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1014
                                               "Short read while reading %s parameter: %m", iftype);
1015
                if (!ifname_valid(a))
101✔
1016
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3✔
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)) {
98✔
1023
                        if (!ifname_valid(interface))
35✔
1024
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1025
                                                       "%s, interface name not valid: %s", iftype, interface);
1026

1027
                        b = strdup(interface);
35✔
1028
                } else if (ifprefix)
63✔
1029
                        b = strjoin(ifprefix, a);
42✔
1030
                else
1031
                        b = strdup(a);
21✔
1032
                if (!b)
98✔
1033
                        return log_oom();
×
1034

1035
                r = strv_consume_pair(l, TAKE_PTR(a), TAKE_PTR(b));
98✔
1036
                if (r < 0)
98✔
1037
                        return log_oom();
×
1038
        }
1039

1040
        return 0;
42✔
1041
}
1042

1043
int interface_pair_parse(char ***l, const char *p) {
15✔
1044
        return network_iface_pair_parse("Network interface", l, p, NULL);
15✔
1045
}
1046

1047
int macvlan_pair_parse(char ***l, const char *p) {
15✔
1048
        return network_iface_pair_parse("MACVLAN network interface", l, p, "mv-");
15✔
1049
}
1050

1051
int ipvlan_pair_parse(char ***l, const char *p) {
15✔
1052
        return network_iface_pair_parse("IPVLAN network interface", l, p, "iv-");
15✔
1053
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc