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/>.
24 #include "path-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
29 #define VLANID_MAX 4094
31 static const char* const netdev_kind_table[] = {
32 [NETDEV_KIND_BRIDGE] = "bridge",
33 [NETDEV_KIND_BOND] = "bond",
34 [NETDEV_KIND_VLAN] = "vlan",
37 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
38 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
40 void netdev_free(NetDev *netdev) {
41 netdev_enslave_callback *callback;
46 while ((callback = netdev->callbacks)) {
47 LIST_REMOVE(callbacks, netdev->callbacks, callback);
52 hashmap_remove(netdev->manager->netdevs, netdev->name);
54 free(netdev->filename);
56 free(netdev->description);
62 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
69 netdev = hashmap_get(manager->netdevs, name);
80 static int netdev_enter_failed(NetDev *netdev) {
81 netdev->state = NETDEV_STATE_FAILED;
86 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
87 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
91 assert(netdev->state == NETDEV_STATE_READY);
95 r = sd_rtnl_message_new_link(RTM_SETLINK, link->ifindex, &req);
97 log_error_netdev(netdev,
98 "Could not allocate RTM_SETLINK message: %s",
103 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
105 log_error_netdev(netdev,
106 "Could not append IFLA_MASTER attribute: %s",
111 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
113 log_error_netdev(netdev,
114 "Could not send rtnetlink message: %s",
119 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
124 static int netdev_enter_ready(NetDev *netdev) {
125 netdev_enslave_callback *callback;
128 assert(netdev->name);
130 netdev->state = NETDEV_STATE_READY;
132 log_info_netdev(netdev, "netdev ready");
134 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
135 /* enslave the links that were attempted to be enslaved befor the
137 netdev_enslave_ready(netdev, callback->link, callback->callback);
143 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
144 NetDev *netdev = userdata;
147 assert(netdev->state != _NETDEV_STATE_INVALID);
149 r = sd_rtnl_message_get_errno(m);
151 log_warning_netdev(netdev, "netdev failed: %s", strerror(-r));
152 netdev_enter_failed(netdev);
160 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
161 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
166 assert(!(netdev->kind == NETDEV_KIND_VLAN) || (link && callback && netdev->vlanid <= VLANID_MAX));
167 assert(netdev->name);
168 assert(netdev->manager);
169 assert(netdev->manager->rtnl);
171 r = sd_rtnl_message_new_link(RTM_NEWLINK, 0, &req);
173 log_error_netdev(netdev,
174 "Could not allocate RTM_NEWLINK message: %s",
180 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
182 log_error_netdev(netdev,
183 "Could not append IFLA_LINK attribute: %s",
189 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
191 log_error_netdev(netdev,
192 "Could not append IFLA_IFNAME attribute: %s",
197 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
199 log_error_netdev(netdev,
200 "Could not open IFLA_LINKINFO container: %s",
205 kind = netdev_kind_to_string(netdev->kind);
207 log_error_netdev(netdev, "Invalid kind");
211 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, kind);
213 log_error_netdev(netdev,
214 "Could not append IFLA_INFO_KIND attribute: %s",
219 if (netdev->vlanid <= VLANID_MAX) {
220 r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
222 log_error_netdev(netdev,
223 "Could not open IFLA_INFO_DATA container: %s",
228 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
230 log_error_netdev(netdev,
231 "Could not append IFLA_VLAN_ID attribute: %s",
236 r = sd_rtnl_message_close_container(req);
238 log_error_netdev(netdev,
239 "Could not close IFLA_INFO_DATA container %s",
245 r = sd_rtnl_message_close_container(req);
247 log_error_netdev(netdev,
248 "Could not close IFLA_LINKINFO container %s",
254 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
256 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
258 log_error_netdev(netdev,
259 "Could not send rtnetlink message: %s", strerror(-r));
263 log_debug_netdev(netdev, "creating netdev");
265 netdev->state = NETDEV_STATE_CREATING;
270 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
271 if (netdev->kind == NETDEV_KIND_VLAN)
272 return netdev_create(netdev, link, callback);
274 if (netdev->state == NETDEV_STATE_READY) {
275 netdev_enslave_ready(netdev, link, callback);
277 /* the netdev is not yet read, save this request for when it is*/
278 netdev_enslave_callback *cb;
280 cb = new0(netdev_enslave_callback, 1);
284 cb->callback = callback;
287 LIST_PREPEND(callbacks, netdev->callbacks, cb);
293 int netdev_set_ifindex(NetDev *netdev, int ifindex) {
297 if (netdev->ifindex > 0) {
298 if (netdev->ifindex == ifindex)
304 netdev->ifindex = ifindex;
306 netdev_enter_ready(netdev);
311 static int netdev_load_one(Manager *manager, const char *filename) {
312 _cleanup_netdev_free_ NetDev *netdev = NULL;
313 _cleanup_fclose_ FILE *file = NULL;
319 file = fopen(filename, "re");
327 netdev = new0(NetDev, 1);
331 netdev->manager = manager;
332 netdev->state = _NETDEV_STATE_INVALID;
333 netdev->kind = _NETDEV_KIND_INVALID;
334 netdev->vlanid = VLANID_MAX + 1;
336 r = config_parse(NULL, filename, file, "NetDev\0VLAN\0", config_item_perf_lookup,
337 (void*) network_gperf_lookup, false, false, netdev);
339 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
343 if (netdev->kind == _NETDEV_KIND_INVALID) {
344 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
349 log_warning("NetDev without Name configured in %s. Ignoring", filename);
353 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
354 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
358 netdev->filename = strdup(filename);
359 if (!netdev->filename)
362 r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev);
366 LIST_HEAD_INIT(netdev->callbacks);
368 if (netdev->kind != NETDEV_KIND_VLAN) {
369 r = netdev_create(netdev, NULL, NULL);
379 int netdev_load(Manager *manager) {
386 while ((netdev = hashmap_first(manager->netdevs)))
389 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
391 log_error("Failed to enumerate netdev files: %s", strerror(-r));
395 STRV_FOREACH_BACKWARDS(f, files) {
396 r = netdev_load_one(manager, *f);