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 /* callback for netdev's created without a backing Link */
226 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
227 _cleanup_netdev_unref_ NetDev *netdev = userdata;
230 assert(netdev->state != _NETDEV_STATE_INVALID);
232 r = sd_rtnl_message_get_errno(m);
234 log_debug_netdev(netdev, "netdev exists, using existing");
236 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
245 int config_parse_tunnel_address(const char *unit,
246 const char *filename,
249 unsigned section_line,
256 unsigned char family = AF_INET;
264 r = net_parse_inaddr(rvalue, &family, n);
266 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
267 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
273 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
274 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
279 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
281 assert(netdev->ifname);
282 assert(netdev->manager);
283 assert(netdev->manager->rtnl);
285 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
287 log_error_netdev(netdev,
288 "Could not allocate RTM_NEWLINK message: %s",
294 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
296 log_error_netdev(netdev,
297 "Could not append IFLA_LINK attribute: %s",
303 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
305 log_error_netdev(netdev,
306 "Could not append IFLA_IFNAME attribute: %s",
312 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
314 log_error_netdev(netdev,
315 "Could not append IFLA_MTU attribute: %s",
322 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
324 log_error_netdev(netdev,
325 "Colud not append IFLA_ADDRESS attribute: %s",
331 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
333 log_error_netdev(netdev,
334 "Could not open IFLA_LINKINFO container: %s",
339 kind = netdev_kind_to_string(netdev->kind);
341 log_error_netdev(netdev, "Invalid kind");
345 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
347 log_error_netdev(netdev,
348 "Could not open IFLA_INFO_DATA container: %s",
353 if (netdev->vlanid <= VLANID_MAX) {
354 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
356 log_error_netdev(netdev,
357 "Could not append IFLA_VLAN_ID attribute: %s",
363 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
364 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
366 log_error_netdev(netdev,
367 "Could not append IFLA_MACVLAN_MODE attribute: %s",
373 r = sd_rtnl_message_close_container(req);
375 log_error_netdev(netdev,
376 "Could not close IFLA_INFO_DATA container %s",
381 r = sd_rtnl_message_close_container(req);
383 log_error_netdev(netdev,
384 "Could not close IFLA_LINKINFO container %s",
390 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
392 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
396 log_error_netdev(netdev,
397 "Could not send rtnetlink message: %s", strerror(-r));
401 log_debug_netdev(netdev, "creating netdev");
403 netdev->state = NETDEV_STATE_CREATING;
408 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
409 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
412 switch(netdev->kind) {
413 case NETDEV_KIND_VLAN:
414 case NETDEV_KIND_MACVLAN:
415 return netdev_create(netdev, link, callback);
416 case NETDEV_KIND_VXLAN:
417 return netdev_create_vxlan(netdev, link, callback);
418 case NETDEV_KIND_IPIP:
419 case NETDEV_KIND_GRE:
420 case NETDEV_KIND_SIT:
421 case NETDEV_KIND_VTI:
422 return netdev_create_tunnel(netdev, link, callback);
427 if (netdev->state == NETDEV_STATE_READY) {
428 r = netdev_enslave_ready(netdev, link, callback);
432 /* the netdev is not yet read, save this request for when it is*/
433 netdev_enslave_callback *cb;
435 cb = new0(netdev_enslave_callback, 1);
439 cb->callback = callback;
442 LIST_PREPEND(callbacks, netdev->callbacks, cb);
448 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
458 r = sd_rtnl_message_get_type(message, &type);
460 log_error_netdev(netdev, "Could not get rtnl message type");
464 if (type != RTM_NEWLINK) {
465 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
469 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
471 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
472 netdev_enter_failed(netdev);
474 } else if (ifindex <= 0) {
475 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
476 netdev_enter_failed(netdev);
480 if (netdev->ifindex > 0) {
481 if (netdev->ifindex != ifindex) {
482 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
483 ifindex, netdev->ifindex);
484 netdev_enter_failed(netdev);
487 /* ifindex already set to the same for this netdev */
491 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
493 log_error_netdev(netdev, "Could not get IFNAME");
497 if (!streq(netdev->ifname, received_name)) {
498 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
500 netdev_enter_failed(netdev);
504 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
506 log_error_netdev(netdev, "Could not get LINKINFO");
510 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
512 log_error_netdev(netdev, "Could not get KIND");
516 r = sd_rtnl_message_exit_container(message);
518 log_error_netdev(netdev, "Could not exit container");
522 kind = netdev_kind_to_string(netdev->kind);
524 log_error_netdev(netdev, "Could not get kind");
525 netdev_enter_failed(netdev);
529 if (!streq(kind, received_kind)) {
530 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
531 "expected %s", received_kind, kind);
532 netdev_enter_failed(netdev);
536 netdev->ifindex = ifindex;
538 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
540 netdev_enter_ready(netdev);
545 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
547 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
548 _cleanup_free_ struct ether_addr *mac = NULL;
557 mac = new0(struct ether_addr, 1);
562 sz = sizeof(sd_id128_t) + l;
565 /* fetch some persistent data unique to the machine */
566 r = sd_id128_get_machine((sd_id128_t*) v);
570 /* combine with some data unique (on this machine) to this
572 memcpy(v + sizeof(sd_id128_t), ifname, l);
574 /* Let's hash the host machine ID plus the container name. We
575 * use a fixed, but originally randomly created hash key here. */
576 siphash24(result, v, sz, HASH_KEY.bytes);
578 assert_cc(ETH_ALEN <= sizeof(result));
579 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
581 /* see eth_random_addr in the kernel */
582 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
583 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
591 static int netdev_load_one(Manager *manager, const char *filename) {
592 _cleanup_netdev_unref_ NetDev *netdev = NULL;
593 _cleanup_fclose_ FILE *file = NULL;
599 if (null_or_empty_path(filename)) {
600 log_debug("skipping empty file: %s", filename);
604 file = fopen(filename, "re");
612 netdev = new0(NetDev, 1);
617 netdev->manager = manager;
618 netdev->state = _NETDEV_STATE_INVALID;
619 netdev->kind = _NETDEV_KIND_INVALID;
620 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
621 netdev->vlanid = VLANID_MAX + 1;
622 netdev->vxlanid = VXLAN_VID_MAX + 1;
623 netdev->tunnel_pmtudisc = true;
624 netdev->learning = true;
626 r = config_parse(NULL, filename, file,
627 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
628 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
629 false, false, netdev);
631 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
635 if (netdev->kind == _NETDEV_KIND_INVALID) {
636 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
640 if (!netdev->ifname) {
641 log_warning("NetDev without Name configured in %s. Ignoring", filename);
645 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
646 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
650 if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
651 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
655 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_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_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
662 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
663 netdev_kind_to_string(netdev->kind), filename);
667 if (netdev->kind != NETDEV_KIND_MACVLAN &&
668 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
669 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
670 netdev_kind_to_string(netdev->kind), filename);
674 netdev->filename = strdup(filename);
675 if (!netdev->filename)
678 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
679 netdev->match_host, netdev->match_virt,
680 netdev->match_kernel, netdev->match_arch,
681 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
685 r = netdev_get_mac(netdev->ifname, &netdev->mac);
687 log_error("Failed to generate predictable MAC address for %s",
693 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
697 LIST_HEAD_INIT(netdev->callbacks);
699 switch (netdev->kind) {
700 case NETDEV_KIND_VETH:
701 if (!netdev->ifname_peer) {
702 log_warning("Veth NetDev without peer name configured "
703 "in %s. Ignoring", filename);
708 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
710 log_error("Failed to generate predictable MAC address for %s",
711 netdev->ifname_peer);
716 r = netdev_create_veth(netdev, netdev_create_handler);
721 case NETDEV_KIND_BRIDGE:
722 case NETDEV_KIND_BOND:
723 r = netdev_create(netdev, NULL, NULL);
731 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
738 int netdev_load(Manager *manager) {
745 while ((netdev = hashmap_first(manager->netdevs)))
746 netdev_unref(netdev);
748 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
750 log_error("Failed to enumerate netdev files: %s", strerror(-r));
754 STRV_FOREACH_BACKWARDS(f, files) {
755 r = netdev_load_one(manager, *f);