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