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 bridge = hashmap_get(manager->bridges, name);
69 static int bridge_enter_failed(Bridge *bridge) {
70 bridge->state = BRIDGE_STATE_FAILED;
75 static int bridge_join_ready(Bridge *bridge, Link* link, sd_rtnl_message_handler_t callback) {
76 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
80 assert(bridge->state == BRIDGE_STATE_READY);
84 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
86 log_error_bridge(bridge,
87 "Could not allocate RTM_SETLINK message: %s",
92 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, bridge->link->ifindex);
94 log_error_bridge(bridge,
95 "Could not append IFLA_MASTER attribute: %s",
100 r = sd_rtnl_call_async(bridge->manager->rtnl, req, callback, link, 0, NULL);
102 log_error_bridge(bridge,
103 "Could not send rtnetlink message: %s",
108 log_debug_bridge(bridge, "joining link %s to bridge", link->ifname);
113 static int bridge_enter_ready(Bridge *bridge) {
114 bridge_join_callback *callback;
116 bridge->state = BRIDGE_STATE_READY;
118 log_info_bridge(bridge, "bridge ready");
120 LIST_FOREACH(callbacks, callback, bridge->callbacks) {
121 /* join the links that were attempted to be joined befor the
123 bridge_join_ready(bridge, callback->link, callback->callback);
129 static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
130 Bridge *bridge = userdata;
133 assert(bridge->state == BRIDGE_STATE_CREATING);
135 r = sd_rtnl_message_get_errno(m);
137 log_warning_bridge(bridge, "bridge failed: %s", strerror(-r));
138 bridge_enter_failed(bridge);
144 bridge_enter_ready(bridge);
146 bridge->state = BRIDGE_STATE_CREATED;
151 static int bridge_create(Bridge *bridge) {
152 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
156 assert(bridge->state == _BRIDGE_STATE_INVALID);
157 assert(bridge->name);
158 assert(bridge->manager);
159 assert(bridge->manager->rtnl);
161 r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req);
163 log_error_bridge(bridge,
164 "Could not allocate RTM_NEWLINK message: %s",
169 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, bridge->name);
171 log_error_bridge(bridge,
172 "Could not append IFLA_IFNAME attribute: %s",
177 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
179 log_error_bridge(bridge,
180 "Could not open IFLA_LINKINFO container: %s",
185 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, "bridge");
187 log_error_bridge(bridge,
188 "Could not append IFLA_INFO_KIND attribute: %s",
193 r = sd_rtnl_message_close_container(req);
195 log_error_bridge(bridge,
196 "Could not close IFLA_LINKINFO container %s",
201 r = sd_rtnl_call_async(bridge->manager->rtnl, req, &bridge_create_handler, bridge, 0, NULL);
203 log_error_bridge(bridge,
204 "Could not send rtnetlink message: %s", strerror(-r));
208 log_debug_bridge(bridge, "creating bridge");
210 bridge->state = BRIDGE_STATE_CREATING;
215 int bridge_join(Bridge *bridge, Link *link, sd_rtnl_message_handler_t callback) {
216 if (bridge->state == BRIDGE_STATE_READY) {
217 bridge_join_ready(bridge, link, callback);
219 /* the bridge is not yet read, save this request for when it is*/
220 bridge_join_callback *cb;
222 cb = new0(bridge_join_callback, 1);
226 cb->callback = callback;
229 LIST_PREPEND(callbacks, bridge->callbacks, cb);
235 int bridge_set_link(Manager *m, Link *link) {
238 bridge = hashmap_get(m->bridges, link->ifname);
242 if (bridge->link && bridge->link != link)
247 if (bridge->state == BRIDGE_STATE_CREATED)
248 bridge_enter_ready(bridge);
253 static int bridge_load_one(Manager *manager, const char *filename) {
254 _cleanup_bridge_free_ Bridge *bridge = NULL;
255 _cleanup_fclose_ FILE *file = NULL;
261 file = fopen(filename, "re");
269 bridge = new0(Bridge, 1);
273 bridge->manager = manager;
274 bridge->state = _BRIDGE_STATE_INVALID;
276 r = config_parse(NULL, filename, file, "Bridge\0", config_item_perf_lookup,
277 (void*) network_gperf_lookup, false, false, bridge);
279 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
284 log_warning("Bridge without Name configured in %s. Ignoring", filename);
288 bridge->filename = strdup(filename);
289 if (!bridge->filename)
292 r = hashmap_put(bridge->manager->bridges, bridge->name, bridge);
296 LIST_HEAD_INIT(bridge->callbacks);
298 r = bridge_create(bridge);
307 int bridge_load(Manager *manager) {
314 while ((bridge = hashmap_first(manager->bridges)))
317 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
319 log_error("Failed to enumerate netdev files: %s", strerror(-r));
323 STRV_FOREACH_BACKWARDS(f, files) {
324 r = bridge_load_one(manager, *f);