chiark / gitweb /
cc5441bc3f088e8e3d94908331fe8c78c878df4f
[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         assert(link);
124         assert(link->state == LINK_STATE_SETTING_ROUTES);
125
126         log_info("Link '%s' configured", link->ifname);
127
128         link->state = LINK_STATE_CONFIGURED;
129
130         return 0;
131 }
132
133 static void link_enter_failed(Link *link) {
134         assert(link);
135
136         link->state = LINK_STATE_FAILED;
137 }
138
139 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
140         Link *link = userdata;
141         int r;
142
143         assert(link->rtnl_messages > 0);
144         assert(link->state == LINK_STATE_SETTING_ROUTES || link->state == LINK_STATE_FAILED);
145
146         link->rtnl_messages --;
147
148         if (link->state == LINK_STATE_FAILED)
149                 return 1;
150
151         r = sd_rtnl_message_get_errno(m);
152         if (r < 0 && r != -EEXIST)
153                 log_warning("Could not set route on interface '%s': %s",
154                             link->ifname, strerror(-r));
155
156         if (link->rtnl_messages == 0) {
157                 log_info("Routes set for link '%s'", link->ifname);
158                 link_enter_configured(link);
159         }
160
161         return 1;
162 }
163
164 static int link_enter_set_routes(Link *link) {
165         Route *route;
166         int r;
167
168         assert(link);
169         assert(link->network);
170         assert(link->rtnl_messages == 0);
171         assert(link->state == LINK_STATE_SETTING_ADDRESSES);
172
173         link->state = LINK_STATE_SETTING_ROUTES;
174
175         if (!link->network->routes)
176                 return link_enter_configured(link);
177
178         LIST_FOREACH(routes, route, link->network->routes) {
179                 r = route_configure(route, link, &route_handler);
180                 if (r < 0) {
181                         log_warning("Could not set routes for link '%s'", link->ifname);
182                         link_enter_failed(link);
183                         return r;
184                 }
185
186                 link->rtnl_messages ++;
187         }
188
189         return 0;
190 }
191
192 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
193         Link *link = userdata;
194         int r;
195
196         assert(link->rtnl_messages > 0);
197         assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
198
199         link->rtnl_messages --;
200
201         if (link->state == LINK_STATE_FAILED)
202                 return 1;
203
204         r = sd_rtnl_message_get_errno(m);
205         if (r < 0 && r != -EEXIST)
206                 log_warning("Could not set address on interface '%s': %s",
207                             link->ifname, strerror(-r));
208
209         if (link->rtnl_messages == 0) {
210                 log_info("Addresses set for link '%s'", link->ifname);
211                 link_enter_set_routes(link);
212         }
213
214         return 1;
215 }
216
217 static int link_enter_set_addresses(Link *link) {
218         Address *address;
219         int r;
220
221         assert(link);
222         assert(link->network);
223         assert(link->state == LINK_STATE_JOINING_BRIDGE);
224         assert(link->rtnl_messages == 0);
225
226         link->state = LINK_STATE_SETTING_ADDRESSES;
227
228         if (!link->network->addresses)
229                 return link_enter_set_routes(link);
230
231         LIST_FOREACH(addresses, address, link->network->addresses) {
232                 r = address_configure(address, link, &address_handler);
233                 if (r < 0) {
234                         log_warning("Could not set addresses for link '%s'", link->ifname);
235                         link_enter_failed(link);
236                         return r;
237                 }
238
239                 link->rtnl_messages ++;
240         }
241
242         return 0;
243 }
244
245 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
246         Link *link = userdata;
247         int r;
248
249         r = sd_rtnl_message_get_errno(m);
250         if (r < 0) {
251                 log_warning("Could not bring up interface '%s': %s",
252                             link->ifname, strerror(-r));
253                 link_enter_failed(link);
254         }
255
256         return 1;
257 }
258
259 static int link_up(Link *link) {
260         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
261         int r;
262
263         assert(link);
264         assert(link->manager);
265         assert(link->manager->rtnl);
266
267         r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
268         if (r < 0) {
269                 log_error("Could not allocate RTM_SETLINK message");
270                 return r;
271         }
272
273         r = sd_rtnl_message_link_set_flags(req, IFF_UP);
274         if (r < 0) {
275                 log_error("Could not set link flags");
276                 return r;
277         }
278
279         r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
280         if (r < 0) {
281                 log_error("Could not send rtnetlink message: %s", strerror(-r));
282                 return r;
283         }
284
285         return 0;
286 }
287
288 static int link_bridge_joined(Link *link) {
289         int r;
290
291         assert(link);
292         assert(link->state == LINK_STATE_JOINING_BRIDGE);
293
294         r = link_up(link);
295         if (r < 0) {
296                 link_enter_failed(link);
297                 return r;
298         }
299
300         r = link_enter_set_addresses(link);
301         if (r < 0) {
302                 link_enter_failed(link);
303                 return r;
304         }
305
306         return 0;
307 }
308
309 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
310         Link *link = userdata;
311         int r;
312
313         assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
314         assert(link->network);
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': %s",
322                             link->ifname, link->network->bridge->name, strerror(-r));
323                 link_enter_failed(link);
324                 return 1;
325         } else
326                 log_info("Join interface '%s' to bridge: %s",
327                             link->ifname, link->network->bridge->name);
328
329         link_bridge_joined(link);
330
331         return 1;
332 }
333
334 static int link_enter_join_bridge(Link *link) {
335         int r;
336
337         assert(link);
338         assert(link->network);
339         assert(link->state == _LINK_STATE_INVALID);
340
341         link->state = LINK_STATE_JOINING_BRIDGE;
342
343         if (!link->network->bridge)
344                 return link_bridge_joined(link);
345
346         r = bridge_join(link->network->bridge, link, &bridge_handler);
347         if (r < 0) {
348                 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
349                             link->network->bridge->name);
350                 link_enter_failed(link);
351                 return r;
352         }
353
354         return 0;
355 }
356
357 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
358         Link *link = userdata;
359         int r;
360
361         r = sd_rtnl_message_get_errno(m);
362         if (r < 0) {
363                 log_warning("Could not get state of interface '%s': %s",
364                             link->ifname, strerror(-r));
365                 link_enter_failed(link);
366         }
367
368         return 1;
369 }
370
371 static int link_get(Link *link) {
372         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
373         int r;
374
375         assert(link);
376         assert(link->manager);
377         assert(link->manager->rtnl);
378
379         r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
380         if (r < 0) {
381                 log_error("Could not allocate RTM_GETLINK message");
382                 return r;
383         }
384
385         r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
386         if (r < 0) {
387                 log_error("Could not send rtnetlink message: %s", strerror(-r));
388                 return r;
389         }
390
391         return 0;
392 }
393
394 int link_configure(Link *link) {
395         int r;
396
397         assert(link);
398         assert(link->network);
399         assert(link->state == _LINK_STATE_INVALID);
400
401         r = link_get(link);
402         if (r < 0) {
403                 link_enter_failed(link);
404                 return r;
405         }
406
407         r = link_enter_join_bridge(link);
408         if (r < 0)
409                 return r;
410
411         return 0;
412 }
413
414 int link_update(Link *link, sd_rtnl_message *m) {
415         unsigned flags;
416         int r;
417
418         assert(link);
419         assert(m);
420
421         r = sd_rtnl_message_link_get_flags(m, &flags);
422         if (r < 0) {
423                 log_warning("Could not get link flags of '%s'", link->ifname);
424                 return r;
425         }
426
427         if (link->flags & IFF_UP && !(flags & IFF_UP))
428                 log_info("Interface '%s' is down", link->ifname);
429         else if (!(link->flags & IFF_UP) && flags & IFF_UP)
430                 log_info("Interface '%s' is up", link->ifname);
431
432         if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP))
433                 log_info("Interface '%s' is disconnected", link->ifname);
434         else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP)
435                 log_info("Interface '%s' is connected", link->ifname);
436
437         link->flags = flags;
438
439         return 0;
440 }