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 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
33 [NETDEV_KIND_BRIDGE] = "bridge",
34 [NETDEV_KIND_BOND] = "bond",
35 [NETDEV_KIND_VLAN] = "vlan",
36 [NETDEV_KIND_MACVLAN] = "macvlan",
37 [NETDEV_KIND_VXLAN] = "vxlan",
38 [NETDEV_KIND_IPIP] = "ipip",
39 [NETDEV_KIND_GRE] = "gre",
40 [NETDEV_KIND_SIT] = "sit",
41 [NETDEV_KIND_VETH] = "veth",
42 [NETDEV_KIND_VTI] = "vti",
43 [NETDEV_KIND_DUMMY] = "dummy",
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 void netdev_cancel_callbacks(NetDev *netdev) {
50 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
51 netdev_enslave_callback *callback;
56 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
58 while ((callback = netdev->callbacks)) {
60 assert(callback->link);
61 assert(callback->callback);
62 assert(netdev->manager);
63 assert(netdev->manager->rtnl);
65 callback->callback(netdev->manager->rtnl, m, link);
68 LIST_REMOVE(callbacks, netdev->callbacks, callback);
73 static void netdev_free(NetDev *netdev) {
77 netdev_cancel_callbacks(netdev);
80 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
82 free(netdev->filename);
84 free(netdev->description);
86 free(netdev->ifname_peer);
88 free(netdev->mac_peer);
90 condition_free_list(netdev->match_host);
91 condition_free_list(netdev->match_virt);
92 condition_free_list(netdev->match_kernel);
93 condition_free_list(netdev->match_arch);
98 NetDev *netdev_unref(NetDev *netdev) {
99 if (netdev && (-- netdev->n_ref <= 0))
105 NetDev *netdev_ref(NetDev *netdev) {
107 assert_se(++ netdev->n_ref >= 2);
112 void netdev_drop(NetDev *netdev) {
113 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
116 netdev->state = NETDEV_STATE_LINGER;
118 log_debug_netdev(netdev, "netdev removed");
120 netdev_cancel_callbacks(netdev);
122 netdev_unref(netdev);
127 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
134 netdev = hashmap_get(manager->netdevs, name);
145 static int netdev_enter_failed(NetDev *netdev) {
146 netdev->state = NETDEV_STATE_FAILED;
151 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
152 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
156 assert(netdev->state == NETDEV_STATE_READY);
157 assert(netdev->manager);
158 assert(netdev->manager->rtnl);
162 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
163 RTM_SETLINK, link->ifindex);
165 log_error_netdev(netdev,
166 "Could not allocate RTM_SETLINK message: %s",
171 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
173 log_error_netdev(netdev,
174 "Could not append IFLA_MASTER attribute: %s",
179 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
181 log_error_netdev(netdev,
182 "Could not send rtnetlink message: %s",
187 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
192 static int netdev_enter_ready(NetDev *netdev) {
193 netdev_enslave_callback *callback;
196 assert(netdev->ifname);
198 if (netdev->state != NETDEV_STATE_CREATING)
201 netdev->state = NETDEV_STATE_READY;
203 log_info_netdev(netdev, "netdev ready");
205 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
206 /* enslave the links that were attempted to be enslaved before the
208 netdev_enslave_ready(netdev, callback->link, callback->callback);
214 /* callback for netdev's created without a backing Link */
215 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
216 _cleanup_netdev_unref_ NetDev *netdev = userdata;
219 assert(netdev->state != _NETDEV_STATE_INVALID);
221 r = sd_rtnl_message_get_errno(m);
223 log_debug_netdev(netdev, "netdev exists, using existing");
225 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
234 int config_parse_tunnel_address(const char *unit,
235 const char *filename,
238 unsigned section_line,
245 unsigned char family = AF_INET;
253 r = net_parse_inaddr(rvalue, &family, n);
255 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
256 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
262 static int netdev_create(NetDev *netdev) {
263 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
268 assert(netdev->ifname);
269 assert(netdev->manager);
270 assert(netdev->manager->rtnl);
272 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
274 log_error_netdev(netdev,
275 "Could not allocate RTM_NEWLINK message: %s",
280 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
282 log_error_netdev(netdev,
283 "Could not append IFLA_IFNAME attribute: %s",
289 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
291 log_error_netdev(netdev,
292 "Could not append IFLA_MTU attribute: %s",
299 r = sd_rtnl_message_append_ether_addr(req, IFLA_ADDRESS, netdev->mac);
301 log_error_netdev(netdev,
302 "Colud not append IFLA_ADDRESS attribute: %s",
308 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
310 log_error_netdev(netdev,
311 "Could not open IFLA_LINKINFO container: %s",
316 kind = netdev_kind_to_string(netdev->kind);
318 log_error_netdev(netdev, "Invalid kind");
322 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
324 log_error_netdev(netdev,
325 "Could not open IFLA_INFO_DATA container: %s",
330 r = sd_rtnl_message_close_container(req);
332 log_error_netdev(netdev,
333 "Could not close IFLA_INFO_DATA container %s",
338 r = sd_rtnl_message_close_container(req);
340 log_error_netdev(netdev,
341 "Could not close IFLA_LINKINFO container %s",
346 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
348 log_error_netdev(netdev,
349 "Could not send rtnetlink message: %s", strerror(-r));
355 log_debug_netdev(netdev, "creating netdev");
357 netdev->state = NETDEV_STATE_CREATING;
362 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
363 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
366 switch(netdev->kind) {
367 case NETDEV_KIND_VLAN:
368 return netdev_create_vlan(netdev, link, callback);
369 case NETDEV_KIND_MACVLAN:
370 return netdev_create_macvlan(netdev, link, callback);
371 case NETDEV_KIND_VXLAN:
372 return netdev_create_vxlan(netdev, link, callback);
373 case NETDEV_KIND_IPIP:
374 case NETDEV_KIND_GRE:
375 case NETDEV_KIND_SIT:
376 case NETDEV_KIND_VTI:
377 return netdev_create_tunnel(netdev, link, callback);
382 if (netdev->state == NETDEV_STATE_READY) {
383 r = netdev_enslave_ready(netdev, link, callback);
387 /* the netdev is not yet read, save this request for when it is*/
388 netdev_enslave_callback *cb;
390 cb = new0(netdev_enslave_callback, 1);
394 cb->callback = callback;
397 LIST_PREPEND(callbacks, netdev->callbacks, cb);
403 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
413 r = sd_rtnl_message_get_type(message, &type);
415 log_error_netdev(netdev, "Could not get rtnl message type");
419 if (type != RTM_NEWLINK) {
420 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
424 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
426 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
427 netdev_enter_failed(netdev);
429 } else if (ifindex <= 0) {
430 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
431 netdev_enter_failed(netdev);
435 if (netdev->ifindex > 0) {
436 if (netdev->ifindex != ifindex) {
437 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
438 ifindex, netdev->ifindex);
439 netdev_enter_failed(netdev);
442 /* ifindex already set to the same for this netdev */
446 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
448 log_error_netdev(netdev, "Could not get IFNAME");
452 if (!streq(netdev->ifname, received_name)) {
453 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
455 netdev_enter_failed(netdev);
459 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
461 log_error_netdev(netdev, "Could not get LINKINFO");
465 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
467 log_error_netdev(netdev, "Could not get KIND");
471 r = sd_rtnl_message_exit_container(message);
473 log_error_netdev(netdev, "Could not exit container");
477 kind = netdev_kind_to_string(netdev->kind);
479 log_error_netdev(netdev, "Could not get kind");
480 netdev_enter_failed(netdev);
484 if (!streq(kind, received_kind)) {
485 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
486 "expected %s", received_kind, kind);
487 netdev_enter_failed(netdev);
491 netdev->ifindex = ifindex;
493 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
495 netdev_enter_ready(netdev);
500 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
502 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
503 _cleanup_free_ struct ether_addr *mac = NULL;
512 mac = new0(struct ether_addr, 1);
517 sz = sizeof(sd_id128_t) + l;
520 /* fetch some persistent data unique to the machine */
521 r = sd_id128_get_machine((sd_id128_t*) v);
525 /* combine with some data unique (on this machine) to this
527 memcpy(v + sizeof(sd_id128_t), ifname, l);
529 /* Let's hash the host machine ID plus the container name. We
530 * use a fixed, but originally randomly created hash key here. */
531 siphash24(result, v, sz, HASH_KEY.bytes);
533 assert_cc(ETH_ALEN <= sizeof(result));
534 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
536 /* see eth_random_addr in the kernel */
537 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
538 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
546 static int netdev_load_one(Manager *manager, const char *filename) {
547 _cleanup_netdev_unref_ NetDev *netdev = NULL;
548 _cleanup_fclose_ FILE *file = NULL;
554 if (null_or_empty_path(filename)) {
555 log_debug("skipping empty file: %s", filename);
559 file = fopen(filename, "re");
567 netdev = new0(NetDev, 1);
572 netdev->manager = manager;
573 netdev->state = _NETDEV_STATE_INVALID;
574 netdev->kind = _NETDEV_KIND_INVALID;
575 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
576 netdev->vlanid = VLANID_MAX + 1;
577 netdev->vxlanid = VXLAN_VID_MAX + 1;
578 netdev->tunnel_pmtudisc = true;
579 netdev->learning = true;
581 r = config_parse(NULL, filename, file,
582 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
583 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
584 false, false, netdev);
586 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
590 if (netdev->kind == _NETDEV_KIND_INVALID) {
591 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
595 if (!netdev->ifname) {
596 log_warning("NetDev without Name configured in %s. Ignoring", filename);
600 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
601 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
605 if (netdev->kind == NETDEV_KIND_VXLAN && netdev->vxlanid > VXLAN_VID_MAX) {
606 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
610 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
611 log_warning("VLAN Id configured for a %s in %s. Ignoring",
612 netdev_kind_to_string(netdev->kind), filename);
616 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
617 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
618 netdev_kind_to_string(netdev->kind), filename);
622 if (netdev->kind != NETDEV_KIND_MACVLAN &&
623 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
624 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
625 netdev_kind_to_string(netdev->kind), filename);
629 netdev->filename = strdup(filename);
630 if (!netdev->filename)
633 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
634 netdev->match_host, netdev->match_virt,
635 netdev->match_kernel, netdev->match_arch,
636 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
640 r = netdev_get_mac(netdev->ifname, &netdev->mac);
642 log_error("Failed to generate predictable MAC address for %s",
648 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
652 LIST_HEAD_INIT(netdev->callbacks);
654 switch (netdev->kind) {
655 case NETDEV_KIND_VETH:
656 if (!netdev->ifname_peer) {
657 log_warning("Veth NetDev without peer name configured "
658 "in %s. Ignoring", filename);
663 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
665 log_error("Failed to generate predictable MAC address for %s",
666 netdev->ifname_peer);
671 r = netdev_create_veth(netdev, netdev_create_handler);
676 case NETDEV_KIND_DUMMY:
677 r = netdev_create_dummy(netdev, netdev_create_handler);
684 case NETDEV_KIND_BRIDGE:
685 case NETDEV_KIND_BOND:
686 r = netdev_create(netdev);
694 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
701 int netdev_load(Manager *manager) {
708 while ((netdev = hashmap_first(manager->netdevs)))
709 netdev_unref(netdev);
711 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
713 log_error("Failed to enumerate netdev files: %s", strerror(-r));
717 STRV_FOREACH_BACKWARDS(f, files) {
718 r = netdev_load_one(manager, *f);