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

systemd / systemd / 23774132158

30 Mar 2026 09:35PM UTC coverage: 72.398% (+0.2%) from 72.208%
23774132158

push

github

daandemeyer
Only enable `NoAuto=true` for supported partitions

When `Format=empty` is set we need to check for `NoAuto` support for
the partition type, else we print a warning later in the build.

Followup for 381304a

1 of 1 new or added line in 1 file covered. (100.0%)

7091 existing lines in 92 files now uncovered.

318474 of 439892 relevant lines covered (72.4%)

1151474.34 hits per line

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

88.48
/src/network/netdev/netdev.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <linux/if_arp.h>
4
#include <unistd.h>
5

6
#include "sd-netlink.h"
7

8
#include "alloc-util.h"
9
#include "arphrd-util.h"
10
#include "bareudp.h"
11
#include "batadv.h"
12
#include "bond.h"
13
#include "bridge.h"
14
#include "condition.h"
15
#include "conf-files.h"
16
#include "conf-parser.h"
17
#include "dummy.h"
18
#include "fou-tunnel.h"
19
#include "geneve.h"
20
#include "hashmap.h"
21
#include "hsr.h"
22
#include "ifb.h"
23
#include "ipoib.h"
24
#include "ipvlan.h"
25
#include "l2tp-tunnel.h"
26
#include "macsec.h"
27
#include "macvlan.h"
28
#include "netdev.h"
29
#include "netif-util.h"
30
#include "netlink-util.h"
31
#include "network-util.h"
32
#include "networkd-manager.h"
33
#include "networkd-queue.h"
34
#include "networkd-sriov.h"
35
#include "networkd-state-file.h"
36
#include "nlmon.h"
37
#include "path-util.h"
38
#include "stat-util.h"
39
#include "string-table.h"
40
#include "string-util.h"
41
#include "strv.h"
42
#include "tunnel.h"
43
#include "tuntap.h"
44
#include "vcan.h"
45
#include "veth.h"
46
#include "vlan.h"
47
#include "vrf.h"
48
#include "vxcan.h"
49
#include "vxlan.h"
50
#include "wireguard.h"
51
#include "wlan.h"
52
#include "xfrm.h"
53

54
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
55
        [NETDEV_KIND_BAREUDP]   = &bare_udp_vtable,
56
        [NETDEV_KIND_BATADV]    = &batadv_vtable,
57
        [NETDEV_KIND_BOND]      = &bond_vtable,
58
        [NETDEV_KIND_BRIDGE]    = &bridge_vtable,
59
        [NETDEV_KIND_DUMMY]     = &dummy_vtable,
60
        [NETDEV_KIND_ERSPAN]    = &erspan_vtable,
61
        [NETDEV_KIND_FOU]       = &foutnl_vtable,
62
        [NETDEV_KIND_GENEVE]    = &geneve_vtable,
63
        [NETDEV_KIND_GRE]       = &gre_vtable,
64
        [NETDEV_KIND_GRETAP]    = &gretap_vtable,
65
        [NETDEV_KIND_HSR]       = &hsr_vtable,
66
        [NETDEV_KIND_IFB]       = &ifb_vtable,
67
        [NETDEV_KIND_IP6GRE]    = &ip6gre_vtable,
68
        [NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
69
        [NETDEV_KIND_IP6TNL]    = &ip6tnl_vtable,
70
        [NETDEV_KIND_IPIP]      = &ipip_vtable,
71
        [NETDEV_KIND_IPOIB]     = &ipoib_vtable,
72
        [NETDEV_KIND_IPVLAN]    = &ipvlan_vtable,
73
        [NETDEV_KIND_IPVTAP]    = &ipvtap_vtable,
74
        [NETDEV_KIND_L2TP]      = &l2tptnl_vtable,
75
        [NETDEV_KIND_MACSEC]    = &macsec_vtable,
76
        [NETDEV_KIND_MACVLAN]   = &macvlan_vtable,
77
        [NETDEV_KIND_MACVTAP]   = &macvtap_vtable,
78
        [NETDEV_KIND_NLMON]     = &nlmon_vtable,
79
        [NETDEV_KIND_SIT]       = &sit_vtable,
80
        [NETDEV_KIND_TAP]       = &tap_vtable,
81
        [NETDEV_KIND_TUN]       = &tun_vtable,
82
        [NETDEV_KIND_VCAN]      = &vcan_vtable,
83
        [NETDEV_KIND_VETH]      = &veth_vtable,
84
        [NETDEV_KIND_VLAN]      = &vlan_vtable,
85
        [NETDEV_KIND_VRF]       = &vrf_vtable,
86
        [NETDEV_KIND_VTI6]      = &vti6_vtable,
87
        [NETDEV_KIND_VTI]       = &vti_vtable,
88
        [NETDEV_KIND_VXCAN]     = &vxcan_vtable,
89
        [NETDEV_KIND_VXLAN]     = &vxlan_vtable,
90
        [NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
91
        [NETDEV_KIND_WLAN]      = &wlan_vtable,
92
        [NETDEV_KIND_XFRM]      = &xfrm_vtable,
93
};
94

95
static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
96
        [NETDEV_KIND_BAREUDP]   = "bareudp",
97
        [NETDEV_KIND_BATADV]    = "batadv",
98
        [NETDEV_KIND_BOND]      = "bond",
99
        [NETDEV_KIND_BRIDGE]    = "bridge",
100
        [NETDEV_KIND_DUMMY]     = "dummy",
101
        [NETDEV_KIND_ERSPAN]    = "erspan",
102
        [NETDEV_KIND_FOU]       = "fou",
103
        [NETDEV_KIND_GENEVE]    = "geneve",
104
        [NETDEV_KIND_GRE]       = "gre",
105
        [NETDEV_KIND_GRETAP]    = "gretap",
106
        [NETDEV_KIND_HSR]       = "hsr",
107
        [NETDEV_KIND_IFB]       = "ifb",
108
        [NETDEV_KIND_IP6GRE]    = "ip6gre",
109
        [NETDEV_KIND_IP6GRETAP] = "ip6gretap",
110
        [NETDEV_KIND_IP6TNL]    = "ip6tnl",
111
        [NETDEV_KIND_IPIP]      = "ipip",
112
        [NETDEV_KIND_IPOIB]     = "ipoib",
113
        [NETDEV_KIND_IPVLAN]    = "ipvlan",
114
        [NETDEV_KIND_IPVTAP]    = "ipvtap",
115
        [NETDEV_KIND_L2TP]      = "l2tp",
116
        [NETDEV_KIND_MACSEC]    = "macsec",
117
        [NETDEV_KIND_MACVLAN]   = "macvlan",
118
        [NETDEV_KIND_MACVTAP]   = "macvtap",
119
        [NETDEV_KIND_NLMON]     = "nlmon",
120
        [NETDEV_KIND_SIT]       = "sit",
121
        [NETDEV_KIND_TAP]       = "tap",
122
        [NETDEV_KIND_TUN]       = "tun",
123
        [NETDEV_KIND_VCAN]      = "vcan",
124
        [NETDEV_KIND_VETH]      = "veth",
125
        [NETDEV_KIND_VLAN]      = "vlan",
126
        [NETDEV_KIND_VRF]       = "vrf",
127
        [NETDEV_KIND_VTI6]      = "vti6",
128
        [NETDEV_KIND_VTI]       = "vti",
129
        [NETDEV_KIND_VXCAN]     = "vxcan",
130
        [NETDEV_KIND_VXLAN]     = "vxlan",
131
        [NETDEV_KIND_WIREGUARD] = "wireguard",
132
        [NETDEV_KIND_WLAN]      = "wlan",
133
        [NETDEV_KIND_XFRM]      = "xfrm",
134
};
135

