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);
225 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
226 NetDev *netdev = userdata;
229 assert(netdev->state != _NETDEV_STATE_INVALID);
231 r = sd_rtnl_message_get_errno(m);
233 log_debug_netdev(netdev, "netdev exists, using existing");
235 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
244 int config_parse_tunnel_address(const char *unit,
245 const char *filename,
248 unsigned section_line,
255 unsigned char family = AF_INET;
263 r = net_parse_inaddr(rvalue, &family, n);
265 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
266 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
272 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
273 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
278 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
280 assert(netdev->ifname);
281 assert(netdev->manager);
282 assert(netdev->manager->rtnl);
284 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
286 log_error_netdev(netdev,
287 "Could not allocate RTM_NEWLINK message: %s",
293 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
295 log_error_netdev(netdev,
296 "Could not append IFLA_LINK attribute: %s",
302 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
304 log_error_netdev(netdev,
305 "Could not append IFLA_IFNAME attribute: %s",
311 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
313 log_error_netdev(netdev,
314 "Could not append IFLA_MTU attribute: %s",
321 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
323 log_error_netdev(netdev,
324 "Colud not append IFLA_ADDRESS attribute: %s",
330 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
332 log_error_netdev(netdev,
333 "Could not open IFLA_LINKINFO container: %s",
338 kind = netdev_kind_to_string(netdev->kind);
340 log_error_netdev(netdev, "Invalid kind");
344 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
346 log_error_netdev(netdev,
347 "Could not open IFLA_INFO_DATA container: %s",
352 if (netdev->vlanid <= VLANID_MAX) {
353 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
355 log_error_netdev(netdev,
356 "Could not append IFLA_VLAN_ID attribute: %s",
362 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
363 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
365 log_error_netdev(netdev,
366 "Could not append IFLA_MACVLAN_MODE attribute: %s",
372 r = sd_rtnl_message_close_container(req);
374 log_error_netdev(netdev,
375 "Could not close IFLA_INFO_DATA container %s",
380 r = sd_rtnl_message_close_container(req);
382 log_error_netdev(netdev,
383 "Could not close IFLA_LINKINFO container %s",
389 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
391 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
393 log_error_netdev(netdev,
394 "Could not send rtnetlink message: %s", strerror(-r));
398 log_debug_netdev(netdev, "creating netdev");
400 netdev->state = NETDEV_STATE_CREATING;
405 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
408 switch(netdev->kind) {
409 case NETDEV_KIND_VLAN:
410 case NETDEV_KIND_MACVLAN:
411 return netdev_create(netdev, link, callback);
412 case NETDEV_KIND_VXLAN:
413 return netdev_create_vxlan(netdev, link, callback);
414 case NETDEV_KIND_IPIP:
415 case NETDEV_KIND_GRE:
416 case NETDEV_KIND_SIT:
417 case NETDEV_KIND_VTI:
418 return netdev_create_tunnel(link, netdev_create_handler);
423 if (netdev->state == NETDEV_STATE_READY) {
424 r = netdev_enslave_ready(netdev, link, callback);
428 /* the netdev is not yet read, save this request for when it is*/
429 netdev_enslave_callback *cb;
431 cb = new0(netdev_enslave_callback, 1);
435 cb->callback = callback;
438 LIST_PREPEND(callbacks, netdev->callbacks, cb);
444 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
454 r = sd_rtnl_message_get_type(message, &type);
456 log_error_netdev(netdev, "Could not get rtnl message type");
460 if (type != RTM_NEWLINK) {
461 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
465 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
467 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
468 netdev_enter_failed(netdev);
470 } else if (ifindex <= 0) {
471 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
472 netdev_enter_failed(netdev);
476 if (netdev->ifindex > 0) {
477 if (netdev->ifindex != ifindex) {
478 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
479 ifindex, netdev->ifindex);
480 netdev_enter_failed(netdev);
483 /* ifindex already set to the same for this netdev */
487 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
489 log_error_netdev(netdev, "Could not get IFNAME");
493 if (!streq(netdev->ifname, received_name)) {
494 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
496 netdev_enter_failed(netdev);
500 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
502 log_error_netdev(netdev, "Could not get LINKINFO");
506 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
508 log_error_netdev(netdev, "Could not get KIND");
512 r = sd_rtnl_message_exit_container(message);
514 log_error_netdev(netdev, "Could not exit container");
518 kind = netdev_kind_to_string(netdev->kind);
520 log_error_netdev(netdev, "Could not get kind");
521 netdev_enter_failed(netdev);
525 if (!streq(kind, received_kind)) {
526 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
527 "expected %s", received_kind, kind);
528 netdev_enter_failed(netdev);
532 netdev->ifindex = ifindex;
534 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
536 netdev_enter_ready(netdev);
541 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
543 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
544 _cleanup_free_ struct ether_addr *mac = NULL;
553 mac = new0(struct ether_addr, 1);
558 sz = sizeof(sd_id128_t) + l;
561 /* fetch some persistent data unique to the machine */
562 r = sd_id128_get_machine((sd_id128_t*) v);
566 /* combine with some data unique (on this machine) to this
568 memcpy(v + sizeof(sd_id128_t), ifname, l);
570 /* Let's hash the host machine ID plus the container name. We
571 * use a fixed, but originally randomly created hash key here. */
572 siphash24(result, v, sz, HASH_KEY.bytes);
574 assert_cc(ETH_ALEN <= sizeof(result));
575 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
577 /* see eth_random_addr in the kernel */
578 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
579 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
587 static int netdev_load_one(Manager *manager, const char *filename) {
588 _cleanup_netdev_unref_ NetDev *netdev = NULL;
589 _cleanup_fclose_ FILE *file = NULL;
595 if (null_or_empty_path(filename)) {
596 log_debug("skipping empty file: %s", filename);
600 file = fopen(filename, "re");
608 netdev = new0(NetDev, 1);
613 netdev->manager = manager;
614 netdev->state = _NETDEV_STATE_INVALID;
615 netdev->kind = _NETDEV_KIND_INVALID;
616 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
617 netdev->vlanid = VLANID_MAX + 1;
618 netdev->vxlanid = VXLAN_VID_MAX + 1;
619 netdev->tunnel_pmtudisc = true;
620 netdev->learning = true;
622 r = config_parse(NULL, filename, file,
623 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
624 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
625 false, false, netdev);
627 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
631 if (netdev->kind == _NETDEV_KIND_INVALID) {
632 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
636 if (!netdev->ifname) {
637 log_warning("NetDev without Name configured in %s. Ignoring", filename);
641 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
642 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
646 if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
647 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
651 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
652 log_warning("VLAN Id configured for a %s in %s. Ignoring",
653 netdev_kind_to_string(netdev->kind), filename);
657 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
658 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
659 netdev_kind_to_string(netdev->kind), filename);
663 if (netdev->kind != NETDEV_KIND_MACVLAN &&
664 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
665 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
666 netdev_kind_to_string(netdev->kind), filename);
670 netdev->filename = strdup(filename);
671 if (!netdev->filename)
674 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
675 netdev->match_host, netdev->match_virt,
676 netdev->match_kernel, netdev->match_arch,
677 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
681 r = netdev_get_mac(netdev->ifname, &netdev->mac);
683 log_error("Failed to generate predictable MAC address for %s",
689 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
693 LIST_HEAD_INIT(netdev->callbacks);
695 switch (netdev->kind) {
696 case NETDEV_KIND_VETH:
697 if (!netdev->ifname_peer) {
698 log_warning("Veth NetDev without peer name configured "
699 "in %s. Ignoring", filename);
704 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
706 log_error("Failed to generate predictable MAC address for %s",
707 netdev->ifname_peer);
712 r = netdev_create_veth(netdev, netdev_create_handler);
717 case NETDEV_KIND_BRIDGE:
718 case NETDEV_KIND_BOND:
719 r = netdev_create(netdev, NULL, NULL);
727 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
734 int netdev_load(Manager *manager) {
741 while ((netdev = hashmap_first(manager->netdevs)))
742 netdev_unref(netdev);
744 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
746 log_error("Failed to enumerate netdev files: %s", strerror(-r));
750 STRV_FOREACH_BACKWARDS(f, files) {
751 r = netdev_load_one(manager, *f);