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 static const char* const netdev_kind_table[] = {
30 [NETDEV_KIND_BRIDGE] = "bridge",
31 [NETDEV_KIND_BOND] = "bond"
34 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetdevKind);
35 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetdevKind, "Failed to parse netdev kind");
37 void netdev_free(Netdev *netdev) {
38 netdev_enslave_callback *callback;
43 while ((callback = netdev->callbacks)) {
44 LIST_REMOVE(callbacks, netdev->callbacks, callback);
49 hashmap_remove(netdev->manager->netdevs, netdev->name);
51 free(netdev->filename);
53 free(netdev->description);
59 int netdev_get(Manager *manager, const char *name, Netdev **ret) {
66 netdev = hashmap_get(manager->netdevs, name);
77 static int netdev_enter_failed(Netdev *netdev) {
78 netdev->state = NETDEV_STATE_FAILED;
83 static int netdev_enslave_ready(Netdev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
84 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
88 assert(netdev->state == NETDEV_STATE_READY);
92 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
94 log_error_netdev(netdev,
95 "Could not allocate RTM_SETLINK message: %s",
100 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->link->ifindex);
102 log_error_netdev(netdev,
103 "Could not append IFLA_MASTER attribute: %s",
108 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
110 log_error_netdev(netdev,
111 "Could not send rtnetlink message: %s",
116 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
121 static int netdev_enter_ready(Netdev *netdev) {
122 netdev_enslave_callback *callback;
125 assert(netdev->name);
127 netdev->state = NETDEV_STATE_READY;
129 log_info_netdev(netdev, "netdev ready");
131 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
132 /* enslave the links that were attempted to be enslaved befor the
134 netdev_enslave_ready(netdev, callback->link, callback->callback);
140 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
141 Netdev *netdev = userdata;
144 assert(netdev->state != _NETDEV_STATE_INVALID);
146 r = sd_rtnl_message_get_errno(m);
148 log_warning_netdev(netdev, "netdev failed: %s", strerror(-r));
149 netdev_enter_failed(netdev);
157 static int netdev_create(Netdev *netdev) {
158 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
163 assert(netdev->state == _NETDEV_STATE_INVALID);
164 assert(netdev->name);
165 assert(netdev->manager);
166 assert(netdev->manager->rtnl);
168 r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req);
170 log_error_netdev(netdev,
171 "Could not allocate RTM_NEWLINK message: %s",
176 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
178 log_error_netdev(netdev,
179 "Could not append IFLA_IFNAME attribute: %s",
184 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
186 log_error_netdev(netdev,
187 "Could not open IFLA_LINKINFO container: %s",
192 kind = netdev_kind_to_string(netdev->kind);
194 log_error_netdev(netdev, "Invalid kind");
198 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, kind);
200 log_error_netdev(netdev,
201 "Could not append IFLA_INFO_KIND attribute: %s",
206 r = sd_rtnl_message_close_container(req);
208 log_error_netdev(netdev,
209 "Could not close IFLA_LINKINFO container %s",
214 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
216 log_error_netdev(netdev,
217 "Could not send rtnetlink message: %s", strerror(-r));
221 log_debug_netdev(netdev, "creating netdev");
223 netdev->state = NETDEV_STATE_CREATING;
228 int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
229 if (netdev->state == NETDEV_STATE_READY) {
230 netdev_enslave_ready(netdev, link, callback);
232 /* the netdev is not yet read, save this request for when it is*/
233 netdev_enslave_callback *cb;
235 cb = new0(netdev_enslave_callback, 1);
239 cb->callback = callback;
242 LIST_PREPEND(callbacks, netdev->callbacks, cb);
248 int netdev_set_link(Manager *m, NetdevKind kind, Link *link) {
252 r = netdev_get(m, link->ifname, &netdev);
256 if (netdev->link && netdev->link != link)
259 if (netdev->kind != kind)
264 netdev_enter_ready(netdev);
269 static int netdev_load_one(Manager *manager, const char *filename) {
270 _cleanup_netdev_free_ Netdev *netdev = NULL;
271 _cleanup_fclose_ FILE *file = NULL;
277 file = fopen(filename, "re");
285 netdev = new0(Netdev, 1);
289 netdev->manager = manager;
290 netdev->state = _NETDEV_STATE_INVALID;
291 netdev->kind = _NETDEV_KIND_INVALID;
293 r = config_parse(NULL, filename, file, "Netdev\0", config_item_perf_lookup,
294 (void*) network_gperf_lookup, false, false, netdev);
296 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
300 if (netdev->kind == _NETDEV_KIND_INVALID) {
301 log_warning("Netdev without Kind configured in %s. Ignoring", filename);
306 log_warning("Netdev without Name configured in %s. Ignoring", filename);
310 netdev->filename = strdup(filename);
311 if (!netdev->filename)
314 r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev);
318 LIST_HEAD_INIT(netdev->callbacks);
320 r = netdev_create(netdev);
329 int netdev_load(Manager *manager) {
336 while ((netdev = hashmap_first(manager->netdevs)))
339 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
341 log_error("Failed to enumerate netdev files: %s", strerror(-r));
345 STRV_FOREACH_BACKWARDS(f, files) {
346 r = netdev_load_one(manager, *f);