136
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
7,448✔
137

138
bool netdev_is_managed(NetDev *netdev) {
4,084✔
139
        if (!netdev || !netdev->manager || !netdev->ifname)
4,084✔
140
                return false;
141

142
        return hashmap_get(netdev->manager->netdevs, netdev->ifname) == netdev;
4,084✔
143
}
144

145
static bool netdev_is_stacked_and_independent(NetDev *netdev) {
555✔
146
        assert(netdev);
555✔
147

148
        if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
555✔
149
                return false;
150

151
        switch (netdev->kind) {
555✔
152
        case NETDEV_KIND_ERSPAN:
30✔
153
                return ERSPAN(netdev)->independent;
30✔
154
        case NETDEV_KIND_GRE:
30✔
155
                return GRE(netdev)->independent;
30✔
156
        case NETDEV_KIND_GRETAP:
13✔
157
                return GRETAP(netdev)->independent;
13✔
158
        case NETDEV_KIND_IP6GRE:
27✔
159
                return IP6GRE(netdev)->independent;
27✔
160
        case NETDEV_KIND_IP6GRETAP:
10✔
161
                return IP6GRETAP(netdev)->independent;
10✔
162
        case NETDEV_KIND_IP6TNL:
104✔
163
                return IP6TNL(netdev)->independent;
104✔
164
        case NETDEV_KIND_IPIP:
67✔
165
                return IPIP(netdev)->independent;
67✔
166
        case NETDEV_KIND_SIT:
97✔
167
                return SIT(netdev)->independent;
97✔
168
        case NETDEV_KIND_VTI:
20✔
169
                return VTI(netdev)->independent;
20✔
170
        case NETDEV_KIND_VTI6:
15✔
171
                return VTI6(netdev)->independent;
15✔
172
        case NETDEV_KIND_VXLAN:
15✔
173
                return VXLAN(netdev)->independent;
15✔
174
        case NETDEV_KIND_XFRM:
8✔
175
                return XFRM(netdev)->independent;
8✔
176
        default:
177
                return false;
178
        }
179
}
180

181
static bool netdev_is_stacked(NetDev *netdev) {
1,547✔
182
        assert(netdev);
1,547✔
183

184
        if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
1,547✔
185
                return false;
186

187
        if (netdev_is_stacked_and_independent(netdev))
555✔
188
                return false;
35✔
189

190
        return true;
191
}
192

193
NetDev* netdev_detach_name(NetDev *netdev, const char *name) {
2,897✔
194
        assert(netdev);
2,897✔
195

196
        if (!netdev->manager || !name)
2,897✔
197
                return NULL; /* Already detached or not attached yet. */
198

199
        return hashmap_remove_value(netdev->manager->netdevs, name, netdev);
1,272✔
200
}
201

202
static NetDev* netdev_detach_impl(NetDev *netdev) {
2,537✔
203
        assert(netdev);
2,537✔
204

205
        if (netdev->state != _NETDEV_STATE_INVALID &&
2,537✔
206
            NETDEV_VTABLE(netdev) &&
1,691✔
207
            NETDEV_VTABLE(netdev)->detach)
1,691✔
208
                NETDEV_VTABLE(netdev)->detach(netdev);
352✔
209

210
        NetDev *n = netdev_detach_name(netdev, netdev->ifname);
2,537✔
211

212
        netdev->manager = NULL;
2,537✔
213
        return n; /* Return NULL when it is not attached yet, or already detached. */
2,537✔
214
}
215

216
void netdev_detach(NetDev *netdev) {
845✔
217
        assert(netdev);
845✔
218

219
        netdev_unref(netdev_detach_impl(netdev));
845✔
220
}
845✔
221

222
static NetDev* netdev_free(NetDev *netdev) {
1,692✔
223
        assert(netdev);
1,692✔
224

225
        netdev_detach_impl(netdev);
1,692✔
226

227
        /* Invoke the per-kind done() destructor, but only if the state field is initialized. We conditionalize that
228
         * because we parse .netdev files twice: once to determine the kind (with a short, minimal NetDev structure
229
         * allocation, with no room for per-kind fields), and once to read the kind's properties (with a full,
230
         * comprehensive NetDev structure allocation with enough space for whatever the specific kind needs). Now, in
231
         * the first case we shouldn't try to destruct the per-kind NetDev fields on destruction, in the second case we
232
         * should. We use the state field to discern the two cases: it's _NETDEV_STATE_INVALID on the first "raw"
233
         * call. */
234
        if (netdev->state != _NETDEV_STATE_INVALID &&
1,692✔
235
            NETDEV_VTABLE(netdev) &&
846✔
236
            NETDEV_VTABLE(netdev)->done)
846✔
237
                NETDEV_VTABLE(netdev)->done(netdev);
240✔
238

239
        condition_free_list(netdev->conditions);
1,692✔
240
        free(netdev->filename);
1,692✔
241
        strv_free(netdev->dropins);
1,692✔
242
        hashmap_free(netdev->stats_by_path);
1,692✔
243
        free(netdev->description);
1,692✔
244
        free(netdev->ifname);
1,692✔
245

246
        return mfree(netdev);
1,692✔
247
}
248

249
DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
34,253✔
250

