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);
92 assert(netdev->manager);
93 assert(netdev->manager->rtnl);
97 r = sd_rtnl_message_new_link(netdev->manager->rtnl, RTM_SETLINK,
100 log_error_netdev(netdev,
101 "Could not allocate RTM_SETLINK message: %s",
106 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
108 log_error_netdev(netdev,
109 "Could not append IFLA_MASTER attribute: %s",
114 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
116 log_error_netdev(netdev,
117 "Could not send rtnetlink message: %s",
122 log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
127 static int netdev_enter_ready(NetDev *netdev) {
128 netdev_enslave_callback *callback;
131 assert(netdev->name);
133 netdev->state = NETDEV_STATE_READY;
135 log_info_netdev(netdev, "netdev ready");
137 LIST_FOREACH(callbacks, callback, netdev->callbacks) {
138 /* enslave the links that were attempted to be enslaved befor the
140 netdev_enslave_ready(netdev, callback->link, callback->callback);
146 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
147 NetDev *netdev = userdata;
150 assert(netdev->state != _NETDEV_STATE_INVALID);
152 r = sd_rtnl_message_get_errno(m);
154 log_warning_netdev(netdev, "netdev failed: %s", strerror(-r));
155 netdev_enter_failed(netdev);
163 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
164 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
169 assert(!(netdev->kind == NETDEV_KIND_VLAN) ||
170 (link && callback && netdev->vlanid <= VLANID_MAX));
171 assert(netdev->name);
172 assert(netdev->manager);
173 assert(netdev->manager->rtnl);
175 r = sd_rtnl_message_new_link(netdev->manager->rtnl, RTM_NEWLINK, 0, &req);
177 log_error_netdev(netdev,
178 "Could not allocate RTM_NEWLINK message: %s",
184 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
186 log_error_netdev(netdev,
187 "Could not append IFLA_LINK attribute: %s",
193 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
195 log_error_netdev(netdev,
196 "Could not append IFLA_IFNAME attribute: %s",
201 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
203 log_error_netdev(netdev,
204 "Could not open IFLA_LINKINFO container: %s",
209 kind = netdev_kind_to_string(netdev->kind);
211 log_error_netdev(netdev, "Invalid kind");
215 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, kind);
217 log_error_netdev(netdev,
218 "Could not append IFLA_INFO_KIND attribute: %s",
223 if (netdev->vlanid <= VLANID_MAX) {
224 r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
226 log_error_netdev(netdev,
227 "Could not open IFLA_INFO_DATA container: %s",
232 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
234 log_error_netdev(netdev,
235 "Could not append IFLA_VLAN_ID attribute: %s",
240 r = sd_rtnl_message_close_container(req);
242 log_error_netdev(netdev,
243 "Could not close IFLA_INFO_DATA container %s",
249 r = sd_rtnl_message_close_container(req);
251 log_error_netdev(netdev,
252 "Could not close IFLA_LINKINFO container %s",
258 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
260 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
262 log_error_netdev(netdev,
263 "Could not send rtnetlink message: %s", strerror(-r));
267 log_debug_netdev(netdev, "creating netdev");
269 netdev->state = NETDEV_STATE_CREATING;
274 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
275 if (netdev->kind == NETDEV_KIND_VLAN)
276 return netdev_create(netdev, link, callback);
278 if (netdev->state == NETDEV_STATE_READY) {
279 netdev_enslave_ready(netdev, link, callback);
281 /* the netdev is not yet read, save this request for when it is*/
282 netdev_enslave_callback *cb;
284 cb = new0(netdev_enslave_callback, 1);
288 cb->callback = callback;
291 LIST_PREPEND(callbacks, netdev->callbacks, cb);
297 int netdev_set_ifindex(NetDev *netdev, int ifindex) {
301 if (netdev->ifindex > 0) {
302 if (netdev->ifindex == ifindex)
308 netdev->ifindex = ifindex;
310 netdev_enter_ready(netdev);
315 static int netdev_load_one(Manager *manager, const char *filename) {
316 _cleanup_netdev_free_ NetDev *netdev = NULL;
317 _cleanup_fclose_ FILE *file = NULL;
323 file = fopen(filename, "re");
331 netdev = new0(NetDev, 1);
335 netdev->manager = manager;
336 netdev->state = _NETDEV_STATE_INVALID;
337 netdev->kind = _NETDEV_KIND_INVALID;
338 netdev->vlanid = VLANID_MAX + 1;
340 r = config_parse(NULL, filename, file, "NetDev\0VLAN\0", config_item_perf_lookup,
341 (void*) network_gperf_lookup, false, false, netdev);
343 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
347 if (netdev->kind == _NETDEV_KIND_INVALID) {
348 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
353 log_warning("NetDev without Name configured in %s. Ignoring", filename);
357 if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
358 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
362 netdev->filename = strdup(filename);
363 if (!netdev->filename)
366 r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev);
370 LIST_HEAD_INIT(netdev->callbacks);
372 if (netdev->kind != NETDEV_KIND_VLAN) {
373 r = netdev_create(netdev, NULL, NULL);
383 int netdev_load(Manager *manager) {
390 while ((netdev = hashmap_first(manager->netdevs)))
393 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
395 log_error("Failed to enumerate netdev files: %s", strerror(-r));
399 STRV_FOREACH_BACKWARDS(f, files) {
400 r = netdev_load_one(manager, *f);