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