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_SIT] = &sit_vtable,
43 [NETDEV_KIND_VTI] = &vti_vtable,
44 [NETDEV_KIND_VETH] = &veth_vtable,
45 [NETDEV_KIND_DUMMY] = &dummy_vtable,
46 [NETDEV_KIND_TUN] = &tun_vtable,
47 [NETDEV_KIND_TAP] = &tap_vtable,
50 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
51 [NETDEV_KIND_BRIDGE] = "bridge",
52 [NETDEV_KIND_BOND] = "bond",
53 [NETDEV_KIND_VLAN] = "vlan",
54 [NETDEV_KIND_MACVLAN] = "macvlan",
55 [NETDEV_KIND_IPVLAN] = "ipvlan",
56 [NETDEV_KIND_VXLAN] = "vxlan",
57 [NETDEV_KIND_IPIP] = "ipip",
58 [NETDEV_KIND_GRE] = "gre",
59 [NETDEV_KIND_SIT] = "sit",
60 [NETDEV_KIND_VETH] = "veth",
61 [NETDEV_KIND_VTI] = "vti",
62 [NETDEV_KIND_DUMMY] = "dummy",
63 [NETDEV_KIND_TUN] = "tun",
64 [NETDEV_KIND_TAP] = "tap",
67 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
68 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
70 static void netdev_cancel_callbacks(NetDev *netdev) {
71 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
72 netdev_join_callback *callback;
77 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
79 while ((callback = netdev->callbacks)) {
81 assert(callback->link);
82 assert(callback->callback);
83 assert(netdev->manager);
84 assert(netdev->manager->rtnl);
86 callback->callback(netdev->manager->rtnl, m, link);
89 LIST_REMOVE(callbacks, netdev->callbacks, callback);
94 static void netdev_free(NetDev *netdev) {
98 netdev_cancel_callbacks(netdev);
101 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
103 free(netdev->filename);
105 free(netdev->description);
106 free(netdev->ifname);
109 condition_free_list(netdev->match_host);
110 condition_free_list(netdev->match_virt);
111 condition_free_list(netdev->match_kernel);
112 condition_free_list(netdev->match_arch);
114 if (NETDEV_VTABLE(netdev) &&
115 NETDEV_VTABLE(netdev)->done)
116 NETDEV_VTABLE(netdev)->done(netdev);
121 NetDev *netdev_unref(NetDev *netdev) {
122 if (netdev && (-- netdev->n_ref <= 0))
128 NetDev *netdev_ref(NetDev *netdev) {
130 assert_se(++ netdev->n_ref >= 2);
135 void netdev_drop(NetDev *netdev) {
136 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
139 netdev->state = NETDEV_STATE_LINGER;
141 log_netdev_debug(netdev, "netdev removed");
143 netdev_cancel_callbacks(netdev);
145 netdev_unref(netdev);
150 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
157 netdev = hashmap_get(manager->netdevs, name);
168 static int netdev_enter_failed(NetDev *netdev) {
169 netdev->state = NETDEV_STATE_FAILED;
174 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
175 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
179 assert(netdev->state == NETDEV_STATE_READY);
180 assert(netdev->manager);
181 assert(netdev->manager->rtnl);
182 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
186 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
187 RTM_SETLINK, link->ifindex);
189 log_netdev_error(netdev,
190 "Could not allocate RTM_SETLINK message: %s",
195 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
197 log_netdev_error(netdev,
198 "Could not append IFLA_MASTER attribute: %s",
203 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
205 log_netdev_error(netdev,
206 "Could not send rtnetlink message: %s",
213 log_netdev_debug(netdev, "enslaving link '%s'", link->ifname);
218 static int netdev_enter_ready(NetDev *netdev) {
219 netdev_join_callback *callback, *callback_next;
223 assert(netdev->ifname);
225 if (netdev->state != NETDEV_STATE_CREATING)
228 netdev->state = NETDEV_STATE_READY;
230 log_info_netdev(netdev, "netdev ready");
232 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
233 /* enslave the links that were attempted to be enslaved before the
235 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
239 LIST_REMOVE(callbacks, netdev->callbacks, callback);
240 link_unref(callback->link);
247 /* callback for netdev's created without a backing Link */
248 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
249 _cleanup_netdev_unref_ NetDev *netdev = userdata;
252 assert(netdev->state != _NETDEV_STATE_INVALID);
254 r = sd_rtnl_message_get_errno(m);
256 log_netdev_debug(netdev, "netdev exists, using existing");
258 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
264 log_netdev_debug(netdev, "created");
269 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
273 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
275 if (netdev->state == NETDEV_STATE_READY) {
276 r = netdev_enslave_ready(netdev, link, callback);
280 /* the netdev is not yet read, save this request for when it is */
281 netdev_join_callback *cb;
283 cb = new0(netdev_join_callback, 1);
287 cb->callback = callback;
291 LIST_PREPEND(callbacks, netdev->callbacks, cb);
293 log_netdev_debug(netdev, "will enslave '%s', when reday",
300 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
303 const char *received_kind;
304 const char *received_name;
310 r = sd_rtnl_message_get_type(message, &type);
312 log_netdev_error(netdev, "Could not get rtnl message type");
316 if (type != RTM_NEWLINK) {
317 log_netdev_error(netdev, "Can not set ifindex from unexpected rtnl message type");
321 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
323 log_netdev_error(netdev, "Could not get ifindex: %s", strerror(-r));
324 netdev_enter_failed(netdev);
326 } else if (ifindex <= 0) {
327 log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
328 netdev_enter_failed(netdev);
332 if (netdev->ifindex > 0) {
333 if (netdev->ifindex != ifindex) {
334 log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
335 ifindex, netdev->ifindex);
336 netdev_enter_failed(netdev);
339 /* ifindex already set to the same for this netdev */
343 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
345 log_netdev_error(netdev, "Could not get IFNAME");
349 if (!streq(netdev->ifname, received_name)) {
350 log_netdev_error(netdev, "Received newlink with wrong IFNAME %s",
352 netdev_enter_failed(netdev);
356 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
358 log_netdev_error(netdev, "Could not get LINKINFO");
362 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
364 log_netdev_error(netdev, "Could not get KIND");
368 r = sd_rtnl_message_exit_container(message);
370 log_netdev_error(netdev, "Could not exit container");
374 if (netdev->kind == NETDEV_KIND_TAP)
375 /* the kernel does not distinguish between tun and tap */
378 kind = netdev_kind_to_string(netdev->kind);
380 log_netdev_error(netdev, "Could not get kind");
381 netdev_enter_failed(netdev);
386 if (!streq(kind, received_kind)) {
387 log_netdev_error(netdev,
388 "Received newlink with wrong KIND %s, "
389 "expected %s", received_kind, kind);
390 netdev_enter_failed(netdev);
394 netdev->ifindex = ifindex;
396 log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
398 netdev_enter_ready(netdev);
403 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
405 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
406 _cleanup_free_ struct ether_addr *mac = NULL;
415 mac = new0(struct ether_addr, 1);
420 sz = sizeof(sd_id128_t) + l;
423 /* fetch some persistent data unique to the machine */
424 r = sd_id128_get_machine((sd_id128_t*) v);
428 /* combine with some data unique (on this machine) to this
430 memcpy(v + sizeof(sd_id128_t), ifname, l);
432 /* Let's hash the host machine ID plus the container name. We
433 * use a fixed, but originally randomly created hash key here. */
434 siphash24(result, v, sz, HASH_KEY.bytes);
436 assert_cc(ETH_ALEN <= sizeof(result));
437 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
439 /* see eth_random_addr in the kernel */
440 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
441 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
449 static int netdev_create(NetDev *netdev, Link *link,
450 sd_rtnl_message_handler_t callback) {
454 assert(!link || callback);
457 if (NETDEV_VTABLE(netdev)->create) {
460 r = NETDEV_VTABLE(netdev)->create(netdev);
464 log_netdev_debug(netdev, "created");
466 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
468 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
470 log_netdev_error(netdev,
471 "Could not allocate RTM_NEWLINK message: %s",
476 r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
478 log_netdev_error(netdev,
479 "Could not append IFLA_IFNAME, attribute: %s",
485 r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
487 log_netdev_error(netdev,
488 "Could not append IFLA_ADDRESS attribute: %s",
495 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
497 log_netdev_error(netdev,
498 "Could not append IFLA_MTU attribute: %s",
505 r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
507 log_netdev_error(netdev,
508 "Could not append IFLA_LINK attribute: %s",
514 r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
516 log_netdev_error(netdev,
517 "Could not append IFLA_LINKINFO attribute: %s",
522 r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
523 netdev_kind_to_string(netdev->kind));
525 log_netdev_error(netdev,
526 "Could not append IFLA_INFO_DATA attribute: %s",
531 if (NETDEV_VTABLE(netdev)->fill_message_create) {
532 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
537 r = sd_rtnl_message_close_container(m);
539 log_netdev_error(netdev,
540 "Could not append IFLA_LINKINFO attribute: %s",
545 r = sd_rtnl_message_close_container(m);
547 log_netdev_error(netdev,
548 "Could not append IFLA_LINKINFO attribute: %s",
555 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
556 callback, link, 0, NULL);
558 log_netdev_error(netdev,
559 "Could not send rtnetlink message: %s",
566 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
567 netdev_create_handler, netdev, 0,
570 log_netdev_error(netdev,
571 "Could not send rtnetlink message: %s",
579 netdev->state = NETDEV_STATE_CREATING;
581 log_netdev_debug(netdev, "creating");
587 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
588 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
592 assert(netdev->manager);
593 assert(netdev->manager->rtnl);
594 assert(NETDEV_VTABLE(netdev));
596 switch (NETDEV_VTABLE(netdev)->create_type) {
597 case NETDEV_CREATE_MASTER:
598 r = netdev_enslave(netdev, link, callback);
603 case NETDEV_CREATE_STACKED:
604 r = netdev_create(netdev, link, callback);
610 assert_not_reached("Can not join independent netdev");
616 static int netdev_load_one(Manager *manager, const char *filename) {
617 _cleanup_netdev_unref_ NetDev *netdev = NULL;
618 _cleanup_free_ NetDev *netdev_raw = NULL;
619 _cleanup_fclose_ FILE *file = NULL;
625 file = fopen(filename, "re");
633 if (null_or_empty_fd(fileno(file))) {
634 log_debug("Skipping empty file: %s", filename);
638 netdev_raw = new0(NetDev, 1);
642 netdev_raw->kind = _NETDEV_KIND_INVALID;
644 r = config_parse(NULL, filename, file,
646 config_item_perf_lookup, network_netdev_gperf_lookup,
647 true, false, true, netdev_raw);
651 r = fseek(file, 0, SEEK_SET);
655 /* skip out early if configuration does not match the environment */
656 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
657 netdev_raw->match_host, netdev_raw->match_virt,
658 netdev_raw->match_kernel, netdev_raw->match_arch,
659 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
662 if (!NETDEV_VTABLE(netdev_raw)) {
663 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
667 if (!netdev_raw->ifname) {
668 log_warning("NetDev without Name configured in %s. Ignoring", filename);
672 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
677 netdev->manager = manager;
678 netdev->state = _NETDEV_STATE_INVALID;
679 netdev->kind = netdev_raw->kind;
680 netdev->ifname = netdev_raw->ifname;
682 if (NETDEV_VTABLE(netdev)->init)
683 NETDEV_VTABLE(netdev)->init(netdev);
685 r = config_parse(NULL, filename, file,
686 NETDEV_VTABLE(netdev)->sections,
687 config_item_perf_lookup, network_netdev_gperf_lookup,
688 false, false, false, netdev);
692 /* verify configuration */
693 if (NETDEV_VTABLE(netdev)->config_verify) {
694 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
699 netdev->filename = strdup(filename);
700 if (!netdev->filename)
704 r = netdev_get_mac(netdev->ifname, &netdev->mac);
706 log_error("Failed to generate predictable MAC address for %s",
712 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
716 LIST_HEAD_INIT(netdev->callbacks);
718 log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
720 switch (NETDEV_VTABLE(netdev)->create_type) {
721 case NETDEV_CREATE_MASTER:
722 case NETDEV_CREATE_INDEPENDENT:
723 r = netdev_create(netdev, NULL, NULL);
737 int netdev_load(Manager *manager) {
744 while ((netdev = hashmap_first(manager->netdevs)))
745 netdev_unref(netdev);
747 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
749 return log_error_errno(r, "Failed to enumerate netdev files: %m");
751 STRV_FOREACH_BACKWARDS(f, files) {
752 r = netdev_load_one(manager, *f);