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",
32 [NETDEV_KIND_VLAN] = "vlan",
35 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetdevKind);
36 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetdevKind, "Failed to parse netdev kind");
38 void netdev_free(Netdev *netdev) {
39 netdev_enslave_callback *callback;
44 while ((callback = netdev->callbacks)) {
45 LIST_REMOVE(callbacks, netdev->callbacks, callback);
50 hashmap_remove(netdev->manager->netdevs, netdev->name);
52 free(netdev->filename);
54 free(netdev->description);
60 int netdev_get(Manager *manager, const char *name, Netdev **ret) {
67 netdev = hashmap_get(manager->netdevs, name);
78 static int netdev_enter_failed(Netdev *netdev) {
79 netdev->state = NETDEV_STATE_FAILED;
84 static int netdev_enslave_ready(Netdev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
85 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
89 assert(netdev->state == NETDEV_STATE_READY);
93 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
95 log_error_netdev(netdev,
96 "Could not allocate RTM_SETLINK message: %s",
101 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
103 log_error_netdev(netdev,
104 "Could not append IFLA_MASTER attribute: %s",
109 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
111 log_error_netdev(netdev,
112 "Could not send rtnetlink message: %s",
117 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
122 static int netdev_enter_ready(Netdev *netdev) {
123 netdev_enslave_callback *callback;
126 assert(netdev->name);
128 netdev->state = NETDEV_STATE_READY;
130 log_info_netdev(netdev, "netdev ready");
132 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
133 /* enslave the links that were attempted to be enslaved befor the
135 netdev_enslave_ready(netdev, callback->link, callback->callback);
141 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
142 Netdev *netdev = userdata;
145 assert(netdev->state != _NETDEV_STATE_INVALID);
147 r = sd_rtnl_message_get_errno(m);
149 log_warning_netdev(netdev, "netdev failed: %s", strerror(-r));
150 netdev_enter_failed(netdev);
155 r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
157 log_warning_netdev(netdev, "created netdev with unknown ifindex: %s", strerror(-r));
159 log_info_netdev(netdev, "created netdev with ifindex %d", ifindex);
160 netdev_set_ifindex(netdev, ifindex);
166 static int netdev_create(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
167 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
172 assert(!(netdev->kind == NETDEV_KIND_VLAN) || (link && callback && netdev->vlanid >= 0));
173 assert(netdev->name);
174 assert(netdev->manager);
175 assert(netdev->manager->rtnl);
177 r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req);
179 log_error_netdev(netdev,
180 "Could not allocate RTM_NEWLINK message: %s",
186 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
188 log_error_netdev(netdev,
189 "Could not append IFLA_LINK attribute: %s",
195 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
197 log_error_netdev(netdev,
198 "Could not append IFLA_IFNAME attribute: %s",
203 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
205 log_error_netdev(netdev,
206 "Could not open IFLA_LINKINFO container: %s",
211 kind = netdev_kind_to_string(netdev->kind);
213 log_error_netdev(netdev, "Invalid kind");
217 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, kind);
219 log_error_netdev(netdev,
220 "Could not append IFLA_INFO_KIND attribute: %s",
225 if (netdev->vlanid >= 0) {
226 r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
228 log_error_netdev(netdev,
229 "Could not open IFLA_INFO_DATA container: %s",
234 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
236 log_error_netdev(netdev,
237 "Could not append IFLA_VLAN_ID attribute: %s",
242 r = sd_rtnl_message_close_container(req);
244 log_error_netdev(netdev,
245 "Could not close IFLA_INFO_DATA container %s",
251 r = sd_rtnl_message_close_container(req);
253 log_error_netdev(netdev,
254 "Could not close IFLA_LINKINFO container %s",
260 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
262 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
264 log_error_netdev(netdev,
265 "Could not send rtnetlink message: %s", strerror(-r));
269 log_debug_netdev(netdev, "creating netdev");
271 netdev->state = NETDEV_STATE_CREATING;
276 int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
277 if (netdev->kind == NETDEV_KIND_VLAN)
278 return netdev_create(netdev, link, callback);
280 if (netdev->state == NETDEV_STATE_READY) {
281 netdev_enslave_ready(netdev, link, callback);
283 /* the netdev is not yet read, save this request for when it is*/
284 netdev_enslave_callback *cb;
286 cb = new0(netdev_enslave_callback, 1);
290 cb->callback = callback;
293 LIST_PREPEND(callbacks, netdev->callbacks, cb);
299 int netdev_set_ifindex(Netdev *netdev, int ifindex) {
303 if (netdev->ifindex > 0) {
304 if (netdev->ifindex == ifindex)
310 netdev->ifindex = ifindex;
312 netdev_enter_ready(netdev);
317 static int netdev_load_one(Manager *manager, const char *filename) {
318 _cleanup_netdev_free_ Netdev *netdev = NULL;
319 _cleanup_fclose_ FILE *file = NULL;
325 file = fopen(filename, "re");
333 netdev = new0(Netdev, 1);
337 netdev->manager = manager;
338 netdev->state = _NETDEV_STATE_INVALID;
339 netdev->kind = _NETDEV_KIND_INVALID;
342 r = config_parse(NULL, filename, file, "Netdev\0VLAN\0", config_item_perf_lookup,
343 (void*) network_gperf_lookup, false, false, netdev);
345 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
349 if (netdev->kind == _NETDEV_KIND_INVALID) {
350 log_warning("Netdev without Kind configured in %s. Ignoring", filename);
355 log_warning("Netdev without Name configured in %s. Ignoring", filename);
359 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid < 0) {
360 log_warning("VLAN without Id configured in %s. Ignoring", filename);
364 netdev->filename = strdup(filename);
365 if (!netdev->filename)
368 r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev);
372 LIST_HEAD_INIT(netdev->callbacks);
374 if (netdev->kind != NETDEV_KIND_VLAN) {
375 r = netdev_create(netdev, NULL, NULL);
385 int netdev_load(Manager *manager) {
392 while ((netdev = hashmap_first(manager->netdevs)))
395 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
397 log_error("Failed to enumerate netdev files: %s", strerror(-r));
401 STRV_FOREACH_BACKWARDS(f, files) {
402 r = netdev_load_one(manager, *f);