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