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, &req);
89 log_error_bridge(bridge,
90 "Could not allocate RTM_SETLINK message: %s",
95 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, bridge->link->ifindex);
97 log_error_bridge(bridge,
98 "Could not append IFLA_MASTER attribute: %s",
103 r = sd_rtnl_call_async(bridge->manager->rtnl, req, callback, link, 0, NULL);
105 log_error_bridge(bridge,
106 "Could not send rtnetlink message: %s",
114 static int bridge_enter_ready(Bridge *bridge) {
115 bridge_join_callback *callback;
117 bridge->state = BRIDGE_STATE_READY;
119 log_bridge_info(bridge, "bridge ready");
121 LIST_FOREACH(callbacks, callback, bridge->callbacks) {
122 /* join the links that were attempted to be joined befor the
124 bridge_join_ready(bridge, callback->link, callback->callback);
130 static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
131 Bridge *bridge = userdata;
134 assert(bridge->state == BRIDGE_STATE_CREATING);
136 r = sd_rtnl_message_get_errno(m);
138 log_warning_bridge(bridge, "bridge failed: %s", strerror(-r));
139 bridge_enter_failed(bridge);
145 bridge_enter_ready(bridge);
147 bridge->state = BRIDGE_STATE_CREATED;
152 static int bridge_create(Bridge *bridge) {
153 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
157 assert(bridge->state == _BRIDGE_STATE_INVALID);
158 assert(bridge->name);
159 assert(bridge->manager);
160 assert(bridge->manager->rtnl);
162 r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req);
164 log_error_bridge(bridge,
165 "Could not allocate RTM_NEWLINK message: %s",
170 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, bridge->name);
172 log_error_bridge(bridge,
173 "Could not append IFLA_IFNAME attribute: %s",
178 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
180 log_error_bridge(bridge,
181 "Could not open IFLA_LINKINFO container: %s",
186 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, "bridge");
188 log_error_bridge(bridge,
189 "Could not append IFLA_INFO_KIND attribute: %s",
194 r = sd_rtnl_message_close_container(req);
196 log_error_bridge(bridge,
197 "Could not close IFLA_LINKINFO container %s",
202 r = sd_rtnl_call_async(bridge->manager->rtnl, req, &bridge_create_handler, bridge, 0, NULL);
204 log_error_bridge(bridge,
205 "Could not send rtnetlink message: %s", strerror(-r));
209 log_bridge_debug(bridge, "creating bridge");
211 bridge->state = BRIDGE_STATE_CREATING;
216 int bridge_join(Bridge *bridge, Link *link, sd_rtnl_message_handler_t callback) {
217 if (bridge->state == BRIDGE_STATE_READY) {
218 bridge_join_ready(bridge, link, callback);
220 /* the bridge is not yet read, save this request for when it is*/
221 bridge_join_callback *cb;
223 cb = new0(bridge_join_callback, 1);
227 cb->callback = callback;
230 LIST_PREPEND(callbacks, bridge->callbacks, cb);
236 int bridge_set_link(Manager *m, Link *link) {
239 bridge = hashmap_get(m->bridges, link->ifname);
243 if (bridge->link && bridge->link != link)
248 if (bridge->state == BRIDGE_STATE_CREATED)
249 bridge_enter_ready(bridge);
254 static int bridge_load_one(Manager *manager, const char *filename) {
255 _cleanup_bridge_free_ Bridge *bridge = NULL;
256 _cleanup_fclose_ FILE *file = NULL;
262 file = fopen(filename, "re");
270 bridge = new0(Bridge, 1);
274 bridge->manager = manager;
275 bridge->state = _BRIDGE_STATE_INVALID;
277 r = config_parse(NULL, filename, file, "Bridge\0", config_item_perf_lookup,
278 (void*) network_gperf_lookup, false, false, bridge);
280 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
285 log_warning("Bridge without Name configured in %s. Ignoring", filename);
289 bridge->filename = strdup(filename);
290 if (!bridge->filename)
293 r = hashmap_put(bridge->manager->bridges, bridge->name, bridge);
297 LIST_HEAD_INIT(bridge->callbacks);
299 r = bridge_create(bridge);
308 int bridge_load(Manager *manager) {
315 while ((bridge = hashmap_first(manager->bridges)))
318 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
320 log_error("Failed to enumerate netdev files: %s", strerror(-r));
324 STRV_FOREACH_BACKWARDS(f, files) {
325 r = bridge_load_one(manager, *f);