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