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