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/>.
25 #include "network-internal.h"
26 #include "path-util.h"
27 #include "conf-files.h"
28 #include "conf-parser.h"
30 #include "siphash24.h"
32 #define VLANID_MAX 4094
34 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
35 [NETDEV_KIND_BRIDGE] = "bridge",
36 [NETDEV_KIND_BOND] = "bond",
37 [NETDEV_KIND_VLAN] = "vlan",
38 [NETDEV_KIND_MACVLAN] = "macvlan",
39 [NETDEV_KIND_VXLAN] = "vxlan",
40 [NETDEV_KIND_IPIP] = "ipip",
41 [NETDEV_KIND_GRE] = "gre",
42 [NETDEV_KIND_SIT] = "sit",
43 [NETDEV_KIND_VETH] = "veth",
44 [NETDEV_KIND_VTI] = "vti"
47 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
48 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
50 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
51 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
52 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
53 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
54 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
57 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
58 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
60 static void netdev_cancel_callbacks(NetDev *netdev) {
61 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
62 netdev_enslave_callback *callback;
67 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
69 while ((callback = netdev->callbacks)) {
71 assert(callback->link);
72 assert(callback->callback);
73 assert(netdev->manager);
74 assert(netdev->manager->rtnl);
76 callback->callback(netdev->manager->rtnl, m, link);
79 LIST_REMOVE(callbacks, netdev->callbacks, callback);
84 static void netdev_free(NetDev *netdev) {
88 netdev_cancel_callbacks(netdev);
91 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
93 free(netdev->filename);
95 free(netdev->description);
98 free(netdev->mac_peer);
100 condition_free_list(netdev->match_host);
101 condition_free_list(netdev->match_virt);
102 condition_free_list(netdev->match_kernel);
103 condition_free_list(netdev->match_arch);
108 NetDev *netdev_unref(NetDev *netdev) {
109 if (netdev && (-- netdev->n_ref <= 0))
115 NetDev *netdev_ref(NetDev *netdev) {
117 assert_se(++ netdev->n_ref >= 2);
122 void netdev_drop(NetDev *netdev) {
123 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
126 netdev->state = NETDEV_STATE_LINGER;
128 log_debug_netdev(netdev, "netdev removed");
130 netdev_cancel_callbacks(netdev);
132 netdev_unref(netdev);
137 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
144 netdev = hashmap_get(manager->netdevs, name);
155 static int netdev_enter_failed(NetDev *netdev) {
156 netdev->state = NETDEV_STATE_FAILED;
161 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
162 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
166 assert(netdev->state == NETDEV_STATE_READY);
167 assert(netdev->manager);
168 assert(netdev->manager->rtnl);
172 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
173 RTM_SETLINK, link->ifindex);
175 log_error_netdev(netdev,
176 "Could not allocate RTM_SETLINK message: %s",
181 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
183 log_error_netdev(netdev,
184 "Could not append IFLA_MASTER attribute: %s",
189 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
191 log_error_netdev(netdev,
192 "Could not send rtnetlink message: %s",
197 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
202 static int netdev_enter_ready(NetDev *netdev) {
203 netdev_enslave_callback *callback;
206 assert(netdev->ifname);
208 if (netdev->state != NETDEV_STATE_CREATING)
211 netdev->state = NETDEV_STATE_READY;
213 log_info_netdev(netdev, "netdev ready");
215 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
216 /* enslave the links that were attempted to be enslaved before the
218 netdev_enslave_ready(netdev, callback->link, callback->callback);
223 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
224 NetDev *netdev = userdata;
227 assert(netdev->state != _NETDEV_STATE_INVALID);
229 r = sd_rtnl_message_get_errno(m);
231 log_debug_netdev(netdev, "netdev exists, using existing");
233 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
242 int config_parse_tunnel_address(const char *unit,
243 const char *filename,
246 unsigned section_line,
253 unsigned char family = AF_INET;
261 r = net_parse_inaddr(rvalue, &family, n);
263 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
264 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
270 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
271 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
276 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
278 assert(netdev->ifname);
279 assert(netdev->manager);
280 assert(netdev->manager->rtnl);
282 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
284 log_error_netdev(netdev,
285 "Could not allocate RTM_NEWLINK message: %s",
291 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
293 log_error_netdev(netdev,
294 "Could not append IFLA_LINK attribute: %s",
300 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
302 log_error_netdev(netdev,
303 "Could not append IFLA_IFNAME attribute: %s",
309 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
311 log_error_netdev(netdev,
312 "Could not append IFLA_MTU attribute: %s",
319 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
321 log_error_netdev(netdev,
322 "Colud not append IFLA_ADDRESS attribute: %s",
328 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
330 log_error_netdev(netdev,
331 "Could not open IFLA_LINKINFO container: %s",
336 kind = netdev_kind_to_string(netdev->kind);
338 log_error_netdev(netdev, "Invalid kind");
342 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
344 log_error_netdev(netdev,
345 "Could not open IFLA_INFO_DATA container: %s",
350 if (netdev->vlanid <= VLANID_MAX) {
351 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
353 log_error_netdev(netdev,
354 "Could not append IFLA_VLAN_ID attribute: %s",
360 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
361 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
363 log_error_netdev(netdev,
364 "Could not append IFLA_MACVLAN_MODE attribute: %s",
370 r = sd_rtnl_message_close_container(req);
372 log_error_netdev(netdev,
373 "Could not close IFLA_INFO_DATA container %s",
378 r = sd_rtnl_message_close_container(req);
380 log_error_netdev(netdev,
381 "Could not close IFLA_LINKINFO container %s",
387 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
389 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
391 log_error_netdev(netdev,
392 "Could not send rtnetlink message: %s", strerror(-r));
396 log_debug_netdev(netdev, "creating netdev");
398 netdev->state = NETDEV_STATE_CREATING;
403 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
406 switch(netdev->kind) {
407 case NETDEV_KIND_VLAN:
408 case NETDEV_KIND_MACVLAN:
409 return netdev_create(netdev, link, callback);
410 case NETDEV_KIND_VXLAN:
411 return netdev_create_vxlan(netdev, link, callback);
412 case NETDEV_KIND_IPIP:
413 case NETDEV_KIND_GRE:
414 case NETDEV_KIND_SIT:
415 case NETDEV_KIND_VTI:
416 return netdev_create_tunnel(link, netdev_create_handler);
421 if (netdev->state == NETDEV_STATE_READY) {
422 r = netdev_enslave_ready(netdev, link, callback);
426 /* the netdev is not yet read, save this request for when it is*/
427 netdev_enslave_callback *cb;
429 cb = new0(netdev_enslave_callback, 1);
433 cb->callback = callback;
436 LIST_PREPEND(callbacks, netdev->callbacks, cb);
442 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
452 r = sd_rtnl_message_get_type(message, &type);
454 log_error_netdev(netdev, "Could not get rtnl message type");
458 if (type != RTM_NEWLINK) {
459 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
463 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
465 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
466 netdev_enter_failed(netdev);
468 } else if (ifindex <= 0) {
469 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
470 netdev_enter_failed(netdev);
474 if (netdev->ifindex > 0) {
475 if (netdev->ifindex != ifindex) {
476 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
477 ifindex, netdev->ifindex);
478 netdev_enter_failed(netdev);
481 /* ifindex already set to the same for this netdev */
485 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
487 log_error_netdev(netdev, "Could not get IFNAME");
491 if (!streq(netdev->ifname, received_name)) {
492 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
494 netdev_enter_failed(netdev);
498 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
500 log_error_netdev(netdev, "Could not get LINKINFO");
504 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
506 log_error_netdev(netdev, "Could not get KIND");
510 r = sd_rtnl_message_exit_container(message);
512 log_error_netdev(netdev, "Could not exit container");
516 kind = netdev_kind_to_string(netdev->kind);
518 log_error_netdev(netdev, "Could not get kind");
519 netdev_enter_failed(netdev);
523 if (!streq(kind, received_kind)) {
524 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
525 "expected %s", received_kind, kind);
526 netdev_enter_failed(netdev);
530 netdev->ifindex = ifindex;
532 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
534 netdev_enter_ready(netdev);
539 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
541 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
542 _cleanup_free_ struct ether_addr *mac = NULL;
551 mac = new0(struct ether_addr, 1);
556 sz = sizeof(sd_id128_t) + l;
559 /* fetch some persistent data unique to the machine */
560 r = sd_id128_get_machine((sd_id128_t*) v);
564 /* combine with some data unique (on this machine) to this
566 memcpy(v + sizeof(sd_id128_t), ifname, l);
568 /* Let's hash the host machine ID plus the container name. We
569 * use a fixed, but originally randomly created hash key here. */
570 siphash24(result, v, sz, HASH_KEY.bytes);
572 assert_cc(ETH_ALEN <= sizeof(result));
573 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
575 /* see eth_random_addr in the kernel */
576 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
577 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
585 static int netdev_load_one(Manager *manager, const char *filename) {
586 _cleanup_netdev_unref_ NetDev *netdev = NULL;
587 _cleanup_fclose_ FILE *file = NULL;
593 if (null_or_empty_path(filename)) {
594 log_debug("skipping empty file: %s", filename);
598 file = fopen(filename, "re");
606 netdev = new0(NetDev, 1);
611 netdev->manager = manager;
612 netdev->state = _NETDEV_STATE_INVALID;
613 netdev->kind = _NETDEV_KIND_INVALID;
614 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
615 netdev->vlanid = VLANID_MAX + 1;
616 netdev->vxlanid = VXLAN_VID_MAX + 1;
617 netdev->tunnel_pmtudisc = true;
618 netdev->learning = true;
620 r = config_parse(NULL, filename, file,
621 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
622 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
623 false, false, netdev);
625 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
629 if (netdev->kind == _NETDEV_KIND_INVALID) {
630 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
634 if (!netdev->ifname) {
635 log_warning("NetDev without Name configured in %s. Ignoring", filename);
639 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
640 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
644 if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
645 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
649 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
650 log_warning("VLAN Id configured for a %s in %s. Ignoring",
651 netdev_kind_to_string(netdev->kind), filename);
655 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vlanid <= VXLAN_VID_MAX) {
656 log_warning("VLAN Id configured for a %s in %s. Ignoring",
657 netdev_kind_to_string(netdev->kind), filename);
661 if (netdev->kind != NETDEV_KIND_MACVLAN &&
662 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
663 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
664 netdev_kind_to_string(netdev->kind), filename);
668 netdev->filename = strdup(filename);
669 if (!netdev->filename)
672 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
673 netdev->match_host, netdev->match_virt,
674 netdev->match_kernel, netdev->match_arch,
675 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
679 r = netdev_get_mac(netdev->ifname, &netdev->mac);
681 log_error("Failed to generate predictable MAC address for %s",
687 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
691 LIST_HEAD_INIT(netdev->callbacks);
693 if(netdev->kind == NETDEV_KIND_VETH) {
694 if (netdev->ifname_peer) {
695 log_warning("Veth NetDev without Peer Name configured "
696 "in %s. Ignoring", filename);
701 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
703 log_error("Failed to generate predictable MAC address for %s",
704 netdev->ifname_peer);
709 return netdev_create_veth(netdev, netdev_create_handler);
712 if (netdev->kind != NETDEV_KIND_VLAN &&
713 netdev->kind != NETDEV_KIND_MACVLAN &&
714 netdev->kind != NETDEV_KIND_VXLAN &&
715 netdev->kind != NETDEV_KIND_IPIP &&
716 netdev->kind != NETDEV_KIND_GRE &&
717 netdev->kind != NETDEV_KIND_SIT &&
718 netdev->kind != NETDEV_KIND_VTI) {
719 r = netdev_create(netdev, NULL, NULL);
724 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
731 int netdev_load(Manager *manager) {
738 while ((netdev = hashmap_first(manager->netdevs)))
739 netdev_unref(netdev);
741 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
743 log_error("Failed to enumerate netdev files: %s", strerror(-r));
747 STRV_FOREACH_BACKWARDS(f, files) {
748 r = netdev_load_one(manager, *f);