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_VXLAN] = &vxlan_vtable,
39 [NETDEV_KIND_IPIP] = &ipip_vtable,
40 [NETDEV_KIND_GRE] = &gre_vtable,
41 [NETDEV_KIND_SIT] = &sit_vtable,
42 [NETDEV_KIND_VTI] = &vti_vtable,
43 [NETDEV_KIND_VETH] = &veth_vtable,
44 [NETDEV_KIND_DUMMY] = &dummy_vtable,
45 [NETDEV_KIND_TUN] = &tun_vtable,
46 [NETDEV_KIND_TAP] = &tap_vtable,
49 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
50 [NETDEV_KIND_BRIDGE] = "bridge",
51 [NETDEV_KIND_BOND] = "bond",
52 [NETDEV_KIND_VLAN] = "vlan",
53 [NETDEV_KIND_MACVLAN] = "macvlan",
54 [NETDEV_KIND_VXLAN] = "vxlan",
55 [NETDEV_KIND_IPIP] = "ipip",
56 [NETDEV_KIND_GRE] = "gre",
57 [NETDEV_KIND_SIT] = "sit",
58 [NETDEV_KIND_VETH] = "veth",
59 [NETDEV_KIND_VTI] = "vti",
60 [NETDEV_KIND_DUMMY] = "dummy",
61 [NETDEV_KIND_TUN] = "tun",
62 [NETDEV_KIND_TAP] = "tap",
65 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
66 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
68 static void netdev_cancel_callbacks(NetDev *netdev) {
69 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
70 netdev_join_callback *callback;
75 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
77 while ((callback = netdev->callbacks)) {
79 assert(callback->link);
80 assert(callback->callback);
81 assert(netdev->manager);
82 assert(netdev->manager->rtnl);
84 callback->callback(netdev->manager->rtnl, m, link);
87 LIST_REMOVE(callbacks, netdev->callbacks, callback);
92 static void netdev_free(NetDev *netdev) {
96 netdev_cancel_callbacks(netdev);
99 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
101 free(netdev->filename);
103 free(netdev->description);
104 free(netdev->ifname);
107 condition_free_list(netdev->match_host);
108 condition_free_list(netdev->match_virt);
109 condition_free_list(netdev->match_kernel);
110 condition_free_list(netdev->match_arch);
112 if (NETDEV_VTABLE(netdev) &&
113 NETDEV_VTABLE(netdev)->done)
114 NETDEV_VTABLE(netdev)->done(netdev);
119 NetDev *netdev_unref(NetDev *netdev) {
120 if (netdev && (-- netdev->n_ref <= 0))
126 NetDev *netdev_ref(NetDev *netdev) {
128 assert_se(++ netdev->n_ref >= 2);
133 void netdev_drop(NetDev *netdev) {
134 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
137 netdev->state = NETDEV_STATE_LINGER;
139 log_netdev_debug(netdev, "netdev removed");
141 netdev_cancel_callbacks(netdev);
143 netdev_unref(netdev);
148 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
155 netdev = hashmap_get(manager->netdevs, name);
166 static int netdev_enter_failed(NetDev *netdev) {
167 netdev->state = NETDEV_STATE_FAILED;
172 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
173 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
177 assert(netdev->state == NETDEV_STATE_READY);
178 assert(netdev->manager);
179 assert(netdev->manager->rtnl);
180 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
184 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
185 RTM_SETLINK, link->ifindex);
187 log_netdev_error(netdev,
188 "Could not allocate RTM_SETLINK message: %s",
193 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
195 log_netdev_error(netdev,
196 "Could not append IFLA_MASTER attribute: %s",
201 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
203 log_netdev_error(netdev,
204 "Could not send rtnetlink message: %s",
211 log_netdev_debug(netdev, "enslaving link '%s'", link->ifname);
216 static int netdev_enter_ready(NetDev *netdev) {
217 netdev_join_callback *callback, *callback_next;
221 assert(netdev->ifname);
223 if (netdev->state != NETDEV_STATE_CREATING)
226 netdev->state = NETDEV_STATE_READY;
228 log_info_netdev(netdev, "netdev ready");
230 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
231 /* enslave the links that were attempted to be enslaved before the
233 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
237 LIST_REMOVE(callbacks, netdev->callbacks, callback);
238 link_unref(callback->link);
245 /* callback for netdev's created without a backing Link */
246 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
247 _cleanup_netdev_unref_ NetDev *netdev = userdata;
250 assert(netdev->state != _NETDEV_STATE_INVALID);
252 r = sd_rtnl_message_get_errno(m);
254 log_netdev_debug(netdev, "netdev exists, using existing");
256 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
262 log_netdev_debug(netdev, "created");
267 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
271 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
273 if (netdev->state == NETDEV_STATE_READY) {
274 r = netdev_enslave_ready(netdev, link, callback);
278 /* the netdev is not yet read, save this request for when it is */
279 netdev_join_callback *cb;
281 cb = new0(netdev_join_callback, 1);
285 cb->callback = callback;
289 LIST_PREPEND(callbacks, netdev->callbacks, cb);
291 log_netdev_debug(netdev, "will enslave '%s', when reday",
298 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
301 const char *received_kind;
302 const char *received_name;
308 r = sd_rtnl_message_get_type(message, &type);
310 log_netdev_error(netdev, "Could not get rtnl message type");
314 if (type != RTM_NEWLINK) {
315 log_netdev_error(netdev, "Can not set ifindex from unexpected rtnl message type");
319 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
321 log_netdev_error(netdev, "Could not get ifindex: %s", strerror(-r));
322 netdev_enter_failed(netdev);
324 } else if (ifindex <= 0) {
325 log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
326 netdev_enter_failed(netdev);
330 if (netdev->ifindex > 0) {
331 if (netdev->ifindex != ifindex) {
332 log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
333 ifindex, netdev->ifindex);
334 netdev_enter_failed(netdev);
337 /* ifindex already set to the same for this netdev */
341 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
343 log_netdev_error(netdev, "Could not get IFNAME");
347 if (!streq(netdev->ifname, received_name)) {
348 log_netdev_error(netdev, "Received newlink with wrong IFNAME %s",
350 netdev_enter_failed(netdev);
354 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
356 log_netdev_error(netdev, "Could not get LINKINFO");
360 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
362 log_netdev_error(netdev, "Could not get KIND");
366 r = sd_rtnl_message_exit_container(message);
368 log_netdev_error(netdev, "Could not exit container");
372 if (netdev->kind == NETDEV_KIND_TAP)
373 /* the kernel does not distinguish between tun and tap */
376 kind = netdev_kind_to_string(netdev->kind);
378 log_netdev_error(netdev, "Could not get kind");
379 netdev_enter_failed(netdev);
384 if (!streq(kind, received_kind)) {
385 log_netdev_error(netdev,
386 "Received newlink with wrong KIND %s, "
387 "expected %s", received_kind, kind);
388 netdev_enter_failed(netdev);
392 netdev->ifindex = ifindex;
394 log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
396 netdev_enter_ready(netdev);
401 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
403 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
404 _cleanup_free_ struct ether_addr *mac = NULL;
413 mac = new0(struct ether_addr, 1);
418 sz = sizeof(sd_id128_t) + l;
421 /* fetch some persistent data unique to the machine */
422 r = sd_id128_get_machine((sd_id128_t*) v);
426 /* combine with some data unique (on this machine) to this
428 memcpy(v + sizeof(sd_id128_t), ifname, l);
430 /* Let's hash the host machine ID plus the container name. We
431 * use a fixed, but originally randomly created hash key here. */
432 siphash24(result, v, sz, HASH_KEY.bytes);
434 assert_cc(ETH_ALEN <= sizeof(result));
435 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
437 /* see eth_random_addr in the kernel */
438 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
439 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
447 static int netdev_create(NetDev *netdev, Link *link,
448 sd_rtnl_message_handler_t callback) {
452 assert(!link || callback);
455 if (NETDEV_VTABLE(netdev)->create) {
458 r = NETDEV_VTABLE(netdev)->create(netdev);
462 log_netdev_debug(netdev, "created");
464 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
466 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
468 log_netdev_error(netdev,
469 "Could not allocate RTM_NEWLINK message: %s",
474 r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
476 log_netdev_error(netdev,
477 "Could not append IFLA_IFNAME, attribute: %s",
483 r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
485 log_netdev_error(netdev,
486 "Could not append IFLA_ADDRESS attribute: %s",
493 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
495 log_netdev_error(netdev,
496 "Could not append IFLA_MTU attribute: %s",
503 r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
505 log_netdev_error(netdev,
506 "Could not append IFLA_LINK attribute: %s",
512 r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
514 log_netdev_error(netdev,
515 "Could not append IFLA_LINKINFO attribute: %s",
520 r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
521 netdev_kind_to_string(netdev->kind));
523 log_netdev_error(netdev,
524 "Could not append IFLA_INFO_DATA attribute: %s",
529 if (NETDEV_VTABLE(netdev)->fill_message_create) {
530 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
535 r = sd_rtnl_message_close_container(m);
537 log_netdev_error(netdev,
538 "Could not append IFLA_LINKINFO attribute: %s",
543 r = sd_rtnl_message_close_container(m);
545 log_netdev_error(netdev,
546 "Could not append IFLA_LINKINFO attribute: %s",
553 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
554 callback, link, 0, NULL);
556 log_netdev_error(netdev,
557 "Could not send rtnetlink message: %s",
564 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
565 netdev_create_handler, netdev, 0,
568 log_netdev_error(netdev,
569 "Could not send rtnetlink message: %s",
577 netdev->state = NETDEV_STATE_CREATING;
579 log_netdev_debug(netdev, "creating");
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_rtnl_message_handler_t callback) {
590 assert(netdev->manager);
591 assert(netdev->manager->rtnl);
592 assert(NETDEV_VTABLE(netdev));
594 switch (NETDEV_VTABLE(netdev)->create_type) {
595 case NETDEV_CREATE_MASTER:
596 r = netdev_enslave(netdev, link, callback);
601 case NETDEV_CREATE_STACKED:
602 r = netdev_create(netdev, link, callback);
608 assert_not_reached("Can not join independent netdev");
614 static int netdev_load_one(Manager *manager, const char *filename) {
615 _cleanup_netdev_unref_ NetDev *netdev = NULL;
616 _cleanup_free_ NetDev *netdev_raw = NULL;
617 _cleanup_fclose_ FILE *file = NULL;
623 file = fopen(filename, "re");
631 if (null_or_empty_fd(fileno(file))) {
632 log_debug("Skipping empty file: %s", filename);
636 netdev_raw = new0(NetDev, 1);
640 netdev_raw->kind = _NETDEV_KIND_INVALID;
642 r = config_parse(NULL, filename, file,
644 config_item_perf_lookup, network_netdev_gperf_lookup,
645 true, false, true, netdev_raw);
649 r = fseek(file, 0, SEEK_SET);
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, netdev_raw->match_arch,
657 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
660 if (!NETDEV_VTABLE(netdev_raw)) {
661 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
665 if (!netdev_raw->ifname) {
666 log_warning("NetDev without Name configured in %s. Ignoring", filename);
670 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
675 netdev->manager = manager;
676 netdev->state = _NETDEV_STATE_INVALID;
677 netdev->kind = netdev_raw->kind;
678 netdev->ifname = netdev_raw->ifname;
680 if (NETDEV_VTABLE(netdev)->init)
681 NETDEV_VTABLE(netdev)->init(netdev);
683 r = config_parse(NULL, filename, file,
684 NETDEV_VTABLE(netdev)->sections,
685 config_item_perf_lookup, network_netdev_gperf_lookup,
686 false, false, false, netdev);
690 /* verify configuration */
691 if (NETDEV_VTABLE(netdev)->config_verify) {
692 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
697 netdev->filename = strdup(filename);
698 if (!netdev->filename)
702 r = netdev_get_mac(netdev->ifname, &netdev->mac);
704 log_error("Failed to generate predictable MAC address for %s",
710 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
714 LIST_HEAD_INIT(netdev->callbacks);
716 log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
718 switch (NETDEV_VTABLE(netdev)->create_type) {
719 case NETDEV_CREATE_MASTER:
720 case NETDEV_CREATE_INDEPENDENT:
721 r = netdev_create(netdev, NULL, NULL);
735 int netdev_load(Manager *manager) {
742 while ((netdev = hashmap_first(manager->netdevs)))
743 netdev_unref(netdev);
745 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
747 return log_error_errno(r, "Failed to enumerate netdev files: %m");
749 STRV_FOREACH_BACKWARDS(f, files) {
750 r = netdev_load_one(manager, *f);