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