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",
44 [NETDEV_KIND_TUN] = "tun",
45 [NETDEV_KIND_TAP] = "tap",
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");
52 static void netdev_cancel_callbacks(NetDev *netdev) {
53 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
54 netdev_join_callback *callback;
59 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
61 while ((callback = netdev->callbacks)) {
63 assert(callback->link);
64 assert(callback->callback);
65 assert(netdev->manager);
66 assert(netdev->manager->rtnl);
68 callback->callback(netdev->manager->rtnl, m, link);
71 LIST_REMOVE(callbacks, netdev->callbacks, callback);
76 static void netdev_free(NetDev *netdev) {
80 netdev_cancel_callbacks(netdev);
83 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
85 free(netdev->filename);
87 free(netdev->description);
89 free(netdev->ifname_peer);
91 free(netdev->mac_peer);
92 free(netdev->user_name);
93 free(netdev->group_name);
95 condition_free_list(netdev->match_host);
96 condition_free_list(netdev->match_virt);
97 condition_free_list(netdev->match_kernel);
98 condition_free_list(netdev->match_arch);
103 NetDev *netdev_unref(NetDev *netdev) {
104 if (netdev && (-- netdev->n_ref <= 0))
110 NetDev *netdev_ref(NetDev *netdev) {
112 assert_se(++ netdev->n_ref >= 2);
117 void netdev_drop(NetDev *netdev) {
118 if (!netdev || netdev->state == NETDEV_STATE_LINGER)
121 netdev->state = NETDEV_STATE_LINGER;
123 log_debug_netdev(netdev, "netdev removed");
125 netdev_cancel_callbacks(netdev);
127 netdev_unref(netdev);
132 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
139 netdev = hashmap_get(manager->netdevs, name);
150 static int netdev_enter_failed(NetDev *netdev) {
151 netdev->state = NETDEV_STATE_FAILED;
156 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
157 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
161 assert(netdev->state == NETDEV_STATE_READY);
162 assert(netdev->manager);
163 assert(netdev->manager->rtnl);
164 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
168 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
169 RTM_SETLINK, link->ifindex);
171 log_error_netdev(netdev,
172 "Could not allocate RTM_SETLINK message: %s",
177 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
179 log_error_netdev(netdev,
180 "Could not append IFLA_MASTER attribute: %s",
185 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
187 log_error_netdev(netdev,
188 "Could not send rtnetlink message: %s",
195 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
200 static int netdev_enter_ready(NetDev *netdev) {
201 netdev_join_callback *callback, *callback_next;
205 assert(netdev->ifname);
207 if (netdev->state != NETDEV_STATE_CREATING)
210 netdev->state = NETDEV_STATE_READY;
212 log_info_netdev(netdev, "netdev ready");
214 LIST_FOREACH_SAFE(callbacks, callback, callback_next, netdev->callbacks) {
215 /* enslave the links that were attempted to be enslaved before the
217 r = netdev_enslave_ready(netdev, callback->link, callback->callback);
221 LIST_REMOVE(callbacks, netdev->callbacks, callback);
222 link_unref(callback->link);
229 /* callback for netdev's created without a backing Link */
230 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
231 _cleanup_netdev_unref_ NetDev *netdev = userdata;
234 assert(netdev->state != _NETDEV_STATE_INVALID);
236 r = sd_rtnl_message_get_errno(m);
238 log_debug_netdev(netdev, "netdev exists, using existing");
240 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
249 static int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
253 assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND));
255 if (netdev->state == NETDEV_STATE_READY) {
256 r = netdev_enslave_ready(netdev, link, callback);
260 /* the netdev is not yet read, save this request for when it is*/
261 netdev_join_callback *cb;
263 cb = new0(netdev_join_callback, 1);
267 cb->callback = callback;
271 LIST_PREPEND(callbacks, netdev->callbacks, cb);
277 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
278 int netdev_join(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
282 switch(netdev->kind) {
283 case NETDEV_KIND_VLAN:
284 return netdev_create_vlan(netdev, link, callback);
285 case NETDEV_KIND_MACVLAN:
286 return netdev_create_macvlan(netdev, link, callback);
287 case NETDEV_KIND_VXLAN:
288 return netdev_create_vxlan(netdev, link, callback);
289 case NETDEV_KIND_IPIP:
290 case NETDEV_KIND_GRE:
291 case NETDEV_KIND_SIT:
292 case NETDEV_KIND_VTI:
293 return netdev_create_tunnel(netdev, link, callback);
294 case NETDEV_KIND_BRIDGE:
295 case NETDEV_KIND_BOND:
296 return netdev_enslave(netdev, link, callback);
298 assert_not_reached("Enslaving by invalid netdev kind");
304 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
314 r = sd_rtnl_message_get_type(message, &type);
316 log_error_netdev(netdev, "Could not get rtnl message type");
320 if (type != RTM_NEWLINK) {
321 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
325 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
327 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
328 netdev_enter_failed(netdev);
330 } else if (ifindex <= 0) {
331 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
332 netdev_enter_failed(netdev);
336 if (netdev->ifindex > 0) {
337 if (netdev->ifindex != ifindex) {
338 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
339 ifindex, netdev->ifindex);
340 netdev_enter_failed(netdev);
343 /* ifindex already set to the same for this netdev */
347 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
349 log_error_netdev(netdev, "Could not get IFNAME");
353 if (!streq(netdev->ifname, received_name)) {
354 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
356 netdev_enter_failed(netdev);
360 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
362 log_error_netdev(netdev, "Could not get LINKINFO");
366 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
368 log_error_netdev(netdev, "Could not get KIND");
372 r = sd_rtnl_message_exit_container(message);
374 log_error_netdev(netdev, "Could not exit container");
378 if (netdev->kind == NETDEV_KIND_TAP)
379 /* the kernel does not distinguish between tun and tap */
382 kind = netdev_kind_to_string(netdev->kind);
384 log_error_netdev(netdev, "Could not get kind");
385 netdev_enter_failed(netdev);
390 if (!streq(kind, received_kind)) {
391 log_error_netdev(netdev,
392 "Received newlink with wrong KIND %s, "
393 "expected %s", received_kind, kind);
394 netdev_enter_failed(netdev);
398 netdev->ifindex = ifindex;
400 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
402 netdev_enter_ready(netdev);
407 #define HASH_KEY SD_ID128_MAKE(52,e1,45,bd,00,6f,29,96,21,c6,30,6d,83,71,04,48)
409 static int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
410 _cleanup_free_ struct ether_addr *mac = NULL;
419 mac = new0(struct ether_addr, 1);
424 sz = sizeof(sd_id128_t) + l;
427 /* fetch some persistent data unique to the machine */
428 r = sd_id128_get_machine((sd_id128_t*) v);
432 /* combine with some data unique (on this machine) to this
434 memcpy(v + sizeof(sd_id128_t), ifname, l);
436 /* Let's hash the host machine ID plus the container name. We
437 * use a fixed, but originally randomly created hash key here. */
438 siphash24(result, v, sz, HASH_KEY.bytes);
440 assert_cc(ETH_ALEN <= sizeof(result));
441 memcpy(mac->ether_addr_octet, result, ETH_ALEN);
443 /* see eth_random_addr in the kernel */
444 mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
445 mac->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
453 static int netdev_load_one(Manager *manager, const char *filename) {
454 _cleanup_netdev_unref_ NetDev *netdev = NULL;
455 _cleanup_fclose_ FILE *file = NULL;
461 if (null_or_empty_path(filename)) {
462 log_debug("skipping empty file: %s", filename);
466 file = fopen(filename, "re");
474 netdev = new0(NetDev, 1);
479 netdev->manager = manager;
480 netdev->state = _NETDEV_STATE_INVALID;
481 netdev->kind = _NETDEV_KIND_INVALID;
482 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
483 netdev->bond_mode = _NETDEV_BOND_MODE_INVALID;
484 netdev->vlanid = VLANID_MAX + 1;
485 netdev->vxlanid = VXLAN_VID_MAX + 1;
486 netdev->tunnel_pmtudisc = true;
487 netdev->learning = true;
489 r = config_parse(NULL, filename, file,
490 "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0Bond\0",
491 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
492 false, false, netdev);
494 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
498 /* skip out early if configuration does not match the environment */
499 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
500 netdev->match_host, netdev->match_virt,
501 netdev->match_kernel, netdev->match_arch,
502 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
505 /* verify configuration */
506 switch (netdev->kind) {
507 case _NETDEV_KIND_INVALID:
508 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
511 case NETDEV_KIND_VLAN:
512 if (netdev->vlanid > VLANID_MAX) {
513 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
518 case NETDEV_KIND_VXLAN:
519 if (netdev->vxlanid > VXLAN_VID_MAX) {
520 log_warning("VXLAN without valid Id configured in %s. Ignoring", filename);
525 case NETDEV_KIND_IPIP:
526 case NETDEV_KIND_GRE:
527 case NETDEV_KIND_SIT:
528 case NETDEV_KIND_VTI:
529 if (netdev->local.in.s_addr == INADDR_ANY) {
530 log_warning("Tunnel without local address configured in %s. Ignoring", filename);
533 if (netdev->remote.in.s_addr == INADDR_ANY) {
534 log_warning("Tunnel without remote address configured in %s. Ignoring", filename);
537 if (netdev->family != AF_INET) {
538 log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename);
543 case NETDEV_KIND_VETH:
544 if (!netdev->ifname_peer) {
545 log_warning("Veth NetDev without peer name configured "
546 "in %s. Ignoring", filename);
550 if (!netdev->mac_peer) {
551 r = netdev_get_mac(netdev->ifname_peer, &netdev->mac_peer);
553 log_error("Failed to generate predictable MAC address for %s",
554 netdev->ifname_peer);
564 if (!netdev->ifname) {
565 log_warning("NetDev without Name configured in %s. Ignoring", filename);
569 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
570 log_warning("VLAN Id configured for a %s in %s. Ignoring",
571 netdev_kind_to_string(netdev->kind), filename);
575 if (netdev->kind != NETDEV_KIND_VXLAN && netdev->vxlanid <= VXLAN_VID_MAX) {
576 log_warning("VXLAN Id configured for a %s in %s. Ignoring",
577 netdev_kind_to_string(netdev->kind), filename);
581 if (netdev->kind != NETDEV_KIND_MACVLAN &&
582 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
583 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
584 netdev_kind_to_string(netdev->kind), filename);
588 netdev->filename = strdup(filename);
589 if (!netdev->filename)
593 r = netdev_get_mac(netdev->ifname, &netdev->mac);
595 log_error("Failed to generate predictable MAC address for %s",
601 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
605 LIST_HEAD_INIT(netdev->callbacks);
608 switch (netdev->kind) {
609 case NETDEV_KIND_VETH:
610 r = netdev_create_veth(netdev, netdev_create_handler);
615 case NETDEV_KIND_DUMMY:
616 r = netdev_create_dummy(netdev, netdev_create_handler);
621 case NETDEV_KIND_BRIDGE:
622 r = netdev_create_bridge(netdev, netdev_create_handler);
626 case NETDEV_KIND_BOND:
627 r = netdev_create_bond(netdev, netdev_create_handler);
635 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
642 int netdev_load(Manager *manager) {
649 while ((netdev = hashmap_first(manager->netdevs)))
650 netdev_unref(netdev);
652 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
654 log_error("Failed to enumerate netdev files: %s", strerror(-r));
658 STRV_FOREACH_BACKWARDS(f, files) {
659 r = netdev_load_one(manager, *f);