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"
31 #define VLANID_MAX 4094
33 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
34 [NETDEV_KIND_BRIDGE] = "bridge",
35 [NETDEV_KIND_BOND] = "bond",
36 [NETDEV_KIND_VLAN] = "vlan",
37 [NETDEV_KIND_MACVLAN] = "macvlan",
38 [NETDEV_KIND_IPIP] = "ipip",
39 [NETDEV_KIND_GRE] = "gre",
40 [NETDEV_KIND_SIT] = "sit",
41 [NETDEV_KIND_VETH] = "veth",
44 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
45 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
47 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
48 [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
49 [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
50 [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
51 [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
54 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
55 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
57 static void netdev_cancel_callbacks(NetDev *netdev) {
58 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
59 netdev_enslave_callback *callback;
64 rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
66 while ((callback = netdev->callbacks)) {
68 assert(callback->link);
69 assert(callback->callback);
70 assert(netdev->manager);
71 assert(netdev->manager->rtnl);
73 callback->callback(netdev->manager->rtnl, m, link);
76 LIST_REMOVE(callbacks, netdev->callbacks, callback);
81 static void netdev_free(NetDev *netdev) {
85 netdev_cancel_callbacks(netdev);
88 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
90 free(netdev->filename);
92 free(netdev->description);
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);
167 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
168 RTM_SETLINK, link->ifindex);
170 log_error_netdev(netdev,
171 "Could not allocate RTM_SETLINK message: %s",
176 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
178 log_error_netdev(netdev,
179 "Could not append IFLA_MASTER attribute: %s",
184 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
186 log_error_netdev(netdev,
187 "Could not send rtnetlink message: %s",
192 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
197 static int netdev_enter_ready(NetDev *netdev) {
198 netdev_enslave_callback *callback;
201 assert(netdev->ifname);
203 if (netdev->state != NETDEV_STATE_CREATING)
206 netdev->state = NETDEV_STATE_READY;
208 log_info_netdev(netdev, "netdev ready");
210 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
211 /* enslave the links that were attempted to be enslaved before the
213 netdev_enslave_ready(netdev, callback->link, callback->callback);
218 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
219 NetDev *netdev = userdata;
222 assert(netdev->state != _NETDEV_STATE_INVALID);
224 r = sd_rtnl_message_get_errno(m);
226 log_debug_netdev(netdev, "netdev exists, using existing");
228 log_warning_netdev(netdev, "netdev could not be created: %s", strerror(-r));
237 int config_parse_tunnel_address(const char *unit,
238 const char *filename,
241 unsigned section_line,
248 unsigned char family = AF_INET;
256 r = net_parse_inaddr(rvalue, &family, n);
258 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
259 "Tunnel address is invalid, ignoring assignment: %s", rvalue);
265 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
266 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
271 assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
273 assert(netdev->ifname);
274 assert(netdev->manager);
275 assert(netdev->manager->rtnl);
277 r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
279 log_error_netdev(netdev,
280 "Could not allocate RTM_NEWLINK message: %s",
286 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
288 log_error_netdev(netdev,
289 "Could not append IFLA_LINK attribute: %s",
295 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
297 log_error_netdev(netdev,
298 "Could not append IFLA_IFNAME attribute: %s",
304 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
306 log_error_netdev(netdev,
307 "Could not append IFLA_MTU attribute: %s",
313 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
315 log_error_netdev(netdev,
316 "Could not open IFLA_LINKINFO container: %s",
321 kind = netdev_kind_to_string(netdev->kind);
323 log_error_netdev(netdev, "Invalid kind");
327 r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
329 log_error_netdev(netdev,
330 "Could not open IFLA_INFO_DATA container: %s",
335 if (netdev->vlanid <= VLANID_MAX) {
336 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
338 log_error_netdev(netdev,
339 "Could not append IFLA_VLAN_ID attribute: %s",
345 if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
346 r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
348 log_error_netdev(netdev,
349 "Could not append IFLA_MACVLAN_MODE attribute: %s",
355 r = sd_rtnl_message_close_container(req);
357 log_error_netdev(netdev,
358 "Could not close IFLA_INFO_DATA container %s",
363 r = sd_rtnl_message_close_container(req);
365 log_error_netdev(netdev,
366 "Could not close IFLA_LINKINFO container %s",
372 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
374 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
376 log_error_netdev(netdev,
377 "Could not send rtnetlink message: %s", strerror(-r));
381 log_debug_netdev(netdev, "creating netdev");
383 netdev->state = NETDEV_STATE_CREATING;
388 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
391 if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
392 return netdev_create(netdev, link, callback);
394 if(netdev->kind == NETDEV_KIND_IPIP ||
395 netdev->kind == NETDEV_KIND_GRE ||
396 netdev->kind == NETDEV_KIND_SIT)
397 return netdev_create_tunnel(link, netdev_create_handler);
399 if (netdev->state == NETDEV_STATE_READY) {
400 r = netdev_enslave_ready(netdev, link, callback);
404 /* the netdev is not yet read, save this request for when it is*/
405 netdev_enslave_callback *cb;
407 cb = new0(netdev_enslave_callback, 1);
411 cb->callback = callback;
414 LIST_PREPEND(callbacks, netdev->callbacks, cb);
420 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
430 r = sd_rtnl_message_get_type(message, &type);
432 log_error_netdev(netdev, "Could not get rtnl message type");
436 if (type != RTM_NEWLINK) {
437 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
441 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
443 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
444 netdev_enter_failed(netdev);
446 } else if (ifindex <= 0) {
447 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
448 netdev_enter_failed(netdev);
453 if (netdev->ifindex > 0) {
454 if (netdev->ifindex != ifindex) {
455 log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
456 ifindex, netdev->ifindex);
457 netdev_enter_failed(netdev);
460 /* ifindex already set to the same for this netdev */
464 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
466 log_error_netdev(netdev, "Could not get IFNAME");
470 if (!streq(netdev->ifname, received_name)) {
471 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
473 netdev_enter_failed(netdev);
477 r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
479 log_error_netdev(netdev, "Could not get LINKINFO");
483 r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
485 log_error_netdev(netdev, "Could not get KIND");
489 r = sd_rtnl_message_exit_container(message);
491 log_error_netdev(netdev, "Could not exit container");
495 kind = netdev_kind_to_string(netdev->kind);
497 log_error_netdev(netdev, "Could not get kind");
498 netdev_enter_failed(netdev);
502 if (!streq(kind, received_kind)) {
503 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
504 "expected %s", received_kind, kind);
505 netdev_enter_failed(netdev);
509 netdev->ifindex = ifindex;
511 log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
513 netdev_enter_ready(netdev);
518 static int netdev_load_one(Manager *manager, const char *filename) {
519 _cleanup_netdev_unref_ NetDev *netdev = NULL;
520 _cleanup_fclose_ FILE *file = NULL;
526 if (null_or_empty_path(filename)) {
527 log_debug("skipping empty file: %s", filename);
531 file = fopen(filename, "re");
539 netdev = new0(NetDev, 1);
544 netdev->manager = manager;
545 netdev->state = _NETDEV_STATE_INVALID;
546 netdev->kind = _NETDEV_KIND_INVALID;
547 netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
548 netdev->vlanid = VLANID_MAX + 1;
550 r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0Peer\0",
551 config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
552 false, false, netdev);
554 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
558 if (netdev->kind == _NETDEV_KIND_INVALID) {
559 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
563 if (!netdev->ifname) {
564 log_warning("NetDev without Name configured in %s. Ignoring", filename);
568 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
569 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
573 if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
574 log_warning("VLAN Id configured for a %s in %s. Ignoring",
575 netdev_kind_to_string(netdev->kind), filename);
579 if (netdev->kind != NETDEV_KIND_MACVLAN &&
580 netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
581 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
582 netdev_kind_to_string(netdev->kind), filename);
586 netdev->filename = strdup(filename);
587 if (!netdev->filename)
590 if (net_match_config(NULL, NULL, NULL, NULL, NULL,
591 netdev->match_host, netdev->match_virt,
592 netdev->match_kernel, netdev->match_arch,
593 NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
596 r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
600 LIST_HEAD_INIT(netdev->callbacks);
602 if(netdev->kind == NETDEV_KIND_VETH)
603 return netdev_create_veth(netdev, netdev_create_handler);
605 if (netdev->kind != NETDEV_KIND_VLAN &&
606 netdev->kind != NETDEV_KIND_MACVLAN &&
607 netdev->kind != NETDEV_KIND_IPIP &&
608 netdev->kind != NETDEV_KIND_GRE &&
609 netdev->kind != NETDEV_KIND_SIT) {
610 r = netdev_create(netdev, NULL, NULL);
615 log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
622 int netdev_load(Manager *manager) {
629 while ((netdev = hashmap_first(manager->netdevs)))
630 netdev_unref(netdev);
632 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
634 log_error("Failed to enumerate netdev files: %s", strerror(-r));
638 STRV_FOREACH_BACKWARDS(f, files) {
639 r = netdev_load_one(manager, *f);