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

systemd / systemd / 29173644007

11 Jul 2026 09:56PM UTC coverage: 72.704% (-0.2%) from 72.912%
29173644007

push

github

yuwata
claude-review: bump timeout from 60m to 120m

Claude got slower, but in many cases it's on the brink of finishing the
review when the timeout kicks in. Double it.

343647 of 472668 relevant lines covered (72.7%)

1407344.9 hits per line

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

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

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

7
#include "sd-netlink.h"
8

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

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

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

138
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
7,450✔
139

140
bool netdev_is_managed(NetDev *netdev) {
4,651✔
141
        if (!netdev || !netdev->manager || !netdev->ifname)
4,651✔
142
                return false;
143

144
        return hashmap_get(netdev->manager->netdevs, netdev->ifname) == netdev;
4,651✔
145
}
146

147
static bool netdev_is_stacked_and_independent(NetDev *netdev) {
560✔
148
        assert(netdev);
560✔
149

150
        if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
560✔
151
                return false;
152

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

183
static bool netdev_is_stacked(NetDev *netdev) {
1,557✔
184
        assert(netdev);
1,557✔
185

186
        if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
1,557✔
187
                return false;
188

189
        if (netdev_is_stacked_and_independent(netdev))
560✔
190
                return false;
35✔
191

192
        return true;
193
}
194

195
NetDev* netdev_detach_name(NetDev *netdev, const char *name) {
2,917✔
196
        assert(netdev);
2,917✔
197

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

201
        return hashmap_remove_value(netdev->manager->netdevs, name, netdev);
1,285✔
202
}
203

204
static NetDev* netdev_detach_impl(NetDev *netdev) {
2,555✔
205
        assert(netdev);
2,555✔
206

207
        if (netdev->state != _NETDEV_STATE_INVALID &&
2,555✔
208
            NETDEV_VTABLE(netdev) &&
1,703✔
209
            NETDEV_VTABLE(netdev)->detach)
1,703✔
210
                NETDEV_VTABLE(netdev)->detach(netdev);
354✔
211

212
        NetDev *n = netdev_detach_name(netdev, netdev->ifname);
2,555✔
213

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

218
void netdev_detach(NetDev *netdev) {
851✔
219
        assert(netdev);
851✔
220

221
        netdev_unref(netdev_detach_impl(netdev));
851✔
222
}
851✔
223

224
static NetDev* netdev_free(NetDev *netdev) {
1,704✔
225
        assert(netdev);
1,704✔
226

227
        netdev_detach_impl(netdev);
1,704✔
228

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

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

248
        return mfree(netdev);
1,704✔
249
}
250

251
DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
34,059✔
252

253
void netdev_drop(NetDev *netdev) {
726✔
254
        if (!netdev)
726✔
255
                return;
256

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

263
                log_netdev_debug(netdev, "netdev removed");
107✔
264
                return;
265
        }
266

267
        if (NETDEV_VTABLE(netdev) && NETDEV_VTABLE(netdev)->drop)
378✔
268
                NETDEV_VTABLE(netdev)->drop(netdev);
4✔
269

270
        netdev->state = NETDEV_STATE_LINGER;
378✔
271

272
        log_netdev_debug(netdev, "netdev removed");
378✔
273

274
        netdev_detach(netdev);
378✔
275
}
276

277
static int netdev_attach_name_full(NetDev *netdev, const char *name, Hashmap **netdevs) {
1,358✔
278
        int r;
1,358✔
279

280
        assert(netdev);
1,358✔
281
        assert(name);
1,358✔
282
        assert(netdevs);
1,358✔
283

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

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

296
                return -EEXIST;
297
        }
298
        assert(r > 0);
1,357✔
299

300
        return 0;
301
}
302

303
int netdev_attach_name(NetDev *netdev, const char *name) {
1,033✔
304
        assert(netdev);
1,033✔
305
        assert(netdev->manager);
1,033✔
306

307
        return netdev_attach_name_full(netdev, name, &netdev->manager->netdevs);
1,033✔
308
}
309

310
static int netdev_attach(NetDev *netdev) {
852✔
311
        int r;
852✔
312

313
        assert(netdev);
852✔
314
        assert(netdev->ifname);
852✔
315

316
        r = netdev_attach_name(netdev, netdev->ifname);
852✔
317
        if (r < 0)
852✔
318
                return r;
319

320
        if (NETDEV_VTABLE(netdev)->attach) {
851✔
321
                r = NETDEV_VTABLE(netdev)->attach(netdev);
177✔
322
                if (r < 0)
177✔
323
                        return r;
×
324
        }
325

326
        return 0;
327
}
328

329
int netdev_get(Manager *manager, const char *name, NetDev **ret) {
11,234✔
330
        NetDev *netdev;
11,234✔
331

332
        assert(manager);
11,234✔
333
        assert(name);
11,234✔
334
        assert(ret);
11,234✔
335

336
        netdev = hashmap_get(manager->netdevs, name);
11,234✔
337
        if (!netdev)
11,234✔
338
                return -ENOENT;
339

340
        *ret = netdev;
6,155✔
341

342
        return 0;
6,155✔
343
}
344

