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",
45 [NETDEV_KIND_DUMMY] = "dummy",
48 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
49 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
51 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
52 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
53 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
54 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
55 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
58 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
59 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
61 static void netdev_cancel_callbacks(NetDev *netdev) {
62 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
63 netdev_enslave_callback *callback;
68 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
70 while ((callback = netdev->callbacks)) {
72 assert(callback->link);
73 assert(callback->callback);
74 assert(netdev->manager);
75 assert(netdev->manager->rtnl);
77 callback->callback(netdev->manager->rtnl, m, link);
80 LIST_REMOVE(callbacks, netdev->callbacks, callback);
85 static void netdev_free(NetDev *netdev) {
89 netdev_cancel_callbacks(netdev);
92 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
94 free(netdev->filename);
96 free(netdev->description);
98 free(netdev->ifname_peer);
100 free(netdev->mac_peer);
102 condition_free_list(netdev->match_host);
103 condition_free_list(netdev->match_virt);
104 condition_free_list(netdev->match_kernel);
105 condition_free_list(netdev->match_arch);
110 NetDev *netdev_unref(NetDev *netdev) {
111 if (netdev && (-- netdev->n_ref <= 0))
117 NetDev *netdev_ref(NetDev *netdev) {
119 assert_se(++ netdev->n_ref >= 2);
124 void netdev_drop(NetDev *netdev) {
125 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
128 netdev->state = NETDEV_STATE_LINGER;
130 log_debug_netdev(netdev, "netdev removed");
132 netdev_cancel_callbacks(netdev);
134 netdev_unref(netdev);
139 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
146 netdev = hashmap_get(manager->netdevs, name);
157 static int netdev_enter_failed(NetDev *netdev) {
158 netdev->state = NETDEV_STATE_FAILED;
163 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
164 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
168 assert(netdev->state == NETDEV_STATE_READY);
169 assert(netdev->manager);
170 assert(netdev->manager->rtnl);
174 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
175 RTM_SETLINK, link->ifindex);
177 log_error_netdev(netdev,
178 "Could not allocate RTM_SETLINK message: %s",
183 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
185 log_error_netdev(netdev,
186 "Could not append IFLA_MASTER attribute: %s",
191 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
193 log_error_netdev(netdev,
194 "Could not send rtnetlink message: %s",
199 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
204 static int netdev_enter_ready(NetDev *netdev) {
205 netdev_enslave_callback *callback;
208 assert(netdev->ifname);
210 if (netdev->state != NETDEV_STATE_CREATING)
213 netdev->state = NETDEV_STATE_READY;
215 log_info_netdev(netdev, "netdev ready");
217 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
218 /* enslave the links that were attempted to be enslaved before the
220 netdev_enslave_ready(netdev, callback->link, callback->callback);
226 /* callback for netdev's created without a backing Link */
227 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
228 _cleanup_netdev_unref_ NetDev *netdev = userdata;
231 assert(netdev->state != _NETDEV_STATE_INVALID);
233 r = sd_rtnl_message_get_errno(m);
235 log_debug_netdev(netdev, "netdev exists, using existing");
237 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
246 int config_parse_tunnel_address(const char *unit,
247 const char *filename,
250 unsigned section_line,
257 unsigned char family = AF_INET;
265 r = net_parse_inaddr(rvalue, &family, n);
267 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
268 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
274 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
275 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
280 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
282 assert(netdev->ifname);
283 assert(netdev->manager);
284 assert(netdev->manager->rtnl);
286 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
288 log_error_netdev(netdev,
289 "Could not allocate RTM_NEWLINK message: %s",
295 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
297 log_error_netdev(netdev,
298 "Could not append IFLA_LINK attribute: %s",
304 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
306 log_error_netdev(netdev,
307 "Could not append IFLA_IFNAME attribute: %s",
313 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
315 log_error_netdev(netdev,
316 "Could not append IFLA_MTU attribute: %s",
323 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
325 log_error_netdev(netdev,
326 "Colud not append IFLA_ADDRESS attribute: %s",
332 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
334 log_error_netdev(netdev,
335 "Could not open IFLA_LINKINFO container: %s",
340 kind = netdev_kind_to_string(netdev->kind);
342 log_error_netdev(netdev, "Invalid kind");
346 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
348 log_error_netdev(netdev,
349 "Could not open IFLA_INFO_DATA container: %s",
354 if (netdev->vlanid <= VLANID_MAX) {
355 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
357 log_error_netdev(netdev,
358 "Could not append IFLA_VLAN_ID attribute: %s",
364 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
365 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
367 log_error_netdev(netdev,
368 "Could not append IFLA_MACVLAN_MODE attribute: %s",
374 r = sd_rtnl_message_close_container(req);
376 log_error_netdev(netdev,
377 "Could not close IFLA_INFO_DATA container %s",
382 r = sd_rtnl_message_close_container(req);
384 log_error_netdev(netdev,
385 "Could not close IFLA_LINKINFO container %s",
391 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
393 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
397 log_error_netdev(netdev,
398 "Could not send rtnetlink message: %s", strerror(-r));
402 log_debug_netdev(netdev, "creating netdev");
404 netdev->state = NETDEV_STATE_CREATING;
409 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
410 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
413 switch(netdev->kind) {
414 case NETDEV_KIND_VLAN:
415 case NETDEV_KIND_MACVLAN:
416 return netdev_create(netdev, link, callback);
417 case NETDEV_KIND_VXLAN:
418 return netdev_create_vxlan(netdev, link, callback);
419 case NETDEV_KIND_IPIP:
420 case NETDEV_KIND_GRE:
421 case NETDEV_KIND_SIT:
422 case NETDEV_KIND_VTI:
423 return netdev_create_tunnel(netdev, link, callback);
428 if (netdev->state == NETDEV_STATE_READY) {
429 r = netdev_enslave_ready(netdev, link, callback);
433 /* the netdev is not yet read, save this request for when it is*/
434 netdev_enslave_callback *cb;
436 cb = new0(netdev_enslave_callback, 1);
440 cb->callback = callback;
443 LIST_PREPEND(callbacks, netdev->callbacks, cb);
449 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
459 r = sd_rtnl_message_get_type(message, &type);
461 log_error_netdev(netdev, "Could not get rtnl message type");
465 if (type != RTM_NEWLINK) {
466 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
470 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
472 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
473 netdev_enter_failed(netdev);
475 } else if (ifindex <= 0) {
476 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
477 netdev_enter_failed(netdev);
481 if (netdev->ifindex > 0) {
482 if (netdev->ifindex != ifindex) {
483 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
484 ifindex, netdev->ifindex);
485 netdev_enter_failed(netdev);
488 /* ifindex already set to the same for this netdev */
492 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
494 log_error_netdev(netdev, "Could not get IFNAME");
498 if (!streq(netdev->ifname, received_name)) {
499 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
501 netdev_enter_failed(netdev);
505 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
507 log_error_netdev(netdev, "Could not get LINKINFO");
511 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
513 log_error_netdev(netdev, "Could not get KIND");
517 r = sd_rtnl_message_exit_container(message);
519 log_error_netdev(netdev, "Could not exit container");
523 kind = netdev_kind_to_string(netdev->kind);
525 log_error_netdev(netdev, "Could not get kind");
526 netdev_enter_failed(netdev);
530 if (!streq(kind, received_kind)) {
531 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
532 "expected %s", received_kind, kind);
533 netdev_enter_failed(netdev);
537 netdev->ifindex = ifindex;
539 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
541 netdev_enter_ready(netdev);
546 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
548 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
549 _cleanup_free_ struct ether_addr *mac = NULL;
558 mac = new0(struct ether_addr, 1);
563 sz = sizeof(sd_id128_t) + l;
566 /* fetch some persistent data unique to the machine */
567 r = sd_id128_get_machine((sd_id128_t*) v);
571 /* combine with some data unique (on this machine) to this
573 memcpy(v + sizeof(sd_id128_t), ifname, l);
575 /* Let's hash the host machine ID plus the container name. We
576 * use a fixed, but originally randomly created hash key here. */
577 siphash24(result, v, sz, HASH_KEY.bytes);
579 assert_cc(ETH_ALEN <= sizeof(result));
580 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
582 /* see eth_random_addr in the kernel */
583 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
584 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
592 static int netdev_load_one(Manager *manager, const char *filename) {
593 _cleanup_netdev_unref_ NetDev *netdev = NULL;
594 _cleanup_fclose_ FILE *file = NULL;
600 if (null_or_empty_path(filename)) {
601 log_debug("skipping empty file: %s", filename);
605 file = fopen(filename, "re");
613 netdev = new0(NetDev, 1);
618 netdev->manager = manager;
619 netdev->state = _NETDEV_STATE_INVALID;
620 netdev->kind = _NETDEV_KIND_INVALID;
621 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
622 netdev->vlanid = VLANID_MAX + 1;
623 netdev->vxlanid = VXLAN_VID_MAX + 1;
624 netdev->tunnel_pmtudisc = true;
625 netdev->learning = true;
627 r = config_parse(NULL, filename, file,
628 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
629 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
630 false, false, netdev);
632 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
636 if (netdev->kind == _NETDEV_KIND_INVALID) {
637 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
641 if (!netdev->ifname) {
642 log_warning("NetDev without Name configured in %s. Ignoring", filename);
646 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
647 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
651 if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
652 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
656 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
657 log_warning("VLAN Id configured for a %s in %s. Ignoring",
658 netdev_kind_to_string(netdev->kind), filename);
662 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
663 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
664 netdev_kind_to_string(netdev->kind), filename);
668 if (netdev->kind != NETDEV_KIND_MACVLAN &&
669 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
670 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
671 netdev_kind_to_string(netdev->kind), filename);
675 netdev->filename = strdup(filename);
676 if (!netdev->filename)
679 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
680 netdev->match_host, netdev->match_virt,
681 netdev->match_kernel, netdev->match_arch,
682 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
686 r = netdev_get_mac(netdev->ifname, &netdev->mac);
688 log_error("Failed to generate predictable MAC address for %s",
694 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
698 LIST_HEAD_INIT(netdev->callbacks);
700 switch (netdev->kind) {
701 case NETDEV_KIND_VETH:
702 if (!netdev->ifname_peer) {
703 log_warning("Veth NetDev without peer name configured "
704 "in %s. Ignoring", filename);
709 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
711 log_error("Failed to generate predictable MAC address for %s",
712 netdev->ifname_peer);
717 r = netdev_create_veth(netdev, netdev_create_handler);
722 case NETDEV_KIND_DUMMY:
723 r = netdev_create_dummy(netdev, netdev_create_handler);
730 case NETDEV_KIND_BRIDGE:
731 case NETDEV_KIND_BOND:
732 r = netdev_create(netdev, NULL, NULL);
740 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
747 int netdev_load(Manager *manager) {
754 while ((netdev = hashmap_first(manager->netdevs)))
755 netdev_unref(netdev);
757 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
759 log_error("Failed to enumerate netdev files: %s", strerror(-r));
763 STRV_FOREACH_BACKWARDS(f, files) {
764 r = netdev_load_one(manager, *f);