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