]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/netdev.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / network / netdev / netdev.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
02b59d57 2
1cf40697 3#include <linux/if_arp.h>
a0b191b7 4#include <unistd.h>
987efa17 5
baa3fadf
DDM
6#include "sd-netlink.h"
7
b5efdb8a 8#include "alloc-util.h"
007899f4 9#include "arphrd-util.h"
e6980c72 10#include "bareudp.h"
c0267a59 11#include "batadv.h"
737f1405
YW
12#include "bond.h"
13#include "bridge.h"
baa3fadf 14#include "condition.h"
02b59d57
TG
15#include "conf-files.h"
16#include "conf-parser.h"
737f1405 17#include "dummy.h"
737f1405
YW
18#include "fou-tunnel.h"
19#include "geneve.h"
baa3fadf 20#include "hashmap.h"
f7996e2a 21#include "hsr.h"
3295a461 22#include "ifb.h"
b90d0f83 23#include "ipoib.h"
737f1405
YW
24#include "ipvlan.h"
25#include "l2tp-tunnel.h"
737f1405
YW
26#include "macsec.h"
27#include "macvlan.h"
28#include "netdev.h"
007899f4 29#include "netif-util.h"
3a56e697 30#include "netlink-util.h"
cd7d732d 31#include "network-util.h"
3a56e697 32#include "networkd-manager.h"
71a754f7 33#include "networkd-queue.h"
e33232d4 34#include "networkd-sriov.h"
d1608355 35#include "networkd-state-file.h"
737f1405 36#include "nlmon.h"
6b783209 37#include "path-util.h"
3a56e697
SS
38#include "stat-util.h"
39#include "string-table.h"
40#include "string-util.h"
41#include "strv.h"
737f1405
YW
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"
dedf2d00 51#include "wlan.h"
737f1405 52#include "xfrm.h"
23f53b99 53
3be1d7e0 54const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
bc945c2b
YW
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,
f7996e2a 65 [NETDEV_KIND_HSR] = &hsr_vtable,
bc945c2b
YW
66 [NETDEV_KIND_IFB] = &ifb_vtable,
67 [NETDEV_KIND_IP6GRE] = &ip6gre_vtable,
b16492f8 68 [NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
bc945c2b
YW
69 [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
70 [NETDEV_KIND_IPIP] = &ipip_vtable,
b90d0f83 71 [NETDEV_KIND_IPOIB] = &ipoib_vtable,
bc945c2b
YW
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,
bc945c2b
YW
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,
dedf2d00 91 [NETDEV_KIND_WLAN] = &wlan_vtable,
bc945c2b 92 [NETDEV_KIND_XFRM] = &xfrm_vtable,
3be1d7e0
TG
93};
94
2c5859af 95static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
bc945c2b
YW
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",
f7996e2a 106 [NETDEV_KIND_HSR] = "hsr",
bc945c2b
YW
107 [NETDEV_KIND_IFB] = "ifb",
108 [NETDEV_KIND_IP6GRE] = "ip6gre",
b16492f8 109 [NETDEV_KIND_IP6GRETAP] = "ip6gretap",
bc945c2b
YW
110 [NETDEV_KIND_IP6TNL] = "ip6tnl",
111 [NETDEV_KIND_IPIP] = "ipip",
b90d0f83 112 [NETDEV_KIND_IPOIB] = "ipoib",
bc945c2b
YW
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",
bc945c2b
YW
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",
ec4954d9 132 [NETDEV_KIND_WLAN] = "wlan",
bc945c2b 133 [NETDEV_KIND_XFRM] = "xfrm",
52433f6b 134};
02b59d57 135
1a436809 136DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
62facba1 137
9e2bbf99
YW
138bool netdev_is_managed(NetDev *netdev) {
139 if (!netdev || !netdev->manager || !netdev->ifname)
140 return false;
141
142 return hashmap_get(netdev->manager->netdevs, netdev->ifname) == netdev;
143}
144
798e5dc8
YW
145static bool netdev_is_stacked_and_independent(NetDev *netdev) {
146 assert(netdev);
147
3d24b0dd 148 if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
798e5dc8
YW
149 return false;
150
151 switch (netdev->kind) {
152 case NETDEV_KIND_ERSPAN:
153 return ERSPAN(netdev)->independent;
154 case NETDEV_KIND_GRE:
155 return GRE(netdev)->independent;
156 case NETDEV_KIND_GRETAP:
157 return GRETAP(netdev)->independent;
158 case NETDEV_KIND_IP6GRE:
159 return IP6GRE(netdev)->independent;
160 case NETDEV_KIND_IP6GRETAP:
161 return IP6GRETAP(netdev)->independent;
162 case NETDEV_KIND_IP6TNL:
163 return IP6TNL(netdev)->independent;
164 case NETDEV_KIND_IPIP:
165 return IPIP(netdev)->independent;
166 case NETDEV_KIND_SIT:
167 return SIT(netdev)->independent;
168 case NETDEV_KIND_VTI:
169 return VTI(netdev)->independent;
170 case NETDEV_KIND_VTI6:
171 return VTI6(netdev)->independent;
172 case NETDEV_KIND_VXLAN:
173 return VXLAN(netdev)->independent;
174 case NETDEV_KIND_XFRM:
175 return XFRM(netdev)->independent;
176 default:
177 return false;
178 }
179}
180
2f117922
YW
181static bool netdev_is_stacked(NetDev *netdev) {
182 assert(netdev);
183
3d24b0dd 184 if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
2f117922
YW
185 return false;
186
187 if (netdev_is_stacked_and_independent(netdev))
188 return false;
189
190 return true;
191}
192
0dc71b95
YW
193NetDev* netdev_detach_name(NetDev *netdev, const char *name) {
194 assert(netdev);
195
196 if (!netdev->manager || !name)
197 return NULL; /* Already detached or not attached yet. */
198
199 return hashmap_remove_value(netdev->manager->netdevs, name, netdev);
200}
201
202static NetDev* netdev_detach_impl(NetDev *netdev) {
203 assert(netdev);
204
c60cd572
YW
205 if (netdev->state != _NETDEV_STATE_INVALID &&
206 NETDEV_VTABLE(netdev) &&
207 NETDEV_VTABLE(netdev)->detach)
208 NETDEV_VTABLE(netdev)->detach(netdev);
209
0dc71b95
YW
210 NetDev *n = netdev_detach_name(netdev, netdev->ifname);
211
212 netdev->manager = NULL;
213 return n; /* Return NULL when it is not attached yet, or already detached. */
214}
215
216void netdev_detach(NetDev *netdev) {
217 assert(netdev);
218
219 netdev_unref(netdev_detach_impl(netdev));
c4397d94
YW
220}
221
0dc71b95 222static NetDev* netdev_free(NetDev *netdev) {
8301aa0b 223 assert(netdev);
59cb64e6 224
c60cd572
YW
225 netdev_detach_impl(netdev);
226
f3c33b23
LP
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 &&
235 NETDEV_VTABLE(netdev) &&
aa9f1140
TG
236 NETDEV_VTABLE(netdev)->done)
237 NETDEV_VTABLE(netdev)->done(netdev);
238
f475584e
YW
239 condition_free_list(netdev->conditions);
240 free(netdev->filename);
2cf9b1a0 241 strv_free(netdev->dropins);
b3ae4e86 242 hashmap_free(netdev->stats_by_path);
f475584e
YW
243 free(netdev->description);
244 free(netdev->ifname);
245
8301aa0b 246 return mfree(netdev);
14b746f7
TG
247}
248
8301aa0b 249DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
14b746f7 250
2cc7e981 251void netdev_drop(NetDev *netdev) {
2f117922 252 if (!netdev)
2cc7e981
TG
253 return;
254
2f117922
YW
255 if (netdev_is_stacked(netdev)) {
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;
259 netdev->ifindex = 0;
260
261 log_netdev_debug(netdev, "netdev removed");
262 return;
263 }
264
af7a86b8
YW
265 if (NETDEV_VTABLE(netdev) && NETDEV_VTABLE(netdev)->drop)
266 NETDEV_VTABLE(netdev)->drop(netdev);
267
2cc7e981
TG
268 netdev->state = NETDEV_STATE_LINGER;
269
79008bdd 270 log_netdev_debug(netdev, "netdev removed");
370e9930 271
0dc71b95 272 netdev_detach(netdev);
2cc7e981
TG
273}
274
3252a1f2 275static int netdev_attach_name_full(NetDev *netdev, const char *name, Hashmap **netdevs) {
bfacb8fe
YW
276 int r;
277
278 assert(netdev);
bfacb8fe
YW
279 assert(name);
280
3252a1f2 281 r = hashmap_ensure_put(netdevs, &string_hash_ops, name, netdev);
bfacb8fe
YW
282 if (r == -ENOMEM)
283 return log_oom();
284 if (r == -EEXIST) {
3252a1f2 285 NetDev *n = hashmap_get(*netdevs, name);
bfacb8fe
YW
286
287 assert(n);
288 if (!streq(netdev->filename, n->filename))
289 log_netdev_warning_errno(netdev, r,
290 "Device \"%s\" was already configured by \"%s\", ignoring %s.",
291 name, n->filename, netdev->filename);
292
293 return -EEXIST;
294 }
295 assert(r > 0);
296
297 return 0;
298}
299
3252a1f2
YW
300int netdev_attach_name(NetDev *netdev, const char *name) {
301 assert(netdev);
302 assert(netdev->manager);
303
304 return netdev_attach_name_full(netdev, name, &netdev->manager->netdevs);
305}
306
bfacb8fe
YW
307static int netdev_attach(NetDev *netdev) {
308 int r;
309
310 assert(netdev);
311 assert(netdev->ifname);
312
313 r = netdev_attach_name(netdev, netdev->ifname);
314 if (r < 0)
315 return r;
316
c60cd572
YW
317 if (NETDEV_VTABLE(netdev)->attach) {
318 r = NETDEV_VTABLE(netdev)->attach(netdev);
319 if (r < 0)
320 return r;
321 }
322
bfacb8fe
YW
323 return 0;
324}
325
1a436809
TG
326int netdev_get(Manager *manager, const char *name, NetDev **ret) {
327 NetDev *netdev;
02b59d57
TG
328
329 assert(manager);
330 assert(name);
331 assert(ret);
332
52433f6b 333 netdev = hashmap_get(manager->netdevs, name);
fef805b9 334 if (!netdev)
02b59d57 335 return -ENOENT;
02b59d57 336
52433f6b 337 *ret = netdev;
02b59d57
TG
338
339 return 0;
340}
341
1788c346
YW
342void link_assign_netdev(Link *link) {
343 _unused_ _cleanup_(netdev_unrefp) NetDev *old = NULL;
344 NetDev *netdev;
345
346 assert(link);
347 assert(link->manager);
348 assert(link->ifname);
349
350 old = TAKE_PTR(link->netdev);
351
352 if (netdev_get(link->manager, link->ifname, &netdev) < 0)
d1608355 353 goto not_found;
1788c346 354
c60cd572
YW
355 int ifindex = NETDEV_VTABLE(netdev)->get_ifindex ?
356 NETDEV_VTABLE(netdev)->get_ifindex(netdev, link->ifname) :
357 netdev->ifindex;
358 if (ifindex != link->ifindex)
d1608355 359 goto not_found;
1788c346
YW
360
361 if (NETDEV_VTABLE(netdev)->iftype != link->iftype)
d1608355 362 goto not_found;
1788c346
YW
363
364 if (!NETDEV_VTABLE(netdev)->skip_netdev_kind_check) {
365 const char *kind;
366
367 if (netdev->kind == NETDEV_KIND_TAP)
368 kind = "tun"; /* the kernel does not distinguish between tun and tap */
369 else
370 kind = netdev_kind_to_string(netdev->kind);
371
372 if (!streq_ptr(kind, link->kind))
d1608355 373 goto not_found;
1788c346
YW
374 }
375
376 link->netdev = netdev_ref(netdev);
377
d1608355
YW
378 if (netdev == old)
379 return; /* The same NetDev found. */
380
381 log_link_debug(link, "Found matching .netdev file: %s", netdev->filename);
382 link_dirty(link);
383 return;
384
385not_found:
386
387 if (old)
388 /* Previously assigned NetDev is detached from Manager? Update the state file. */
389 link_dirty(link);
1788c346
YW
390}
391
8f65304c 392void netdev_enter_failed(NetDev *netdev) {
52433f6b 393 netdev->state = NETDEV_STATE_FAILED;
02b59d57
TG
394}
395
5dc20e1a 396int netdev_enter_ready(NetDev *netdev) {
52433f6b 397 assert(netdev);
af4e9e2c 398 assert(netdev->ifname);
924fe430 399
422b7c85 400 if (!IN_SET(netdev->state, NETDEV_STATE_LOADING, NETDEV_STATE_CREATING))
ba5596ec
TG
401 return 0;
402
52433f6b 403 netdev->state = NETDEV_STATE_READY;
02b59d57 404
98b32556 405 log_netdev_info(netdev, "netdev ready");
02b59d57 406
540eb5f0 407 if (NETDEV_VTABLE(netdev)->post_create)
c2b19b8f 408 NETDEV_VTABLE(netdev)->post_create(netdev, NULL);
540eb5f0 409
02b59d57
TG
410 return 0;
411}
8469c1d3 412
b8b0c1a0
YW
413bool netdev_needs_reconfigure(NetDev *netdev, NetDevLocalAddressType type) {
414 assert(netdev);
415 assert(type < _NETDEV_LOCAL_ADDRESS_TYPE_MAX);
416
417 if (type < 0)
418 return true;
419
420 return NETDEV_VTABLE(netdev)->needs_reconfigure &&
421 NETDEV_VTABLE(netdev)->needs_reconfigure(netdev, type);
422}
423
d5b3d845 424/* callback for netdev's created without a backing Link */
302a796f 425static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
172f6635 426 int r;
02b59d57 427
1046bf9b 428 assert(netdev);
52433f6b 429 assert(netdev->state != _NETDEV_STATE_INVALID);
02b59d57 430
1c4baffc 431 r = sd_netlink_message_get_errno(m);
b0d2ce83
YW
432 if (r >= 0)
433 log_netdev_debug(netdev, "Created.");
434 else if (r == -EEXIST && netdev->ifindex > 0)
435 log_netdev_debug(netdev, "Already exists.");
436 else {
437 log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
8f65304c 438 netdev_enter_failed(netdev);
b0d2ce83 439 return 0;
02b59d57
TG
440 }
441
b0d2ce83 442 return netdev_enter_ready(netdev);
02b59d57
TG
443}
444
5dc20e1a
YW
445int netdev_set_ifindex_internal(NetDev *netdev, int ifindex) {
446 assert(netdev);
447 assert(ifindex > 0);
448
449 if (netdev->ifindex == ifindex)
450 return 0; /* Already set. */
451
452 if (netdev->ifindex > 0 && netdev->ifindex != ifindex)
453 return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EEXIST),
454 "Could not set ifindex to %i, already set to %i.",
455 ifindex, netdev->ifindex);
456
457 netdev->ifindex = ifindex;
458 log_netdev_debug(netdev, "Gained index %i.", ifindex);
459 return 1; /* set new ifindex. */
460}
461
462static int netdev_set_ifindex_impl(NetDev *netdev, const char *name, int ifindex) {
5dc20e1a
YW
463 assert(netdev);
464 assert(name);
465 assert(ifindex > 0);
466
c60cd572
YW
467 if (NETDEV_VTABLE(netdev)->set_ifindex)
468 return NETDEV_VTABLE(netdev)->set_ifindex(netdev, name, ifindex);
469
5dc20e1a
YW
470 if (!streq(netdev->ifname, name))
471 return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
472 "Received netlink message with unexpected interface name %s (ifindex=%i).",
473 name, ifindex);
474
b0d2ce83 475 return netdev_set_ifindex_internal(netdev, ifindex);
5dc20e1a
YW
476}
477
1c4baffc 478int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
c3ebdce3 479 uint16_t type;
d39edfc7 480 const char *kind;
ca4e095a
LP
481 const char *received_kind;
482 const char *received_name;
5d7de250 483 int r, ifindex, family;
d39edfc7 484
50add290 485 assert(netdev);
c3ebdce3 486 assert(message);
02b59d57 487
1c4baffc 488 r = sd_netlink_message_get_type(message, &type);
6a7a4e4d 489 if (r < 0)
bc0d3f38 490 return log_netdev_warning_errno(netdev, r, "Could not get rtnl message type: %m");
c3ebdce3 491
5a9494be 492 if (type != RTM_NEWLINK)
bc0d3f38 493 return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Cannot set ifindex from unexpected rtnl message type.");
d39edfc7 494
5d7de250
YW
495 r = sd_rtnl_message_get_family(message, &family);
496 if (r < 0)
497 return log_netdev_warning_errno(netdev, r, "Failed to get family from received rtnl message: %m");
498
499 if (family != AF_UNSPEC)
500 return 0; /* IFLA_LINKINFO is only contained in the message with AF_UNSPEC. */
501
a21df104 502 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
bc0d3f38
YW
503 if (r < 0)
504 return log_netdev_warning_errno(netdev, r, "Could not get ifindex: %m");
505 if (ifindex <= 0)
506 return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Got invalid ifindex: %d", ifindex);
a21df104 507
1c4baffc 508 r = sd_netlink_message_read_string(message, IFLA_IFNAME, &received_name);
6a7a4e4d 509 if (r < 0)
bc0d3f38 510 return log_netdev_warning_errno(netdev, r, "Could not get IFNAME: %m");
c6315a7a 511
1d4312d5
YW
512 if (!NETDEV_VTABLE(netdev)->skip_netdev_kind_check) {
513
514 r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
515 if (r < 0)
bc0d3f38 516 return log_netdev_warning_errno(netdev, r, "Could not get LINKINFO: %m");
1d4312d5
YW
517
518 r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
519 if (r < 0)
bc0d3f38 520 return log_netdev_warning_errno(netdev, r, "Could not get KIND: %m");
1d4312d5
YW
521
522 r = sd_netlink_message_exit_container(message);
523 if (r < 0)
bc0d3f38 524 return log_netdev_warning_errno(netdev, r, "Could not exit container: %m");
1d4312d5
YW
525
526 if (netdev->kind == NETDEV_KIND_TAP)
527 /* the kernel does not distinguish between tun and tap */
528 kind = "tun";
bc0d3f38 529 else
1d4312d5 530 kind = netdev_kind_to_string(netdev->kind);
bc0d3f38
YW
531 if (!kind)
532 return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Could not get netdev kind.");
533
534 if (!streq(kind, received_kind))
535 return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
536 "Received newlink with wrong KIND %s, expected %s",
537 received_kind, kind);
c3ebdce3
TG
538 }
539
5dc20e1a 540 return netdev_set_ifindex_impl(netdev, received_name, ifindex);
02b59d57
TG
541}
542
5c8f858d
TG
543#define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
544
a8ee2b8e
YW
545int netdev_generate_hw_addr(
546 NetDev *netdev,
b90d0f83 547 Link *parent,
a8ee2b8e
YW
548 const char *name,
549 const struct hw_addr_data *hw_addr,
550 struct hw_addr_data *ret) {
551
552 struct hw_addr_data a = HW_ADDR_NULL;
45aa0e84 553 bool is_static = false;
5c8f858d
TG
554 int r;
555
007899f4
YW
556 assert(netdev);
557 assert(name);
558 assert(hw_addr);
a8ee2b8e 559 assert(ret);
5c8f858d 560
a8ee2b8e
YW
561 if (hw_addr_equal(hw_addr, &HW_ADDR_NONE)) {
562 *ret = HW_ADDR_NULL;
aaa5ca57 563 return 0;
a8ee2b8e 564 }
aaa5ca57 565
007899f4
YW
566 if (hw_addr->length == 0) {
567 uint64_t result;
5c8f858d 568
007899f4 569 /* HardwareAddress= is not specified. */
5c8f858d 570
007899f4 571 if (!NETDEV_VTABLE(netdev)->generate_mac)
a8ee2b8e 572 goto finalize;
5c8f858d 573
b90d0f83 574 if (!IN_SET(NETDEV_VTABLE(netdev)->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
a8ee2b8e 575 goto finalize;
5c8f858d 576
007899f4
YW
577 r = net_get_unique_predictable_data_from_name(name, &HASH_KEY, &result);
578 if (r < 0) {
579 log_netdev_warning_errno(netdev, r,
580 "Failed to generate persistent MAC address, ignoring: %m");
a8ee2b8e 581 goto finalize;
007899f4 582 }
5c8f858d 583
007899f4 584 a.length = arphrd_to_hw_addr_len(NETDEV_VTABLE(netdev)->iftype);
5c8f858d 585
b90d0f83
YW
586 switch (NETDEV_VTABLE(netdev)->iftype) {
587 case ARPHRD_ETHER:
588 assert(a.length <= sizeof(result));
589 memcpy(a.bytes, &result, a.length);
590
591 if (ether_addr_is_null(&a.ether) || ether_addr_is_broadcast(&a.ether)) {
4e494e6a 592 log_netdev_warning(netdev, "Failed to generate persistent MAC address, ignoring.");
b90d0f83
YW
593 a = HW_ADDR_NULL;
594 goto finalize;
595 }
596
597 break;
598 case ARPHRD_INFINIBAND:
599 if (result == 0) {
4e494e6a 600 log_netdev_warning(netdev, "Failed to generate persistent MAC address.");
b90d0f83
YW
601 goto finalize;
602 }
603
604 assert(a.length >= sizeof(result));
605 memzero(a.bytes, a.length - sizeof(result));
606 memcpy(a.bytes + a.length - sizeof(result), &result, sizeof(result));
607 break;
608 default:
609 assert_not_reached();
007899f4 610 }
b90d0f83 611
007899f4
YW
612 } else {
613 a = *hw_addr;
45aa0e84 614 is_static = true;
007899f4
YW
615 }
616
45aa0e84 617 r = net_verify_hardware_address(name, is_static, NETDEV_VTABLE(netdev)->iftype,
b90d0f83 618 parent ? &parent->hw_addr : NULL, &a);
007899f4
YW
619 if (r < 0)
620 return r;
621
a8ee2b8e
YW
622finalize:
623 *ret = a;
5c8f858d
TG
624 return 0;
625}
626
17c5337f
YW
627static bool netdev_can_set_mac(NetDev *netdev, const struct hw_addr_data *hw_addr) {
628 assert(netdev);
09db4106 629 assert(netdev->manager);
17c5337f
YW
630 assert(hw_addr);
631
632 if (hw_addr->length <= 0)
633 return false;
634
09db4106
YW
635 Link *link;
636 if (link_get_by_index(netdev->manager, netdev->ifindex, &link) < 0)
637 return true; /* The netdev does not exist yet. We can set MAC address. */
638
639 if (hw_addr_equal(&link->hw_addr, hw_addr))
640 return false; /* Unchanged, not necessary to set. */
641
efb158a1 642 /* Some netdevs refuse to update MAC address even if the interface is not running, e.g. ipvlan.
09db4106
YW
643 * Some other netdevs have the IFF_LIVE_ADDR_CHANGE flag and can update update MAC address even if
644 * the interface is running, e.g. dummy. For those cases, use custom checkers. */
645 if (NETDEV_VTABLE(netdev)->can_set_mac)
646 return NETDEV_VTABLE(netdev)->can_set_mac(netdev, hw_addr);
647
648 /* Before ad72c4a06acc6762e84994ac2f722da7a07df34e and 0ec92a8f56ff07237dbe8af7c7a72aba7f957baf
649 * (both in v6.5), the kernel refuse to set MAC address for existing netdevs even if it is unchanged.
650 * So, by default, do not update MAC address if the it is running. See eth_prepare_mac_addr_change(),
651 * which is called by eth_mac_addr(). Note, the result of netif_running() is mapped to operstate
652 * and flags. See rtnl_fill_ifinfo() and dev_get_flags(). */
653 return link->kernel_operstate == IF_OPER_DOWN &&
654 (link->flags & (IFF_RUNNING | IFF_LOWER_UP | IFF_DORMANT)) == 0;
17c5337f
YW
655}
656
657static bool netdev_can_set_mtu(NetDev *netdev, uint32_t mtu) {
658 assert(netdev);
659
660 if (mtu <= 0)
661 return false;
662
09db4106
YW
663 Link *link;
664 if (link_get_by_index(netdev->manager, netdev->ifindex, &link) < 0)
665 return true; /* The netdev does not exist yet. We can set MTU. */
17c5337f 666
09db4106
YW
667 if (mtu < link->min_mtu || link->max_mtu < mtu)
668 return false; /* The MTU is out of range. */
669
670 if (link->mtu == mtu)
671 return false; /* Unchanged, not necessary to set. */
672
673 /* Some netdevs cannot change MTU, e.g. vxlan. Let's use the custom checkers in such cases. */
674 if (NETDEV_VTABLE(netdev)->can_set_mtu)
675 return NETDEV_VTABLE(netdev)->can_set_mtu(netdev, mtu);
676
677 /* By default, allow to update the MTU. */
678 return true;
17c5337f
YW
679}
680
0c50cb50 681static int netdev_create_message(NetDev *netdev, Link *link, sd_netlink_message *m) {
aa9f1140
TG
682 int r;
683
ab6d4275
YW
684 if (netdev->ifindex <= 0) {
685 /* Set interface name when it is newly created. Otherwise, the kernel older than
686 * bd039b5ea2a91ea707ee8539df26456bd5be80af (v6.2) will refuse the netlink message even if
687 * the name is unchanged. */
688 r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
689 if (r < 0)
690 return r;
691 }
aa9f1140 692
0c50cb50 693 struct hw_addr_data hw_addr;
b90d0f83 694 r = netdev_generate_hw_addr(netdev, link, netdev->ifname, &netdev->hw_addr, &hw_addr);
a8ee2b8e
YW
695 if (r < 0)
696 return r;
697
17c5337f 698 if (netdev_can_set_mac(netdev, &hw_addr)) {
a8ee2b8e
YW
699 log_netdev_debug(netdev, "Using MAC address: %s", HW_ADDR_TO_STR(&hw_addr));
700 r = netlink_message_append_hw_addr(m, IFLA_ADDRESS, &hw_addr);
6a7a4e4d 701 if (r < 0)
0c50cb50 702 return r;
28a8cc0a 703 }
aa9f1140 704
17c5337f 705 if (netdev_can_set_mtu(netdev, netdev->mtu)) {
28a8cc0a 706 r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
6a7a4e4d 707 if (r < 0)
0c50cb50 708 return r;
28a8cc0a 709 }
aa9f1140 710
28a8cc0a
YW
711 if (link) {
712 r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
713 if (r < 0)
0c50cb50 714 return r;
28a8cc0a 715 }
aa9f1140 716
28a8cc0a
YW
717 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
718 if (r < 0)
0c50cb50 719 return r;
aa9f1140 720
28a8cc0a
YW
721 if (NETDEV_VTABLE(netdev)->fill_message_create) {
722 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
723 if (r < 0)
0c50cb50 724 return r;
aa9f1140 725
28a8cc0a 726 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
6a7a4e4d 727 if (r < 0)
0c50cb50 728 return r;
aa9f1140 729
1c4baffc 730 r = sd_netlink_message_close_container(m);
6a7a4e4d 731 if (r < 0)
0c50cb50 732 return r;
28a8cc0a
YW
733 } else {
734 r = sd_netlink_message_append_string(m, IFLA_INFO_KIND, netdev_kind_to_string(netdev->kind));
735 if (r < 0)
0c50cb50 736 return r;
28a8cc0a 737 }
aa9f1140 738
28a8cc0a
YW
739 r = sd_netlink_message_close_container(m);
740 if (r < 0)
0c50cb50
ZJS
741 return r;
742
743 return 0;
744}
745
b4d6ae63 746static int independent_netdev_create(NetDev *netdev) {
0c50cb50
ZJS
747 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
748 int r;
749
750 assert(netdev);
10030936 751 assert(netdev->manager);
0c50cb50
ZJS
752
753 /* create netdev */
754 if (NETDEV_VTABLE(netdev)->create) {
0c50cb50
ZJS
755 r = NETDEV_VTABLE(netdev)->create(netdev);
756 if (r < 0)
757 return r;
758
759 log_netdev_debug(netdev, "Created");
760 return 0;
761 }
762
890bd722 763 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex);
0c50cb50 764 if (r < 0)
b4d6ae63 765 return r;
0c50cb50 766
b4d6ae63 767 r = netdev_create_message(netdev, NULL, m);
0c50cb50 768 if (r < 0)
b4d6ae63 769 return r;
aa9f1140 770
b4d6ae63
YW
771 r = netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
772 netdev_destroy_callback, netdev);
773 if (r < 0)
774 return r;
28a8cc0a 775
b4d6ae63 776 netdev_ref(netdev);
aa9f1140 777
28a8cc0a 778 netdev->state = NETDEV_STATE_CREATING;
28a8cc0a 779 log_netdev_debug(netdev, "Creating");
aa9f1140
TG
780 return 0;
781}
782
54ff39f7 783static int stacked_netdev_create(NetDev *netdev, Link *link, Request *req) {
b4d6ae63 784 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
aa9f1140
TG
785 int r;
786
787 assert(netdev);
788 assert(netdev->manager);
b4d6ae63 789 assert(link);
54ff39f7 790 assert(req);
aa9f1140 791
890bd722 792 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, netdev->ifindex);
b4d6ae63
YW
793 if (r < 0)
794 return r;
aa9f1140 795
b4d6ae63
YW
796 r = netdev_create_message(netdev, link, m);
797 if (r < 0)
798 return r;
799
80d62d4f 800 r = request_call_netlink_async(netdev->manager->rtnl, m, req);
b4d6ae63
YW
801 if (r < 0)
802 return r;
803
b4d6ae63
YW
804 netdev->state = NETDEV_STATE_CREATING;
805 log_netdev_debug(netdev, "Creating");
aa9f1140
TG
806 return 0;
807}
808
e33232d4 809static bool link_is_ready_to_create_stacked_netdev_one(Link *link, bool allow_unmanaged) {
00117f88
YW
810 assert(link);
811
e33232d4 812 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED, LINK_STATE_UNMANAGED))
00117f88
YW
813 return false;
814
e33232d4
YW
815 if (!link->network)
816 return allow_unmanaged;
817
00117f88
YW
818 if (link->set_link_messages > 0)
819 return false;
820
821 /* If stacked netdevs are created before the underlying interface being activated, then
822 * the activation policy for the netdevs are ignored. See issue #22593. */
823 if (!link->activated)
824 return false;
825
826 return true;
827}
828
e33232d4
YW
829static bool link_is_ready_to_create_stacked_netdev(Link *link) {
830 return check_ready_for_all_sr_iov_ports(link, /* allow_unmanaged = */ false,
831 link_is_ready_to_create_stacked_netdev_one);
832}
833
d708bc6e 834static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
71a754f7 835 assert(netdev);
71a754f7 836
00117f88
YW
837 if (link && !link_is_ready_to_create_stacked_netdev(link))
838 return false;
71a754f7 839
562729d7
YW
840 if (NETDEV_VTABLE(netdev)->is_ready_to_create)
841 return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link);
842
71a754f7
YW
843 return true;
844}
845
09d09207 846static int stacked_netdev_process_request(Request *req, Link *link, void *userdata) {
ff51134c 847 NetDev *netdev = ASSERT_PTR(userdata);
71a754f7
YW
848 int r;
849
850 assert(req);
ff51134c 851 assert(link);
b4d6ae63 852
10030936 853 if (!netdev_is_managed(netdev))
f264cd20 854 goto cancelled; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
10030936 855
422b7c85
YW
856 if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
857 /* Already exists, and the netdev does not support updating, entering the ready state. */
858 r = netdev_enter_ready(netdev);
859 if (r < 0)
860 return r;
861
862 goto cancelled;
863 }
864
b4d6ae63 865 r = netdev_is_ready_to_create(netdev, link);
d708bc6e
YW
866 if (r <= 0)
867 return r;
71a754f7 868
54ff39f7 869 r = stacked_netdev_create(netdev, link, req);
71a754f7 870 if (r < 0)
b4d6ae63 871 return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
71a754f7
YW
872
873 return 1;
f264cd20
YW
874
875cancelled:
876 assert_se(TAKE_PTR(req->counter) == &link->create_stacked_netdev_messages);
877 link->create_stacked_netdev_messages--;
878
879 if (link->create_stacked_netdev_messages == 0) {
880 link->stacked_netdevs_created = true;
881 log_link_debug(link, "Stacked netdevs created.");
882 link_check_ready(link);
883 }
884
885 return 1;
71a754f7
YW
886}
887
80d62d4f 888static int create_stacked_netdev_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
b0d2ce83 889 NetDev *netdev = ASSERT_PTR(userdata);
71a754f7
YW
890 int r;
891
892 assert(m);
893 assert(link);
71a754f7
YW
894
895 r = sd_netlink_message_get_errno(m);
b0d2ce83
YW
896 if (r >= 0)
897 log_netdev_debug(netdev, "Created.");
898 else if (r == -EEXIST && netdev->ifindex > 0)
899 log_netdev_debug(netdev, "Already exists.");
900 else {
901 log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
902 netdev_enter_failed(netdev);
71a754f7
YW
903 link_enter_failed(link);
904 return 0;
905 }
906
b0d2ce83
YW
907 (void) netdev_enter_ready(netdev);
908
71a754f7
YW
909 if (link->create_stacked_netdev_messages == 0) {
910 link->stacked_netdevs_created = true;
911 log_link_debug(link, "Stacked netdevs created.");
bb916f35 912 link_check_ready(link);
71a754f7
YW
913 }
914
915 return 0;
916}
917
b14686ff 918int link_request_stacked_netdev(Link *link, NetDev *netdev) {
71a754f7
YW
919 int r;
920
921 assert(link);
922 assert(netdev);
923
2f117922 924 if (!netdev_is_stacked(netdev))
71a754f7
YW
925 return -EINVAL;
926
10030936
YW
927 if (!netdev_is_managed(netdev))
928 return 0; /* Already detached, due to e.g. reloading .netdev files. */
929
3d24b0dd 930 link->stacked_netdevs_created = false;
09d09207 931 r = link_queue_request_full(link, REQUEST_TYPE_NETDEV_STACKED,
d256945f 932 netdev, (mfree_func_t) netdev_unref,
09d09207
YW
933 trivial_hash_func, trivial_compare_func,
934 stacked_netdev_process_request,
935 &link->create_stacked_netdev_messages,
936 create_stacked_netdev_handler, NULL);
71a754f7 937 if (r < 0)
b14686ff 938 return log_link_error_errno(link, r, "Failed to request stacked netdev '%s': %m",
71a754f7 939 netdev->ifname);
d256945f
YW
940 if (r == 0)
941 return 0;
71a754f7 942
d256945f 943 netdev_ref(netdev);
b14686ff 944 log_link_debug(link, "Requested stacked netdev '%s'", netdev->ifname);
d256945f 945 return 1;
71a754f7
YW
946}
947
09d09207 948static int independent_netdev_process_request(Request *req, Link *link, void *userdata) {
ff51134c 949 NetDev *netdev = ASSERT_PTR(userdata);
5d4a925a
YW
950 int r;
951
ff51134c 952 assert(!link);
b4d6ae63 953
10030936
YW
954 if (!netdev_is_managed(netdev))
955 return 1; /* Already detached, due to e.g. reloading .netdev files, cancelling the request. */
956
422b7c85
YW
957 if (NETDEV_VTABLE(netdev)->keep_existing && netdev->ifindex > 0) {
958 /* Already exists, and the netdev does not support updating, entering the ready state. */
959 r = netdev_enter_ready(netdev);
960 if (r < 0)
961 return r;
962
963 return 1; /* Skip this request. */
964 }
965
b4d6ae63 966 r = netdev_is_ready_to_create(netdev, NULL);
5d4a925a
YW
967 if (r <= 0)
968 return r;
969
b4d6ae63 970 r = independent_netdev_create(netdev);
5d4a925a 971 if (r < 0)
b4d6ae63 972 return log_netdev_warning_errno(netdev, r, "Failed to create netdev: %m");
5d4a925a
YW
973
974 return 1;
975}
976
b4d6ae63 977static int netdev_request_to_create(NetDev *netdev) {
5d4a925a
YW
978 int r;
979
980 assert(netdev);
4f6ae866
YW
981 assert(netdev->manager);
982
983 if (netdev->manager->test_mode)
984 return 0;
5d4a925a 985
eae0d010 986 if (netdev_is_stacked(netdev))
5d4a925a
YW
987 return 0;
988
10030936
YW
989 if (!netdev_is_managed(netdev))
990 return 0; /* Already detached, due to e.g. reloading .netdev files. */
991
890bd722
YW
992 if (netdev->state != NETDEV_STATE_LOADING)
993 return 0; /* Already configured (at least tried previously). Not necessary to reconfigure. */
994
259125d5 995 r = netdev_queue_request(netdev, independent_netdev_process_request, NULL);
5d4a925a 996 if (r < 0)
259125d5 997 return log_netdev_warning_errno(netdev, r, "Failed to request to create netdev: %m");
5d4a925a 998
b4d6ae63 999 return 0;
5d4a925a
YW
1000}
1001
933d88f7 1002int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) {
8e766630 1003 _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
6b783209 1004 _cleanup_free_ char *file_basename = NULL;
2cc34d5b 1005 const char *dropin_dirname;
02b59d57
TG
1006 int r;
1007
bf1bc670
TA
1008 assert(manager);
1009 assert(filename);
933d88f7 1010 assert(ret);
bf1bc670 1011
4e54a17d 1012 r = null_or_empty_path(filename);
4e54a17d 1013 if (r < 0)
61ec7bea 1014 return log_warning_errno(r, "Failed to check if \"%s\" is empty: %m", filename);
933d88f7
YW
1015 if (r > 0)
1016 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Skipping empty file: %s", filename);
ed88bcfb 1017
17f9c355 1018 netdev_raw = new(NetDev, 1);
aa9f1140 1019 if (!netdev_raw)
02b59d57
TG
1020 return log_oom();
1021
17f9c355
YW
1022 *netdev_raw = (NetDev) {
1023 .n_ref = 1,
1024 .kind = _NETDEV_KIND_INVALID,
1025 .state = _NETDEV_STATE_INVALID, /* an invalid state means done() of the implementation won't be called on destruction */
1026 };
02b59d57 1027
6b783209
W
1028 r = path_extract_filename(filename, &file_basename);
1029 if (r < 0)
1030 return log_warning_errno(r, "Failed to extract file name of '%s': %m", filename);
1031
1032 dropin_dirname = strjoina(file_basename, ".d");
4f9ff96a 1033 r = config_parse_many(
947f59ba 1034 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root = */ NULL,
4f9ff96a
LP
1035 NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
1036 config_item_perf_lookup, network_netdev_gperf_lookup,
1037 CONFIG_PARSE_WARN,
1038 netdev_raw,
ead3a3fc 1039 NULL,
4f9ff96a 1040 NULL);
36f822c4 1041 if (r < 0)
61ec7bea 1042 return r; /* config_parse_many() logs internally. */
02b59d57 1043
2023dc8a 1044 /* skip out early if configuration does not match the environment */
933d88f7
YW
1045 if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL))
1046 return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "%s: Conditions in the file do not match the system environment, skipping.", filename);
2023dc8a 1047
61ec7bea
YW
1048 if (netdev_raw->kind == _NETDEV_KIND_INVALID)
1049 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev has no Kind= configured in \"%s\", ignoring.", filename);
2023dc8a 1050
61ec7bea
YW
1051 if (!netdev_raw->ifname)
1052 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "NetDev without Name= configured in \"%s\", ignoring.", filename);
326cb406 1053
aa9f1140
TG
1054 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
1055 if (!netdev)
1056 return log_oom();
fe6b2d55 1057
aa9f1140
TG
1058 netdev->n_ref = 1;
1059 netdev->manager = manager;
aa9f1140 1060 netdev->kind = netdev_raw->kind;
c6e77d7b
YW
1061 netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time,
1062 so that done() will be called on destruction */
326cb406 1063
aa9f1140
TG
1064 if (NETDEV_VTABLE(netdev)->init)
1065 NETDEV_VTABLE(netdev)->init(netdev);
1066
4f9ff96a 1067 r = config_parse_many(
947f59ba 1068 STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, /* root = */ NULL,
4f9ff96a
LP
1069 NETDEV_VTABLE(netdev)->sections,
1070 config_item_perf_lookup, network_netdev_gperf_lookup,
1071 CONFIG_PARSE_WARN,
2cf9b1a0 1072 netdev,
b3ae4e86 1073 &netdev->stats_by_path,
2cf9b1a0 1074 &netdev->dropins);
aa9f1140 1075 if (r < 0)
61ec7bea 1076 return r; /* config_parse_many() logs internally. */
aa9f1140
TG
1077
1078 /* verify configuration */
1079 if (NETDEV_VTABLE(netdev)->config_verify) {
1080 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
1081 if (r < 0)
61ec7bea 1082 return r; /* config_verify() logs internally. */
fe6b2d55
TG
1083 }
1084
52433f6b
TG
1085 netdev->filename = strdup(filename);
1086 if (!netdev->filename)
02b59d57
TG
1087 return log_oom();
1088
25da422b 1089 log_syntax(/* unit = */ NULL, LOG_DEBUG, filename, /* config_line = */ 0, /* error = */ 0, "Successfully loaded.");
3be1d7e0 1090
933d88f7 1091 *ret = TAKE_PTR(netdev);
02b59d57
TG
1092 return 0;
1093}
1094
173c9f63 1095int netdev_load(Manager *manager) {
6a7a4e4d 1096 _cleanup_strv_free_ char **files = NULL;
02b59d57
TG
1097 int r;
1098
1099 assert(manager);
1100
dc0d4078 1101 r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS);
f647962d
MS
1102 if (r < 0)
1103 return log_error_errno(r, "Failed to enumerate netdev files: %m");
02b59d57 1104
933d88f7
YW
1105 STRV_FOREACH(f, files) {
1106 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
1107
1108 if (netdev_load_one(manager, *f, &netdev) < 0)
1109 continue;
1110
1111 if (netdev_attach(netdev) < 0)
1112 continue;
1113
1114 if (netdev_request_to_create(netdev) < 0)
1115 continue;
1116
1117 TAKE_PTR(netdev);
1118 }
02b59d57 1119
02b59d57
TG
1120 return 0;
1121}
5dcc5b1a 1122
b3ae4e86
YW
1123int netdev_reload(Manager *manager) {
1124 _cleanup_hashmap_free_ Hashmap *new_netdevs = NULL;
1125 _cleanup_strv_free_ char **files = NULL;
1126 int r;
1127
1128 assert(manager);
1129
1130 r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS);
1131 if (r < 0)
1132 return log_error_errno(r, "Failed to enumerate netdev files: %m");
1133
1134 STRV_FOREACH(f, files) {
1135 _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
1136 NetDev *old;
1137
1138 if (netdev_load_one(manager, *f, &netdev) < 0)
1139 continue;
1140
1141 if (netdev_get(manager, netdev->ifname, &old) < 0) {
1142 log_netdev_debug(netdev, "Found new .netdev file: %s", netdev->filename);
1143
1144 if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0)
1145 TAKE_PTR(netdev);
1146
1147 continue;
1148 }
1149
1150 if (!stats_by_path_equal(netdev->stats_by_path, old->stats_by_path)) {
1151 log_netdev_debug(netdev, "Found updated .netdev file: %s", netdev->filename);
1152
1153 /* Copy ifindex. */
1154 netdev->ifindex = old->ifindex;
1155
1156 if (netdev_attach_name_full(netdev, netdev->ifname, &new_netdevs) >= 0)
1157 TAKE_PTR(netdev);
1158
1159 continue;
1160 }
1161
1162 /* Keep the original object, and drop the new one. */
1163 if (netdev_attach_name_full(old, old->ifname, &new_netdevs) >= 0)
1164 netdev_ref(old);
1165 }
1166
1167 /* Detach old NetDev objects from Manager.
bdf4f200 1168 * The same object may be registered with multiple names, and netdev_detach() may drop multiple entries. */
b3ae4e86
YW
1169 for (NetDev *n; (n = hashmap_first(manager->netdevs)); )
1170 netdev_detach(n);
1171
1172 /* Attach new NetDev objects to Manager. */
1173 for (;;) {
1174 _cleanup_(netdev_unrefp) NetDev *netdev = hashmap_steal_first(new_netdevs);
1175 if (!netdev)
1176 break;
1177
1178 netdev->manager = manager;
1179 if (netdev_attach(netdev) < 0)
1180 continue;
1181
1182 /* Create a new netdev or update existing netdev, */
1183 if (netdev_request_to_create(netdev) < 0)
1184 continue;
1185
1186 TAKE_PTR(netdev);
1187 }
1188
1189 /* Reassign NetDev objects to Link object. */
1190 Link *link;
1191 HASHMAP_FOREACH(link, manager->links_by_index)
1192 link_assign_netdev(link);
1193
1194 return 0;
1195}
1196
5dcc5b1a
YW
1197int config_parse_netdev_kind(
1198 const char *unit,
1199 const char *filename,
1200 unsigned line,
1201 const char *section,
1202 unsigned section_line,
1203 const char *lvalue,
1204 int ltype,
1205 const char *rvalue,
1206 void *data,
1207 void *userdata) {
1208
99534007 1209 NetDevKind k, *kind = ASSERT_PTR(data);
5dcc5b1a
YW
1210
1211 assert(filename);
1212 assert(rvalue);
5dcc5b1a
YW
1213
1214 k = netdev_kind_from_string(rvalue);
1215 if (k < 0) {
1216 log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse netdev kind, ignoring assignment: %s", rvalue);
1217 return 0;
1218 }
1219
1220 if (*kind != _NETDEV_KIND_INVALID && *kind != k) {
1221 log_syntax(unit, LOG_WARNING, filename, line, 0,
1222 "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s",
1223 netdev_kind_to_string(*kind), rvalue);
1224 return 0;
1225 }
1226
1227 *kind = k;
1228
1229 return 0;
1230}
aaa5ca57
YW
1231
1232int config_parse_netdev_hw_addr(
1233 const char *unit,
1234 const char *filename,
1235 unsigned line,
1236 const char *section,
1237 unsigned section_line,
1238 const char *lvalue,
1239 int ltype,
1240 const char *rvalue,
1241 void *data,
1242 void *userdata) {
1243
99534007 1244 struct hw_addr_data *hw_addr = ASSERT_PTR(data);
aaa5ca57
YW
1245
1246 assert(rvalue);
aaa5ca57
YW
1247
1248 if (streq(rvalue, "none")) {
1249 *hw_addr = HW_ADDR_NONE;
1250 return 0;
1251 }
1252
1253 return config_parse_hw_addr(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
1254}