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