chiark / gitweb /
networkd: veth - fix creation of veth netdev
[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 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
225         NetDev *netdev = userdata;
226         int r;
227
228         assert(netdev->state != _NETDEV_STATE_INVALID);
229
230         r = sd_rtnl_message_get_errno(m);
231         if (r == -EEXIST)
232                 log_debug_netdev(netdev, "netdev exists, using existing");
233         else if (r < 0) {
234                 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
235                 netdev_drop(netdev);
236
237                 return 1;
238         }
239
240         return 1;
241 }
242
243 int config_parse_tunnel_address(const char *unit,
244                                 const char *filename,
245                                 unsigned line,
246                                 const char *section,
247                                 unsigned section_line,
248                                 const char *lvalue,
249                                 int ltype,
250                                 const char *rvalue,
251                                 void *data,
252                                 void *userdata) {
253         NetDev *n = data;
254         unsigned char family = AF_INET;
255         int r;
256
257         assert(filename);
258         assert(lvalue);
259         assert(rvalue);
260         assert(data);
261
262         r = net_parse_inaddr(rvalue, &family, n);
263         if (r < 0) {
264                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
265                            "Tunnel address is invalid, ignoring assignment: %s", rvalue);
266                 return 0;
267         }
268        return 0;
269 }
270
271 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
272         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
273         const char *kind;
274         int r;
275
276         assert(netdev);
277         assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
278                (link && callback));
279         assert(netdev->ifname);
280         assert(netdev->manager);
281         assert(netdev->manager->rtnl);
282
283         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
284         if (r < 0) {
285                 log_error_netdev(netdev,
286                                  "Could not allocate RTM_NEWLINK message: %s",
287                                  strerror(-r));
288                 return r;
289         }
290
291         if (link) {
292                 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
293                 if (r < 0) {
294                         log_error_netdev(netdev,
295                                          "Could not append IFLA_LINK attribute: %s",
296                                          strerror(-r));
297                         return r;
298                 }
299         }
300
301         r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
302         if (r < 0) {
303                 log_error_netdev(netdev,
304                                  "Could not append IFLA_IFNAME attribute: %s",
305                                  strerror(-r));
306                 return r;
307         }
308
309         if (netdev->mtu) {
310                 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
311                 if (r < 0) {
312                         log_error_netdev(netdev,
313                                          "Could not append IFLA_MTU attribute: %s",
314                                          strerror(-r));
315                         return r;
316                 }
317         }
318
319         if (netdev->mac) {
320                 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
321                 if (r < 0) {
322                         log_error_netdev(netdev,
323                                          "Colud not append IFLA_ADDRESS attribute: %s",
324                                          strerror(-r));
325                     return r;
326                 }
327         }
328
329         r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
330         if (r < 0) {
331                 log_error_netdev(netdev,
332                                  "Could not open IFLA_LINKINFO container: %s",
333                                  strerror(-r));
334                 return r;
335         }
336
337         kind = netdev_kind_to_string(netdev->kind);
338         if (!kind) {
339                 log_error_netdev(netdev, "Invalid kind");
340                 return -EINVAL;
341         }
342
343         r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
344         if (r < 0) {
345                 log_error_netdev(netdev,
346                                  "Could not open IFLA_INFO_DATA container: %s",
347                                   strerror(-r));
348                 return r;
349         }
350
351         if (netdev->vlanid <= VLANID_MAX) {
352                 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
353                 if (r < 0) {
354                         log_error_netdev(netdev,
355                                          "Could not append IFLA_VLAN_ID attribute: %s",
356                                          strerror(-r));
357                         return r;
358                 }
359         }
360
361         if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
362         r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
363         if (r < 0) {
364                 log_error_netdev(netdev,
365                                  "Could not append IFLA_MACVLAN_MODE attribute: %s",
366                                  strerror(-r));
367                         return r;
368                 }
369         }
370
371         r = sd_rtnl_message_close_container(req);
372         if (r < 0) {
373                 log_error_netdev(netdev,
374                                  "Could not close IFLA_INFO_DATA container %s",
375                                  strerror(-r));
376                 return r;
377         }
378
379         r = sd_rtnl_message_close_container(req);
380         if (r < 0) {
381                 log_error_netdev(netdev,
382                                  "Could not close IFLA_LINKINFO container %s",
383                                  strerror(-r));
384                 return r;
385         }
386
387         if (link)
388                 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
389         else
390                 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
391         if (r < 0) {
392                 log_error_netdev(netdev,
393                                  "Could not send rtnetlink message: %s", strerror(-r));
394                 return r;
395         }
396
397         log_debug_netdev(netdev, "creating netdev");
398
399         netdev->state = NETDEV_STATE_CREATING;
400
401         return 0;
402 }
403
404 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
405         int r;
406
407         switch(netdev->kind) {
408         case NETDEV_KIND_VLAN:
409         case NETDEV_KIND_MACVLAN:
410                 return netdev_create(netdev, link, callback);
411         case NETDEV_KIND_VXLAN:
412                 return netdev_create_vxlan(netdev, link, callback);
413         case NETDEV_KIND_IPIP:
414         case NETDEV_KIND_GRE:
415         case NETDEV_KIND_SIT:
416         case NETDEV_KIND_VTI:
417                 return netdev_create_tunnel(link, netdev_create_handler);
418         default:
419                 break;
420         }
421
422         if (netdev->state == NETDEV_STATE_READY) {
423                 r = netdev_enslave_ready(netdev, link, callback);
424                 if (r < 0)
425                         return r;
426         } else {
427                 /* the netdev is not yet read, save this request for when it is*/
428                 netdev_enslave_callback *cb;
429
430                 cb = new0(netdev_enslave_callback, 1);
431                 if (!cb)
432                         return log_oom();
433
434                 cb->callback = callback;
435                 cb->link = link;
436
437                 LIST_PREPEND(callbacks, netdev->callbacks, cb);
438         }
439
440         return 0;
441 }
442
443 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
444         uint16_t type;
445         const char *kind;
446         char *received_kind;
447         char *received_name;
448         int r, ifindex;
449
450         assert(netdev);
451         assert(message);
452
453         r = sd_rtnl_message_get_type(message, &type);
454         if (r < 0) {
455                 log_error_netdev(netdev, "Could not get rtnl message type");
456                 return r;
457         }
458
459         if (type != RTM_NEWLINK) {
460                 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
461                 return -EINVAL;
462         }
463
464         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
465         if (r < 0) {
466                 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
467                 netdev_enter_failed(netdev);
468                 return r;
469         } else if (ifindex <= 0) {
470                 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
471                 netdev_enter_failed(netdev);
472                 return r;
473         }
474
475         if (netdev->ifindex > 0) {
476                 if (netdev->ifindex != ifindex) {
477                         log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
478                                          ifindex, netdev->ifindex);
479                         netdev_enter_failed(netdev);
480                         return -EEXIST;
481                 } else
482                         /* ifindex already set to the same for this netdev */
483                         return 0;
484         }
485
486         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
487         if (r < 0) {
488                 log_error_netdev(netdev, "Could not get IFNAME");
489                 return r;
490         }
491
492         if (!streq(netdev->ifname, received_name)) {
493                 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
494                                  received_name);
495                 netdev_enter_failed(netdev);
496                 return r;
497         }
498
499         r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
500         if (r < 0) {
501                 log_error_netdev(netdev, "Could not get LINKINFO");
502                 return r;
503         }
504
505         r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
506         if (r < 0) {
507                 log_error_netdev(netdev, "Could not get KIND");
508                 return r;
509         }
510
511         r = sd_rtnl_message_exit_container(message);
512         if (r < 0) {
513                 log_error_netdev(netdev, "Could not exit container");
514                 return r;
515         }
516
517         kind = netdev_kind_to_string(netdev->kind);
518         if (!kind) {
519                 log_error_netdev(netdev, "Could not get kind");
520                 netdev_enter_failed(netdev);
521                 return -EINVAL;
522         }
523
524         if (!streq(kind, received_kind)) {
525                 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
526                                  "expected %s", received_kind, kind);
527                 netdev_enter_failed(netdev);
528                 return r;
529         }
530
531         netdev->ifindex = ifindex;
532
533         log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
534
535         netdev_enter_ready(netdev);
536
537         return 0;
538 }
539
540 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
541
542 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
543         _cleanup_free_ struct ether_addr *mac = NULL;
544         uint8_t result[8];
545         size_t l, sz;
546         uint8_t *v;
547         int r;
548
549         assert(ifname);
550         assert(ret);
551
552         mac = new0(struct ether_addr, 1);
553         if (!mac)
554                 return -ENOMEM;
555
556         l = strlen(ifname);
557         sz = sizeof(sd_id128_t) + l;
558         v = alloca(sz);
559
560         /* fetch some persistent data unique to the machine */
561         r = sd_id128_get_machine((sd_id128_t*) v);
562         if (r < 0)
563                 return r;
564
565         /* combine with some data unique (on this machine) to this
566          * netdev */
567         memcpy(v + sizeof(sd_id128_t), ifname, l);
568
569         /* Let's hash the host machine ID plus the container name. We
570          * use a fixed, but originally randomly created hash key here. */
571         siphash24(result, v, sz, HASH_KEY.bytes);
572
573         assert_cc(ETH_ALEN <= sizeof(result));
574         memcpy(mac->ether_addr_octet, result, ETH_ALEN);
575
576         /* see eth_random_addr in the kernel */
577         mac->ether_addr_octet[0] &= 0xfe;        /* clear multicast bit */
578         mac->ether_addr_octet[0] |= 0x02;        /* set local assignment bit (IEEE802) */
579
580         *ret = mac;
581         mac = NULL;
582
583         return 0;
584 }
585
586 static int netdev_load_one(Manager *manager, const char *filename) {
587         _cleanup_netdev_unref_ NetDev *netdev = NULL;
588         _cleanup_fclose_ FILE *file = NULL;
589         int r;
590
591         assert(manager);
592         assert(filename);
593
594         if (null_or_empty_path(filename)) {
595                 log_debug("skipping empty file: %s", filename);
596                 return 0;
597         }
598
599         file = fopen(filename, "re");
600         if (!file) {
601                 if (errno == ENOENT)
602                         return 0;
603                 else
604                         return -errno;
605         }
606
607         netdev = new0(NetDev, 1);
608         if (!netdev)
609                 return log_oom();
610
611         netdev->n_ref = 1;
612         netdev->manager = manager;
613         netdev->state = _NETDEV_STATE_INVALID;
614         netdev->kind = _NETDEV_KIND_INVALID;
615         netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
616         netdev->vlanid = VLANID_MAX + 1;
617         netdev->vxlanid = VXLAN_VID_MAX + 1;
618         netdev->tunnel_pmtudisc = true;
619         netdev->learning = true;
620
621         r = config_parse(NULL, filename, file,
622                          "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
623                          config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
624                          false, false, netdev);
625         if (r < 0) {
626                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
627                 return r;
628         }
629
630         if (netdev->kind == _NETDEV_KIND_INVALID) {
631                 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
632                 return 0;
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 without valid Id configured in %s. Ignoring", filename);
642                 return 0;
643         }
644
645         if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
646                 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
647                 return 0;
648         }
649
650         if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
651                 log_warning("VLAN Id configured for a %s in %s. Ignoring",
652                             netdev_kind_to_string(netdev->kind), filename);
653                 return 0;
654         }
655
656         if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
657                 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
658                             netdev_kind_to_string(netdev->kind), filename);
659                 return 0;
660         }
661
662         if (netdev->kind != NETDEV_KIND_MACVLAN &&
663             netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
664                 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
665                             netdev_kind_to_string(netdev->kind), filename);
666                 return 0;
667         }
668
669         netdev->filename = strdup(filename);
670         if (!netdev->filename)
671                 return log_oom();
672
673         if (net_match_config(NULL, NULL, NULL, NULL, NULL,
674                              netdev->match_host, netdev->match_virt,
675                              netdev->match_kernel, netdev->match_arch,
676                              NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
677                 return 0;
678
679         if (!netdev->mac) {
680                 r = netdev_get_mac(netdev->ifname, &netdev->mac);
681                 if (r < 0) {
682                         log_error("Failed to generate predictable MAC address for %s",
683                                   netdev->ifname);
684                         return r;
685                 }
686         }
687
688         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
689         if (r < 0)
690                 return r;
691
692         LIST_HEAD_INIT(netdev->callbacks);
693
694         switch (netdev->kind) {
695         case NETDEV_KIND_VETH:
696                 if (!netdev->ifname_peer) {
697                         log_warning("Veth NetDev without peer name configured "
698                                     "in %s. Ignoring", filename);
699                         return 0;
700                 }
701
702                 if (!netdev->mac) {
703                         r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
704                         if (r < 0) {
705                                 log_error("Failed to generate predictable MAC address for %s",
706                                           netdev->ifname_peer);
707                                 return r;
708                         }
709                 }
710
711                 r = netdev_create_veth(netdev, netdev_create_handler);
712                 if (r < 0)
713                         return r;
714
715                 break;
716         case NETDEV_KIND_BRIDGE:
717         case NETDEV_KIND_BOND:
718                 r = netdev_create(netdev, NULL, NULL);
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 }