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