251
void netdev_drop(NetDev *netdev) {
891✔
252
        if (!netdev)
891✔
253
                return;
254

255
        if (netdev_is_stacked(netdev)) {
486✔
256
                /* The netdev may be removed due to the underlying device removal, and the device may
257
                 * be re-added later. */
258
                netdev->state = NETDEV_STATE_LOADING;
107✔
259
                netdev->ifindex = 0;
107✔
260

261
                log_netdev_debug(netdev, "netdev removed");
107✔
262
                return;
107✔
263
        }
264

265
        if (NETDEV_VTABLE(netdev) && NETDEV_VTABLE(netdev)->drop)
379✔
266
                NETDEV_VTABLE(netdev)->drop(netdev);
4✔
267

268
        netdev->state = NETDEV_STATE_LINGER;
379✔
269

270
        log_netdev_debug(netdev, "netdev removed");
379✔
271

272
        netdev_detach(netdev);
379✔
273
}
274

275
static int netdev_attach_name_full(NetDev *netdev, const char *name, Hashmap **netdevs) {
1,344✔
276
        int r;
1,344✔
277

278
        assert(netdev);
1,344✔
279
        assert(name);
1,344✔
280
        assert(netdevs);
1,344✔
281

282
        r = hashmap_ensure_put(netdevs, &string_hash_ops, name, netdev);
1,344✔
283
        if (r == -ENOMEM)
1,344✔
UNCOV
284
                return log_oom();
×
285
        if (r == -EEXIST) {
1,344✔
286
                NetDev *n = hashmap_get(*netdevs, name);
1✔
287

288
                assert(n);
1✔
289
                if (!streq(netdev->filename, n->filename))
1✔
290
                        log_netdev_warning_errno(netdev, r,
1✔
291
                                                 "Device \"%s\" was already configured by \"%s\", ignoring %s.",
292
                                                 name, n->filename, netdev->filename);
293

294
                return -EEXIST;
1✔
295
        }
296
        assert(r > 0);
1,343✔
297

298
        return 0;
299
}
300

301
int netdev_attach_name(NetDev *netdev, const char *name) {
1,026✔
302
        assert(netdev);
1,026✔
303
        assert(netdev->manager);
1,026✔
304

305
        return netdev_attach_name_full(netdev, name, &netdev->manager->netdevs);
1,026✔
306
}
307

308
static int netdev_attach(NetDev *netdev) {
846✔
309
        int r;
846✔
310

311
        assert(netdev);
846✔
312
        assert(netdev->ifname);
846✔
313

314
        r = netdev_attach_name(netdev, netdev->ifname);
846✔
315
        if (r < 0)
846✔
316
                return r;
317

318
        if (NETDEV_VTABLE(netdev)->attach) {
845✔
319
                r = NETDEV_VTABLE(netdev)->attach(netdev);
176✔
320
                if (r < 0)
176✔
UNCOV
321
                        return r;
×
322
        }
323

324
        return 0;
325
}
326

327
int netdev_get(Manager *manager, const char *name, NetDev **ret) {
13,982✔
328
        NetDev *netdev;
13,982✔
329

330
        assert(manager);
13,982✔
331
        assert(name);
13,982✔
332
        assert(ret);
13,982✔
333

334
        netdev = hashmap_get(manager->netdevs, name);
13,982✔
335
        if (!netdev)
13,982✔
336
                return -ENOENT;
337

338
        *ret = netdev;
6,163✔
339

340
        return 0;
6,163✔
341
}
342

343
void link_assign_netdev(Link *link) {
6,779✔
344
        _unused_ _cleanup_(netdev_unrefp) NetDev *old = NULL;
6,779✔
345
        NetDev *netdev;
6,779✔
346

347
        assert(link);
6,779✔
348
        assert(link->manager);
6,779✔
349
        assert(link->ifname);
6,779✔
350

351
        old = TAKE_PTR(link->netdev);
6,779✔
352

353
        if (netdev_get(link->manager, link->ifname, &netdev) < 0)
6,779✔
354
                goto not_found;
4,562✔
355

356
        int ifindex = NETDEV_VTABLE(netdev)->get_ifindex ?
3,632✔
357
                NETDEV_VTABLE(netdev)->get_ifindex(netdev, link->ifname) :
2,217✔
358
                netdev->ifindex;
359
        if (ifindex != link->ifindex)
2,217✔
360
                goto not_found;
22✔
361

362
        if (NETDEV_VTABLE(netdev)->iftype != link->iftype)
2,195✔
UNCOV
363
                goto not_found;
×
364

365
        if (!NETDEV_VTABLE(netdev)->skip_netdev_kind_check) {
2,195✔
366
                const char *kind;
2,183✔
367

368
                if (netdev->kind == NETDEV_KIND_TAP)
2,183✔
369
                        kind = "tun"; /* the kernel does not distinguish between tun and tap */
370
                else
371
                        kind = netdev_kind_to_string(netdev->kind);
2,170✔
372

373
                if (!streq_ptr(kind, link->kind))
2,183✔
UNCOV
374
                        goto not_found;
×
375
        }
376

377
        link->netdev = netdev_ref(netdev);
2,195✔
378

379
        if (netdev == old)
2,195✔
380
                return; /* The same NetDev found. */
381

382
        log_link_debug(link, "Found matching .netdev file: %s", netdev->filename);
763✔
383
        link_dirty(link);
763✔
384
        return;
385

386
not_found:
4,584✔
387

388
        if (old)
4,584✔
389
                /* Previously assigned NetDev is detached from Manager? Update the state file. */
390
                link_dirty(link);
9✔
391
}
392

393
void netdev_enter_failed(NetDev *netdev) {
22✔
394
        netdev->state = NETDEV_STATE_FAILED;
22✔
395
}
22✔
396

397
int netdev_enter_ready(NetDev *netdev) {
766✔
398
        assert(netdev);
766✔
399
        assert(netdev->ifname);
766✔
400

401
        if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_CREATING))
766✔
402
                return 0;
403

404
        netdev->state = NETDEV_STATE_READY;
659✔
405

406
        log_netdev_info(netdev, "netdev ready");
659✔
407

408
        if (NETDEV_VTABLE(netdev)->post_create)
659✔
409
                NETDEV_VTABLE(netdev)->post_create(netdev, NULL);
25✔
410

411
        return 0;
412
}
413

414
bool netdev_needs_reconfigure(NetDev *netdev, NetDevLocalAddressType type) {
512✔
415
        assert(netdev);
512✔
416
        assert(type < _NETDEV_LOCAL_ADDRESS_TYPE_MAX);
512✔
417

418
        if (type < 0)
512✔
419
                return true;
420

421
        return NETDEV_VTABLE(netdev)->needs_reconfigure &&
774✔
422
                NETDEV_VTABLE(netdev)->needs_reconfigure(netdev, type);
239✔
423
}
424

425
/* callback for netdev's created without a backing Link */
426
static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
437✔
427
        int r;
437✔
428

429
        assert(netdev);
437✔
430
        assert(netdev->state != _NETDEV_STATE_INVALID);
437✔
431

432
        r = sd_netlink_message_get_errno(m);
