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