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-netdev-bridge.h"
26 #include "networkd-netdev-bond.h"
27 #include "networkd-netdev-vlan.h"
28 #include "networkd-netdev-macvlan.h"
29 #include "networkd-netdev-vxlan.h"
30 #include "networkd-netdev-tunnel.h"
31 #include "networkd-netdev-veth.h"
32 #include "networkd-netdev-dummy.h"
33 #include "networkd-netdev-tuntap.h"
34 #include "network-internal.h"
35 #include "path-util.h"
36 #include "conf-files.h"
37 #include "conf-parser.h"
39 #include "siphash24.h"
41 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
42 [NETDEV_KIND_BRIDGE] = &bridge_vtable,
43 [NETDEV_KIND_BOND] = &bond_vtable,
44 [NETDEV_KIND_VLAN] = &vlan_vtable,
45 [NETDEV_KIND_MACVLAN] = &macvlan_vtable,
46 [NETDEV_KIND_VXLAN] = &vxlan_vtable,
47 [NETDEV_KIND_IPIP] = &ipip_vtable,
48 [NETDEV_KIND_GRE] = &gre_vtable,
49 [NETDEV_KIND_SIT] = &sit_vtable,
50 [NETDEV_KIND_VTI] = &vti_vtable,
51 [NETDEV_KIND_VETH] = &veth_vtable,
52 [NETDEV_KIND_DUMMY] = &dummy_vtable,
53 [NETDEV_KIND_TUN] = &tun_vtable,
54 [NETDEV_KIND_TAP] = &tap_vtable,
57 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
58 [NETDEV_KIND_BRIDGE] = "bridge",
59 [NETDEV_KIND_BOND] = "bond",
60 [NETDEV_KIND_VLAN] = "vlan",
61 [NETDEV_KIND_MACVLAN] = "macvlan",
62 [NETDEV_KIND_VXLAN] = "vxlan",
63 [NETDEV_KIND_IPIP] = "ipip",
64 [NETDEV_KIND_GRE] = "gre",
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",
73 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
74 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);
114 free(netdev->ifname_peer);
116 free(netdev->mac_peer);
117 free(netdev->user_name);
118 free(netdev->group_name);
120 condition_free_list(netdev->match_host);
121 condition_free_list(netdev->match_virt);
122 condition_free_list(netdev->match_kernel);
123 condition_free_list(netdev->match_arch);
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_debug_netdev(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_error_netdev(netdev,
197 "Could not allocate RTM_SETLINK message: %s",
202 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
204 log_error_netdev(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_error_netdev(netdev,
213 "Could not send rtnetlink message: %s",
220 log_debug_netdev(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_debug_netdev(netdev, "netdev exists, using existing");
265 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
274 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
278 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
280 if (netdev->state == NETDEV_STATE_READY) {
281 r = netdev_enslave_ready(netdev, link, callback);
285 /* the netdev is not yet read, save this request for when it is*/
286 netdev_join_callback *cb;
288 cb = new0(netdev_join_callback, 1);
292 cb->callback = callback;
296 LIST_PREPEND(callbacks, netdev->callbacks, cb);
302 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
303 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
307 assert(netdev->manager);
308 assert(netdev->manager->rtnl);
309 assert(NETDEV_VTABLE(netdev));
311 if (NETDEV_VTABLE(netdev)->fill_message_create_on_link) {
312 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
314 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
317 log_error_netdev(netdev,
318 "Could not allocate RTM_SETLINK message: %s",
323 NETDEV_VTABLE(netdev)->fill_message_create_on_link(netdev, link, req);
325 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
327 log_error_netdev(netdev,
328 "Could not send rtnetlink message: %s", strerror(-r));
333 } else if (NETDEV_VTABLE(netdev)->enslave) {
334 return NETDEV_VTABLE(netdev)->enslave(netdev, link, callback);
336 assert_not_reached("Joining link to netdev of invalid kind");
341 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
351 r = sd_rtnl_message_get_type(message, &type);
353 log_error_netdev(netdev, "Could not get rtnl message type");
357 if (type != RTM_NEWLINK) {
358 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
362 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
364 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
365 netdev_enter_failed(netdev);
367 } else if (ifindex <= 0) {
368 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
369 netdev_enter_failed(netdev);
373 if (netdev->ifindex > 0) {
374 if (netdev->ifindex != ifindex) {
375 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
376 ifindex, netdev->ifindex);
377 netdev_enter_failed(netdev);
380 /* ifindex already set to the same for this netdev */
384 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
386 log_error_netdev(netdev, "Could not get IFNAME");
390 if (!streq(netdev->ifname, received_name)) {
391 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
393 netdev_enter_failed(netdev);
397 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
399 log_error_netdev(netdev, "Could not get LINKINFO");
403 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
405 log_error_netdev(netdev, "Could not get KIND");
409 r = sd_rtnl_message_exit_container(message);
411 log_error_netdev(netdev, "Could not exit container");
415 if (netdev->kind == NETDEV_KIND_TAP)
416 /* the kernel does not distinguish between tun and tap */
419 kind = netdev_kind_to_string(netdev->kind);
421 log_error_netdev(netdev, "Could not get kind");
422 netdev_enter_failed(netdev);
427 if (!streq(kind, received_kind)) {
428 log_error_netdev(netdev,
429 "Received newlink with wrong KIND %s, "
430 "expected %s", received_kind, kind);
431 netdev_enter_failed(netdev);
435 netdev->ifindex = ifindex;
437 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
439 netdev_enter_ready(netdev);
444 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
446 int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
447 _cleanup_free_ struct ether_addr *mac = NULL;
456 mac = new0(struct ether_addr, 1);
461 sz = sizeof(sd_id128_t) + l;
464 /* fetch some persistent data unique to the machine */
465 r = sd_id128_get_machine((sd_id128_t*) v);
469 /* combine with some data unique (on this machine) to this
471 memcpy(v + sizeof(sd_id128_t), ifname, l);
473 /* Let's hash the host machine ID plus the container name. We
474 * use a fixed, but originally randomly created hash key here. */
475 siphash24(result, v, sz, HASH_KEY.bytes);
477 assert_cc(ETH_ALEN <= sizeof(result));
478 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
480 /* see eth_random_addr in the kernel */
481 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
482 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
490 static int netdev_load_one(Manager *manager, const char *filename) {
491 _cleanup_netdev_unref_ NetDev *netdev = NULL;
492 _cleanup_fclose_ FILE *file = NULL;
498 if (null_or_empty_path(filename)) {
499 log_debug("skipping empty file: %s", filename);
503 file = fopen(filename, "re");
511 netdev = new0(NetDev, 1);
516 netdev->manager = manager;
517 netdev->state = _NETDEV_STATE_INVALID;
518 netdev->kind = _NETDEV_KIND_INVALID;
519 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
520 netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
521 netdev->vlanid = VLANID_MAX + 1;
522 netdev->vxlanid = VXLAN_VID_MAX + 1;
523 netdev->tunnel_pmtudisc = true;
524 netdev->learning = true;
526 r = config_parse(NULL, filename, file,
527 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
528 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
529 false, false, netdev);
531 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
535 /* skip out early if configuration does not match the environment */
536 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
537 netdev->match_host, netdev->match_virt,
538 netdev->match_kernel, netdev->match_arch,
539 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
542 if (!NETDEV_VTABLE(netdev)) {
543 log_warning("NetDev with invalid Kind configured in %s. Igonring", filename);
547 /* verify configuration */
548 if (NETDEV_VTABLE(netdev)->config_verify) {
549 r = NETDEV_VTABLE(netdev)->config_verify(netdev, filename);
554 if (!netdev->ifname) {
555 log_warning("NetDev without Name configured in %s. Ignoring", filename);
559 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
560 log_warning("VLAN Id configured for a %s in %s. Ignoring",
561 netdev_kind_to_string(netdev->kind), filename);
565 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
566 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
567 netdev_kind_to_string(netdev->kind), filename);
571 if (netdev->kind != NETDEV_KIND_MACVLAN &&
572 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
573 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
574 netdev_kind_to_string(netdev->kind), filename);
578 netdev->filename = strdup(filename);
579 if (!netdev->filename)
583 r = netdev_get_mac(netdev->ifname, &netdev->mac);
585 log_error("Failed to generate predictable MAC address for %s",
591 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
595 LIST_HEAD_INIT(netdev->callbacks);
597 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
600 if (NETDEV_VTABLE(netdev)->fill_message_create) {
601 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
603 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0);
605 log_error_netdev(netdev,
606 "Could not allocate RTM_NEWLINK message: %s",
611 r = NETDEV_VTABLE(netdev)->fill_message_create(netdev, m);
615 r = sd_rtnl_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
617 log_error_netdev(netdev,
618 "Could not send rtnetlink message: %s", strerror(-r));
624 log_debug_netdev(netdev, "creating");
626 netdev->state = NETDEV_STATE_CREATING;
627 } else if (NETDEV_VTABLE(netdev)->create) {
628 r = NETDEV_VTABLE(netdev)->create(netdev);
638 int netdev_load(Manager *manager) {
645 while ((netdev = hashmap_first(manager->netdevs)))
646 netdev_unref(netdev);
648 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
650 log_error("Failed to enumerate netdev files: %s", strerror(-r));
654 STRV_FOREACH_BACKWARDS(f, files) {
655 r = netdev_load_one(manager, *f);