437✔
433
        if (r >= 0)
437✔
434
                log_netdev_debug(netdev, "Created.");
424✔
435
        else if (r == -EEXIST && netdev->ifindex > 0)
13✔
UNCOV
436
                log_netdev_debug(netdev, "Already exists.");
×
437
        else {
438
                log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
13✔
439
                netdev_enter_failed(netdev);
13✔
440
                return 0;
13✔
441
        }
442

443
        return netdev_enter_ready(netdev);
424✔
444
}
445

446
int netdev_set_ifindex_internal(NetDev *netdev, int ifindex) {
2,261✔
447
        assert(netdev);
2,261✔
448
        assert(ifindex > 0);
2,261✔
449

450
        if (netdev->ifindex == ifindex)
2,261✔
451
                return 0; /* Already set. */
452

453
        if (netdev->ifindex > 0 && netdev->ifindex != ifindex)
540✔
UNCOV
454
                return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EEXIST),
×
455
                                                "Could not set ifindex to %i, already set to %i.",
456
                                                ifindex, netdev->ifindex);
457

458
        netdev->ifindex = ifindex;
540✔
459
        log_netdev_debug(netdev, "Gained index %i.", ifindex);
540✔
460
        return 1; /* set new ifindex. */
461
}
462

463
static int netdev_set_ifindex_impl(NetDev *netdev, const char *name, int ifindex) {
2,761✔
464
        assert(netdev);
2,761✔
465
        assert(name);
2,761✔
466
        assert(ifindex > 0);
2,761✔
467

468
        if (NETDEV_VTABLE(netdev)->set_ifindex)
2,761✔
469
                return NETDEV_VTABLE(netdev)->set_ifindex(netdev, name, ifindex);
1,013✔
470

471
        if (!streq(netdev->ifname, name))
1,748✔
UNCOV
472
                return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
×
473
                                                "Received netlink message with unexpected interface name %s (ifindex=%i).",
474
                                                name, ifindex);
475

476
        return netdev_set_ifindex_internal(netdev, ifindex);
1,748✔
477
}
478

479
int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
2,913✔
480
        uint16_t type;
2,913✔
481
        const char *kind;
2,913✔
482
        const char *received_kind;
2,913✔
483
        const char *received_name;
2,913✔
484
        int r, ifindex, family;
2,913✔
485

486
        assert(netdev);
2,913✔
487
        assert(message);
2,913✔
488

489
        r = sd_netlink_message_get_type(message, &type);
2,913✔
490
        if (r < 0)
2,913✔
UNCOV
491
                return log_netdev_warning_errno(netdev, r, "Could not get rtnl message type: %m");
×
492

493
        if (type != RTM_NEWLINK)
2,913✔
UNCOV
494
                return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Cannot set ifindex from unexpected rtnl message type.");
×
495

496
        r = sd_rtnl_message_get_family(message, &family);
2,913✔
497
        if (r < 0)
2,913✔
UNCOV
498
                return log_netdev_warning_errno(netdev, r, "Failed to get family from received rtnl message: %m");
×
499

500
        if (family != AF_UNSPEC)
2,913✔
501
                return 0; /* IFLA_LINKINFO is only contained in the message with AF_UNSPEC. */
502

503
        r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
2,761✔
504
        if (r < 0)
2,761✔
UNCOV
505
                return log_netdev_warning_errno(netdev, r, "Could not get ifindex: %m");
×
506
        if (ifindex <= 0)
2,761✔
UNCOV
507
                return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Got invalid ifindex: %d", ifindex);
×
508

509
        r = sd_netlink_message_read_string(message, IFLA_IFNAME, &received_name);
2,761✔
510
        if (r < 0)
2,761✔
UNCOV
511
                return log_netdev_warning_errno(netdev, r, "Could not get IFNAME: %m");
×
512

513
        if (!NETDEV_VTABLE(netdev)->skip_netdev_kind_check) {
2,761✔
514

515
                r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
2,747✔
516
                if (r < 0)
2,747✔
UNCOV
517
                        return log_netdev_warning_errno(netdev, r, "Could not get LINKINFO: %m");
×
518

519
                r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
2,747✔
520
                if (r < 0)
2,747✔
UNCOV
521
                        return log_netdev_warning_errno(netdev, r, "Could not get KIND: %m");
×
522

523
                r = sd_netlink_message_exit_container(message);
2,747✔
524
                if (r < 0)
2,747✔
UNCOV
525
                        return log_netdev_warning_errno(netdev, r, "Could not exit container: %m");
×
526

527
                if (netdev->kind == NETDEV_KIND_TAP)
2,747✔
528
                        /* the kernel does not distinguish between tun and tap */
529
                        kind = "tun";
530
                else
531
                        kind = netdev_kind_to_string(netdev->kind);
2,729✔
532
                if (!kind)
2,729✔
UNCOV
533
                        return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Could not get netdev kind.");
×
534

535
                if (!streq(kind, received_kind))
2,747✔
UNCOV
536
                        return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
×
537
                                                        "Received newlink with wrong KIND %s, expected %s",
538
                                                        received_kind, kind);
539
        }
540

541
        return netdev_set_ifindex_impl(netdev, received_name, ifindex);
2,761✔
542
}
543

544
#define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
545