345
void link_assign_netdev(Link *link) {
5,420✔
346
        _unused_ _cleanup_(netdev_unrefp) NetDev *old = NULL;
5,420✔
347
        NetDev *netdev;
5,420✔
348

349
        assert(link);
5,420✔
350
        assert(link->manager);
5,420✔
351
        assert(link->ifname);
5,420✔
352

353
        old = TAKE_PTR(link->netdev);
5,420✔
354

355
        if (netdev_get(link->manager, link->ifname, &netdev) < 0)
5,420✔
356
                goto not_found;
3,193✔
357

358
        int ifindex = NETDEV_VTABLE(netdev)->get_ifindex ?
3,648✔
359
                NETDEV_VTABLE(netdev)->get_ifindex(netdev, link->ifname) :
2,227✔
360
                netdev->ifindex;
361
        if (ifindex != link->ifindex)
2,227✔
362
                goto not_found;
22✔
363

364
        if (NETDEV_VTABLE(netdev)->iftype != link->iftype)
2,205✔
365
                goto not_found;
×
366

367
        if (!NETDEV_VTABLE(netdev)->skip_netdev_kind_check) {
2,205✔
368
                const char *kind;
2,193✔
369

370
                if (netdev->kind == NETDEV_KIND_TAP)
2,193✔
371
                        kind = "tun"; /* the kernel does not distinguish between tun and tap */
372
                else
373
                        kind = netdev_kind_to_string(netdev->kind);
2,180✔
374

375
                if (!streq_ptr(kind, link->kind))
2,193✔
376
                        goto not_found;
×
377
        }
378

379
        link->netdev = netdev_ref(netdev);
2,205✔
380

381
        if (netdev == old)
2,205✔
382
                return; /* The same NetDev found. */
383

384
        log_link_debug(link, "Found matching .netdev file: %s", netdev->filename);
764✔
385
        link_dirty(link);
764✔
386
        return;
387

388
not_found:
3,215✔
389

390
        if (old)
3,215✔
391
                /* Previously assigned NetDev is detached from Manager? Update the state file. */
392
                link_dirty(link);
10✔
393
}
394

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

399
int netdev_enter_ready(NetDev *netdev) {
767✔
400
        assert(netdev);
767✔
401
        assert(netdev->ifname);
767✔
402

403
        if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_CREATING))
767✔
404
                return 0;
405

406
        netdev->state = NETDEV_STATE_READY;
659✔
407

408
        log_netdev_info(netdev, "netdev ready");
659✔
409

410
        if (NETDEV_VTABLE(netdev)->post_create)
659✔
411
                NETDEV_VTABLE(netdev)->post_create(netdev, NULL);
25✔
412

413
        return 0;
414
}
415

416
bool netdev_needs_reconfigure(NetDev *netdev, NetDevLocalAddressType type) {
716✔
417
        assert(netdev);
716✔
418
        assert(type < _NETDEV_LOCAL_ADDRESS_TYPE_MAX);
716✔
419

420
        if (type < 0)
716✔
421
                return true;
422

423
        return NETDEV_VTABLE(netdev)->needs_reconfigure &&
1,277✔
424
                NETDEV_VTABLE(netdev)->needs_reconfigure(netdev, type);
391✔
425
}
426

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

431
        assert(netdev);
437✔
432
        assert(netdev->state != _NETDEV_STATE_INVALID);
437✔
433

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

445
        return netdev_enter_ready(netdev);
424✔
446
}
447

