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 "conf-files.h"
28 #include "conf-parser.h"
30 #include "siphash24.h"
32 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
33 [NETDEV_KIND_BRIDGE] = &bridge_vtable,
34 [NETDEV_KIND_BOND] = &bond_vtable,
35 [NETDEV_KIND_VLAN] = &vlan_vtable,
36 [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
37 [NETDEV_KIND_IPVLAN] = &ipvlan_vtable,
38 [NETDEV_KIND_VXLAN] = &vxlan_vtable,
39 [NETDEV_KIND_IPIP] = &ipip_vtable,
40 [NETDEV_KIND_GRE] = &gre_vtable,
41 [NETDEV_KIND_GRETAP] = &gretap_vtable,
42 [NETDEV_KIND_IP6GRE] = &ip6gre_vtable,
43 [NETDEV_KIND_IP6GRETAP] = &ip6gretap_vtable,
44 [NETDEV_KIND_SIT] = &sit_vtable,
45 [NETDEV_KIND_VTI] = &vti_vtable,
46 [NETDEV_KIND_VETH] = &veth_vtable,
47 [NETDEV_KIND_DUMMY] = &dummy_vtable,
48 [NETDEV_KIND_TUN] = &tun_vtable,
49 [NETDEV_KIND_TAP] = &tap_vtable,
50 [NETDEV_KIND_IP6TNL] = &ip6tnl_vtable,
53 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
54 [NETDEV_KIND_BRIDGE] = "bridge",
55 [NETDEV_KIND_BOND] = "bond",
56 [NETDEV_KIND_VLAN] = "vlan",
57 [NETDEV_KIND_MACVLAN] = "macvlan",
58 [NETDEV_KIND_IPVLAN] = "ipvlan",
59 [NETDEV_KIND_VXLAN] = "vxlan",
60 [NETDEV_KIND_IPIP] = "ipip",
61 [NETDEV_KIND_GRE] = "gre",
62 [NETDEV_KIND_GRETAP] = "gretap",
63 [NETDEV_KIND_IP6GRE] = "ip6gre",
64 [NETDEV_KIND_IP6GRETAP] = "ip6gretap",
65 [NETDEV_KIND_SIT] = "sit",
66 [NETDEV_KIND_VETH] = "veth",
67 [NETDEV_KIND_VTI] = "vti",
68 [NETDEV_KIND_DUMMY] = "dummy",
69 [NETDEV_KIND_TUN] = "tun",
70 [NETDEV_KIND_TAP] = "tap",
71 [NETDEV_KIND_IP6TNL] = "ip6tnl",
74 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
75 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
77 static void netdev_cancel_callbacks(NetDev *netdev) {
78 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
79 netdev_join_callback *callback;
84 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
86 while ((callback = netdev->callbacks)) {
88 assert(callback->link);
89 assert(callback->callback);
90 assert(netdev->manager);
91 assert(netdev->manager->rtnl);
93 callback->callback(netdev->manager->rtnl, m, link);
96 LIST_REMOVE(callbacks, netdev->callbacks, callback);
101 static void netdev_free(NetDev *netdev) {
105 netdev_cancel_callbacks(netdev);
108 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
110 free(netdev->filename);
112 free(netdev->description);
113 free(netdev->ifname);
116 condition_free_list(netdev->match_host);
117 condition_free_list(netdev->match_virt);
118 condition_free_list(netdev->match_kernel);
119 condition_free_list(netdev->match_arch);
121 if (NETDEV_VTABLE(netdev) &&
122 NETDEV_VTABLE(netdev)->done)
123 NETDEV_VTABLE(netdev)->done(netdev);
128 NetDev *netdev_unref(NetDev *netdev) {
129 if (netdev && (-- netdev->n_ref <= 0))
135 NetDev *netdev_ref(NetDev *netdev) {
137 assert_se(++ netdev->n_ref >= 2);
142 void netdev_drop(NetDev *netdev) {
143 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
146 netdev->state = NETDEV_STATE_LINGER;
148 log_netdev_debug(netdev, "netdev removed");
150 netdev_cancel_callbacks(netdev);
152 netdev_unref(netdev);
157 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
164 netdev = hashmap_get(manager->netdevs, name);
175 static int netdev_enter_failed(NetDev *netdev) {
176 netdev->state = NETDEV_STATE_FAILED;
181 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
182 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
186 assert(netdev->state == NETDEV_STATE_READY);
187 assert(netdev->manager);
188 assert(netdev->manager->rtnl);
189 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
193 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
194 RTM_SETLINK, link->ifindex);
196 log_netdev_error(netdev,
197 "Could not allocate RTM_SETLINK message: %s",
202 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
204 log_netdev_error(netdev,
205 "Could not append IFLA_MASTER attribute: %s",
210 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
212 log_netdev_error(netdev,
213 "Could not send rtnetlink message: %s",
220 log_netdev_debug(netdev, "enslaving link '%s'", link->ifname);
225 static int netdev_enter_ready(NetDev *netdev) {
226 netdev_join_callback *callback, *callback_next;
230 assert(netdev->ifname);
232 if (netdev->state != NETDEV_STATE_CREATING)
235 netdev->state = NETDEV_STATE_READY;
237 log_info_netdev(netdev, "netdev ready");
239 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
240 /* enslave the links that were attempted to be enslaved before the
242 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
246 LIST_REMOVE(callbacks, netdev->callbacks, callback);
247 link_unref(callback->link);
254 /* callback for netdev's created without a backing Link */
255 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
256 _cleanup_netdev_unref_ NetDev *netdev = userdata;
259 assert(netdev->state != _NETDEV_STATE_INVALID);
261 r = sd_rtnl_message_get_errno(m);
263 log_info_netdev(netdev, "netdev exists, using existing without changing its parameters");
265 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
271 log_netdev_debug(netdev, "created");
276 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
280 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
282 if (netdev->state == NETDEV_STATE_READY) {
283 r = netdev_enslave_ready(netdev, link, callback);
287 /* the netdev is not yet read, save this request for when it is */
288 netdev_join_callback *cb;
290 cb = new0(netdev_join_callback, 1);
294 cb->callback = callback;
298 LIST_PREPEND(callbacks, netdev->callbacks, cb);
300 log_netdev_debug(netdev, "will enslave '%s', when reday",
307 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
310 const char *received_kind;
311 const char *received_name;
317 r = sd_rtnl_message_get_type(message, &type);
319 log_netdev_error(netdev, "Could not get rtnl message type");
323 if (type != RTM_NEWLINK) {
324 log_netdev_error(netdev, "Can not set ifindex from unexpected rtnl message type");
328 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
330 log_netdev_error(netdev, "Could not get ifindex: %s", strerror(-r));
331 netdev_enter_failed(netdev);
333 } else if (ifindex <= 0) {
334 log_netdev_error(netdev, "Got invalid ifindex: %d", ifindex);
335 netdev_enter_failed(netdev);
339 if (netdev->ifindex > 0) {
340 if (netdev->ifindex != ifindex) {
341 log_netdev_error(netdev, "Could not set ifindex to %d, already set to %d",
342 ifindex, netdev->ifindex);
343 netdev_enter_failed(netdev);
346 /* ifindex already set to the same for this netdev */
350 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
352 log_netdev_error(netdev, "Could not get IFNAME");
356 if (!streq(netdev->ifname, received_name)) {
357 log_netdev_error(netdev, "Received newlink with wrong IFNAME %s",
359 netdev_enter_failed(netdev);
363 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
365 log_netdev_error(netdev, "Could not get LINKINFO");
369 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
371 log_netdev_error(netdev, "Could not get KIND");
375 r = sd_rtnl_message_exit_container(message);
377 log_netdev_error(netdev, "Could not exit container");
381 if (netdev->kind == NETDEV_KIND_TAP)
382 /* the kernel does not distinguish between tun and tap */
385 kind = netdev_kind_to_string(netdev->kind);
387 log_netdev_error(netdev, "Could not get kind");
388 netdev_enter_failed(netdev);
393 if (!streq(kind, received_kind)) {
394 log_netdev_error(netdev,
395 "Received newlink with wrong KIND %s, "
396 "expected %s", received_kind, kind);
397 netdev_enter_failed(netdev);
401 netdev->ifindex = ifindex;
403 log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
405 netdev_enter_ready(netdev);
410 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
412 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
413 _cleanup_free_ struct ether_addr *mac = NULL;
422 mac = new0(struct ether_addr, 1);
427 sz = sizeof(sd_id128_t) + l;
430 /* fetch some persistent data unique to the machine */
431 r = sd_id128_get_machine((sd_id128_t*) v);
435 /* combine with some data unique (on this machine) to this
437 memcpy(v + sizeof(sd_id128_t), ifname, l);
439 /* Let's hash the host machine ID plus the container name. We
440 * use a fixed, but originally randomly created hash key here. */
441 siphash24(result, v, sz, HASH_KEY.bytes);
443 assert_cc(ETH_ALEN <= sizeof(result));
444 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
446 /* see eth_random_addr in the kernel */
447 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
448 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
456 static int netdev_create(NetDev *netdev, Link *link,
457 sd_rtnl_message_handler_t callback) {
461 assert(!link || callback);
464 if (NETDEV_VTABLE(netdev)->create) {
467 r = NETDEV_VTABLE(netdev)->create(netdev);
471 log_netdev_debug(netdev, "created");
473 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
475 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
477 log_netdev_error(netdev,
478 "Could not allocate RTM_NEWLINK message: %s",
483 r = sd_rtnl_message_append_string(m, IFLA_IFNAME, netdev->ifname);
485 log_netdev_error(netdev,
486 "Could not append IFLA_IFNAME, attribute: %s",
492 r = sd_rtnl_message_append_ether_addr(m, IFLA_ADDRESS, netdev->mac);
494 log_netdev_error(netdev,
495 "Could not append IFLA_ADDRESS attribute: %s",
502 r = sd_rtnl_message_append_u32(m, IFLA_MTU, netdev->mtu);
504 log_netdev_error(netdev,
505 "Could not append IFLA_MTU attribute: %s",
512 r = sd_rtnl_message_append_u32(m, IFLA_LINK, link->ifindex);
514 log_netdev_error(netdev,
515 "Could not append IFLA_LINK attribute: %s",
521 r = sd_rtnl_message_open_container(m, IFLA_LINKINFO);
523 log_netdev_error(netdev,
524 "Could not append IFLA_LINKINFO attribute: %s",
529 r = sd_rtnl_message_open_container_union(m, IFLA_INFO_DATA,
530 netdev_kind_to_string(netdev->kind));
532 log_netdev_error(netdev,
533 "Could not append IFLA_INFO_DATA attribute: %s",
538 if (NETDEV_VTABLE(netdev)->fill_message_create) {
539 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, link, m);
544 r = sd_rtnl_message_close_container(m);
546 log_netdev_error(netdev,
547 "Could not append IFLA_LINKINFO attribute: %s",
552 r = sd_rtnl_message_close_container(m);
554 log_netdev_error(netdev,
555 "Could not append IFLA_LINKINFO attribute: %s",
562 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
563 callback, link, 0, NULL);
565 log_netdev_error(netdev,
566 "Could not send rtnetlink message: %s",
573 r = sd_rtnl_call_async(netdev->manager->rtnl, m,
574 netdev_create_handler, netdev, 0,
577 log_netdev_error(netdev,
578 "Could not send rtnetlink message: %s",
586 netdev->state = NETDEV_STATE_CREATING;
588 log_netdev_debug(netdev, "creating");
594 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
595 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
599 assert(netdev->manager);
600 assert(netdev->manager->rtnl);
601 assert(NETDEV_VTABLE(netdev));
603 switch (NETDEV_VTABLE(netdev)->create_type) {
604 case NETDEV_CREATE_MASTER:
605 r = netdev_enslave(netdev, link, callback);
610 case NETDEV_CREATE_STACKED:
611 r = netdev_create(netdev, link, callback);
617 assert_not_reached("Can not join independent netdev");
623 static int netdev_load_one(Manager *manager, const char *filename) {
624 _cleanup_netdev_unref_ NetDev *netdev = NULL;
625 _cleanup_free_ NetDev *netdev_raw = NULL;
626 _cleanup_fclose_ FILE *file = NULL;
632 file = fopen(filename, "re");
640 if (null_or_empty_fd(fileno(file))) {
641 log_debug("Skipping empty file: %s", filename);
645 netdev_raw = new0(NetDev, 1);
649 netdev_raw->kind = _NETDEV_KIND_INVALID;
651 r = config_parse(NULL, filename, file,
653 config_item_perf_lookup, network_netdev_gperf_lookup,
654 true, false, true, netdev_raw);
658 r = fseek(file, 0, SEEK_SET);
662 /* skip out early if configuration does not match the environment */
663 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
664 netdev_raw->match_host, netdev_raw->match_virt,
665 netdev_raw->match_kernel, netdev_raw->match_arch,
666 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
669 if (!NETDEV_VTABLE(netdev_raw)) {
670 log_warning("NetDev with invalid Kind configured in %s. Ignoring", filename);
674 if (!netdev_raw->ifname) {
675 log_warning("NetDev without Name configured in %s. Ignoring", filename);
679 netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size);
684 netdev->manager = manager;
685 netdev->state = _NETDEV_STATE_INVALID;
686 netdev->kind = netdev_raw->kind;
687 netdev->ifname = netdev_raw->ifname;
689 if (NETDEV_VTABLE(netdev)->init)
690 NETDEV_VTABLE(netdev)->init(netdev);
692 r = config_parse(NULL, filename, file,
693 NETDEV_VTABLE(netdev)->sections,
694 config_item_perf_lookup, network_netdev_gperf_lookup,
695 false, false, false, netdev);
699 /* verify configuration */
700 if (NETDEV_VTABLE(netdev)->config_verify) {
701 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
706 netdev->filename = strdup(filename);
707 if (!netdev->filename)
711 r = netdev_get_mac(netdev->ifname, &netdev->mac);
713 log_error("Failed to generate predictable MAC address for %s",
719 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
723 LIST_HEAD_INIT(netdev->callbacks);
725 log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
727 switch (NETDEV_VTABLE(netdev)->create_type) {
728 case NETDEV_CREATE_MASTER:
729 case NETDEV_CREATE_INDEPENDENT:
730 r = netdev_create(netdev, NULL, NULL);
744 int netdev_load(Manager *manager) {
751 while ((netdev = hashmap_first(manager->netdevs)))
752 netdev_unref(netdev);
754 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
756 return log_error_errno(r, "Failed to enumerate netdev files: %m");
758 STRV_FOREACH_BACKWARDS(f, files) {
759 r = netdev_load_one(manager, *f);