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