546
int netdev_generate_hw_addr(
723✔
547
                NetDev *netdev,
548
                Link *parent,
549
                const char *name,
550
                const struct hw_addr_data *hw_addr,
551
                struct hw_addr_data *ret) {
552

553
        struct hw_addr_data a = HW_ADDR_NULL;
723✔
554
        bool is_static = false;
723✔
555
        int r;
723✔
556

557
        assert(netdev);
723✔
558
        assert(name);
723✔
559
        assert(hw_addr);
723✔
560
        assert(ret);
723✔
561

562
        if (hw_addr_equal(hw_addr, &HW_ADDR_NONE)) {
723✔
563
                *ret = HW_ADDR_NULL;
1✔
564
                return 0;
1✔
565
        }
566

567
        if (hw_addr->length == 0) {
722✔
568
                uint64_t result;
531✔
569

570
                /* HardwareAddress= is not specified. */
571

572
                if (!NETDEV_VTABLE(netdev)->generate_mac)
531✔
573
                        goto finalize;
177✔
574

575
                if (!IN_SET(NETDEV_VTABLE(netdev)->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
354✔
UNCOV
576
                        goto finalize;
×
577

578
                r = net_get_unique_predictable_data_from_name(name, &HASH_KEY, &result);
354✔
579
                if (r < 0) {
354✔
UNCOV
580
                        log_netdev_warning_errno(netdev, r,
×
581
                                                 "Failed to generate persistent MAC address, ignoring: %m");
UNCOV
582
                        goto finalize;
×
583
                }
584

585
                a.length = arphrd_to_hw_addr_len(NETDEV_VTABLE(netdev)->iftype);
354✔
586

587
                switch (NETDEV_VTABLE(netdev)->iftype) {
354✔
588
                case ARPHRD_ETHER:
354✔
589
                        assert(a.length <= sizeof(result));
354✔
590
                        memcpy(a.bytes, &result, a.length);
354✔
591

592
                        if (ether_addr_is_null(&a.ether) || ether_addr_is_broadcast(&a.ether)) {
354✔
593
                                log_netdev_warning(netdev, "Failed to generate persistent MAC address, ignoring.");
×
594
                                a = HW_ADDR_NULL;
×
UNCOV
595
                                goto finalize;
×
596
                        }
597

598
                        break;
599
                case ARPHRD_INFINIBAND:
×
600
                        if (result == 0) {
×
601
                                log_netdev_warning(netdev, "Failed to generate persistent MAC address.");
×
UNCOV
602
                                goto finalize;
×
603
                        }
604

605
                        assert(a.length >= sizeof(result));
×
606
                        memzero(a.bytes, a.length - sizeof(result));
×
607
                        memcpy(a.bytes + a.length - sizeof(result), &result, sizeof(result));
×
608
                        break;
×
609
                default:
×
UNCOV
610
                        assert_not_reached();
×
611
                }
612

613
        } else {
614
                a = *hw_addr;
191✔
615
                is_static = true;
191✔
616
        }
617

618
        r = net_verify_hardware_address(name, is_static, NETDEV_VTABLE(netdev)->iftype,
545✔
619
                                        parent ? &parent->hw_addr : NULL, &a);
620
        if (r < 0)
545✔
621
                return r;
622

623
finalize:
545✔
624
        *ret = a;
722✔
625
        return 0;
722✔
626
}
627

628
static bool netdev_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
629✔
629
        assert(netdev);
629✔
630
        assert(netdev->manager);
629✔
631
        assert(hw_addr);
629✔
632

633
        if (hw_addr->length <= 0)
629✔
634
                return false;
629✔
635

636
        Link *link;
451✔
637
        if (link_get_by_index(netdev->manager, netdev->ifindex, &link) < 0)
451✔
638
                return true; /* The netdev does not exist yet. We can set MAC address. */
639

640
        if (hw_addr_equal(&link->hw_addr, hw_addr))
59✔
641
                return false; /* Unchanged, not necessary to set. */
642

643
        /* Some netdevs refuse to update MAC address even if the interface is not running, e.g. ipvlan.
644
         * Some other netdevs have the IFF_LIVE_ADDR_CHANGE flag and can update update MAC address even if
645
         * the interface is running, e.g. dummy. For those cases, use custom checkers. */
646
        if (NETDEV_VTABLE(netdev)->can_set_mac)
7✔
647
                return NETDEV_VTABLE(netdev)->can_set_mac(netdev, hw_addr);
5✔
648

649
        /* Before ad72c4a06acc6762e84994ac2f722da7a07df34e and 0ec92a8f56ff07237dbe8af7c7a72aba7f957baf
650
         * (both in v6.5), the kernel refuse to set MAC address for existing netdevs even if it is unchanged.
651
         * So, by default, do not update MAC address if the it is running. See eth_prepare_mac_addr_change(),
652
         * which is called by eth_mac_addr(). Note, the result of netif_running() is mapped to operstate
653
         * and flags. See rtnl_fill_ifinfo() and dev_get_flags(). */
654
        return link->kernel_operstate == IF_OPER_DOWN &&
4✔
UNCOV
655
                (link->flags & (IFF_RUNNING | IFF_LOWER_UP | IFF_DORMANT)) == 0;
×
656
}
657

658
static bool netdev_can_set_mtu(NetDev *netdev, uint32_t mtu) {
629✔
659
        assert(netdev);
629✔
660

661
        if (mtu <= 0)
629✔
662
                return false;
629✔
663

664
        Link *link;
54✔
665
        if (link_get_by_index(netdev->manager, netdev->ifindex, &link) < 0)
54✔
666
                return true; /* The netdev does not exist yet. We can set MTU. */
667

668
        if (mtu < link->min_mtu || link->max_mtu < mtu)
17✔
669
                return false; /* The MTU is out of range. */
670

671
        if (link->mtu == mtu)
17✔
672
                return false; /* Unchanged, not necessary to set. */
673

674
        /* Some netdevs cannot change MTU, e.g. vxlan. Let's use the custom checkers in such cases. */
675
        if (NETDEV_VTABLE(netdev)->can_set_mtu)
×
UNCOV
676
                return NETDEV_VTABLE(netdev)->can_set_mtu(netdev, mtu);
×
677

678
        /* By default, allow to update the MTU. */
679
        return true;
680
}
681

682
static int netdev_create_message(NetDev *netdev, Link *link, sd_netlink_message *m) {
629✔
683
        int r;
629✔
684

685
        if (netdev->ifindex <= 0) {
629✔
686
                /* Set interface name when it is newly created. Otherwise, the kernel older than
687
                 * bd039b5ea2a91ea707ee8539df26456bd5be80af (v6.2) will refuse the netlink message even if
688
                 * the name is unchanged. */
689
                r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
487✔
690
                if (r < 0)
487✔
691
                        return r;
629✔
692
        }
693

694
        struct hw_addr_data hw_addr;
629✔
695
        r = netdev_generate_hw_addr(netdev, link, netdev->ifname, &netdev->hw_addr, &hw_addr);
629✔
696
        if (r < 0)
629✔
697
                return r;
698

699
        if (netdev_can_set_mac(netdev, &hw_addr)) {
629✔
700
                log_netdev_debug(netdev, "Using MAC address: %s", HW_ADDR_TO_STR(&hw_addr));
397✔
701
                r = netlink_message_append_hw_addr(m, IFLA_ADDRESS, &hw_addr);
397✔
702
                if (r < 0)
397✔
703
                        return r;
704
        }
705

706
        if (netdev_can_set_mtu(netdev, netdev->mtu)) {
629✔
707
                r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
37✔
708
                if (r < 0)
37✔
709
                        return r;
710
        }
711

712
        if (link) {
629✔
713
                r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
192✔
714
                if (r < 0)
192✔
715
                        return r;
716
        }
717

718
        r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
629✔
719
        if (r < 0)
629✔
720
                return r;
721

722
        if (NETDEV_VTABLE(netdev)->fill_message_create) {
629✔
723
                r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
331✔
724
                if (r < 0)
331✔
725
                        return r;
726

727
                r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
331✔
728
                if (r < 0)
331✔
729
                        return r;
730

731
                r = sd_netlink_message_close_container(m);
331✔
732
                if (r < 0)
331✔
733
                        return r;
734
        } else {
735
                r = sd_netlink_message_append_string(m, IFLA_INFO_KIND, netdev_kind_to_string(netdev->kind));
298✔
736
                if (r < 0)
298✔
737
                        return r;
738
        }
739

740
        r = sd_netlink_message_close_container(m);
629✔
741
        if (r < 0)
629✔
UNCOV
742
                return r;
×
743

744
        return 0;
745
}
746

747
static int independent_netdev_create(NetDev *netdev) {
455✔
748
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
455✔
749
        int r;
455✔
750

751
        assert(netdev);
455✔
752
        assert(netdev->manager);
455✔
753

754
        /* create netdev */
755
        if (NETDEV_VTABLE(netdev)->create) {
455✔
756
                r = NETDEV_VTABLE(netdev)->create(netdev);
18✔
757
                if (r < 0)
18✔
758
                        return r;
759

760
                log_netdev_debug(netdev, "Created");
18✔
761
                return 0;
18✔
762
        }
763

764
        r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex);
437✔
765
        if (r < 0)
437✔
766
                return r;
767

768
        r = netdev_create_message(netdev, NULL, m);
437✔
769
        if (r < 0)
437✔
770
                return r;
771

772
        r = netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
437✔
773
                               netdev_destroy_callback, netdev);
