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