1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
24 #include "networkd-netdev.h"
25 #include "networkd-link.h"
26 #include "network-internal.h"
27 #include "path-util.h"
28 #include "conf-files.h"
29 #include "conf-parser.h"
31 #include "siphash24.h"
33 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
34 [NETDEV_KIND_BRIDGE] = &bridge_vtable,
35 [NETDEV_KIND_BOND] = &bond_vtable,
36 [NETDEV_KIND_VLAN] = &vlan_vtable,
37 [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
38 [NETDEV_KIND_IPVLAN] = &ipvlan_vtable,
39 [NETDEV_KIND_VXLAN] = &vxlan_vtable,
40 [NETDEV_KIND_IPIP] = &ipip_vtable,
41 [NETDEV_KIND_GRE] = &gre_vtable,
42 [NETDEV_KIND_GRETAP] = &gretap_vtable,
43 [NETDEV_KIND_SIT] = &sit_vtable,
44 [NETDEV_KIND_VTI] = &vti_vtable,
45 [NETDEV_KIND_VETH] = &veth_vtable,
46 [NETDEV_KIND_DUMMY] = &dummy_vtable,
47 [NETDEV_KIND_TUN] = &tun_vtable,
48 [NETDEV_KIND_TAP] = &tap_vtable,
51 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
52 [NETDEV_KIND_BRIDGE] = "bridge",
53 [NETDEV_KIND_BOND] = "bond",
54 [NETDEV_KIND_VLAN] = "vlan",
55 [NETDEV_KIND_MACVLAN] = "macvlan",
56 [NETDEV_KIND_IPVLAN] = "ipvlan",
57 [NETDEV_KIND_VXLAN] = "vxlan",
58 [NETDEV_KIND_IPIP] = "ipip",
59 [NETDEV_KIND_GRE] = "gre",
60 [NETDEV_KIND_GRETAP] = "gretap",
61 [NETDEV_KIND_SIT] = "sit",
62 [NETDEV_KIND_VETH] = "veth",
63 [NETDEV_KIND_VTI] = "vti",
64 [NETDEV_KIND_DUMMY] = "dummy",
65 [NETDEV_KIND_TUN] = "tun",
66 [NETDEV_KIND_TAP] = "tap",
69 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
70 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
72 static void netdev_cancel_callbacks(NetDev *netdev) {
73 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
74 netdev_join_callback *callback;
79 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
81 while ((callback = netdev->callbacks)) {
83 assert(callback->link);
84 assert(callback->callback);
85 assert(netdev->manager);
86 assert(netdev->manager->rtnl);
88 callback->callback(netdev->manager->rtnl, m, link);
91 LIST_REMOVE(callbacks, netdev->callbacks, callback);
96 static void netdev_free(NetDev *netdev) {
100 netdev_cancel_callbacks(netdev);
103 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
105 free(netdev->filename);
107 free(netdev->description);
108 free(netdev->ifname);
111 condition_free_list(netdev->match_host);
112 condition_free_list(netdev->match_virt);
113 condition_free_list(netdev->match_kernel);
114 condition_free_list(netdev->match_arch);
116 if (NETDEV_VTABLE(netdev) &&
117 NETDEV_VTABLE(netdev)->done)
118 NETDEV_VTABLE(netdev)->done(netdev);
123 NetDev *netdev_unref(NetDev *netdev) {
124 if (netdev && (-- netdev->n_ref <= 0))
130 NetDev *netdev_ref(NetDev *netdev) {
132 assert_se(++ netdev->n_ref >= 2);
137 void netdev_drop(NetDev *netdev) {
138 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
141 netdev->state = NETDEV_STATE_LINGER;
143 log_netdev_debug(netdev, "netdev removed");
145 netdev_cancel_callbacks(netdev);
147 netdev_unref(netdev);
152 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
159 netdev = hashmap_get(manager->netdevs, name);
170 static int netdev_enter_failed(NetDev *netdev) {
171 netdev->state = NETDEV_STATE_FAILED;
176 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
177 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
181 assert(netdev->state == NETDEV_STATE_READY);
182 assert(netdev->manager);
183 assert(netdev->manager->rtnl);
184 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
188 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
189 RTM_SETLINK, link->ifindex);
191 log_netdev_error(netdev,
192 "Could not allocate RTM_SETLINK message: %s",
197 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
199 log_netdev_error(netdev,
200 "Could not append IFLA_MASTER attribute: %s",
205 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
207 log_netdev_error(netdev,
208 "Could not send rtnetlink message: %s",
215 log_netdev_debug(netdev, "enslaving link '%s'", link->ifname);
220 static int netdev_enter_ready(NetDev *netdev) {
221 netdev_join_callback *callback, *callback_next;
225 assert(netdev->ifname);
227 if (netdev->state != NETDEV_STATE_CREATING)
230 netdev->state = NETDEV_STATE_READY;
232 log_info_netdev(netdev, "netdev ready");
234 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
235 /* enslave the links that were attempted to be enslaved before the
237 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
241 LIST_REMOVE(callbacks, netdev->callbacks, callback);
242 link_unref(callback->link);
249 /* callback for netdev's created without a backing Link */
250 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
251 _cleanup_netdev_unref_ NetDev *netdev = userdata;
254 assert(netdev->state != _NETDEV_STATE_INVALID);
256 r = sd_rtnl_message_get_errno(m);
258 log_netdev_debug(netdev, "netdev exists, using existing");
260 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
266 log_netdev_debug(netdev, "created");
271 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
275 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
277 if (netdev->state == NETDEV_STATE_READY) {
278 r = netdev_enslave_ready(netdev, link, callback);
282 /* the netdev is not yet read, save this request for when it is */
283 netdev_join_callback *cb;
285 cb = new0(netdev_join_callback, 1);
289 cb->callback = callback;
293 LIST_PREPEND(callbacks, netdev->callbacks, cb);
295 log_netdev_debug(netdev, "will enslave '%s', when reday",
302 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
305 const char *received_kind;
306 const char *received_name;
312 r = sd_rtnl_message_get_type(message, &type);
314 log_netdev_error(netdev, "Could not get rtnl message type");
318 if (type != RTM_NEWLINK) {
319 log_netdev_error(netdev, "Can not set ifindex from unexpected rtnl message type");
323 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
325 log_netdev_error(netdev, "Could not get ifindex: %s", strerror(-r));
326 netdev_enter_failed(netdev);
328 } else if (ifindex <= 0) {
329 log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
330 netdev_enter_failed(netdev);
334 if (netdev->ifindex > 0) {
335 if (netdev->ifindex != ifindex) {
336 log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
337 ifindex, netdev->ifindex);
338 netdev_enter_failed(netdev);
341 /* ifindex already set to the same for this netdev */
345 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
347 log_netdev_error(netdev, "Could not get IFNAME");
351 if (!streq(netdev->ifname, received_name)) {
352 log_netdev_error(netdev, "Received newlink with wrong IFNAME %s",
354 netdev_enter_failed(netdev);
358 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
360 log_netdev_error(netdev, "Could not get LINKINFO");
364 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
366 log_netdev_error(netdev, "Could not get KIND");
370 r = sd_rtnl_message_exit_container(message);
372 log_netdev_error(netdev, "Could not exit container");
376 if (netdev->kind == NETDEV_KIND_TAP)
377 /* the kernel does not distinguish between tun and tap */
380 kind = netdev_kind_to_string(netdev->kind);
382 log_netdev_error(netdev, "Could not get kind");
383 netdev_enter_failed(netdev);
388 if (!streq(kind, received_kind)) {
389 log_netdev_error(netdev,
390 "Received newlink with wrong KIND %s, "
391 "expected %s", received_kind, kind);
392 netdev_enter_failed(netdev);
396 netdev->ifindex = ifindex;
398 log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
400 netdev_enter_ready(netdev);
405 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
407 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
408 _cleanup_free_ struct ether_addr *mac = NULL;
417 mac = new0(struct ether_addr, 1);
422 sz = sizeof(sd_id128_t) + l;
425 /* fetch some persistent data unique to the machine */
426 r = sd_id128_get_machine((sd_id128_t*) v);
430 /* combine with some data unique (on this machine) to this
432 memcpy(v + sizeof(sd_id128_t), ifname, l);
434 /* Let's hash the host machine ID plus the container name. We
435 * use a fixed, but originally randomly created hash key here. */
436 siphash24(result, v, sz, HASH_KEY.bytes);
438 assert_cc(ETH_ALEN <= sizeof(result));
439 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
441 /* see eth_random_addr in the kernel */
442 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
443 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
451 static int netdev_create(NetDev *netdev, Link *link,
452 sd_rtnl_message_handler_t callback) {
456 assert(!link || callback);
459 if (NETDEV_VTABLE(netdev)->create) {
462 r = NETDEV_VTABLE(netdev)->create(netdev);
466 log_netdev_debug(netdev, "created");
468 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
470 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
472 log_netdev_error(netdev,
473 "Could not allocate RTM_NEWLINK message: %s",
478 r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
480 log_netdev_error(netdev,
481 "Could not append IFLA_IFNAME, attribute: %s",
487 r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
489 log_netdev_error(netdev,
490 "Could not append IFLA_ADDRESS attribute: %s",
497 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
499 log_netdev_error(netdev,
500 "Could not append IFLA_MTU attribute: %s",
507 r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
509 log_netdev_error(netdev,
510 "Could not append IFLA_LINK attribute: %s",
516 r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
518 log_netdev_error(netdev,
519 "Could not append IFLA_LINKINFO attribute: %s",
524 r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
525 netdev_kind_to_string(netdev->kind));
527 log_netdev_error(netdev,
528 "Could not append IFLA_INFO_DATA attribute: %s",
533 if (NETDEV_VTABLE(netdev)->fill_message_create) {
534 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
539 r = sd_rtnl_message_close_container(m);
541 log_netdev_error(netdev,
542 "Could not append IFLA_LINKINFO attribute: %s",
547 r = sd_rtnl_message_close_container(m);
549 log_netdev_error(netdev,
550 "Could not append IFLA_LINKINFO attribute: %s",
557 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
558 callback, link, 0, NULL);
560 log_netdev_error(netdev,
561 "Could not send rtnetlink message: %s",
568 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
569 netdev_create_handler, netdev, 0,
572 log_netdev_error(netdev,
573 "Could not send rtnetlink message: %s",
581 netdev->state = NETDEV_STATE_CREATING;
583 log_netdev_debug(netdev, "creating");
589 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
590 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
594 assert(netdev->manager);
595 assert(netdev->manager->rtnl);
596 assert(NETDEV_VTABLE(netdev));
598 switch (NETDEV_VTABLE(netdev)->create_type) {
599 case NETDEV_CREATE_MASTER:
600 r = netdev_enslave(netdev, link, callback);
605 case NETDEV_CREATE_STACKED:
606 r = netdev_create(netdev, link, callback);
612 assert_not_reached("Can not join independent netdev");
618 static int netdev_load_one(Manager *manager, const char *filename) {
619 _cleanup_netdev_unref_ NetDev *netdev = NULL;
620 _cleanup_free_ NetDev *netdev_raw = NULL;
621 _cleanup_fclose_ FILE *file = NULL;
627 file = fopen(filename, "re");
635 if (null_or_empty_fd(fileno(file))) {
636 log_debug("Skipping empty file: %s", filename);
640 netdev_raw = new0(NetDev, 1);
644 netdev_raw->kind = _NETDEV_KIND_INVALID;
646 r = config_parse(NULL, filename, file,
648 config_item_perf_lookup, network_netdev_gperf_lookup,
649 true, false, true, netdev_raw);
653 r = fseek(file, 0, SEEK_SET);
657 /* skip out early if configuration does not match the environment */
658 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
659 netdev_raw->match_host, netdev_raw->match_virt,
660 netdev_raw->match_kernel, netdev_raw->match_arch,
661 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
664 if (!NETDEV_VTABLE(netdev_raw)) {
665 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
669 if (!netdev_raw->ifname) {
670 log_warning("NetDev without Name configured in %s. Ignoring", filename);
674 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
679 netdev->manager = manager;
680 netdev->state = _NETDEV_STATE_INVALID;
681 netdev->kind = netdev_raw->kind;
682 netdev->ifname = netdev_raw->ifname;
684 if (NETDEV_VTABLE(netdev)->init)
685 NETDEV_VTABLE(netdev)->init(netdev);
687 r = config_parse(NULL, filename, file,
688 NETDEV_VTABLE(netdev)->sections,
689 config_item_perf_lookup, network_netdev_gperf_lookup,
690 false, false, false, netdev);
694 /* verify configuration */
695 if (NETDEV_VTABLE(netdev)->config_verify) {
696 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
701 netdev->filename = strdup(filename);
702 if (!netdev->filename)
706 r = netdev_get_mac(netdev->ifname, &netdev->mac);
708 log_error("Failed to generate predictable MAC address for %s",
714 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
718 LIST_HEAD_INIT(netdev->callbacks);
720 log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
722 switch (NETDEV_VTABLE(netdev)->create_type) {
723 case NETDEV_CREATE_MASTER:
724 case NETDEV_CREATE_INDEPENDENT:
725 r = netdev_create(netdev, NULL, NULL);
739 int netdev_load(Manager *manager) {
746 while ((netdev = hashmap_first(manager->netdevs)))
747 netdev_unref(netdev);
749 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
751 return log_error_errno(r, "Failed to enumerate netdev files: %m");
753 STRV_FOREACH_BACKWARDS(f, files) {
754 r = netdev_load_one(manager, *f);