448
int netdev_set_ifindex_internal(NetDev *netdev, int ifindex) {
2,234✔
449
        assert(netdev);
2,234✔
450
        assert(ifindex > 0);
2,234✔
451

452
        if (netdev->ifindex == ifindex)
2,234✔
453
                return 0; /* Already set. */
454

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

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

465
static int netdev_set_ifindex_impl(NetDev *netdev, const char *name, int ifindex) {
2,741✔
466
        assert(netdev);
2,741✔
467
        assert(name);
2,741✔
468
        assert(ifindex > 0);
2,741✔
469

470
        if (NETDEV_VTABLE(netdev)->set_ifindex)
2,741✔
471
                return NETDEV_VTABLE(netdev)->set_ifindex(netdev, name, ifindex);
1,030✔
472

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

478
        return netdev_set_ifindex_internal(netdev, ifindex);
1,711✔
479
}
480

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

488
        assert(netdev);
2,890✔
489
        assert(message);
2,890✔
490

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

495
        if (type != RTM_NEWLINK)
2,890✔
496
                return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Cannot set ifindex from unexpected rtnl message type.");
×
497

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

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

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

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

515
        if (!NETDEV_VTABLE(netdev)->skip_netdev_kind_check) {
2,741✔
516

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

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

525
                r = sd_netlink_message_exit_container(message);
2,727✔
526
                if (r < 0)
2,727✔
527
                        return log_netdev_warning_errno(netdev, r, "Could not exit container: %m");
×
528

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

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

543
        return netdev_set_ifindex_impl(netdev, received_name, ifindex);
2,741✔
544
}
545

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

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

555
        struct hw_addr_data a = HW_ADDR_NULL;
724✔
556
        bool is_static = false;
724✔
557
        int r;
724✔
558

559
        assert(netdev);
724✔
560
        assert(name);
724✔
561
        assert(hw_addr);
724✔
562
        assert(ret);
724✔
563

564
        if (hw_addr_equal(hw_addr, &HW_ADDR_NONE)) {
724✔
565
                *ret = HW_ADDR_NULL;
1✔
566
                return 0;
1✔
567
        }
568

569
        if (hw_addr->length == 0) {
723✔
570
                uint64_t result;
530✔
571

572
                /* HardwareAddress= is not specified. */
573

574
                if (!NETDEV_VTABLE(netdev)->generate_mac)
530✔
575
                        goto finalize;
234✔
576

577
                if (!IN_SET(NETDEV_VTABLE(netdev)->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
353✔
578
                        goto finalize;
×
579

580
                /* If the interface already exists and its MAC address has been set by userspace
581
                 * (e.g. through MACAddress= in the matching .network file, or manually), do not
582
                 * generate a new address. Otherwise, on reconfiguration the generated address would
583
                 * override the one set by userspace and, as they differ, both would be re-applied on
584
                 * every reload/restart. See issue #42457. */
585
                Link *link;
353✔
586
                unsigned addr_assign_type;
353✔
587
                if (link_get_by_index(netdev->manager, netdev->ifindex, &link) >= 0 &&
353✔
588
                    link->dev &&
59✔
589
                    device_get_sysattr_unsigned(link->dev, "addr_assign_type", &addr_assign_type) >= 0 &&
57✔
590
                    addr_assign_type == NET_ADDR_SET) {
57✔
591
                        log_netdev_debug(netdev, "MAC address is already set by userspace, not generating a new one.");
57✔
592
                        goto finalize;
57✔
593
                }
594

595
                r = net_get_unique_predictable_data_from_name(name, &HASH_KEY, &result);
296✔
596
                if (r < 0) {
296✔
597
                        log_netdev_warning_errno(netdev, r,
×
598
                                                 "Failed to generate persistent MAC address, ignoring: %m");
599
                        goto finalize;
×
600
                }
601

602
                a.length = arphrd_to_hw_addr_len(NETDEV_VTABLE(netdev)->iftype);
296✔
603

604
                switch (NETDEV_VTABLE(netdev)->iftype) {
296✔
605
                case ARPHRD_ETHER:
296✔
606
                        assert(a.length <= sizeof(result));
296✔
607
                        memcpy(a.bytes, &result, a.length);
296✔
608

609
                        if (ether_addr_is_null(&a.ether) || ether_addr_is_broadcast(&a.ether)) {
296✔
610
                                log_netdev_warning(netdev, "Failed to generate persistent MAC address, ignoring.");
×
611
                                a = HW_ADDR_NULL;
×
612
                                goto finalize;
×
613
                        }
614

615
                        break;
616
                case ARPHRD_INFINIBAND:
×
617
                        if (result == 0) {
×
618
                                log_netdev_warning(netdev, "Failed to generate persistent MAC address.");
×
619
                                goto finalize;
×
620
                        }
621

622
                        assert(a.length >= sizeof(result));
×
623
                        memzero(a.bytes, a.length - sizeof(result));
×
624
                        memcpy(a.bytes + a.length - sizeof(result), &result, sizeof(result));
×
625
                        break;
×
626
                default:
×
627
                        assert_not_reached();
×
628
                }
629

630
        } else {
631
                a = *hw_addr;
193✔
632
                is_static = true;
193✔
633
        }
634

635
        r = net_verify_hardware_address(name, is_static, NETDEV_VTABLE(netdev)->iftype,
489✔
636
                                        parent ? &parent->hw_addr : NULL, &a);
637
        if (r < 0)
489✔
638
                return r;
639

640
finalize:
489✔
641
        *ret = a;
723✔
642
        return 0;
723✔
643
}
644

645
static bool netdev_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
629✔
646
        assert(netdev);
629✔
647
        assert(netdev->manager);
629✔
648
        assert(hw_addr);
629✔
649

650
        if (hw_addr->length <= 0)
629✔
651
                return false;
629✔
652

653
        Link *link;
394✔
654
        if (link_get_by_index(netdev->manager, netdev->ifindex, &link) < 0)
394✔
655
                return true; /* The netdev does not exist yet. We can set MAC address. */
656

657
        if (hw_addr_equal(&link->hw_addr, hw_addr))
2✔
658
                return false; /* Unchanged, not necessary to set. */
659

660
        /* Some netdevs refuse to update MAC address even if the interface is not running, e.g. ipvlan.
661
         * Some other netdevs have the IFF_LIVE_ADDR_CHANGE flag and can update update MAC address even if
662
         * the interface is running, e.g. dummy. For those cases, use custom checkers. */
663
        if (NETDEV_VTABLE(netdev)->can_set_mac)
×
664
                return NETDEV_VTABLE(netdev)->can_set_mac(netdev, hw_addr);
×
665

666
        /* Before ad72c4a06acc6762e84994ac2f722da7a07df34e and 0ec92a8f56ff07237dbe8af7c7a72aba7f957baf
667
         * (both in v6.5), the kernel refuse to set MAC address for existing netdevs even if it is unchanged.
668
         * So, by default, do not update MAC address if the it is running. See eth_prepare_mac_addr_change(),
669
         * which is called by eth_mac_addr(). Note, the result of netif_running() is mapped to operstate
670
         * and flags. See rtnl_fill_ifinfo() and dev_get_flags(). */
671
        return link->kernel_operstate == IF_OPER_DOWN &&
×
672
                (link->flags & (IFF_RUNNING | IFF_LOWER_UP | IFF_DORMANT)) == 0;
×
673
}
674

675
static bool netdev_can_set_mtu(NetDev *netdev, uint32_t mtu) {
629✔
676
        assert(netdev);
629✔
677

678
        if (mtu <= 0)
629✔
679
                return false;
629✔
680

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

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

688
        if (link->mtu == mtu)
17✔
689
                return false; /* Unchanged, not necessary to set. */
690

691
        /* Some netdevs cannot change MTU, e.g. vxlan. Let's use the custom checkers in such cases. */
692
        if (NETDEV_VTABLE(netdev)->can_set_mtu)
×
693
                return NETDEV_VTABLE(netdev)->can_set_mtu(netdev, mtu);
×
694

695
        /* By default, allow to update the MTU. */
696
        return true;
697
}
698

699
static int netdev_create_message(NetDev *netdev, Link *link, sd_netlink_message *m) {
629✔
700
        int r;
629✔
701

702
        if (netdev->ifindex <= 0) {
629✔
703
                /* Set interface name when it is newly created. Otherwise, the kernel older than
704
                 * bd039b5ea2a91ea707ee8539df26456bd5be80af (v6.2) will refuse the netlink message even if
705
                 * the name is unchanged. */
706
                r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
487✔
707
                if (r < 0)
487✔
708
                        return r;
629✔
709
        }
710

711
        struct hw_addr_data hw_addr;
629✔
712
        r = netdev_generate_hw_addr(netdev, link, netdev->ifname, &netdev->hw_addr, &hw_addr);
629✔
713
        if (r < 0)
629✔
714
                return r;
715

716
        if (netdev_can_set_mac(netdev, &hw_addr)) {
629✔
717
                log_netdev_debug(netdev, "Using MAC address: %s", HW_ADDR_TO_STR(&hw_addr));
392✔
718
                r = netlink_message_append_hw_addr(m, IFLA_ADDRESS, &hw_addr);
392✔
719
                if (r < 0)
392✔
720
                        return r;
721
        }
722

723
        if (netdev_can_set_mtu(netdev, netdev->mtu)) {
629✔
724
                r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
37✔
725
                if (r < 0)
37✔
726
                        return r;
727
        }
728

729
        if (link) {
629✔
730
                r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
192✔
731
                if (r < 0)
192✔
732
                        return r;
733
        }
734

735
        r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
629✔
736
        if (r < 0)
629✔
737
                return r;
738

739
        if (NETDEV_VTABLE(netdev)->fill_message_create) {
629✔
740
                r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
332✔
741
                if (r < 0)
332✔
742
                        return r;
743

744
                r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
332✔
745
                if (r < 0)
332✔
746
                        return r;
747

748
                r = sd_netlink_message_close_container(m);
332✔
749
                if (r < 0)
332✔
750
                        return r;
751
        } else {
752
                r = sd_netlink_message_append_string(m, IFLA_INFO_KIND, netdev_kind_to_string(netdev->kind));
297✔
753
                if (r < 0)
297✔
754
                        return r;
755
        }
756

757
        r = sd_netlink_message_close_container(m);
629✔
758
        if (r < 0)
629✔
759
                return r;
×
760

761
        return 0;
762
}
763

764
static int independent_netdev_create(NetDev *netdev) {
455✔
765
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
455✔
766
        int r;
455✔
767

768
        assert(netdev);
455✔
769
        assert(netdev->manager);
455✔
770

771
        /* create netdev */
772
        if (NETDEV_VTABLE(netdev)->create) {
455✔
773
                r = NETDEV_VTABLE(netdev)->create(netdev);
18✔
774
                if (r < 0)
18✔
775
                        return r;
776

777
                log_netdev_debug(netdev, "Created");
18✔
778
                return 0;
779
        }
780

781
        r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex);
437✔
782
        if (r < 0)
437✔
783
                return r;
784

785
        r = netdev_create_message(netdev, NULL, m);
437✔
786
        if (r < 0)
437✔
787
                return r;
788

789
        r = netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
437✔
790
                               netdev_destroy_callback, netdev);
