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 void bridge_free(Bridge *bridge) {
30 bridge_join_callback *callback;
35 while ((callback = bridge->callbacks)) {
36 LIST_REMOVE(callbacks, bridge->callbacks, callback);
41 hashmap_remove(bridge->manager->bridges, bridge->name);
43 free(bridge->filename);
45 free(bridge->description);
51 int bridge_get(Manager *manager, const char *name, Bridge **ret) {
58 if (manager_should_reload(manager))
59 manager_load_config(manager);
61 bridge = hashmap_get(manager->bridges, name);
72 static int bridge_enter_failed(Bridge *bridge) {
73 bridge->state = BRIDGE_STATE_FAILED;
78 static int bridge_join_ready(Bridge *bridge, Link* link, sd_rtnl_message_handler_t callback) {
79 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
83 assert(bridge->state == BRIDGE_STATE_READY);
87 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, 0, 0, &req);
89 log_error("Could not allocate RTM_SETLINK message: %s",
94 r = sd_rtnl_message_append(req, IFLA_MASTER, &bridge->link->ifindex);
96 log_error("Could not append IFLA_MASTER attribute: %s",
101 r = sd_rtnl_call_async(bridge->manager->rtnl, req, callback, link, 0, NULL);
103 log_error("Could not send rtnetlink message: %s", strerror(-r));
110 static int bridge_enter_ready(Bridge *bridge) {
111 bridge_join_callback *callback;
113 bridge->state = BRIDGE_STATE_READY;
115 log_info("Bridge '%s' ready", bridge->name);
117 LIST_FOREACH(callbacks, callback, bridge->callbacks) {
118 /* join the links that were attempted to be joined befor the
120 bridge_join_ready(bridge, callback->link, callback->callback);
126 static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
127 Bridge *bridge = userdata;
130 assert(bridge->state == BRIDGE_STATE_CREATING);
132 r = sd_rtnl_message_get_errno(m);
134 log_warning("Bridge '%s' failed: %s", bridge->name, strerror(-r));
135 return bridge_enter_failed(bridge);
139 return bridge_enter_ready(bridge);
141 bridge->state = BRIDGE_STATE_CREATED;
146 static int bridge_create(Bridge *bridge) {
147 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
151 assert(bridge->state == _BRIDGE_STATE_INVALID);
152 assert(bridge->name);
153 assert(bridge->manager);
154 assert(bridge->manager->rtnl);
156 r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, 0, 0, &req);
158 log_error("Could not allocate RTM_NEWLINK message: %s",
163 r = sd_rtnl_message_append(req, IFLA_IFNAME, bridge->name);
165 log_error("Could not append IFLA_IFNAME attribute: %s",
170 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
172 log_error("Colud not open IFLA_LINKINFO container: %s",
177 r = sd_rtnl_message_append(req, IFLA_INFO_KIND, "bridge");
179 log_error("Could not append IFLA_INFO_KIND attribute: %s",
184 r = sd_rtnl_message_close_container(req);
186 log_error("Could not close IFLA_LINKINFO container %s",
191 r = sd_rtnl_call_async(bridge->manager->rtnl, req, &bridge_create_handler, bridge, 0, NULL);
193 log_error("Could not send rtnetlink message: %s", strerror(-r));
197 log_info("Creating bridge '%s'", bridge->name);
199 bridge->state = BRIDGE_STATE_CREATING;
204 int bridge_join(Bridge *bridge, Link *link, sd_rtnl_message_handler_t callback) {
205 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
207 if (bridge->state == BRIDGE_STATE_READY) {
208 bridge_join_ready(bridge, link, callback);
210 /* the bridge is not yet read, save this request for when it is*/
211 bridge_join_callback *cb;
213 cb = new0(bridge_join_callback, 1);
217 cb->callback = callback;
220 LIST_PREPEND(callbacks, bridge->callbacks, cb);
226 int bridge_set_link(Manager *m, Link *link) {
229 bridge = hashmap_get(m->bridges, link->ifname);
233 if (bridge->link && bridge->link != link)
238 if (bridge->state == BRIDGE_STATE_CREATED)
239 bridge_enter_ready(bridge);
244 static int bridge_load_one(Manager *manager, const char *filename) {
245 _cleanup_bridge_free_ Bridge *bridge = NULL;
246 _cleanup_fclose_ FILE *file = NULL;
249 file = fopen(filename, "re");
257 bridge = new0(Bridge, 1);
261 bridge->manager = manager;
262 bridge->state = _BRIDGE_STATE_INVALID;
264 r = config_parse(NULL, filename, file, "Bridge\0", config_item_perf_lookup,
265 (void*) network_gperf_lookup, false, false, bridge);
267 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
270 log_debug("Parsed configuration file %s", filename);
273 log_warning("Bridge without Name configured in %s. Ignoring", filename);
277 bridge->filename = strdup(filename);
278 if (!bridge->filename)
281 r = hashmap_put(bridge->manager->bridges, bridge->name, bridge);
285 LIST_HEAD_INIT(bridge->callbacks);
287 r = bridge_create(bridge);
296 int bridge_load(Manager *manager) {
303 while ((bridge = hashmap_first(manager->bridges)))
306 r = conf_files_list_strv(&files, ".netdev", NULL, (const char **)manager->network_dirs);
308 log_error("Failed to enumerate netdev files: %s", strerror(-r));
312 STRV_FOREACH_BACKWARDS(f, files) {
313 r = bridge_load_one(manager, *f);