chiark / gitweb /
networkd: improve logging a bit
[elogind.git] / src / network / networkd-bridge.c
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
29 void 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
51 int 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
72 static int bridge_enter_failed(Bridge *bridge) {
73         bridge->state = BRIDGE_STATE_FAILED;
74
75         return 0;
76 }
77
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;
80         int r;
81
82         assert(bridge);
83         assert(bridge->state == BRIDGE_STATE_READY);
84         assert(link);
85         assert(callback);
86
87         r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
88         if (r < 0) {
89                 log_error_bridge(bridge,
90                                  "Could not allocate RTM_SETLINK message: %s",
91                                  strerror(-r));
92                 return r;
93         }
94
95         r = sd_rtnl_message_append_u32(req, IFLA_MASTER, bridge->link->ifindex);
96         if (r < 0) {
97                 log_error_bridge(bridge,
98                                  "Could not append IFLA_MASTER attribute: %s",
99                                  strerror(-r));
100                 return r;
101         }
102
103         r = sd_rtnl_call_async(bridge->manager->rtnl, req, callback, link, 0, NULL);
104         if (r < 0) {
105                 log_error_bridge(bridge,
106                                  "Could not send rtnetlink message: %s",
107                                  strerror(-r));
108                 return r;
109         }
110
111         log_debug_bridge(bridge, "joining link %s to bridge", link->ifname);
112
113         return 0;
114 }
115
116 static int bridge_enter_ready(Bridge *bridge) {
117         bridge_join_callback *callback;
118
119         bridge->state = BRIDGE_STATE_READY;
120
121         log_info_bridge(bridge, "bridge ready");
122
123         LIST_FOREACH(callbacks, callback, bridge->callbacks) {
124                 /* join the links that were attempted to be joined befor the
125                  * link was ready */
126                 bridge_join_ready(bridge, callback->link, callback->callback);
127         }
128
129         return 0;
130 }
131
132 static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
133         Bridge *bridge = userdata;
134         int r;
135
136         assert(bridge->state == BRIDGE_STATE_CREATING);
137
138         r = sd_rtnl_message_get_errno(m);
139         if (r < 0) {
140                 log_warning_bridge(bridge, "bridge failed: %s", strerror(-r));
141                 bridge_enter_failed(bridge);
142
143                 return 1;
144         }
145
146         if (bridge->link)
147                 bridge_enter_ready(bridge);
148         else
149                 bridge->state = BRIDGE_STATE_CREATED;
150
151         return 1;
152 }
153
154 static int bridge_create(Bridge *bridge) {
155         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
156         int r;
157
158         assert(bridge);
159         assert(bridge->state == _BRIDGE_STATE_INVALID);
160         assert(bridge->name);
161         assert(bridge->manager);
162         assert(bridge->manager->rtnl);
163
164         r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req);
165         if (r < 0) {
166                 log_error_bridge(bridge,
167                                  "Could not allocate RTM_NEWLINK message: %s",
168                                  strerror(-r));
169                 return r;
170         }
171
172         r = sd_rtnl_message_append_string(req, IFLA_IFNAME, bridge->name);
173         if (r < 0) {
174                 log_error_bridge(bridge,
175                                  "Could not append IFLA_IFNAME attribute: %s",
176                                  strerror(-r));
177                 return r;
178         }
179
180         r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
181         if (r < 0) {
182                 log_error_bridge(bridge,
183                                  "Could not open IFLA_LINKINFO container: %s",
184                                  strerror(-r));
185                 return r;
186         }
187
188         r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, "bridge");
189         if (r < 0) {
190                 log_error_bridge(bridge,
191                                  "Could not append IFLA_INFO_KIND attribute: %s",
192                                  strerror(-r));
193                 return r;
194         }
195
196         r = sd_rtnl_message_close_container(req);
197         if (r < 0) {
198                 log_error_bridge(bridge,
199                                  "Could not close IFLA_LINKINFO container %s",
200                                  strerror(-r));
201                 return r;
202         }
203
204         r = sd_rtnl_call_async(bridge->manager->rtnl, req, &bridge_create_handler, bridge, 0, NULL);
205         if (r < 0) {
206                 log_error_bridge(bridge,
207                                  "Could not send rtnetlink message: %s", strerror(-r));
208                 return r;
209         }
210
211         log_debug_bridge(bridge, "creating bridge");
212
213         bridge->state = BRIDGE_STATE_CREATING;
214
215         return 0;
216 }
217
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);
221         } else {
222                 /* the bridge is not yet read, save this request for when it is*/
223                 bridge_join_callback *cb;
224
225                 cb = new0(bridge_join_callback, 1);
226                 if (!cb)
227                         return log_oom();
228
229                 cb->callback = callback;
230                 cb->link = link;
231
232                 LIST_PREPEND(callbacks, bridge->callbacks, cb);
233         }
234
235         return 0;
236 }
237
238 int bridge_set_link(Manager *m, Link *link) {
239         Bridge *bridge;
240
241         bridge = hashmap_get(m->bridges, link->ifname);
242         if (!bridge)
243                 return -ENOENT;
244
245         if (bridge->link && bridge->link != link)
246                 return -EEXIST;
247
248         bridge->link = link;
249
250         if (bridge->state == BRIDGE_STATE_CREATED)
251                 bridge_enter_ready(bridge);
252
253         return 0;
254 }
255
256 static int bridge_load_one(Manager *manager, const char *filename) {
257         _cleanup_bridge_free_ Bridge *bridge = NULL;
258         _cleanup_fclose_ FILE *file = NULL;
259         int r;
260
261         assert(manager);
262         assert(filename);
263
264         file = fopen(filename, "re");
265         if (!file) {
266                 if (errno == ENOENT)
267                         return 0;
268                 else
269                         return errno;
270         }
271
272         bridge = new0(Bridge, 1);
273         if (!bridge)
274                 return log_oom();
275
276         bridge->manager = manager;
277         bridge->state = _BRIDGE_STATE_INVALID;
278
279         r = config_parse(NULL, filename, file, "Bridge\0", config_item_perf_lookup,
280                         (void*) network_gperf_lookup, false, false, bridge);
281         if (r < 0) {
282                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
283                 return r;
284         }
285
286         if (!bridge->name) {
287                 log_warning("Bridge without Name configured in %s. Ignoring", filename);
288                 return 0;
289         }
290
291         bridge->filename = strdup(filename);
292         if (!bridge->filename)
293                 return log_oom();
294
295         r = hashmap_put(bridge->manager->bridges, bridge->name, bridge);
296         if (r < 0)
297                 return r;
298
299         LIST_HEAD_INIT(bridge->callbacks);
300
301         r = bridge_create(bridge);
302         if (r < 0)
303                 return r;
304
305         bridge = NULL;
306
307         return 0;
308 }
309
310 int bridge_load(Manager *manager) {
311         Bridge *bridge;
312         char **files, **f;
313         int r;
314
315         assert(manager);
316
317         while ((bridge = hashmap_first(manager->bridges)))
318                 bridge_free(bridge);
319
320         r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
321         if (r < 0) {
322                 log_error("Failed to enumerate netdev files: %s", strerror(-r));
323                 return r;
324         }
325
326         STRV_FOREACH_BACKWARDS(f, files) {
327                 r = bridge_load_one(manager, *f);
328                 if (r < 0)
329                         return r;
330         }
331
332         strv_free(files);
333
334         return 0;
335 }