791
        if (r < 0)
437✔
792
                return r;
793

794
        netdev_ref(netdev);
437✔
795

796
        netdev->state = NETDEV_STATE_CREATING;
437✔
797
        log_netdev_debug(netdev, "Creating");
437✔
798
        return 0;
799
}
800

801
static int stacked_netdev_create(NetDev *netdev, Link *link, Request *req) {
192✔
802
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
192✔
803
        int r;
192✔
804

805
        assert(netdev);
192✔
806
        assert(netdev->manager);
192✔
807
        assert(link);
192✔
808
        assert(req);
192✔
809

810
        r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex);
192✔
811
        if (r < 0)
192✔
812
                return r;
813

814
        r = netdev_create_message(netdev, link, m);
192✔
815
        if (r < 0)
192✔
816
                return r;
817

818
        r = request_call_netlink_async(netdev->manager->rtnl, m, req);
192✔
819
        if (r < 0)
192✔
820
                return r;
821

822
        netdev->state = NETDEV_STATE_CREATING;
192✔
823
        log_netdev_debug(netdev, "Creating");
192✔
824
        return 0;
825
}
826

827
static bool link_is_ready_to_create_stacked_netdev_one(Link *link, bool allow_unmanaged) {
2,947✔
828
        assert(link);
2,947✔
829

830
        if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
2,947✔
831
                return false;
832

833
        if (!link->network)
2,947✔
834
                return allow_unmanaged;
835

836
        if (link->set_link_messages > 0)
2,947✔
837
                return false;
838

839
        /* If stacked netdevs are created before the underlying interface being activated, then
840
         * the activation policy for the netdevs are ignored. See issue #22593. */
841
        if (!link->activated)
2,827✔
842
                return false;
1,831✔
843

844
        return true;
845
}
846

