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