774
        if (r < 0)
437✔
775
                return r;
776

777
        netdev_ref(netdev);
437✔
778

779
        netdev->state = NETDEV_STATE_CREATING;
437✔
780
        log_netdev_debug(netdev, "Creating");
437✔
781
        return 0;
782
}
783

784
static int stacked_netdev_create(NetDev *netdev, Link *link, Request *req) {
192✔
785
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
192✔
786
        int r;
192✔
787

788
        assert(netdev);
192✔
789
        assert(netdev->manager);
192✔
790
        assert(link);
192✔
791
        assert(req);
192✔
792

793
        r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex);
192✔
794
        if (r < 0)
192✔
795
                return r;
796

797
        r = netdev_create_message(netdev, link, m);
192✔
798
        if (r < 0)
192✔
799
                return r;
800

801
        r = request_call_netlink_async(netdev->manager->rtnl, m, req);
192✔
802
        if (r < 0)
192✔
803
                return r;
804

805
        netdev->state = NETDEV_STATE_CREATING;
192✔
806
        log_netdev_debug(netdev, "Creating");
192✔
807
        return 0;
808
}
809

810
static bool link_is_ready_to_create_stacked_netdev_one(Link *link, bool allow_unmanaged) {
2,521✔
811
        assert(link);
2,521✔
812

813
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
2,521✔
814
                return false;
815

816
        if (!link->network)
2,521✔
817
                return allow_unmanaged;
818

819
        if (link->set_link_messages > 0)
2,521✔
820
                return false;
821

822
        /* If stacked netdevs are created before the underlying interface being activated, then
823
         * the activation policy for the netdevs are ignored. See issue #22593. */
824
        if (!link->activated)
2,439✔
825
                return false;
1,569✔
826

827
        return true;
828
}
829

830
static bool link_is_ready_to_create_stacked_netdev(Link *link) {
2,521✔
831
        return check_ready_for_all_sr_iov_ports(link, /* allow_unmanaged= */ false,
2,521✔
832
                                                link_is_ready_to_create_stacked_netdev_one);
833
}
834

835
static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
3,078✔
836
        assert(netdev);
3,078✔
837

838
        if (link && !link_is_ready_to_create_stacked_netdev(link))
3,078✔
839
                return false;
840

841
        if (NETDEV_VTABLE(netdev)->is_ready_to_create)
1,427✔
842
                return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link);
966✔
843

844
        return true;
845
}
846

847
static int stacked_netdev_process_request(Request *req, Link *link, void *userdata) {
2,535✔
848
        NetDev *netdev = ASSERT_PTR(userdata);
2,535✔
849
        int r;
2,535✔
850

851
        assert(req);
2,535✔
852
        assert(link);
2,535✔
853

854
        if (!netdev_is_managed(netdev))
2,535✔
UNCOV
855
                goto cancelled; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
×
856

857
        if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
2,535✔
858
                /* Already exists, and the netdev does not support updating, entering the ready state. */
859
                r = netdev_enter_ready(netdev);
14✔
860
                if (r < 0)
14✔
861
                        return r;
862

863
                goto cancelled;
14✔
864
        }
865

866
        r = netdev_is_ready_to_create(netdev, link);
2,521✔
867
        if (r <= 0)
2,521✔
868
                return r;
869

870
        r = stacked_netdev_create(netdev, link, req);
192✔
871
        if (r < 0)
192✔
UNCOV
872
                return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
×
873

874
        return 1;
875

876
cancelled:
14✔
877
        assert_se(TAKE_PTR(req->counter) == &link->create_stacked_netdev_messages);
14✔
878
        link->create_stacked_netdev_messages--;
14✔
879

880
        if (link->create_stacked_netdev_messages == 0) {
14✔
881
                link->stacked_netdevs_created = true;
14✔
882
                log_link_debug(link, "Stacked netdevs created.");
14✔
883
                link_check_ready(link);
14✔
884
        }
885

886
        return 1;
887
}
888

889
static int create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
192✔
890
        NetDev *netdev = ASSERT_PTR(userdata);
192✔
891
        int r;
192✔
892

893
        assert(m);
192✔
894
        assert(link);
192✔
895

896
        r = sd_netlink_message_get_errno(m);
192✔
897
        if (r >= 0)
192✔
898
                log_netdev_debug(netdev, "Created.");
192✔
899
        else if (r == -EEXIST && netdev->ifindex > 0)
×
UNCOV
900
                log_netdev_debug(netdev, "Already exists.");
×
901
        else {
902
                log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
×
903
                netdev_enter_failed(netdev);
×
904
                link_enter_failed(link);
×
UNCOV
905
                return 0;
×
906
        }
907

908
        (void) netdev_enter_ready(netdev);
192✔
909

910
        if (link->create_stacked_netdev_messages == 0) {
192✔
911
                link->stacked_netdevs_created = true;
98✔
912
                log_link_debug(link, "Stacked netdevs created.");
98✔
913
                link_check_ready(link);
98✔
914
        }
915

916
        return 0;
917
}
918

