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