847
static bool link_is_ready_to_create_stacked_netdev(Link *link) {
2,947✔
848
        return check_ready_for_all_sr_iov_ports(link, /* allow_unmanaged= */ false,
2,947✔
849
                                                link_is_ready_to_create_stacked_netdev_one);
850
}
851

852
static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
3,502✔
853
        assert(netdev);
3,502✔
854

855
        if (link && !link_is_ready_to_create_stacked_netdev(link))
3,502✔
856
                return false;
857

858
        if (NETDEV_VTABLE(netdev)->is_ready_to_create)
1,551✔
859
                return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link);
1,090✔
860

861
        return true;
862
}
863

864
static int stacked_netdev_process_request(Request *req, Link *link, void *userdata) {
2,961✔
865
        NetDev *netdev = ASSERT_PTR(userdata);
2,961✔
866
        int r;
2,961✔
867

868
        assert(req);
2,961✔
869
        assert(link);
2,961✔
870

871
        if (!netdev_is_managed(netdev))
2,961✔
872
                goto cancelled; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
×
873

874
        if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
2,961✔
875
                /* Already exists, and the netdev does not support updating, entering the ready state. */
876
                r = netdev_enter_ready(netdev);
14✔
877
                if (r < 0)
14✔
878
                        return r;
879

880
                goto cancelled;
14✔
881
        }
882

883
        r = netdev_is_ready_to_create(netdev, link);
2,947✔
884
        if (r <= 0)
2,947✔
885
                return r;
886

887
        r = stacked_netdev_create(netdev, link, req);
192✔
888
        if (r < 0)
192✔
889
                return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
×
890

891
        return 1;
892

893
cancelled:
14✔
894
        assert_se(TAKE_PTR(req->counter) == &link->create_stacked_netdev_messages);
14✔
895
        link->create_stacked_netdev_messages--;
14✔
896

897
        if (link->create_stacked_netdev_messages == 0) {
14✔
898
                link->stacked_netdevs_created = true;
14✔
899
                log_link_debug(link, "Stacked netdevs created.");
14✔
900
                link_check_ready(link);
14✔
901
        }
902

903
        return 1;
904
}
905

906
static int create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
192✔
907
        NetDev *netdev = ASSERT_PTR(userdata);
192✔
908
        int r;
192✔
909

910
        assert(m);
192✔
911
        assert(link);
192✔
912

913
        r = sd_netlink_message_get_errno(m);
192✔
914
        if (r >= 0)
192✔
915
                log_netdev_debug(netdev, "Created.");
192✔
916
        else if (r == -EEXIST && netdev->ifindex > 0)
×
917
                log_netdev_debug(netdev, "Already exists.");