919
int link_request_stacked_netdev(Link *link, NetDev *netdev) {
216✔
920
        int r;
216✔
921

922
        assert(link);
216✔
923
        assert(netdev);
216✔
924

925
        if (!netdev_is_stacked(netdev))
216✔
926
                return -EINVAL;
927

928
        if (!netdev_is_managed(netdev))
216✔
929
                return 0; /* Already detached, due to e.g. reloading .netdev files. */
930

931
        link->stacked_netdevs_created = false;
216✔
932
        r = link_queue_request_full(link, REQUEST_TYPE_NETDEV_STACKED,
216✔
933
                                    netdev, (mfree_func_t) netdev_unref,
934
                                    trivial_hash_func, trivial_compare_func,
935
                                    stacked_netdev_process_request,
936
                                    &link->create_stacked_netdev_messages,
937
                                    create_stacked_netdev_handler, NULL);
938
        if (r < 0)
216✔
UNCOV
939
                return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m",
×
940
                                            netdev->ifname);
941
        if (r == 0)
216✔
942
                return 0;
943

944
        netdev_ref(netdev);
211✔
945
        log_link_debug(link, "Requested stacked netdev '%s'", netdev->ifname);
211✔
946
        return 1;
947
}
948

949
static int independent_netdev_process_request(Request *req, Link *link, void *userdata) {
574✔
950
        NetDev *netdev = ASSERT_PTR(userdata);
574✔
951
        int r;
574✔
952

953
        assert(!link);
574✔
954

955
        if (!netdev_is_managed(netdev))
574✔
956
                return 1; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
957

958
        if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
574✔
959
                /* Already exists, and the netdev does not support updating, entering the ready state. */
960
                r = netdev_enter_ready(netdev);
17✔
961
                if (r < 0)
17✔
962
                        return r;
963

964
                return 1; /* Skip this request. */
17✔
965
        }
966

967
        r = netdev_is_ready_to_create(netdev, NULL);
557✔
968
        if (r <= 0)
557✔
969
                return r;
970

971
        r = independent_netdev_create(netdev);
455✔
972
        if (r < 0)
455✔
UNCOV
973
                return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
×
974

975
        return 1;
976
}
977

978
static int netdev_request_to_create(NetDev *netdev) {
845✔
979
        int r;
845✔
980

981
        assert(netdev);
845✔
982
        assert(netdev->manager);
845✔
983

984
        if (netdev->manager->test_mode)
845✔
985
                return 0;
986

987
        if (netdev_is_stacked(netdev))
845✔
988
                return 0;
989

990
        if (!netdev_is_managed(netdev))
648✔
991
                return 0; /* Already detached, due to e.g. reloading .netdev files. */
992

993
        if (netdev->state != NETDEV_STATE_LOADING)
648✔
994
                return 0; /* Already configured (at least tried previously). Not necessary to reconfigure. */
995

996
        r = netdev_queue_request(netdev, independent_netdev_process_request, NULL);
472✔
997
        if (r < 0)
472✔
UNCOV
998
                return log_netdev_warning_errno(netdev, r, "Failed to request to create netdev: %m");
×
999

1000
        return 0;
1001
}
1002

1003
int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) {
846✔
1004
        _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
846✔
1005
        _cleanup_free_ char *file_basename = NULL;
846✔
1006
        const char *dropin_dirname;
846✔
1007
        int r;
846✔
1008

1009
        assert(manager);
846✔
1010
        assert(filename);
846✔
1011
        assert(ret);
846✔
1012

1013
        r = null_or_empty_path(filename);
846✔
1014
        if (r < 0)
846✔
UNCOV
1015
                return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
×
1016
        if (r > 0)
846✔
UNCOV
1017
                return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Skipping empty file: %s", filename);
×
1018

1019
        netdev_raw = new(NetDev, 1);
846✔
1020
        if (!netdev_raw)
846✔
UNCOV
1021
                return log_oom();
×
1022

1023
        *netdev_raw = (NetDev) {
846✔
1024
                .n_ref = 1,
1025
                .kind = _NETDEV_KIND_INVALID,
1026
                .state = _NETDEV_STATE_INVALID, /* an invalid state means done() of the implementation won't be called on destruction */
1027
        };
1028

1029
        r = path_extract_filename(filename, &file_basename);
846✔
1030
        if (r < 0)
846✔
UNCOV
1031
                return log_warning_errno(r, "Failed to extract file name of '%s': %m", filename);
×
1032

1033
        dropin_dirname = strjoina(file_basename, ".d");
4,230✔
1034
        r = config_parse_many(
1,692✔
1035
                        STRV_MAKE_CONST(filename),
846✔
1036
                        NETWORK_DIRS,
846✔
1037
                        dropin_dirname,
1038
                        NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
1039
                        config_item_perf_lookup,
1040
                        network_netdev_gperf_lookup,
1041
                        CONFIG_PARSE_WARN,
1042
                        netdev_raw);
1043
        if (r < 0)
846✔
1044
                return r; /* config_parse_many() logs internally. */
1045

1046
        /* skip out early if configuration does not match the environment */
1047
        if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL))
846✔
UNCOV
1048
                return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "%s: Conditions in the file do not match the system environment, skipping.", filename);
×
1049

1050
        if (netdev_raw->kind == _NETDEV_KIND_INVALID)
846✔
UNCOV
1051
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev has no Kind= configured in \"%s\", ignoring.", filename);
×
1052

1053
        if (!netdev_raw->ifname)
846✔
UNCOV
1054
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev without Name= configured in \"%s\", ignoring.", filename);
×
1055

1056
        netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
846✔
1057
        if (!netdev)
846✔
UNCOV
1058
                return log_oom();
×
1059

1060
        netdev->n_ref = 1;
846✔
1061
        netdev->manager = manager;
846✔
1062
        netdev->kind = netdev_raw->kind;
846✔
1063
        netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time,
846✔
1064
                                                 so that done() will be called on destruction */
1065

1066
        if (NETDEV_VTABLE(netdev)->init)
846✔
1067
                NETDEV_VTABLE(netdev)->init(netdev);
289✔
1068

1069
        r = config_parse_many_full(
2,538✔
1070
                        STRV_MAKE_CONST(filename),
846✔
1071
                        NETWORK_DIRS,
846✔
1072
                        dropin_dirname,
1073
                        /* root= */ NULL,
1074
                        /* root_fd= */ -EBADF,
1075
                        NETDEV_VTABLE(netdev)->sections,
846✔
1076
                        config_item_perf_lookup,
1077
                        network_netdev_gperf_lookup,
1078
                        CONFIG_PARSE_WARN,
1079
                        netdev,
1080
                        &netdev->stats_by_path,
1081
                        &netdev->dropins);
846✔
1082
        if (r < 0)
846✔
1083
                return r; /* config_parse_many() logs internally. */
1084

1085
        /* verify configuration */
1086
        if (NETDEV_VTABLE(netdev)->config_verify) {
846✔
1087
                r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
397✔
1088
                if (r < 0)
397✔
1089
                        return r; /* config_verify() logs internally. */
1090
        }
