]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev.c
networkd: netdev - rename 'enslave' to 'join'
[thirdparty/systemd.git] / src / network / networkd-netdev.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <net/if.h>
23
24 #include "networkd.h"
25 #include "network-internal.h"
26 #include "path-util.h"
27 #include "conf-files.h"
28 #include "conf-parser.h"
29 #include "list.h"
30 #include "siphash24.h"
31
32 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
33 [NETDEV_KIND_BRIDGE] = "bridge",
34 [NETDEV_KIND_BOND] = "bond",
35 [NETDEV_KIND_VLAN] = "vlan",
36 [NETDEV_KIND_MACVLAN] = "macvlan",
37 [NETDEV_KIND_VXLAN] = "vxlan",
38 [NETDEV_KIND_IPIP] = "ipip",
39 [NETDEV_KIND_GRE] = "gre",
40 [NETDEV_KIND_SIT] = "sit",
41 [NETDEV_KIND_VETH] = "veth",
42 [NETDEV_KIND_VTI] = "vti",
43 [NETDEV_KIND_DUMMY] = "dummy",
44 [NETDEV_KIND_TUN] = "tun",
45 [NETDEV_KIND_TAP] = "tap",
46 };
47
48 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
49 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
50
51
52 static void netdev_cancel_callbacks(NetDev *netdev) {
53 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
54 netdev_join_callback *callback;
55
56 if (!netdev)
57 return;
58
59 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
60
61 while ((callback = netdev->callbacks)) {
62 if (m) {
63 assert(callback->link);
64 assert(callback->callback);
65 assert(netdev->manager);
66 assert(netdev->manager->rtnl);
67
68 callback->callback(netdev->manager->rtnl, m, link);
69 }
70
71 LIST_REMOVE(callbacks, netdev->callbacks, callback);
72 free(callback);
73 }
74 }
75
76 static void netdev_free(NetDev *netdev) {
77 if (!netdev)
78 return;
79
80 netdev_cancel_callbacks(netdev);
81
82 if (netdev->ifname)
83 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
84
85 free(netdev->filename);
86
87 free(netdev->description);
88 free(netdev->ifname);
89 free(netdev->ifname_peer);
90 free(netdev->mac);
91 free(netdev->mac_peer);
92 free(netdev->user_name);
93 free(netdev->group_name);
94
95 condition_free_list(netdev->match_host);
96 condition_free_list(netdev->match_virt);
97 condition_free_list(netdev->match_kernel);
98 condition_free_list(netdev->match_arch);
99
100 free(netdev);
101 }
102
103 NetDev *netdev_unref(NetDev *netdev) {
104 if (netdev && (-- netdev->n_ref <= 0))
105 netdev_free(netdev);
106
107 return NULL;
108 }
109
110 NetDev *netdev_ref(NetDev *netdev) {
111 if (netdev)
112 assert_se(++ netdev->n_ref >= 2);
113
114 return netdev;
115 }
116
117 void netdev_drop(NetDev *netdev) {
118 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
119 return;
120
121 netdev->state = NETDEV_STATE_LINGER;
122
123 log_debug_netdev(netdev, "netdev removed");
124
125 netdev_cancel_callbacks(netdev);
126
127 netdev_unref(netdev);
128
129 return;
130 }
131
132 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
133 NetDev *netdev;
134
135 assert(manager);
136 assert(name);
137 assert(ret);
138
139 netdev = hashmap_get(manager->netdevs, name);
140 if (!netdev) {
141 *ret = NULL;
142 return -ENOENT;
143 }
144
145 *ret = netdev;
146
147 return 0;
148 }
149
150 static int netdev_enter_failed(NetDev *netdev) {
151 netdev->state = NETDEV_STATE_FAILED;
152
153 return 0;
154 }
155
156 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
157 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
158 int r;
159
160 assert(netdev);
161 assert(netdev->state == NETDEV_STATE_READY);
162 assert(netdev->manager);
163 assert(netdev->manager->rtnl);
164 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
165 assert(link);
166 assert(callback);
167
168 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
169 RTM_SETLINK, link->ifindex);
170 if (r < 0) {
171 log_error_netdev(netdev,
172 "Could not allocate RTM_SETLINK message: %s",
173 strerror(-r));
174 return r;
175 }
176
177 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
178 if (r < 0) {
179 log_error_netdev(netdev,
180 "Could not append IFLA_MASTER attribute: %s",
181 strerror(-r));
182 return r;
183 }
184
185 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
186 if (r < 0) {
187 log_error_netdev(netdev,
188 "Could not send rtnetlink message: %s",
189 strerror(-r));
190 return r;
191 }
192
193 link_ref(link);
194
195 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
196
197 return 0;
198 }
199
200 static int netdev_enter_ready(NetDev *netdev) {
201 netdev_join_callback *callback, *callback_next;
202 int r;
203
204 assert(netdev);
205 assert(netdev->ifname);
206
207 if (netdev->state != NETDEV_STATE_CREATING)
208 return 0;
209
210 netdev->state = NETDEV_STATE_READY;
211
212 log_info_netdev(netdev, "netdev ready");
213
214 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
215 /* enslave the links that were attempted to be enslaved before the
216 * link was ready */
217 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
218 if (r < 0)
219 return r;
220
221 LIST_REMOVE(callbacks, netdev->callbacks, callback);
222 link_unref(callback->link);
223 free(callback);
224 }
225
226 return 0;
227 }
228
229 /* callback for netdev's created without a backing Link */
230 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
231 _cleanup_netdev_unref_ NetDev *netdev = userdata;
232 int r;
233
234 assert(netdev->state != _NETDEV_STATE_INVALID);
235
236 r = sd_rtnl_message_get_errno(m);
237 if (r == -EEXIST)
238 log_debug_netdev(netdev, "netdev exists, using existing");
239 else if (r < 0) {
240 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
241 netdev_drop(netdev);
242
243 return 1;
244 }
245
246 return 1;
247 }
248
249 static int netdev_create(NetDev *netdev) {
250 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
251 const char *kind;
252 int r;
253
254 assert(netdev);
255 assert(netdev->ifname);
256 assert(netdev->manager);
257 assert(netdev->manager->rtnl);
258
259 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
260 if (r < 0) {
261 log_error_netdev(netdev,
262 "Could not allocate RTM_NEWLINK message: %s",
263 strerror(-r));
264 return r;
265 }
266
267 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
268 if (r < 0) {
269 log_error_netdev(netdev,
270 "Could not append IFLA_IFNAME attribute: %s",
271 strerror(-r));
272 return r;
273 }
274
275 if (netdev->mtu) {
276 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
277 if (r < 0) {
278 log_error_netdev(netdev,
279 "Could not append IFLA_MTU attribute: %s",
280 strerror(-r));
281 return r;
282 }
283 }
284
285 if (netdev->mac) {
286 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
287 if (r < 0) {
288 log_error_netdev(netdev,
289 "Colud not append IFLA_ADDRESS attribute: %s",
290 strerror(-r));
291 return r;
292 }
293 }
294
295 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
296 if (r < 0) {
297 log_error_netdev(netdev,
298 "Could not open IFLA_LINKINFO container: %s",
299 strerror(-r));
300 return r;
301 }
302
303 kind = netdev_kind_to_string(netdev->kind);
304 if (!kind) {
305 log_error_netdev(netdev, "Invalid kind");
306 return -EINVAL;
307 }
308
309 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
310 if (r < 0) {
311 log_error_netdev(netdev,
312 "Could not open IFLA_INFO_DATA container: %s",
313 strerror(-r));
314 return r;
315 }
316
317 r = sd_rtnl_message_close_container(req);
318 if (r < 0) {
319 log_error_netdev(netdev,
320 "Could not close IFLA_INFO_DATA container %s",
321 strerror(-r));
322 return r;
323 }
324
325 r = sd_rtnl_message_close_container(req);
326 if (r < 0) {
327 log_error_netdev(netdev,
328 "Could not close IFLA_LINKINFO container %s",
329 strerror(-r));
330 return r;
331 }
332
333 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
334 if (r < 0) {
335 log_error_netdev(netdev,
336 "Could not send rtnetlink message: %s", strerror(-r));
337 return r;
338 }
339
340 netdev_ref(netdev);
341
342 log_debug_netdev(netdev, "creating netdev");
343
344 netdev->state = NETDEV_STATE_CREATING;
345
346 return 0;
347 }
348
349 static int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
350 int r;
351
352 assert(netdev);
353 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
354
355 if (netdev->state == NETDEV_STATE_READY) {
356 r = netdev_enslave_ready(netdev, link, callback);
357 if (r < 0)
358 return r;
359 } else {
360 /* the netdev is not yet read, save this request for when it is*/
361 netdev_join_callback *cb;
362
363 cb = new0(netdev_join_callback, 1);
364 if (!cb)
365 return log_oom();
366
367 cb->callback = callback;
368 cb->link = link;
369 link_ref(link);
370
371 LIST_PREPEND(callbacks, netdev->callbacks, cb);
372 }
373
374 return 0;
375 }
376
377 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
378 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
379
380 assert(netdev);
381
382 switch(netdev->kind) {
383 case NETDEV_KIND_VLAN:
384 return netdev_create_vlan(netdev, link, callback);
385 case NETDEV_KIND_MACVLAN:
386 return netdev_create_macvlan(netdev, link, callback);
387 case NETDEV_KIND_VXLAN:
388 return netdev_create_vxlan(netdev, link, callback);
389 case NETDEV_KIND_IPIP:
390 case NETDEV_KIND_GRE:
391 case NETDEV_KIND_SIT:
392 case NETDEV_KIND_VTI:
393 return netdev_create_tunnel(netdev, link, callback);
394 case NETDEV_KIND_BRIDGE:
395 case NETDEV_KIND_BOND:
396 return netdev_enslave(netdev, link, callback);
397 default:
398 assert_not_reached("Enslaving by invalid netdev kind");
399 }
400
401 return 0;
402 }
403
404 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
405 uint16_t type;
406 const char *kind;
407 char *received_kind;
408 char *received_name;
409 int r, ifindex;
410
411 assert(netdev);
412 assert(message);
413
414 r = sd_rtnl_message_get_type(message, &type);
415 if (r < 0) {
416 log_error_netdev(netdev, "Could not get rtnl message type");
417 return r;
418 }
419
420 if (type != RTM_NEWLINK) {
421 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
422 return -EINVAL;
423 }
424
425 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
426 if (r < 0) {
427 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
428 netdev_enter_failed(netdev);
429 return r;
430 } else if (ifindex <= 0) {
431 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
432 netdev_enter_failed(netdev);
433 return r;
434 }
435
436 if (netdev->ifindex > 0) {
437 if (netdev->ifindex != ifindex) {
438 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
439 ifindex, netdev->ifindex);
440 netdev_enter_failed(netdev);
441 return -EEXIST;
442 } else
443 /* ifindex already set to the same for this netdev */
444 return 0;
445 }
446
447 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
448 if (r < 0) {
449 log_error_netdev(netdev, "Could not get IFNAME");
450 return r;
451 }
452
453 if (!streq(netdev->ifname, received_name)) {
454 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
455 received_name);
456 netdev_enter_failed(netdev);
457 return r;
458 }
459
460 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
461 if (r < 0) {
462 log_error_netdev(netdev, "Could not get LINKINFO");
463 return r;
464 }
465
466 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
467 if (r < 0) {
468 log_error_netdev(netdev, "Could not get KIND");
469 return r;
470 }
471
472 r = sd_rtnl_message_exit_container(message);
473 if (r < 0) {
474 log_error_netdev(netdev, "Could not exit container");
475 return r;
476 }
477
478 if (netdev->kind == NETDEV_KIND_TAP)
479 /* the kernel does not distinguish between tun and tap */
480 kind = "tun";
481 else {
482 kind = netdev_kind_to_string(netdev->kind);
483 if (!kind) {
484 log_error_netdev(netdev, "Could not get kind");
485 netdev_enter_failed(netdev);
486 return -EINVAL;
487 }
488 }
489
490 if (!streq(kind, received_kind)) {
491 log_error_netdev(netdev,
492 "Received newlink with wrong KIND %s, "
493 "expected %s", received_kind, kind);
494 netdev_enter_failed(netdev);
495 return r;
496 }
497
498 netdev->ifindex = ifindex;
499
500 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
501
502 netdev_enter_ready(netdev);
503
504 return 0;
505 }
506
507 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
508
509 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
510 _cleanup_free_ struct ether_addr *mac = NULL;
511 uint8_t result[8];
512 size_t l, sz;
513 uint8_t *v;
514 int r;
515
516 assert(ifname);
517 assert(ret);
518
519 mac = new0(struct ether_addr, 1);
520 if (!mac)
521 return -ENOMEM;
522
523 l = strlen(ifname);
524 sz = sizeof(sd_id128_t) + l;
525 v = alloca(sz);
526
527 /* fetch some persistent data unique to the machine */
528 r = sd_id128_get_machine((sd_id128_t*) v);
529 if (r < 0)
530 return r;
531
532 /* combine with some data unique (on this machine) to this
533 * netdev */
534 memcpy(v + sizeof(sd_id128_t), ifname, l);
535
536 /* Let's hash the host machine ID plus the container name. We
537 * use a fixed, but originally randomly created hash key here. */
538 siphash24(result, v, sz, HASH_KEY.bytes);
539
540 assert_cc(ETH_ALEN <= sizeof(result));
541 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
542
543 /* see eth_random_addr in the kernel */
544 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
545 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
546
547 *ret = mac;
548 mac = NULL;
549
550 return 0;
551 }
552
553 static int netdev_load_one(Manager *manager, const char *filename) {
554 _cleanup_netdev_unref_ NetDev *netdev = NULL;
555 _cleanup_fclose_ FILE *file = NULL;
556 int r;
557
558 assert(manager);
559 assert(filename);
560
561 if (null_or_empty_path(filename)) {
562 log_debug("skipping empty file: %s", filename);
563 return 0;
564 }
565
566 file = fopen(filename, "re");
567 if (!file) {
568 if (errno == ENOENT)
569 return 0;
570 else
571 return -errno;
572 }
573
574 netdev = new0(NetDev, 1);
575 if (!netdev)
576 return log_oom();
577
578 netdev->n_ref = 1;
579 netdev->manager = manager;
580 netdev->state = _NETDEV_STATE_INVALID;
581 netdev->kind = _NETDEV_KIND_INVALID;
582 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
583 netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
584 netdev->vlanid = VLANID_MAX + 1;
585 netdev->vxlanid = VXLAN_VID_MAX + 1;
586 netdev->tunnel_pmtudisc = true;
587 netdev->learning = true;
588
589 r = config_parse(NULL, filename, file,
590 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
591 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
592 false, false, netdev);
593 if (r < 0) {
594 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
595 return r;
596 }
597
598 switch (netdev->kind) {
599 case _NETDEV_KIND_INVALID:
600 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
601 return 0;
602 case NETDEV_KIND_VLAN:
603 if (netdev->vlanid > VLANID_MAX) {
604 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
605 return 0;
606 }
607 break;
608 case NETDEV_KIND_VXLAN:
609 if (netdev->vxlanid > VXLAN_VID_MAX) {
610 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
611 return 0;
612 }
613 break;
614 case NETDEV_KIND_IPIP:
615 case NETDEV_KIND_GRE:
616 case NETDEV_KIND_SIT:
617 case NETDEV_KIND_VTI:
618 if (netdev->local.in.s_addr == INADDR_ANY) {
619 log_warning("Tunnel without local address configured in %s. Ignoring", filename);
620 return 0;
621 }
622 if (netdev->remote.in.s_addr == INADDR_ANY) {
623 log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
624 return 0;
625 }
626 if (netdev->family != AF_INET) {
627 log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
628 return 0;
629 }
630 break;
631 default:
632 break;
633 }
634
635 if (!netdev->ifname) {
636 log_warning("NetDev without Name configured in %s. Ignoring", filename);
637 return 0;
638 }
639
640 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
641 log_warning("VLAN Id configured for a %s in %s. Ignoring",
642 netdev_kind_to_string(netdev->kind), filename);
643 return 0;
644 }
645
646 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
647 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
648 netdev_kind_to_string(netdev->kind), filename);
649 return 0;
650 }
651
652 if (netdev->kind != NETDEV_KIND_MACVLAN &&
653 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
654 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
655 netdev_kind_to_string(netdev->kind), filename);
656 return 0;
657 }
658
659 netdev->filename = strdup(filename);
660 if (!netdev->filename)
661 return log_oom();
662
663 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
664 netdev->match_host, netdev->match_virt,
665 netdev->match_kernel, netdev->match_arch,
666 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
667 return 0;
668
669 if (!netdev->mac) {
670 r = netdev_get_mac(netdev->ifname, &netdev->mac);
671 if (r < 0) {
672 log_error("Failed to generate predictable MAC address for %s",
673 netdev->ifname);
674 return r;
675 }
676 }
677
678 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
679 if (r < 0)
680 return r;
681
682 LIST_HEAD_INIT(netdev->callbacks);
683
684 switch (netdev->kind) {
685 case NETDEV_KIND_VETH:
686 if (!netdev->ifname_peer) {
687 log_warning("Veth NetDev without peer name configured "
688 "in %s. Ignoring", filename);
689 return 0;
690 }
691
692 if (!netdev->mac) {
693 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
694 if (r < 0) {
695 log_error("Failed to generate predictable MAC address for %s",
696 netdev->ifname_peer);
697 return r;
698 }
699 }
700
701 r = netdev_create_veth(netdev, netdev_create_handler);
702 if (r < 0)
703 return r;
704
705 break;
706 case NETDEV_KIND_DUMMY:
707 r = netdev_create_dummy(netdev, netdev_create_handler);
708 if (r < 0)
709 return r;
710
711 break;
712 case NETDEV_KIND_BRIDGE:
713 r = netdev_create(netdev);
714 if (r < 0)
715 return r;
716 break;
717 case NETDEV_KIND_BOND:
718 r = netdev_create_bond(netdev, netdev_create_handler);
719 if (r < 0)
720 return r;
721 break;
722 default:
723 break;
724 }
725
726 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
727
728 netdev = NULL;
729
730 return 0;
731 }
732
733 int netdev_load(Manager *manager) {
734 NetDev *netdev;
735 char **files, **f;
736 int r;
737
738 assert(manager);
739
740 while ((netdev = hashmap_first(manager->netdevs)))
741 netdev_unref(netdev);
742
743 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
744 if (r < 0) {
745 log_error("Failed to enumerate netdev files: %s", strerror(-r));
746 return r;
747 }
748
749 STRV_FOREACH_BACKWARDS(f, files) {
750 r = netdev_load_one(manager, *f);
751 if (r < 0)
752 return r;
753 }
754
755 strv_free(files);
756
757 return 0;
758 }