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);
97 free(netdev->ifname_peer);
99 free(netdev->mac_peer);
101 condition_free_list(netdev->match_host);
102 condition_free_list(netdev->match_virt);
103 condition_free_list(netdev->match_kernel);
104 condition_free_list(netdev->match_arch);
109 NetDev *netdev_unref(NetDev *netdev) {
110 if (netdev && (-- netdev->n_ref <= 0))
116 NetDev *netdev_ref(NetDev *netdev) {
118 assert_se(++ netdev->n_ref >= 2);
123 void netdev_drop(NetDev *netdev) {
124 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
127 netdev->state = NETDEV_STATE_LINGER;
129 log_debug_netdev(netdev, "netdev removed");
131 netdev_cancel_callbacks(netdev);
133 netdev_unref(netdev);
138 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
145 netdev = hashmap_get(manager->netdevs, name);
156 static int netdev_enter_failed(NetDev *netdev) {
157 netdev->state = NETDEV_STATE_FAILED;
162 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
163 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
167 assert(netdev->state == NETDEV_STATE_READY);
168 assert(netdev->manager);
169 assert(netdev->manager->rtnl);
173 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
174 RTM_SETLINK, link->ifindex);
176 log_error_netdev(netdev,
177 "Could not allocate RTM_SETLINK message: %s",
182 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
184 log_error_netdev(netdev,
185 "Could not append IFLA_MASTER attribute: %s",
190 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
192 log_error_netdev(netdev,
193 "Could not send rtnetlink message: %s",
198 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
203 static int netdev_enter_ready(NetDev *netdev) {
204 netdev_enslave_callback *callback;
207 assert(netdev->ifname);
209 if (netdev->state != NETDEV_STATE_CREATING)
212 netdev->state = NETDEV_STATE_READY;
214 log_info_netdev(netdev, "netdev ready");
216 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
217 /* enslave the links that were attempted to be enslaved before the
219 netdev_enslave_ready(netdev, callback->link, callback->callback);
224 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
225 NetDev *netdev = userdata;
228 assert(netdev->state != _NETDEV_STATE_INVALID);
230 r = sd_rtnl_message_get_errno(m);
232 log_debug_netdev(netdev, "netdev exists, using existing");
234 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
243 int config_parse_tunnel_address(const char *unit,
244 const char *filename,
247 unsigned section_line,
254 unsigned char family = AF_INET;
262 r = net_parse_inaddr(rvalue, &family, n);
264 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
265 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
271 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
272 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
277 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
279 assert(netdev->ifname);
280 assert(netdev->manager);
281 assert(netdev->manager->rtnl);
283 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
285 log_error_netdev(netdev,
286 "Could not allocate RTM_NEWLINK message: %s",
292 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
294 log_error_netdev(netdev,
295 "Could not append IFLA_LINK attribute: %s",
301 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
303 log_error_netdev(netdev,
304 "Could not append IFLA_IFNAME attribute: %s",
310 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
312 log_error_netdev(netdev,
313 "Could not append IFLA_MTU attribute: %s",
320 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
322 log_error_netdev(netdev,
323 "Colud not append IFLA_ADDRESS attribute: %s",
329 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
331 log_error_netdev(netdev,
332 "Could not open IFLA_LINKINFO container: %s",
337 kind = netdev_kind_to_string(netdev->kind);
339 log_error_netdev(netdev, "Invalid kind");
343 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
345 log_error_netdev(netdev,
346 "Could not open IFLA_INFO_DATA container: %s",
351 if (netdev->vlanid <= VLANID_MAX) {
352 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
354 log_error_netdev(netdev,
355 "Could not append IFLA_VLAN_ID attribute: %s",
361 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
362 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
364 log_error_netdev(netdev,
365 "Could not append IFLA_MACVLAN_MODE attribute: %s",
371 r = sd_rtnl_message_close_container(req);
373 log_error_netdev(netdev,
374 "Could not close IFLA_INFO_DATA container %s",
379 r = sd_rtnl_message_close_container(req);
381 log_error_netdev(netdev,
382 "Could not close IFLA_LINKINFO container %s",
388 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
390 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
392 log_error_netdev(netdev,
393 "Could not send rtnetlink message: %s", strerror(-r));
397 log_debug_netdev(netdev, "creating netdev");
399 netdev->state = NETDEV_STATE_CREATING;
404 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
407 switch(netdev->kind) {
408 case NETDEV_KIND_VLAN:
409 case NETDEV_KIND_MACVLAN:
410 return netdev_create(netdev, link, callback);
411 case NETDEV_KIND_VXLAN:
412 return netdev_create_vxlan(netdev, link, callback);
413 case NETDEV_KIND_IPIP:
414 case NETDEV_KIND_GRE:
415 case NETDEV_KIND_SIT:
416 case NETDEV_KIND_VTI:
417 return netdev_create_tunnel(link, netdev_create_handler);
422 if (netdev->state == NETDEV_STATE_READY) {
423 r = netdev_enslave_ready(netdev, link, callback);
427 /* the netdev is not yet read, save this request for when it is*/
428 netdev_enslave_callback *cb;
430 cb = new0(netdev_enslave_callback, 1);
434 cb->callback = callback;
437 LIST_PREPEND(callbacks, netdev->callbacks, cb);
443 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
453 r = sd_rtnl_message_get_type(message, &type);
455 log_error_netdev(netdev, "Could not get rtnl message type");
459 if (type != RTM_NEWLINK) {
460 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
464 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
466 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
467 netdev_enter_failed(netdev);
469 } else if (ifindex <= 0) {
470 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
471 netdev_enter_failed(netdev);
475 if (netdev->ifindex > 0) {
476 if (netdev->ifindex != ifindex) {
477 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
478 ifindex, netdev->ifindex);
479 netdev_enter_failed(netdev);
482 /* ifindex already set to the same for this netdev */
486 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
488 log_error_netdev(netdev, "Could not get IFNAME");
492 if (!streq(netdev->ifname, received_name)) {
493 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
495 netdev_enter_failed(netdev);
499 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
501 log_error_netdev(netdev, "Could not get LINKINFO");
505 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
507 log_error_netdev(netdev, "Could not get KIND");
511 r = sd_rtnl_message_exit_container(message);
513 log_error_netdev(netdev, "Could not exit container");
517 kind = netdev_kind_to_string(netdev->kind);
519 log_error_netdev(netdev, "Could not get kind");
520 netdev_enter_failed(netdev);
524 if (!streq(kind, received_kind)) {
525 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
526 "expected %s", received_kind, kind);
527 netdev_enter_failed(netdev);
531 netdev->ifindex = ifindex;
533 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
535 netdev_enter_ready(netdev);
540 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
542 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
543 _cleanup_free_ struct ether_addr *mac = NULL;
552 mac = new0(struct ether_addr, 1);
557 sz = sizeof(sd_id128_t) + l;
560 /* fetch some persistent data unique to the machine */
561 r = sd_id128_get_machine((sd_id128_t*) v);
565 /* combine with some data unique (on this machine) to this
567 memcpy(v + sizeof(sd_id128_t), ifname, l);
569 /* Let's hash the host machine ID plus the container name. We
570 * use a fixed, but originally randomly created hash key here. */
571 siphash24(result, v, sz, HASH_KEY.bytes);
573 assert_cc(ETH_ALEN <= sizeof(result));
574 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
576 /* see eth_random_addr in the kernel */
577 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
578 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
586 static int netdev_load_one(Manager *manager, const char *filename) {
587 _cleanup_netdev_unref_ NetDev *netdev = NULL;
588 _cleanup_fclose_ FILE *file = NULL;
594 if (null_or_empty_path(filename)) {
595 log_debug("skipping empty file: %s", filename);
599 file = fopen(filename, "re");
607 netdev = new0(NetDev, 1);
612 netdev->manager = manager;
613 netdev->state = _NETDEV_STATE_INVALID;
614 netdev->kind = _NETDEV_KIND_INVALID;
615 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
616 netdev->vlanid = VLANID_MAX + 1;
617 netdev->vxlanid = VXLAN_VID_MAX + 1;
618 netdev->tunnel_pmtudisc = true;
619 netdev->learning = true;
621 r = config_parse(NULL, filename, file,
622 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
623 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
624 false, false, netdev);
626 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
630 if (netdev->kind == _NETDEV_KIND_INVALID) {
631 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
635 if (!netdev->ifname) {
636 log_warning("NetDev without Name configured in %s. Ignoring", filename);
640 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
641 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
645 if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
646 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
650 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
651 log_warning("VLAN Id configured for a %s in %s. Ignoring",
652 netdev_kind_to_string(netdev->kind), filename);
656 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
657 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
658 netdev_kind_to_string(netdev->kind), filename);
662 if (netdev->kind != NETDEV_KIND_MACVLAN &&
663 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
664 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
665 netdev_kind_to_string(netdev->kind), filename);
669 netdev->filename = strdup(filename);
670 if (!netdev->filename)
673 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
674 netdev->match_host, netdev->match_virt,
675 netdev->match_kernel, netdev->match_arch,
676 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
680 r = netdev_get_mac(netdev->ifname, &netdev->mac);
682 log_error("Failed to generate predictable MAC address for %s",
688 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
692 LIST_HEAD_INIT(netdev->callbacks);
694 switch (netdev->kind) {
695 case NETDEV_KIND_VETH:
696 if (!netdev->ifname_peer) {
697 log_warning("Veth NetDev without peer name configured "
698 "in %s. Ignoring", filename);
703 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
705 log_error("Failed to generate predictable MAC address for %s",
706 netdev->ifname_peer);
711 r = netdev_create_veth(netdev, netdev_create_handler);
716 case NETDEV_KIND_BRIDGE:
717 case NETDEV_KIND_BOND:
718 r = netdev_create(netdev, NULL, NULL);
726 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
733 int netdev_load(Manager *manager) {
740 while ((netdev = hashmap_first(manager->netdevs)))
741 netdev_unref(netdev);
743 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
745 log_error("Failed to enumerate netdev files: %s", strerror(-r));
749 STRV_FOREACH_BACKWARDS(f, files) {
750 r = netdev_load_one(manager, *f);