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