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",
111 log_debug_bridge(bridge, "joining link %s to bridge", link->ifname);
116 static int bridge_enter_ready(Bridge *bridge) {
117 bridge_join_callback *callback;
119 bridge->state = BRIDGE_STATE_READY;
121 log_info_bridge(bridge, "bridge ready");
123 LIST_FOREACH(callbacks, callback, bridge->callbacks) {
124 /* join the links that were attempted to be joined befor the
126 bridge_join_ready(bridge, callback->link, callback->callback);
132 static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
133 Bridge *bridge = userdata;
136 assert(bridge->state == BRIDGE_STATE_CREATING);
138 r = sd_rtnl_message_get_errno(m);
140 log_warning_bridge(bridge, "bridge failed: %s", strerror(-r));
141 bridge_enter_failed(bridge);
147 bridge_enter_ready(bridge);
149 bridge->state = BRIDGE_STATE_CREATED;
154 static int bridge_create(Bridge *bridge) {
155 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
159 assert(bridge->state == _BRIDGE_STATE_INVALID);
160 assert(bridge->name);
161 assert(bridge->manager);
162 assert(bridge->manager->rtnl);
164 r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req);
166 log_error_bridge(bridge,
167 "Could not allocate RTM_NEWLINK message: %s",
172 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, bridge->name);
174 log_error_bridge(bridge,
175 "Could not append IFLA_IFNAME attribute: %s",
180 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
182 log_error_bridge(bridge,
183 "Could not open IFLA_LINKINFO container: %s",
188 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, "bridge");
190 log_error_bridge(bridge,
191 "Could not append IFLA_INFO_KIND attribute: %s",
196 r = sd_rtnl_message_close_container(req);
198 log_error_bridge(bridge,
199 "Could not close IFLA_LINKINFO container %s",
204 r = sd_rtnl_call_async(bridge->manager->rtnl, req, &bridge_create_handler, bridge, 0, NULL);
206 log_error_bridge(bridge,
207 "Could not send rtnetlink message: %s", strerror(-r));
211 log_debug_bridge(bridge, "creating bridge");
213 bridge->state = BRIDGE_STATE_CREATING;
218 int bridge_join(Bridge *bridge, Link *link, sd_rtnl_message_handler_t callback) {
219 if (bridge->state == BRIDGE_STATE_READY) {
220 bridge_join_ready(bridge, link, callback);
222 /* the bridge is not yet read, save this request for when it is*/
223 bridge_join_callback *cb;
225 cb = new0(bridge_join_callback, 1);
229 cb->callback = callback;
232 LIST_PREPEND(callbacks, bridge->callbacks, cb);
238 int bridge_set_link(Manager *m, Link *link) {
241 bridge = hashmap_get(m->bridges, link->ifname);
245 if (bridge->link && bridge->link != link)
250 if (bridge->state == BRIDGE_STATE_CREATED)
251 bridge_enter_ready(bridge);
256 static int bridge_load_one(Manager *manager, const char *filename) {
257 _cleanup_bridge_free_ Bridge *bridge = NULL;
258 _cleanup_fclose_ FILE *file = NULL;
264 file = fopen(filename, "re");
272 bridge = new0(Bridge, 1);
276 bridge->manager = manager;
277 bridge->state = _BRIDGE_STATE_INVALID;
279 r = config_parse(NULL, filename, file, "Bridge\0", config_item_perf_lookup,
280 (void*) network_gperf_lookup, false, false, bridge);
282 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
287 log_warning("Bridge without Name configured in %s. Ignoring", filename);
291 bridge->filename = strdup(filename);
292 if (!bridge->filename)
295 r = hashmap_put(bridge->manager->bridges, bridge->name, bridge);
299 LIST_HEAD_INIT(bridge->callbacks);
301 r = bridge_create(bridge);
310 int bridge_load(Manager *manager) {
317 while ((bridge = hashmap_first(manager->bridges)))
320 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
322 log_error("Failed to enumerate netdev files: %s", strerror(-r));
326 STRV_FOREACH_BACKWARDS(f, files) {
327 r = bridge_load_one(manager, *f);