1091

1092
        netdev->filename = strdup(filename);
846✔
1093
        if (!netdev->filename)
846✔
UNCOV
1094
                return log_oom();
×
1095

1096
        log_syntax(/* unit= */ NULL, LOG_DEBUG, filename, /* config_line= */ 0, /* error= */ 0, "Successfully loaded.");
846✔
1097

1098
        *ret = TAKE_PTR(netdev);
846✔
1099
        return 0;
846✔
1100
}
1101

1102
int netdev_load(Manager *manager) {
450✔
1103
        _cleanup_strv_free_ char **files = NULL;
450✔
1104
        int r;
450✔
1105

1106
        assert(manager);
450✔
1107

1108
        r = conf_files_list_strv(&files, ".netdev", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS);
450✔
1109
        if (r < 0)
450✔
UNCOV
1110
                return log_error_errno(r, "Failed to enumerate netdev files: %m");
×
1111

1112
        STRV_FOREACH(f, files) {
978✔
1113
                _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
1✔
1114

1115
                if (netdev_load_one(manager, *f, &netdev) < 0)
528✔
UNCOV
1116
                        continue;
×
1117

1118
                if (netdev_attach(netdev) < 0)
528✔
1119
                        continue;
1✔
1120

1121
                if (netdev_request_to_create(netdev) < 0)
527✔
UNCOV
1122
                        continue;
×
1123

1124
                TAKE_PTR(netdev);
527✔
1125
        }
1126

1127
        return 0;
1128
}
1129

1130
int netdev_reload(Manager *manager) {
154✔
1131
        _cleanup_hashmap_free_ Hashmap *new_netdevs = NULL;
154✔
1132
        _cleanup_strv_free_ char **files = NULL;
154✔
1133
        int r;
154✔
1134

1135
        assert(manager);
154✔
1136

1137
        r = conf_files_list_strv(&files, ".netdev", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS);
154✔
1138
        if (r < 0)
154✔
UNCOV
1139
                return log_error_errno(r, "Failed to enumerate netdev files: %m");
×
1140

1141
        STRV_FOREACH(f, files) {
472✔
1142
                _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
318✔
1143
                NetDev *old;
318✔
1144

1145
                if (netdev_load_one(manager, *f, &netdev) < 0)
318✔
UNCOV
1146
                        continue;
×
1147

1148
                if (netdev_get(manager, netdev->ifname, &old) < 0) {
318✔
1149
                        log_netdev_debug(netdev, "Found new .netdev file: %s", netdev->filename);
12✔
1150

1151
                        if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0)
12✔
1152
                                TAKE_PTR(netdev);
12✔
1153

1154
                        continue;
12✔
1155
                }
1156

1157
                if (!stats_by_path_equal(netdev->stats_by_path, old->stats_by_path)) {
306✔
1158
                        log_netdev_debug(netdev, "Found updated .netdev file: %s", netdev->filename);
125✔
1159

1160
                        /* Copy ifindex. */
1161
                        netdev->ifindex = old->ifindex;
125✔
1162

1163
                        if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0)
125✔
1164
                                TAKE_PTR(netdev);
125✔
1165

1166
                        continue;
125✔
1167
                }
1168

1169
                /* Keep the original object, and drop the new one. */
1170
                if (netdev_attach_name_full(old, old->ifname, &new_netdevs) >= 0)
181✔
1171
                        netdev_ref(old);
181✔
1172
        }
1173

1174
        /* Detach old NetDev objects from Manager.
1175
         * The same object may be registered with multiple names, and netdev_detach() may drop multiple entries. */
1176
        for (NetDev *n; (n = hashmap_first(manager->netdevs)); )
462✔
1177
                netdev_detach(n);
308✔
1178

1179
        /* Attach new NetDev objects to Manager. */
1180
        for (;;) {
472✔
1181
                _cleanup_(netdev_unrefp) NetDev *netdev = hashmap_steal_first(new_netdevs);
626✔
1182
                if (!netdev)
472✔
1183
                        break;
1184

1185
                netdev->manager = manager;
318✔
1186
                if (netdev_attach(netdev) < 0)
318✔
UNCOV
1187
                        continue;
×
1188

1189
                /* Create a new netdev or update existing netdev, */
1190
                if (netdev_request_to_create(netdev) < 0)
318✔
UNCOV
1191
                        continue;
×
1192

1193
                TAKE_PTR(netdev);
318✔
1194
        }
1195

1196
        /* Reassign NetDev objects to Link object. */
1197
        Link *link;
154✔
1198
        HASHMAP_FOREACH(link, manager->links_by_index)
1,376✔
1199
                link_assign_netdev(link);
1,222✔
1200

1201
        return 0;
154✔
1202
}
1203

1204
int config_parse_netdev_kind(
1,692✔
1205
                const char *unit,
1206
                const char *filename,
1207
                unsigned line,
1208
                const char *section,
1209
                unsigned section_line,
1210
                const char *lvalue,
1211
                int ltype,
1212
                const char *rvalue,
1213
                void *data,
1214
                void *userdata) {
1215

1216
        NetDevKind k, *kind = ASSERT_PTR(data);
1,692✔
1217

1218
        assert(filename);
1,692✔
1219
        assert(rvalue);
1,692✔
1220

1221
        k = netdev_kind_from_string(rvalue);
1,692✔
1222
        if (k < 0) {
1,692✔
1223
                log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse netdev kind, ignoring assignment: %s", rvalue);
×
UNCOV
1224
                return 0;
×
1225
        }
1226

1227
        if (*kind != _NETDEV_KIND_INVALID && *kind != k) {
1,692✔
UNCOV
1228
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1229
                           "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s",
1230
                           netdev_kind_to_string(*kind), rvalue);
UNCOV
1231
                return 0;
×
1232
        }
1233

1234
        *kind = k;
1,692✔
1235

1236
        return 0;
1,692✔
1237
}
1238

1239
int config_parse_netdev_hw_addr(
525✔
1240
                const char *unit,
1241
                const char *filename,
1242
                unsigned line,
1243
                const char *section,
1244
                unsigned section_line,
1245
                const char *lvalue,
1246
                int ltype,
1247
                const char *rvalue,
1248
                void *data,
1249
                void *userdata) {
1250

1251
        struct hw_addr_data *hw_addr = ASSERT_PTR(data);
525✔
1252

1253
        assert(rvalue);
525✔
1254

1255
        if (streq(rvalue, "none")) {
525✔
1256
                *hw_addr = HW_ADDR_NONE;
2✔
1257
                return 0;
2✔
1258
        }
1259

1260
        return config_parse_hw_addr(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
523✔
1261
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc