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