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