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