×
918
        else {
919
                log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
×
920
                netdev_enter_failed(netdev);
×
921
                link_enter_failed(link);
×
922
                return 0;
×
923
        }
924

925
        (void) netdev_enter_ready(netdev);
192✔
926

927
        if (link->create_stacked_netdev_messages == 0) {
192✔
928
                link->stacked_netdevs_created = true;
98✔
929
                log_link_debug(link, "Stacked netdevs created.");
98✔
930
                link_check_ready(link);
98✔
931
        }
932

933
        return 0;
934
}
935

936
int link_request_stacked_netdev(Link *link, NetDev *netdev) {
221✔
937
        int r;
221✔
938

939
        assert(link);
221✔
940
        assert(netdev);
221✔
941

942
        if (!netdev_is_stacked(netdev))
221✔
943
                return -EINVAL;
944

945
        if (!netdev_is_managed(netdev))
221✔
946
                return 0; /* Already detached, due to e.g. reloading .netdev files. */
947

948
        link->stacked_netdevs_created = false;
221✔
949
        r = link_queue_request_full(link, REQUEST_TYPE_NETDEV_STACKED,
221✔
950
                                    netdev, (mfree_func_t) netdev_unref,
951
                                    trivial_hash_func, trivial_compare_func,
952
                                    stacked_netdev_process_request,
953
                                    &link->create_stacked_netdev_messages,
954
                                    create_stacked_netdev_handler, NULL);
955
        if (r < 0)
221✔
956
                return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m",
×
957
                                            netdev->ifname);
958
        if (r == 0)
221✔
959
                return 0;
960

961
        netdev_ref(netdev);
211✔
962
        log_link_debug(link, "Requested stacked netdev '%s'", netdev->ifname);
211✔
963
        return 1;
964
}
965

966
static int independent_netdev_process_request(Request *req, Link *link, void *userdata) {
704✔
967
        NetDev *netdev = ASSERT_PTR(userdata);
704✔
968
        int r;
704✔
969

970
        assert(!link);
704✔
971

972
        if (!netdev_is_managed(netdev))
704✔
973
                return 1; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
704✔
974

975
        if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
704✔
976
                /* Already exists, and the netdev does not support updating, entering the ready state. */
977
                r = netdev_enter_ready(netdev);
17✔
978
                if (r < 0)
17✔
979
                        return r;
980

981
                return 1; /* Skip this request. */
17✔
982
        }
983

984
        Link *existing;
687✔
985
        if (link_get_by_index(netdev->manager, netdev->ifindex, &existing) >= 0 &&
687✔
986
            IN_SET(existing->state,
194✔
987
                   LINK_STATE_PENDING, /* Already exists and is being processed by udevd. Postpone the request. */
988
                   LINK_STATE_LINGER)) /* Already removed; wait for the stale information to be cleared. */
989
                return 0;
990

991
        r = netdev_is_ready_to_create(netdev, NULL);
555✔
992
        if (r <= 0)
555✔
993
                return r;
994

995
        r = independent_netdev_create(netdev);
455✔
996
        if (r < 0)
455✔
997
                return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
×
998

999
        return 1;
1000
}
1001

1002
static int netdev_request_to_create(NetDev *netdev) {
851✔
1003
        int r;
851✔
1004

1005
        assert(netdev);
851✔
1006
        assert(netdev->manager);
851✔
1007

1008
        if (netdev->manager->test_mode)
851✔
1009
                return 0;
1010

1011
        if (netdev_is_stacked(netdev))
851✔
1012
                return 0;
1013

1014
        if (!netdev_is_managed(netdev))
654✔
1015
                return 0; /* Already detached, due to e.g. reloading .netdev files. */
1016

1017
        if (netdev->state != NETDEV_STATE_LOADING)
654✔
1018
                return 0; /* Already configured (at least tried previously). Not necessary to reconfigure. */
1019

1020
        r = netdev_queue_request(netdev, independent_netdev_process_request, NULL);
472✔
1021
        if (r < 0)
472✔
1022
                return log_netdev_warning_errno(netdev, r, "Failed to request to create netdev: %m");
×
1023

1024
        return 0;
1025
}
1026

