]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-netdev.c
tty-ask-password: Split out password sending
[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 "alloc-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
27 #include "fd-util.h"
28 #include "list.h"
29 #include "netlink-util.h"
30 #include "network-internal.h"
31 #include "networkd-netdev.h"
32 #include "networkd.h"
33 #include "siphash24.h"
34 #include "stat-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
37
38 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
39
40 [NETDEV_KIND_BRIDGE] = &bridge_vtable,
41 [NETDEV_KIND_BOND] = &bond_vtable,
42 [NETDEV_KIND_VLAN] = &vlan_vtable,
43 [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
44 [NETDEV_KIND_MACVTAP] = &macvtap_vtable,
45 [NETDEV_KIND_IPVLAN] = &ipvlan_vtable,
46 [NETDEV_KIND_VXLAN] = &vxlan_vtable,
47 [NETDEV_KIND_IPIP] = &ipip_vtable,
48 [NETDEV_KIND_GRE] = &gre_vtable,
49 [NETDEV_KIND_GRETAP] = &gretap_vtable,
50 [NETDEV_KIND_IP6GRE] = &ip6gre_vtable,
51 [NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
52 [NETDEV_KIND_SIT] = &sit_vtable,
53 [NETDEV_KIND_VTI] = &vti_vtable,
54 [NETDEV_KIND_VTI6] = &vti6_vtable,
55 [NETDEV_KIND_VETH] = &veth_vtable,
56 [NETDEV_KIND_DUMMY] = &dummy_vtable,
57 [NETDEV_KIND_TUN] = &tun_vtable,
58 [NETDEV_KIND_TAP] = &tap_vtable,
59 [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
60 };
61
62 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
63 [NETDEV_KIND_BRIDGE] = "bridge",
64 [NETDEV_KIND_BOND] = "bond",
65 [NETDEV_KIND_VLAN] = "vlan",
66 [NETDEV_KIND_MACVLAN] = "macvlan",
67 [NETDEV_KIND_MACVTAP] = "macvtap",
68 [NETDEV_KIND_IPVLAN] = "ipvlan",
69 [NETDEV_KIND_VXLAN] = "vxlan",
70 [NETDEV_KIND_IPIP] = "ipip",
71 [NETDEV_KIND_GRE] = "gre",
72 [NETDEV_KIND_GRETAP] = "gretap",
73 [NETDEV_KIND_IP6GRE] = "ip6gre",
74 [NETDEV_KIND_IP6GRETAP] = "ip6gretap",
75 [NETDEV_KIND_SIT] = "sit",
76 [NETDEV_KIND_VETH] = "veth",
77 [NETDEV_KIND_VTI] = "vti",
78 [NETDEV_KIND_VTI6] = "vti6",
79 [NETDEV_KIND_DUMMY] = "dummy",
80 [NETDEV_KIND_TUN] = "tun",
81 [NETDEV_KIND_TAP] = "tap",
82 [NETDEV_KIND_IP6TNL] = "ip6tnl",
83 };
84
85 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
86 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
87
88 static void netdev_cancel_callbacks(NetDev *netdev) {
89 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
90 netdev_join_callback *callback;
91
92 if (!netdev)
93 return;
94
95 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
96
97 while ((callback = netdev->callbacks)) {
98 if (m) {
99 assert(callback->link);
100 assert(callback->callback);
101 assert(netdev->manager);
102 assert(netdev->manager->rtnl);
103
104 callback->callback(netdev->manager->rtnl, m, callback->link);
105 }
106
107 LIST_REMOVE(callbacks, netdev->callbacks, callback);
108 link_unref(callback->link);
109 free(callback);
110 }
111 }
112
113 static void netdev_free(NetDev *netdev) {
114 if (!netdev)
115 return;
116
117 netdev_cancel_callbacks(netdev);
118
119 if (netdev->ifname)
120 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
121
122 free(netdev->filename);
123
124 free(netdev->description);
125 free(netdev->ifname);
126 free(netdev->mac);
127
128 condition_free_list(netdev->match_host);
129 condition_free_list(netdev->match_virt);
130 condition_free_list(netdev->match_kernel);
131 condition_free_list(netdev->match_arch);
132
133 if (NETDEV_VTABLE(netdev) &&
134 NETDEV_VTABLE(netdev)->done)
135 NETDEV_VTABLE(netdev)->done(netdev);
136
137 free(netdev);
138 }
139
140 NetDev *netdev_unref(NetDev *netdev) {
141 if (netdev && (-- netdev->n_ref <= 0))
142 netdev_free(netdev);
143
144 return NULL;
145 }
146
147 NetDev *netdev_ref(NetDev *netdev) {
148 if (netdev)
149 assert_se(++ netdev->n_ref >= 2);
150
151 return netdev;
152 }
153
154 void netdev_drop(NetDev *netdev) {
155 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
156 return;
157
158 netdev->state = NETDEV_STATE_LINGER;
159
160 log_netdev_debug(netdev, "netdev removed");
161
162 netdev_cancel_callbacks(netdev);
163
164 netdev_unref(netdev);
165
166 return;
167 }
168
169 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
170 NetDev *netdev;
171
172 assert(manager);
173 assert(name);
174 assert(ret);
175
176 netdev = hashmap_get(manager->netdevs, name);
177 if (!netdev) {
178 *ret = NULL;
179 return -ENOENT;
180 }
181
182 *ret = netdev;
183
184 return 0;
185 }
186
187 static int netdev_enter_failed(NetDev *netdev) {
188 netdev->state = NETDEV_STATE_FAILED;
189
190 netdev_cancel_callbacks(netdev);
191
192 return 0;
193 }
194
195 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) {
196 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
197 int r;
198
199 assert(netdev);
200 assert(netdev->state == NETDEV_STATE_READY);
201 assert(netdev->manager);
202 assert(netdev->manager->rtnl);
203 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
204 assert(link);
205 assert(callback);
206
207 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
208 if (r < 0)
209 return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
210
211 r = sd_netlink_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
212 if (r < 0)
213 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
214
215 r = sd_netlink_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
216 if (r < 0)
217 return log_netdev_error(netdev, "Could not send rtnetlink message: %m");
218
219 link_ref(link);
220
221 log_netdev_debug(netdev, "Enslaving link '%s'", link->ifname);
222
223 return 0;
224 }
225
226 static int netdev_enter_ready(NetDev *netdev) {
227 netdev_join_callback *callback, *callback_next;
228 int r;
229
230 assert(netdev);
231 assert(netdev->ifname);
232
233 if (netdev->state != NETDEV_STATE_CREATING)
234 return 0;
235
236 netdev->state = NETDEV_STATE_READY;
237
238 log_netdev_info(netdev, "netdev ready");
239
240 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
241 /* enslave the links that were attempted to be enslaved before the
242 * link was ready */
243 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
244 if (r < 0)
245 return r;
246
247 LIST_REMOVE(callbacks, netdev->callbacks, callback);
248 link_unref(callback->link);
249 free(callback);
250 }
251
252 if (NETDEV_VTABLE(netdev)->post_create)
253 NETDEV_VTABLE(netdev)->post_create(netdev, NULL, NULL);
254
255 return 0;
256 }
257
258 /* callback for netdev's created without a backing Link */
259 static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
260 _cleanup_netdev_unref_ NetDev *netdev = userdata;
261 int r;
262
263 assert(netdev->state != _NETDEV_STATE_INVALID);
264
265 r = sd_netlink_message_get_errno(m);
266 if (r == -EEXIST)
267 log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
268 else if (r < 0) {
269 log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
270 netdev_drop(netdev);
271
272 return 1;
273 }
274
275 log_netdev_debug(netdev, "Created");
276
277 return 1;
278 }
279
280 int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
281 int r;
282
283 assert(netdev);
284 assert(netdev->manager);
285 assert(netdev->manager->rtnl);
286 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
287
288 if (netdev->state == NETDEV_STATE_READY) {
289 r = netdev_enslave_ready(netdev, link, callback);
290 if (r < 0)
291 return r;
292 } else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) {
293 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
294
295 r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
296 if (r >= 0)
297 callback(netdev->manager->rtnl, m, link);
298 } else {
299 /* the netdev is not yet read, save this request for when it is */
300 netdev_join_callback *cb;
301
302 cb = new0(netdev_join_callback, 1);
303 if (!cb)
304 return log_oom();
305
306 cb->callback = callback;
307 cb->link = link;
308 link_ref(link);
309
310 LIST_PREPEND(callbacks, netdev->callbacks, cb);
311
312 log_netdev_debug(netdev, "Will enslave '%s', when ready", link->ifname);
313 }
314
315 return 0;
316 }
317
318 int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
319 uint16_t type;
320 const char *kind;
321 const char *received_kind;
322 const char *received_name;
323 int r, ifindex;
324
325 assert(netdev);
326 assert(message);
327
328 r = sd_netlink_message_get_type(message, &type);
329 if (r < 0)
330 return log_netdev_error_errno(netdev, r, "Could not get rtnl message type: %m");
331
332 if (type != RTM_NEWLINK) {
333 log_netdev_error(netdev, "Cannot set ifindex from unexpected rtnl message type.");
334 return -EINVAL;
335 }
336
337 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
338 if (r < 0) {
339 log_netdev_error_errno(netdev, r, "Could not get ifindex: %m");
340 netdev_enter_failed(netdev);
341 return r;
342 } else if (ifindex <= 0) {
343 log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
344 netdev_enter_failed(netdev);
345 return -EINVAL;
346 }
347
348 if (netdev->ifindex > 0) {
349 if (netdev->ifindex != ifindex) {
350 log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
351 ifindex, netdev->ifindex);
352 netdev_enter_failed(netdev);
353 return -EEXIST;
354 } else
355 /* ifindex already set to the same for this netdev */
356 return 0;
357 }
358
359 r = sd_netlink_message_read_string(message, IFLA_IFNAME, &received_name);
360 if (r < 0)
361 return log_netdev_error_errno(netdev, r, "Could not get IFNAME: %m");
362
363 if (!streq(netdev->ifname, received_name)) {
364 log_netdev_error(netdev, "Received newlink with wrong IFNAME %s", received_name);
365 netdev_enter_failed(netdev);
366 return r;
367 }
368
369 r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
370 if (r < 0)
371 return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
372
373 r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
374 if (r < 0)
375 return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
376
377 r = sd_netlink_message_exit_container(message);
378 if (r < 0)
379 return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
380
381 if (netdev->kind == NETDEV_KIND_TAP)
382 /* the kernel does not distinguish between tun and tap */
383 kind = "tun";
384 else {
385 kind = netdev_kind_to_string(netdev->kind);
386 if (!kind) {
387 log_netdev_error(netdev, "Could not get kind");
388 netdev_enter_failed(netdev);
389 return -EINVAL;
390 }
391 }
392
393 if (!streq(kind, received_kind)) {
394 log_netdev_error(netdev,
395 "Received newlink with wrong KIND %s, "
396 "expected %s", received_kind, kind);
397 netdev_enter_failed(netdev);
398 return r;
399 }
400
401 netdev->ifindex = ifindex;
402
403 log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
404
405 netdev_enter_ready(netdev);
406
407 return 0;
408 }
409
410 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
411
412 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
413 _cleanup_free_ struct ether_addr *mac = NULL;
414 uint64_t result;
415 size_t l, sz;
416 uint8_t *v;
417 int r;
418
419 assert(ifname);
420 assert(ret);
421
422 mac = new0(struct ether_addr, 1);
423 if (!mac)
424 return -ENOMEM;
425
426 l = strlen(ifname);
427 sz = sizeof(sd_id128_t) + l;
428 v = alloca(sz);
429
430 /* fetch some persistent data unique to the machine */
431 r = sd_id128_get_machine((sd_id128_t*) v);
432 if (r < 0)
433 return r;
434
435 /* combine with some data unique (on this machine) to this
436 * netdev */
437 memcpy(v + sizeof(sd_id128_t), ifname, l);
438
439 /* Let's hash the host machine ID plus the container name. We
440 * use a fixed, but originally randomly created hash key here. */
441 result = siphash24(v, sz, HASH_KEY.bytes);
442
443 assert_cc(ETH_ALEN <= sizeof(result));
444 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
445
446 /* see eth_random_addr in the kernel */
447 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
448 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
449
450 *ret = mac;
451 mac = NULL;
452
453 return 0;
454 }
455
456 static int netdev_create(NetDev *netdev, Link *link,
457 sd_netlink_message_handler_t callback) {
458 int r;
459
460 assert(netdev);
461 assert(!link || callback);
462
463 /* create netdev */
464 if (NETDEV_VTABLE(netdev)->create) {
465 assert(!link);
466
467 r = NETDEV_VTABLE(netdev)->create(netdev);
468 if (r < 0)
469 return r;
470
471 log_netdev_debug(netdev, "Created");
472 } else {
473 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
474
475 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
476 if (r < 0)
477 return log_netdev_error_errno(netdev, r, "Could not allocate RTM_NEWLINK message: %m");
478
479 r = sd_netlink_message_append_string(m, IFLA_IFNAME, netdev->ifname);
480 if (r < 0)
481 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m");
482
483 if (netdev->mac) {
484 r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
485 if (r < 0)
486 return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");
487 }
488
489 if (netdev->mtu) {
490 r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu);
491 if (r < 0)
492 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m");
493 }
494
495 if (link) {
496 r = sd_netlink_message_append_u32(m, IFLA_LINK, link->ifindex);
497 if (r < 0)
498 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINK attribute: %m");
499 }
500
501 r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
502 if (r < 0)
503 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
504
505 r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
506 if (r < 0)
507 return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
508
509 if (NETDEV_VTABLE(netdev)->fill_message_create) {
510 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
511 if (r < 0)
512 return r;
513 }
514
515 r = sd_netlink_message_close_container(m);
516 if (r < 0)
517 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
518
519 r = sd_netlink_message_close_container(m);
520 if (r < 0)
521 return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
522
523 if (link) {
524 r = sd_netlink_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
525 if (r < 0)
526 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
527
528 link_ref(link);
529 } else {
530 r = sd_netlink_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
531 if (r < 0)
532 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
533
534 netdev_ref(netdev);
535 }
536
537 netdev->state = NETDEV_STATE_CREATING;
538
539 log_netdev_debug(netdev, "Creating");
540 }
541
542 return 0;
543 }
544
545 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
546 int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
547 int r;
548
549 assert(netdev);
550 assert(netdev->manager);
551 assert(netdev->manager->rtnl);
552 assert(NETDEV_VTABLE(netdev));
553
554 switch (NETDEV_VTABLE(netdev)->create_type) {
555 case NETDEV_CREATE_MASTER:
556 r = netdev_enslave(netdev, link, callback);
557 if (r < 0)
558 return r;
559
560 break;
561 case NETDEV_CREATE_STACKED:
562 r = netdev_create(netdev, link, callback);
563 if (r < 0)
564 return r;
565
566 break;
567 default:
568 assert_not_reached("Can not join independent netdev");
569 }
570
571 return 0;
572 }
573
574 static int netdev_load_one(Manager *manager, const char *filename) {
575 _cleanup_netdev_unref_ NetDev *netdev = NULL;
576 _cleanup_free_ NetDev *netdev_raw = NULL;
577 _cleanup_fclose_ FILE *file = NULL;
578 int r;
579
580 assert(manager);
581 assert(filename);
582
583 file = fopen(filename, "re");
584 if (!file) {
585 if (errno == ENOENT)
586 return 0;
587 else
588 return -errno;
589 }
590
591 if (null_or_empty_fd(fileno(file))) {
592 log_debug("Skipping empty file: %s", filename);
593 return 0;
594 }
595
596 netdev_raw = new0(NetDev, 1);
597 if (!netdev_raw)
598 return log_oom();
599
600 netdev_raw->kind = _NETDEV_KIND_INVALID;
601
602 r = config_parse(NULL, filename, file,
603 "Match\0NetDev\0",
604 config_item_perf_lookup, network_netdev_gperf_lookup,
605 true, false, true, netdev_raw);
606 if (r < 0)
607 return r;
608
609 r = fseek(file, 0, SEEK_SET);
610 if (r < 0)
611 return -errno;
612
613 /* skip out early if configuration does not match the environment */
614 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
615 netdev_raw->match_host, netdev_raw->match_virt,
616 netdev_raw->match_kernel, netdev_raw->match_arch,
617 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
618 return 0;
619
620 if (!NETDEV_VTABLE(netdev_raw)) {
621 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
622 return 0;
623 }
624
625 if (!netdev_raw->ifname) {
626 log_warning("NetDev without Name configured in %s. Ignoring", filename);
627 return 0;
628 }
629
630 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
631 if (!netdev)
632 return log_oom();
633
634 netdev->n_ref = 1;
635 netdev->manager = manager;
636 netdev->state = _NETDEV_STATE_INVALID;
637 netdev->kind = netdev_raw->kind;
638 netdev->ifname = netdev_raw->ifname;
639
640 if (NETDEV_VTABLE(netdev)->init)
641 NETDEV_VTABLE(netdev)->init(netdev);
642
643 r = config_parse(NULL, filename, file,
644 NETDEV_VTABLE(netdev)->sections,
645 config_item_perf_lookup, network_netdev_gperf_lookup,
646 false, false, false, netdev);
647 if (r < 0)
648 return r;
649
650 /* verify configuration */
651 if (NETDEV_VTABLE(netdev)->config_verify) {
652 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
653 if (r < 0)
654 return 0;
655 }
656
657 netdev->filename = strdup(filename);
658 if (!netdev->filename)
659 return log_oom();
660
661 if (!netdev->mac) {
662 r = netdev_get_mac(netdev->ifname, &netdev->mac);
663 if (r < 0)
664 return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
665 }
666
667 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
668 if (r < 0)
669 return r;
670
671 LIST_HEAD_INIT(netdev->callbacks);
672
673 log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
674
675 switch (NETDEV_VTABLE(netdev)->create_type) {
676 case NETDEV_CREATE_MASTER:
677 case NETDEV_CREATE_INDEPENDENT:
678 r = netdev_create(netdev, NULL, NULL);
679 if (r < 0)
680 return 0;
681
682 break;
683 default:
684 break;
685 }
686
687 netdev = NULL;
688
689 return 0;
690 }
691
692 int netdev_load(Manager *manager) {
693 _cleanup_strv_free_ char **files = NULL;
694 NetDev *netdev;
695 char **f;
696 int r;
697
698 assert(manager);
699
700 while ((netdev = hashmap_first(manager->netdevs)))
701 netdev_unref(netdev);
702
703 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
704 if (r < 0)
705 return log_error_errno(r, "Failed to enumerate netdev files: %m");
706
707 STRV_FOREACH_BACKWARDS(f, files) {
708 r = netdev_load_one(manager, *f);
709 if (r < 0)
710 return r;
711 }
712
713 return 0;
714 }