chiark / gitweb /
core: initialize variable
[elogind.git] / src / network / networkd-link.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 <netinet/ether.h>
23 #include <linux/if.h>
24
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "util.h"
28
29 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30         _cleanup_link_free_ Link *link = NULL;
31         const char *mac;
32         struct ether_addr *mac_addr;
33         const char *ifname;
34         int r;
35
36         assert(device);
37         assert(ret);
38
39         link = new0(Link, 1);
40         if (!link)
41                 return -ENOMEM;
42
43         link->manager = manager;
44         link->state = _LINK_STATE_INVALID;
45
46         link->ifindex = udev_device_get_ifindex(device);
47         if (link->ifindex <= 0)
48                 return -EINVAL;
49
50         mac = udev_device_get_sysattr_value(device, "address");
51         if (mac) {
52                 mac_addr = ether_aton(mac);
53                 if (mac_addr)
54                         memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
55         }
56
57         ifname = udev_device_get_sysname(device);
58         link->ifname = strdup(ifname);
59
60         r = hashmap_put(manager->links, &link->ifindex, link);
61         if (r < 0)
62                 return r;
63
64         *ret = link;
65         link = NULL;
66
67         return 0;
68 }
69
70 void link_free(Link *link) {
71         if (!link)
72                 return;
73
74         assert(link->manager);
75
76         hashmap_remove(link->manager->links, &link->ifindex);
77
78         free(link->ifname);
79
80         free(link);
81 }
82
83 int link_add(Manager *m, struct udev_device *device) {
84         Link *link;
85         Network *network;
86         int r;
87         uint64_t ifindex;
88         const char *devtype;
89
90         assert(m);
91         assert(device);
92
93         ifindex = udev_device_get_ifindex(device);
94         link = hashmap_get(m->links, &ifindex);
95         if (link)
96                 return 0;
97
98         r = link_new(m, device, &link);
99         if (r < 0) {
100                 log_error("Could not create link: %s", strerror(-r));
101                 return r;
102         }
103
104         devtype = udev_device_get_devtype(device);
105         if (streq_ptr(devtype, "bridge")) {
106                 r = bridge_set_link(m, link);
107                 if (r < 0)
108                         return r == -ENOENT ? 0 : r;
109         }
110
111         r = network_get(m, device, &network);
112         if (r < 0)
113                 return r == -ENOENT ? 0 : r;
114
115         r = network_apply(m, network, link);
116         if (r < 0)
117                 return r;
118
119         return 0;
120 }
121
122 static int link_enter_configured(Link *link) {
123         log_info("Link '%s' configured", link->ifname);
124
125         link->state = LINK_STATE_CONFIGURED;
126
127         return 0;
128 }
129
130 static int link_enter_failed(Link *link) {
131         log_warning("Could not configure link '%s'", link->ifname);
132
133         link->state = LINK_STATE_FAILED;
134
135         return 0;
136 }
137
138 static bool link_is_up(Link *link) {
139         return link->flags & IFF_UP;
140 }
141
142 static int link_enter_routes_set(Link *link) {
143         log_info("Routes set for link '%s'", link->ifname);
144
145         if (link_is_up(link))
146                 return link_enter_configured(link);
147
148         link->state = LINK_STATE_ROUTES_SET;
149
150         return 0;
151 }
152
153 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
154         Link *link = userdata;
155         int r;
156
157         assert(link->rtnl_messages > 0);
158         assert(link->state == LINK_STATE_SET_ROUTES || link->state == LINK_STATE_FAILED);
159
160         link->rtnl_messages --;
161
162         if (link->state == LINK_STATE_FAILED)
163                 return 1;
164
165         r = sd_rtnl_message_get_errno(m);
166         if (r < 0 && r != -EEXIST)
167                 log_warning("Could not set route on interface '%s': %s",
168                             link->ifname, strerror(-r));
169
170         if (link->rtnl_messages == 0)
171                 return link_enter_routes_set(link);
172
173         return 1;
174 }
175
176 static int link_enter_set_routes(Link *link) {
177         Route *route;
178         int r;
179
180         assert(link);
181         assert(link->network);
182         assert(link->rtnl_messages == 0);
183         assert(link->state == LINK_STATE_ADDRESSES_SET);
184
185         link->state = LINK_STATE_SET_ROUTES;
186
187         if (!link->network->routes)
188                 return link_enter_routes_set(link);
189
190         LIST_FOREACH(routes, route, link->network->routes) {
191                 r = route_configure(route, link, &route_handler);
192                 if (r < 0)
193                         return link_enter_failed(link);
194
195                 link->rtnl_messages ++;
196         }
197
198         return 0;
199 }
200
201 static int link_enter_addresses_set(Link *link) {
202         log_info("Addresses set for link '%s'", link->ifname);
203
204         link->state = LINK_STATE_ADDRESSES_SET;
205
206         return link_enter_set_routes(link);
207 }
208
209 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
210         Link *link = userdata;
211         int r;
212
213         assert(link->rtnl_messages > 0);
214         assert(link->state == LINK_STATE_SET_ADDRESSES || link->state == LINK_STATE_FAILED);
215
216         link->rtnl_messages --;
217
218         if (link->state == LINK_STATE_FAILED)
219                 return 1;
220
221         r = sd_rtnl_message_get_errno(m);
222         if (r < 0 && r != -EEXIST)
223                 log_warning("Could not set address on interface '%s': %s",
224                             link->ifname, strerror(-r));
225
226         if (link->rtnl_messages == 0)
227                 link_enter_addresses_set(link);
228
229         return 1;
230 }
231
232 static int link_enter_set_addresses(Link *link) {
233         Address *address;
234         int r;
235
236         assert(link);
237         assert(link->network);
238         assert(link->rtnl_messages == 0);
239
240         if (!link->network->addresses)
241                 return link_enter_addresses_set(link);
242
243         link->state = LINK_STATE_SET_ADDRESSES;
244
245         LIST_FOREACH(addresses, address, link->network->addresses) {
246                 r = address_configure(address, link, &address_handler);
247                 if (r < 0)
248                         return link_enter_failed(link);
249
250                 link->rtnl_messages ++;
251         }
252
253         return 0;
254 }
255
256 static int link_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
257         Link *link = userdata;
258         int r;
259
260         r = sd_rtnl_message_get_errno(m);
261         if (r < 0)
262                 log_warning("Could not bring up interface '%s': %s",
263                             link->ifname, strerror(-r));
264
265         link->flags |= IFF_UP;
266
267         log_info("Link '%s' is up", link->ifname);
268
269         if (link->state == LINK_STATE_ROUTES_SET)
270                 return link_enter_configured(link);
271
272         return 1;
273 }
274
275 static int link_up(Link *link) {
276         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
277         int r;
278
279         assert(link);
280         assert(link->manager);
281         assert(link->manager->rtnl);
282
283         r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
284         if (r < 0) {
285                 log_error("Could not allocate RTM_NEWLINK message");
286                 return r;
287         }
288
289         r = sd_rtnl_call_async(link->manager->rtnl, req, link_handler, link, 0, NULL);
290         if (r < 0) {
291                 log_error("Could not send rtnetlink message: %s", strerror(-r));
292                 return r;
293         }
294
295         return 0;
296 }
297
298 static int link_enter_bridge_joined(Link *link) {
299         int r;
300
301         r = link_up(link);
302         if (r < 0)
303                 return link_enter_failed(link);
304
305         link->state = LINK_STATE_BRIDGE_JOINED;
306
307         return link_enter_set_addresses(link);
308 }
309
310 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
311         Link *link = userdata;
312         int r;
313
314         assert(link->state == LINK_STATE_JOIN_BRIDGE || link->state == LINK_STATE_FAILED);
315
316         if (link->state == LINK_STATE_FAILED)
317                 return 1;
318
319         r = sd_rtnl_message_get_errno(m);
320         if (r < 0)
321                 log_warning("Could not join interface '%s' to bridge: %s",
322                             link->ifname, strerror(-r));
323
324         link_enter_bridge_joined(link);
325
326         return 1;
327 }
328
329 static int link_enter_join_bridge(Link *link) {
330         int r;
331
332         assert(link);
333         assert(link->network);
334
335         if (!link->network->bridge)
336                 return link_enter_bridge_joined(link);
337
338         link->state = LINK_STATE_JOIN_BRIDGE;
339
340         r = bridge_join(link->network->bridge, link, &bridge_handler);
341         if (r < 0)
342                 return link_enter_failed(link);
343
344         return 0;
345 }
346
347 int link_configure(Link *link) {
348         int r;
349
350         r = link_enter_join_bridge(link);
351         if (r < 0)
352                 return link_enter_failed(link);
353
354         return 0;
355 }