1027
int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) {
852✔
1028
        _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
852✔
1029
        _cleanup_free_ char *file_basename = NULL;
852✔
1030
        const char *dropin_dirname;
852✔
1031
        int r;
852✔
1032

1033
        assert(manager);
852✔
1034
        assert(filename);
852✔
1035
        assert(ret);
852✔
1036

1037
        r = null_or_empty_path(filename);
852✔
1038
        if (r < 0)
852✔
1039
                return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
×
1040
        if (r > 0)
852✔
1041
                return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Skipping empty file: %s", filename);
×
1042

1043
        netdev_raw = new(NetDev, 1);
852✔
1044
        if (!netdev_raw)
852✔
1045
                return log_oom();
×
1046

1047
        *netdev_raw = (NetDev) {
852✔
1048
                .n_ref = 1,
1049
                .kind = _NETDEV_KIND_INVALID,
1050
                .state = _NETDEV_STATE_INVALID, /* an invalid state means done() of the implementation won't be called on destruction */
1051
        };
1052

1053
        r = path_extract_filename(filename, &file_basename);
852✔
1054
        if (r < 0)
852✔
1055
                return log_warning_errno(r, "Failed to extract file name of '%s': %m", filename);
×
1056

1057
        dropin_dirname = strjoina(file_basename, ".d");
4,260✔
1058
        r = config_parse_many(
1,704✔
1059
                        STRV_MAKE_CONST(filename),
852✔
1060
                        NETWORK_DIRS,
852✔
1061
                        dropin_dirname,
1062
                        NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
1063
                        config_item_perf_lookup,
1064
                        network_netdev_gperf_lookup,
1065
                        CONFIG_PARSE_WARN,
1066
                        netdev_raw);
1067
        if (r < 0)
852✔
1068
                return r; /* config_parse_many() logs internally. */
1069

1070
        /* skip out early if configuration does not match the environment */
1071
        if (!condition_test_list_net(netdev_raw->conditions, environ, NULL, NULL, NULL))
852✔
1072
                return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "%s: Conditions in the file do not match the system environment, skipping.", filename);
×
1073

1074
        if (netdev_raw->kind == _NETDEV_KIND_INVALID)
852✔
1075
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev has no Kind= configured in \"%s\", ignoring.", filename);
×
1076

1077
        if (!netdev_raw->ifname)
852✔
1078
                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev without Name= configured in \"%s\", ignoring.", filename);
×
1079

1080
        netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
852✔
1081
        if (!netdev)
852✔
1082
                return log_oom();
×
1083

1084
        netdev->n_ref = 1;
852✔
1085
        netdev->manager = manager;
852✔
1086
        netdev->kind = netdev_raw->kind;
852✔
1087
        netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time,
852✔
1088
                                                 so that done() will be called on destruction */
1089

1090
        if (NETDEV_VTABLE(netdev)->init)
852✔
1091
                NETDEV_VTABLE(netdev)->init(netdev);
289✔
1092

1093
        r = config_parse_many_full(
2,556✔
1094
                        STRV_MAKE_CONST(filename),
852✔
1095
                        NETWORK_DIRS,
852✔
1096
                        dropin_dirname,
1097
                        /* root= */ NULL,
1098
                        /* root_fd= */ -EBADF,
1099
                        NETDEV_VTABLE(netdev)->sections,
852✔
1100
                        config_item_perf_lookup,
1101
                        network_netdev_gperf_lookup,
1102
                        CONFIG_PARSE_WARN,
1103
                        netdev,
1104
                        &netdev->stats_by_path,
1105
                        &netdev->dropins);
852✔
1106
        if (r < 0)
852✔
1107
                return r; /* config_parse_many() logs internally. */
1108

1109
        /* verify configuration */
1110
        if (NETDEV_VTABLE(netdev)->config_verify) {
852✔
1111
                r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
398✔
1112
                if (r < 0)
398✔
1113
                        return r; /* config_verify() logs internally. */
1114
        }
1115

1116
        netdev->filename = strdup(filename);
852✔
1117
        if (!netdev->filename)
852✔
1118
                return log_oom();
×
1119

1120
        log_syntax(/* unit= */ NULL, LOG_DEBUG, filename, /* config_line= */ 0, /* error= */ 0, "Successfully loaded.");
852✔
1121

1122
        *ret = TAKE_PTR(netdev);
852✔
1123
        return 0;
852✔
1124
}
1125

1126
int netdev_load(Manager *manager) {
466✔
1127
        _cleanup_strv_free_ char **files = NULL;
466✔
1128
        int r;
466✔
1129

1130
        assert(manager);
466✔
1131

1132
        r = conf_files_list_strv(&files, ".netdev", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS);
466✔
1133
        if (r < 0)
466✔
1134
                return log_error_errno(r, "Failed to enumerate netdev files: %m");
×
1135

1136
        STRV_FOREACH(f, files) {
993✔
1137
                _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
1✔
1138

1139
                if (netdev_load_one(manager, *f, &netdev) < 0)
527✔
1140
                        continue;
×
1141

1142
                if (netdev_attach(netdev) < 0)
527✔
1143
                        continue;
1✔
1144

1145
                if (netdev_request_to_create(netdev) < 0)
526✔
1146
                        continue;
×
1147

1148
                TAKE_PTR(netdev);
526✔
1149
        }
1150

1151
        return 0;
1152
}
1153

