chiark / gitweb /
f6951526fb94c550a19c1a558097d13d8184c62d
[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.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 }