]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-bridge.c
bus-proxyd: add some more debugging
[thirdparty/systemd.git] / src / network / networkd-bridge.c
CommitLineData
02b59d57
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
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.
12
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.
17
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/>.
20***/
21
22#include "networkd.h"
23#include "net-util.h"
24#include "path-util.h"
25#include "conf-files.h"
26#include "conf-parser.h"
27#include "list.h"
28
29void bridge_free(Bridge *bridge) {
30 bridge_join_callback *callback;
31
32 if (!bridge)
33 return;
34
35 while ((callback = bridge->callbacks)) {
36 LIST_REMOVE(callbacks, bridge->callbacks, callback);
37 free(callback);
38 }
39
40 if (bridge->name)
41 hashmap_remove(bridge->manager->bridges, bridge->name);
42
43 free(bridge->filename);
44
45 free(bridge->description);
46 free(bridge->name);
47
48 free(bridge);
49}
50
51int bridge_get(Manager *manager, const char *name, Bridge **ret) {
52 Bridge *bridge;
53
54 assert(manager);
55 assert(name);
56 assert(ret);
57
58 if (manager_should_reload(manager))
59 manager_load_config(manager);
60
61 bridge = hashmap_get(manager->bridges, name);
62 if (!bridge) {
63 *ret = NULL;
64 return -ENOENT;
65 }
66
67 *ret = bridge;
68
69 return 0;
70}
71
72static int bridge_enter_failed(Bridge *bridge) {
73 bridge->state = BRIDGE_STATE_FAILED;
74
75 return 0;
76}
77
78static 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;
80 int r;
81
82 assert(bridge);
83 assert(bridge->state == BRIDGE_STATE_READY);
84 assert(link);
85 assert(callback);
86
fc25d7f8 87 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
02b59d57 88 if (r < 0) {
3333d748
ZJS
89 log_error_bridge(bridge,
90 "Could not allocate RTM_SETLINK message: %s",
91 strerror(-r));
02b59d57
TG
92 return r;
93 }
94
0a0dc69b 95 r = sd_rtnl_message_append_u32(req, IFLA_MASTER, bridge->link->ifindex);
02b59d57 96 if (r < 0) {
3333d748
ZJS
97 log_error_bridge(bridge,
98 "Could not append IFLA_MASTER attribute: %s",
99 strerror(-r));
02b59d57
TG
100 return r;
101 }
102
103 r = sd_rtnl_call_async(bridge->manager->rtnl, req, callback, link, 0, NULL);
104 if (r < 0) {
3333d748
ZJS
105 log_error_bridge(bridge,
106 "Could not send rtnetlink message: %s",
107 strerror(-r));
02b59d57
TG
108 return r;
109 }
110
111 return 0;
112}
113
114static int bridge_enter_ready(Bridge *bridge) {
115 bridge_join_callback *callback;
116
117 bridge->state = BRIDGE_STATE_READY;
118
39032b87 119 log_info_bridge(bridge, "bridge ready");
02b59d57
TG
120
121 LIST_FOREACH(callbacks, callback, bridge->callbacks) {
122 /* join the links that were attempted to be joined befor the
123 * link was ready */
124 bridge_join_ready(bridge, callback->link, callback->callback);
125 }
126
127 return 0;
128}
129
130static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
131 Bridge *bridge = userdata;
132 int r;
133
134 assert(bridge->state == BRIDGE_STATE_CREATING);
135
136 r = sd_rtnl_message_get_errno(m);
137 if (r < 0) {
3333d748 138 log_warning_bridge(bridge, "bridge failed: %s", strerror(-r));
dd3efc09
TG
139 bridge_enter_failed(bridge);
140
141 return 1;
02b59d57
TG
142 }
143
144 if (bridge->link)
dd3efc09 145 bridge_enter_ready(bridge);
d638dee0
TG
146 else
147 bridge->state = BRIDGE_STATE_CREATED;
02b59d57 148
dd3efc09 149 return 1;
02b59d57
TG
150}
151
152static int bridge_create(Bridge *bridge) {
153 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
154 int r;
155
156 assert(bridge);
157 assert(bridge->state == _BRIDGE_STATE_INVALID);
158 assert(bridge->name);
159 assert(bridge->manager);
160 assert(bridge->manager->rtnl);
161
fc25d7f8 162 r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req);
02b59d57 163 if (r < 0) {
3333d748
ZJS
164 log_error_bridge(bridge,
165 "Could not allocate RTM_NEWLINK message: %s",
166 strerror(-r));
02b59d57
TG
167 return r;
168 }
169
0a0dc69b 170 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, bridge->name);
02b59d57 171 if (r < 0) {
3333d748
ZJS
172 log_error_bridge(bridge,
173 "Could not append IFLA_IFNAME attribute: %s",
174 strerror(-r));
02b59d57
TG
175 return r;
176 }
177
178 r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
179 if (r < 0) {
3333d748
ZJS
180 log_error_bridge(bridge,
181 "Could not open IFLA_LINKINFO container: %s",
182 strerror(-r));
02b59d57
TG
183 return r;
184 }
185
0a0dc69b 186 r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, "bridge");
02b59d57 187 if (r < 0) {
3333d748
ZJS
188 log_error_bridge(bridge,
189 "Could not append IFLA_INFO_KIND attribute: %s",
190 strerror(-r));
02b59d57
TG
191 return r;
192 }
193
194 r = sd_rtnl_message_close_container(req);
195 if (r < 0) {
3333d748
ZJS
196 log_error_bridge(bridge,
197 "Could not close IFLA_LINKINFO container %s",
198 strerror(-r));
02b59d57
TG
199 return r;
200 }
201
202 r = sd_rtnl_call_async(bridge->manager->rtnl, req, &bridge_create_handler, bridge, 0, NULL);
203 if (r < 0) {
3333d748
ZJS
204 log_error_bridge(bridge,
205 "Could not send rtnetlink message: %s", strerror(-r));
02b59d57
TG
206 return r;
207 }
208
39032b87 209 log_debug_bridge(bridge, "creating bridge");
02b59d57
TG
210
211 bridge->state = BRIDGE_STATE_CREATING;
212
213 return 0;
214}
215
216int bridge_join(Bridge *bridge, Link *link, sd_rtnl_message_handler_t callback) {
02b59d57
TG
217 if (bridge->state == BRIDGE_STATE_READY) {
218 bridge_join_ready(bridge, link, callback);
219 } else {
220 /* the bridge is not yet read, save this request for when it is*/
221 bridge_join_callback *cb;
222
223 cb = new0(bridge_join_callback, 1);
224 if (!cb)
225 return log_oom();
226
227 cb->callback = callback;
228 cb->link = link;
229
230 LIST_PREPEND(callbacks, bridge->callbacks, cb);
231 }
232
233 return 0;
234}
235
236int bridge_set_link(Manager *m, Link *link) {
237 Bridge *bridge;
238
239 bridge = hashmap_get(m->bridges, link->ifname);
240 if (!bridge)
241 return -ENOENT;
242
243 if (bridge->link && bridge->link != link)
244 return -EEXIST;
245
246 bridge->link = link;
247
248 if (bridge->state == BRIDGE_STATE_CREATED)
249 bridge_enter_ready(bridge);
250
251 return 0;
252}
253
254static int bridge_load_one(Manager *manager, const char *filename) {
255 _cleanup_bridge_free_ Bridge *bridge = NULL;
256 _cleanup_fclose_ FILE *file = NULL;
257 int r;
258
bf1bc670
TA
259 assert(manager);
260 assert(filename);
261
02b59d57
TG
262 file = fopen(filename, "re");
263 if (!file) {
264 if (errno == ENOENT)
265 return 0;
266 else
267 return errno;
268 }
269
270 bridge = new0(Bridge, 1);
271 if (!bridge)
272 return log_oom();
273
274 bridge->manager = manager;
275 bridge->state = _BRIDGE_STATE_INVALID;
276
277 r = config_parse(NULL, filename, file, "Bridge\0", config_item_perf_lookup,
278 (void*) network_gperf_lookup, false, false, bridge);
279 if (r < 0) {
280 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
281 return r;
449f7554 282 }
02b59d57
TG
283
284 if (!bridge->name) {
285 log_warning("Bridge without Name configured in %s. Ignoring", filename);
286 return 0;
287 }
288
289 bridge->filename = strdup(filename);
290 if (!bridge->filename)
291 return log_oom();
292
293 r = hashmap_put(bridge->manager->bridges, bridge->name, bridge);
294 if (r < 0)
295 return r;
296
297 LIST_HEAD_INIT(bridge->callbacks);
298
299 r = bridge_create(bridge);
300 if (r < 0)
301 return r;
302
303 bridge = NULL;
304
305 return 0;
306}
307
308int bridge_load(Manager *manager) {
309 Bridge *bridge;
310 char **files, **f;
311 int r;
312
313 assert(manager);
314
315 while ((bridge = hashmap_first(manager->bridges)))
316 bridge_free(bridge);
317
2ad8416d 318 r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
02b59d57
TG
319 if (r < 0) {
320 log_error("Failed to enumerate netdev files: %s", strerror(-r));
321 return r;
322 }
323
324 STRV_FOREACH_BACKWARDS(f, files) {
325 r = bridge_load_one(manager, *f);
326 if (r < 0)
327 return r;
328 }
329
330 strv_free(files);
331
332 return 0;
333}