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");
69 static void netdev_cancel_callbacks(NetDev *netdev) {
70 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
71 netdev_join_callback *callback;
76 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
78 while ((callback = netdev->callbacks)) {
80 assert(callback->link);
81 assert(callback->callback);
82 assert(netdev->manager);
83 assert(netdev->manager->rtnl);
85 callback->callback(netdev->manager->rtnl, m, link);
88 LIST_REMOVE(callbacks, netdev->callbacks, callback);
93 static void netdev_free(NetDev *netdev) {
97 netdev_cancel_callbacks(netdev);
100 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
102 free(netdev->filename);
104 free(netdev->description);
105 free(netdev->ifname);
108 condition_free_list(netdev->match_host);
109 condition_free_list(netdev->match_virt);
110 condition_free_list(netdev->match_kernel);
111 condition_free_list(netdev->match_arch);
113 if (NETDEV_VTABLE(netdev) &&
114 NETDEV_VTABLE(netdev)->done)
115 NETDEV_VTABLE(netdev)->done(netdev);
120 NetDev *netdev_unref(NetDev *netdev) {
121 if (netdev && (-- netdev->n_ref <= 0))
127 NetDev *netdev_ref(NetDev *netdev) {
129 assert_se(++ netdev->n_ref >= 2);
134 void netdev_drop(NetDev *netdev) {
135 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
138 netdev->state = NETDEV_STATE_LINGER;
140 log_debug_netdev(netdev, "netdev removed");
142 netdev_cancel_callbacks(netdev);
144 netdev_unref(netdev);
149 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
156 netdev = hashmap_get(manager->netdevs, name);
167 static int netdev_enter_failed(NetDev *netdev) {
168 netdev->state = NETDEV_STATE_FAILED;
173 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
174 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
178 assert(netdev->state == NETDEV_STATE_READY);
179 assert(netdev->manager);
180 assert(netdev->manager->rtnl);
181 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
185 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
186 RTM_SETLINK, link->ifindex);
188 log_error_netdev(netdev,
189 "Could not allocate RTM_SETLINK message: %s",
194 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
196 log_error_netdev(netdev,
197 "Could not append IFLA_MASTER attribute: %s",
202 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
204 log_error_netdev(netdev,
205 "Could not send rtnetlink message: %s",
212 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
217 static int netdev_enter_ready(NetDev *netdev) {
218 netdev_join_callback *callback, *callback_next;
222 assert(netdev->ifname);
224 if (netdev->state != NETDEV_STATE_CREATING)
227 netdev->state = NETDEV_STATE_READY;
229 log_info_netdev(netdev, "netdev ready");
231 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
232 /* enslave the links that were attempted to be enslaved before the
234 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
238 LIST_REMOVE(callbacks, netdev->callbacks, callback);
239 link_unref(callback->link);
246 /* callback for netdev's created without a backing Link */
247 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
248 _cleanup_netdev_unref_ NetDev *netdev = userdata;
251 assert(netdev->state != _NETDEV_STATE_INVALID);
253 r = sd_rtnl_message_get_errno(m);
255 log_debug_netdev(netdev, "netdev exists, using existing");
257 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
263 log_debug_netdev(netdev, "created");
268 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
272 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
274 if (netdev->state == NETDEV_STATE_READY) {
275 r = netdev_enslave_ready(netdev, link, callback);
279 /* the netdev is not yet read, save this request for when it is*/
280 netdev_join_callback *cb;
282 cb = new0(netdev_join_callback, 1);
286 cb->callback = callback;
290 LIST_PREPEND(callbacks, netdev->callbacks, cb);
292 log_debug_netdev(netdev, "will enslave '%s', when reday",
299 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
302 const char *received_kind;
303 const char *received_name;
309 r = sd_rtnl_message_get_type(message, &type);
311 log_error_netdev(netdev, "Could not get rtnl message type");
315 if (type != RTM_NEWLINK) {
316 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
320 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
322 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
323 netdev_enter_failed(netdev);
325 } else if (ifindex <= 0) {
326 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
327 netdev_enter_failed(netdev);
331 if (netdev->ifindex > 0) {
332 if (netdev->ifindex != ifindex) {
333 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
334 ifindex, netdev->ifindex);
335 netdev_enter_failed(netdev);
338 /* ifindex already set to the same for this netdev */
342 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
344 log_error_netdev(netdev, "Could not get IFNAME");
348 if (!streq(netdev->ifname, received_name)) {
349 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
351 netdev_enter_failed(netdev);
355 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
357 log_error_netdev(netdev, "Could not get LINKINFO");
361 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
363 log_error_netdev(netdev, "Could not get KIND");
367 r = sd_rtnl_message_exit_container(message);
369 log_error_netdev(netdev, "Could not exit container");
373 if (netdev->kind == NETDEV_KIND_TAP)
374 /* the kernel does not distinguish between tun and tap */
377 kind = netdev_kind_to_string(netdev->kind);
379 log_error_netdev(netdev, "Could not get kind");
380 netdev_enter_failed(netdev);
385 if (!streq(kind, received_kind)) {
386 log_error_netdev(netdev,
387 "Received newlink with wrong KIND %s, "
388 "expected %s", received_kind, kind);
389 netdev_enter_failed(netdev);
393 netdev->ifindex = ifindex;
395 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
397 netdev_enter_ready(netdev);
402 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
404 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
405 _cleanup_free_ struct ether_addr *mac = NULL;
414 mac = new0(struct ether_addr, 1);
419 sz = sizeof(sd_id128_t) + l;
422 /* fetch some persistent data unique to the machine */
423 r = sd_id128_get_machine((sd_id128_t*) v);
427 /* combine with some data unique (on this machine) to this
429 memcpy(v + sizeof(sd_id128_t), ifname, l);
431 /* Let's hash the host machine ID plus the container name. We
432 * use a fixed, but originally randomly created hash key here. */
433 siphash24(result, v, sz, HASH_KEY.bytes);
435 assert_cc(ETH_ALEN <= sizeof(result));
436 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
438 /* see eth_random_addr in the kernel */
439 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
440 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
448 static int netdev_create(NetDev *netdev, Link *link,
449 sd_rtnl_message_handler_t callback) {
453 assert(!link || callback);
456 if (NETDEV_VTABLE(netdev)->create) {
459 r = NETDEV_VTABLE(netdev)->create(netdev);
463 log_debug_netdev(netdev, "created");
465 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
467 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
469 log_error_netdev(netdev,
470 "Could not allocate RTM_NEWLINK message: %s",
475 r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
477 log_error_netdev(netdev,
478 "Could not append IFLA_IFNAME, attribute: %s",
484 r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
486 log_error_netdev(netdev,
487 "Could not append IFLA_ADDRESS attribute: %s",
494 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
496 log_error_netdev(netdev,
497 "Could not append IFLA_MTU attribute: %s",
504 r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
506 log_error_netdev(netdev,
507 "Colud not append IFLA_LINK attribute: %s",
513 r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
515 log_error_netdev(netdev,
516 "Could not append IFLA_LINKINFO attribute: %s",
521 r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
522 netdev_kind_to_string(netdev->kind));
524 log_error_netdev(netdev,
525 "Could not append IFLA_INFO_DATA attribute: %s",
530 if (NETDEV_VTABLE(netdev)->fill_message_create) {
531 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
536 r = sd_rtnl_message_close_container(m);
538 log_error_netdev(netdev,
539 "Could not append IFLA_LINKINFO attribute: %s",
544 r = sd_rtnl_message_close_container(m);
546 log_error_netdev(netdev,
547 "Could not append IFLA_LINKINFO attribute: %s",
554 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
555 callback, link, 0, NULL);
557 log_error_netdev(netdev,
558 "Could not send rtnetlink message: %s",
565 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
566 netdev_create_handler, netdev, 0,
569 log_error_netdev(netdev,
570 "Could not send rtnetlink message: %s",
578 netdev->state = NETDEV_STATE_CREATING;
580 log_debug_netdev(netdev, "creating");
586 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
587 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
591 assert(netdev->manager);
592 assert(netdev->manager->rtnl);
593 assert(NETDEV_VTABLE(netdev));
595 switch (NETDEV_VTABLE(netdev)->create_type) {
596 case NETDEV_CREATE_MASTER:
597 r = netdev_enslave(netdev, link, callback);
602 case NETDEV_CREATE_STACKED:
603 r = netdev_create(netdev, link, callback);
609 assert_not_reached("Can not join independent netdev");
615 static int netdev_load_one(Manager *manager, const char *filename) {
616 _cleanup_netdev_unref_ NetDev *netdev = NULL;
617 _cleanup_free_ NetDev *netdev_raw = NULL;
618 _cleanup_fclose_ FILE *file = NULL;
624 file = fopen(filename, "re");
632 if (null_or_empty_fd(fileno(file))) {
633 log_debug("Skipping empty file: %s", filename);
637 netdev_raw = new0(NetDev, 1);
641 netdev_raw->kind = _NETDEV_KIND_INVALID;
643 r = config_parse(NULL, filename, file,
645 config_item_perf_lookup, network_netdev_gperf_lookup,
646 true, false, true, netdev_raw);
650 r = fseek(file, 0, SEEK_SET);
654 /* skip out early if configuration does not match the environment */
655 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
656 netdev_raw->match_host, netdev_raw->match_virt,
657 netdev_raw->match_kernel, netdev_raw->match_arch,
658 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
661 if (!NETDEV_VTABLE(netdev_raw)) {
662 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
666 if (!netdev_raw->ifname) {
667 log_warning("NetDev without Name configured in %s. Ignoring", filename);
671 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
676 netdev->manager = manager;
677 netdev->state = _NETDEV_STATE_INVALID;
678 netdev->kind = netdev_raw->kind;
679 netdev->ifname = netdev_raw->ifname;
681 if (NETDEV_VTABLE(netdev)->init)
682 NETDEV_VTABLE(netdev)->init(netdev);
684 r = config_parse(NULL, filename, file,
685 NETDEV_VTABLE(netdev)->sections,
686 config_item_perf_lookup, network_netdev_gperf_lookup,
687 false, false, false, netdev);
691 /* verify configuration */
692 if (NETDEV_VTABLE(netdev)->config_verify) {
693 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
698 netdev->filename = strdup(filename);
699 if (!netdev->filename)
703 r = netdev_get_mac(netdev->ifname, &netdev->mac);
705 log_error("Failed to generate predictable MAC address for %s",
711 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
715 LIST_HEAD_INIT(netdev->callbacks);
717 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
719 switch (NETDEV_VTABLE(netdev)->create_type) {
720 case NETDEV_CREATE_MASTER:
721 case NETDEV_CREATE_INDEPENDENT:
722 r = netdev_create(netdev, NULL, NULL);
736 int netdev_load(Manager *manager) {
743 while ((netdev = hashmap_first(manager->netdevs)))
744 netdev_unref(netdev);
746 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
748 log_error("Failed to enumerate netdev files: %s", strerror(-r));
752 STRV_FOREACH_BACKWARDS(f, files) {
753 r = netdev_load_one(manager, *f);