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