1154
int netdev_reload(Manager *manager) {
157✔
1155
        _cleanup_hashmap_free_ Hashmap *new_netdevs = NULL;
157✔
1156
        _cleanup_strv_free_ char **files = NULL;
157✔
1157
        int r;
157✔
1158

1159
        assert(manager);
157✔
1160

1161
        r = conf_files_list_strv(&files, ".netdev", /* root= */ NULL, CONF_FILES_WARN, NETWORK_DIRS);
157✔
1162
        if (r < 0)
157✔
1163
                return log_error_errno(r, "Failed to enumerate netdev files: %m");
×
1164

1165
        STRV_FOREACH(f, files) {
482✔
1166
                _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
325✔
1167
                NetDev *old;
325✔
1168

1169
                if (netdev_load_one(manager, *f, &netdev) < 0)
325✔
1170
                        continue;
×
1171

1172
                if (netdev_get(manager, netdev->ifname, &old) < 0) {
325✔
1173
                        log_netdev_debug(netdev, "Found new .netdev file: %s", netdev->filename);
13✔
1174

1175
                        if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0)
13✔
1176
                                TAKE_PTR(netdev);
13✔
1177

1178
                        continue;
13✔
1179
                }
1180

1181
                if (!stats_by_path_equal(netdev->stats_by_path, old->stats_by_path)) {
312✔
1182
                        log_netdev_debug(netdev, "Found updated .netdev file: %s", netdev->filename);
125✔
1183

1184
                        /* Copy ifindex. */
1185
                        netdev->ifindex = old->ifindex;
125✔
1186

1187
                        if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0)
125✔
1188
                                TAKE_PTR(netdev);
125✔
1189

1190
                        continue;
125✔
1191
                }
1192

1193
                /* Keep the original object, and drop the new one. */
1194
                if (netdev_attach_name_full(old, old->ifname, &new_netdevs) >= 0)
187✔
1195
                        netdev_ref(old);
187✔
1196
        }
1197

1198
        /* Detach old NetDev objects from Manager.
1199
         * The same object may be registered with multiple names, and netdev_detach() may drop multiple entries. */
1200
        for (NetDev *n; (n = hashmap_first(manager->netdevs)); )
472✔
1201
                netdev_detach(n);
315✔
1202

1203
        /* Attach new NetDev objects to Manager. */
1204
        for (;;) {
482✔
1205
                _cleanup_(netdev_unrefp) NetDev *netdev = hashmap_steal_first(new_netdevs);
639✔
1206
                if (!netdev)
482✔
1207
                        break;
1208

1209
                netdev->manager = manager;
325✔
1210
                if (netdev_attach(netdev) < 0)
325✔
1211
                        continue;
×
1212

1213
                /* Create a new netdev or update existing netdev, */
1214
                if (netdev_request_to_create(netdev) < 0)
325✔
1215
                        continue;
×
1216

1217
                TAKE_PTR(netdev);
325✔
1218
        }
1219

1220
        /* Reassign NetDev objects to Link object. */
1221
        Link *link;
157✔
1222
        HASHMAP_FOREACH(link, manager->links_by_index)
1,179✔
1223
                link_assign_netdev(link);
1,022✔
1224

1225
        return 0;
157✔
1226
}
1227

1228
int config_parse_netdev_kind(
1,704✔
1229
                const char *unit,
1230
                const char *filename,
1231
                unsigned line,
1232
                const char *section,
1233
                unsigned section_line,
1234
                const char *lvalue,
1235
                int ltype,
1236
                const char *rvalue,
1237
                void *data,
1238
                void *userdata) {
1239

1240
        NetDevKind k, *kind = ASSERT_PTR(data);
1,704✔
1241

1242
        assert(filename);
1,704✔
1243
        assert(rvalue);
1,704✔
1244

1245
        k = netdev_kind_from_string(rvalue);
1,704✔
1246
        if (k < 0) {
1,704✔
1247
                log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse netdev kind, ignoring assignment: %s", rvalue);
×
1248
                return 0;
1249
        }
1250

1251
        if (*kind != _NETDEV_KIND_INVALID && *kind != k) {
1,704✔
1252
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
1253
                           "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s",
1254
                           netdev_kind_to_string(*kind), rvalue);
1255
                return 0;
1256
        }
1257

1258
        *kind = k;
1,704✔
1259

1260
        return 0;
1,704✔
1261
}
1262

1263
int config_parse_netdev_hw_addr(
528✔
1264
                const char *unit,
1265
                const char *filename,
1266
                unsigned line,
1267
                const char *section,
1268
                unsigned section_line,
1269
                const char *lvalue,
1270
                int ltype,
1271
                const char *rvalue,
1272
                void *data,
1273
                void *userdata) {
1274

1275
        struct hw_addr_data *hw_addr = ASSERT_PTR(data);
528✔
1276

1277
        assert(rvalue);
528✔
1278

1279
        if (streq(rvalue, "none")) {
528✔
1280
                *hw_addr = HW_ADDR_NONE;
2✔
1281
                return 0;
2✔
1282
        }
1283

1284
        return config_parse_hw_addr(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
526✔
1285
}
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