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_IPIP] = "ipip",
40 [NETDEV_KIND_GRE] = "gre",
41 [NETDEV_KIND_SIT] = "sit",
42 [NETDEV_KIND_VETH] = "veth",
43 [NETDEV_KIND_VTI] = "vti"
46 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
47 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
49 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
50 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
51 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
52 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
53 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
56 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
57 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
59 static void netdev_cancel_callbacks(NetDev *netdev) {
60 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
61 netdev_enslave_callback *callback;
66 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
68 while ((callback = netdev->callbacks)) {
70 assert(callback->link);
71 assert(callback->callback);
72 assert(netdev->manager);
73 assert(netdev->manager->rtnl);
75 callback->callback(netdev->manager->rtnl, m, link);
78 LIST_REMOVE(callbacks, netdev->callbacks, callback);
83 static void netdev_free(NetDev *netdev) {
87 netdev_cancel_callbacks(netdev);
90 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
92 free(netdev->filename);
94 free(netdev->description);
97 free(netdev->mac_peer);
99 condition_free_list(netdev->match_host);
100 condition_free_list(netdev->match_virt);
101 condition_free_list(netdev->match_kernel);
102 condition_free_list(netdev->match_arch);
107 NetDev *netdev_unref(NetDev *netdev) {
108 if (netdev && (-- netdev->n_ref <= 0))
114 NetDev *netdev_ref(NetDev *netdev) {
116 assert_se(++ netdev->n_ref >= 2);
121 void netdev_drop(NetDev *netdev) {
122 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
125 netdev->state = NETDEV_STATE_LINGER;
127 log_debug_netdev(netdev, "netdev removed");
129 netdev_cancel_callbacks(netdev);
131 netdev_unref(netdev);
136 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
143 netdev = hashmap_get(manager->netdevs, name);
154 static int netdev_enter_failed(NetDev *netdev) {
155 netdev->state = NETDEV_STATE_FAILED;
160 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
161 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
165 assert(netdev->state == NETDEV_STATE_READY);
166 assert(netdev->manager);
167 assert(netdev->manager->rtnl);
171 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
172 RTM_SETLINK, link->ifindex);
174 log_error_netdev(netdev,
175 "Could not allocate RTM_SETLINK message: %s",
180 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
182 log_error_netdev(netdev,
183 "Could not append IFLA_MASTER attribute: %s",
188 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
190 log_error_netdev(netdev,
191 "Could not send rtnetlink message: %s",
196 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
201 static int netdev_enter_ready(NetDev *netdev) {
202 netdev_enslave_callback *callback;
205 assert(netdev->ifname);
207 if (netdev->state != NETDEV_STATE_CREATING)
210 netdev->state = NETDEV_STATE_READY;
212 log_info_netdev(netdev, "netdev ready");
214 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
215 /* enslave the links that were attempted to be enslaved before the
217 netdev_enslave_ready(netdev, callback->link, callback->callback);
222 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
223 NetDev *netdev = userdata;
226 assert(netdev->state != _NETDEV_STATE_INVALID);
228 r = sd_rtnl_message_get_errno(m);
230 log_debug_netdev(netdev, "netdev exists, using existing");
232 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
241 int config_parse_tunnel_address(const char *unit,
242 const char *filename,
245 unsigned section_line,
252 unsigned char family = AF_INET;
260 r = net_parse_inaddr(rvalue, &family, n);
262 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
263 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
269 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
270 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
275 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
277 assert(netdev->ifname);
278 assert(netdev->manager);
279 assert(netdev->manager->rtnl);
281 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
283 log_error_netdev(netdev,
284 "Could not allocate RTM_NEWLINK message: %s",
290 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
292 log_error_netdev(netdev,
293 "Could not append IFLA_LINK attribute: %s",
299 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
301 log_error_netdev(netdev,
302 "Could not append IFLA_IFNAME attribute: %s",
308 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
310 log_error_netdev(netdev,
311 "Could not append IFLA_MTU attribute: %s",
318 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
320 log_error_netdev(netdev,
321 "Colud not append IFLA_ADDRESS attribute: %s",
327 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
329 log_error_netdev(netdev,
330 "Could not open IFLA_LINKINFO container: %s",
335 kind = netdev_kind_to_string(netdev->kind);
337 log_error_netdev(netdev, "Invalid kind");
341 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
343 log_error_netdev(netdev,
344 "Could not open IFLA_INFO_DATA container: %s",
349 if (netdev->vlanid <= VLANID_MAX) {
350 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
352 log_error_netdev(netdev,
353 "Could not append IFLA_VLAN_ID attribute: %s",
359 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
360 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
362 log_error_netdev(netdev,
363 "Could not append IFLA_MACVLAN_MODE attribute: %s",
369 r = sd_rtnl_message_close_container(req);
371 log_error_netdev(netdev,
372 "Could not close IFLA_INFO_DATA container %s",
377 r = sd_rtnl_message_close_container(req);
379 log_error_netdev(netdev,
380 "Could not close IFLA_LINKINFO container %s",
386 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
388 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
390 log_error_netdev(netdev,
391 "Could not send rtnetlink message: %s", strerror(-r));
395 log_debug_netdev(netdev, "creating netdev");
397 netdev->state = NETDEV_STATE_CREATING;
402 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
405 if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
406 return netdev_create(netdev, link, callback);
408 if(netdev->kind == NETDEV_KIND_IPIP ||
409 netdev->kind == NETDEV_KIND_GRE ||
410 netdev->kind == NETDEV_KIND_SIT ||
411 netdev->kind == NETDEV_KIND_VTI)
412 return netdev_create_tunnel(link, netdev_create_handler);
414 if (netdev->state == NETDEV_STATE_READY) {
415 r = netdev_enslave_ready(netdev, link, callback);
419 /* the netdev is not yet read, save this request for when it is*/
420 netdev_enslave_callback *cb;
422 cb = new0(netdev_enslave_callback, 1);
426 cb->callback = callback;
429 LIST_PREPEND(callbacks, netdev->callbacks, cb);
435 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
445 r = sd_rtnl_message_get_type(message, &type);
447 log_error_netdev(netdev, "Could not get rtnl message type");
451 if (type != RTM_NEWLINK) {
452 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
456 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
458 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
459 netdev_enter_failed(netdev);
461 } else if (ifindex <= 0) {
462 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
463 netdev_enter_failed(netdev);
467 if (netdev->ifindex > 0) {
468 if (netdev->ifindex != ifindex) {
469 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
470 ifindex, netdev->ifindex);
471 netdev_enter_failed(netdev);
474 /* ifindex already set to the same for this netdev */
478 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
480 log_error_netdev(netdev, "Could not get IFNAME");
484 if (!streq(netdev->ifname, received_name)) {
485 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
487 netdev_enter_failed(netdev);
491 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
493 log_error_netdev(netdev, "Could not get LINKINFO");
497 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
499 log_error_netdev(netdev, "Could not get KIND");
503 r = sd_rtnl_message_exit_container(message);
505 log_error_netdev(netdev, "Could not exit container");
509 kind = netdev_kind_to_string(netdev->kind);
511 log_error_netdev(netdev, "Could not get kind");
512 netdev_enter_failed(netdev);
516 if (!streq(kind, received_kind)) {
517 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
518 "expected %s", received_kind, kind);
519 netdev_enter_failed(netdev);
523 netdev->ifindex = ifindex;
525 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
527 netdev_enter_ready(netdev);
532 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
534 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
535 _cleanup_free_ struct ether_addr *mac = NULL;
544 mac = new0(struct ether_addr, 1);
549 sz = sizeof(sd_id128_t) + l;
552 /* fetch some persistent data unique to the machine */
553 r = sd_id128_get_machine((sd_id128_t*) v);
557 /* combine with some data unique (on this machine) to this
559 memcpy(v + sizeof(sd_id128_t), ifname, l);
561 /* Let's hash the host machine ID plus the container name. We
562 * use a fixed, but originally randomly created hash key here. */
563 siphash24(result, v, sz, HASH_KEY.bytes);
565 assert_cc(ETH_ALEN <= sizeof(result));
566 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
568 /* see eth_random_addr in the kernel */
569 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
570 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
578 static int netdev_load_one(Manager *manager, const char *filename) {
579 _cleanup_netdev_unref_ NetDev *netdev = NULL;
580 _cleanup_fclose_ FILE *file = NULL;
586 if (null_or_empty_path(filename)) {
587 log_debug("skipping empty file: %s", filename);
591 file = fopen(filename, "re");
599 netdev = new0(NetDev, 1);
604 netdev->manager = manager;
605 netdev->state = _NETDEV_STATE_INVALID;
606 netdev->kind = _NETDEV_KIND_INVALID;
607 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
608 netdev->vlanid = VLANID_MAX + 1;
609 netdev->tunnel_pmtudisc = true;
611 r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0Peer\0",
612 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
613 false, false, netdev);
615 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
619 if (netdev->kind == _NETDEV_KIND_INVALID) {
620 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
624 if (!netdev->ifname) {
625 log_warning("NetDev without Name configured in %s. Ignoring", filename);
629 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
630 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
634 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
635 log_warning("VLAN Id configured for a %s in %s. Ignoring",
636 netdev_kind_to_string(netdev->kind), filename);
640 if (netdev->kind != NETDEV_KIND_MACVLAN &&
641 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
642 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
643 netdev_kind_to_string(netdev->kind), filename);
647 netdev->filename = strdup(filename);
648 if (!netdev->filename)
651 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
652 netdev->match_host, netdev->match_virt,
653 netdev->match_kernel, netdev->match_arch,
654 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
658 r = netdev_get_mac(netdev->ifname, &netdev->mac);
660 log_error("Failed to generate predictable MAC address for %s",
666 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
670 LIST_HEAD_INIT(netdev->callbacks);
672 if(netdev->kind == NETDEV_KIND_VETH) {
673 if (netdev->ifname_peer) {
674 log_warning("Veth NetDev without Peer Name configured "
675 "in %s. Ignoring", filename);
680 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
682 log_error("Failed to generate predictable MAC address for %s",
683 netdev->ifname_peer);
688 return netdev_create_veth(netdev, netdev_create_handler);
691 if (netdev->kind != NETDEV_KIND_VLAN &&
692 netdev->kind != NETDEV_KIND_MACVLAN &&
693 netdev->kind != NETDEV_KIND_IPIP &&
694 netdev->kind != NETDEV_KIND_GRE &&
695 netdev->kind != NETDEV_KIND_SIT &&
696 netdev->kind != NETDEV_KIND_VTI) {
697 r = netdev_create(netdev, NULL, NULL);
702 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
709 int netdev_load(Manager *manager) {
716 while ((netdev = hashmap_first(manager->netdevs)))
717 netdev_unref(netdev);
719 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
721 log_error("Failed to enumerate netdev files: %s", strerror(-r));
725 STRV_FOREACH_BACKWARDS(f, files) {
726 r = netdev_load_one(manager, *f);