chiark / gitweb /
87f32f00a6c18f5ae4cdf9ebe3495cc1e980de35
[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         if (link->dhcp)
77                 sd_dhcp_client_free(link->dhcp);
78
79         route_free(link->dhcp_route);
80         link->dhcp_route = NULL;
81
82         address_free(link->dhcp_address);
83         link->dhcp_address = NULL;
84
85         hashmap_remove(link->manager->links, &link->ifindex);
86
87         free(link->ifname);
88
89         free(link);
90 }
91
92 int link_add(Manager *m, struct udev_device *device) {
93         Link *link;
94         Network *network;
95         int r;
96         uint64_t ifindex;
97         const char *devtype;
98
99         assert(m);
100         assert(device);
101
102         ifindex = udev_device_get_ifindex(device);
103         link = hashmap_get(m->links, &ifindex);
104         if (link)
105                 return 0;
106
107         r = link_new(m, device, &link);
108         if (r < 0) {
109                 log_error("Could not create link: %s", strerror(-r));
110                 return r;
111         }
112
113         devtype = udev_device_get_devtype(device);
114         if (streq_ptr(devtype, "bridge")) {
115                 r = bridge_set_link(m, link);
116                 if (r < 0)
117                         return r == -ENOENT ? 0 : r;
118         }
119
120         r = network_get(m, device, &network);
121         if (r < 0)
122                 return r == -ENOENT ? 0 : r;
123
124         r = network_apply(m, network, link);
125         if (r < 0)
126                 return r;
127
128         return 0;
129 }
130
131 static int link_enter_configured(Link *link) {
132         assert(link);
133         assert(link->state == LINK_STATE_SETTING_ROUTES);
134
135         log_info("%s: link configured", link->ifname);
136
137         link->state = LINK_STATE_CONFIGURED;
138
139         return 0;
140 }
141
142 static void link_enter_failed(Link *link) {
143         assert(link);
144
145         log_warning("%s: failed", link->ifname);
146
147         link->state = LINK_STATE_FAILED;
148 }
149
150 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
151         Link *link = userdata;
152         int r;
153
154         assert(link->route_messages > 0);
155         assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
156                link->state == LINK_STATE_SETTING_ROUTES ||
157                link->state == LINK_STATE_FAILED);
158
159         link->route_messages --;
160
161         if (link->state == LINK_STATE_FAILED)
162                 return 1;
163
164         r = sd_rtnl_message_get_errno(m);
165         if (r < 0 && r != -EEXIST)
166                 log_warning("%s: could not set route: %s",
167                             link->ifname, strerror(-r));
168
169         /* we might have received an old reply after moving back to SETTING_ADDRESSES,
170          * ignore it */
171         if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
172                 log_debug("%s: routes set", link->ifname);
173                 link_enter_configured(link);
174         }
175
176         return 1;
177 }
178
179 static int link_enter_set_routes(Link *link) {
180         Route *route;
181         int r;
182
183         assert(link);
184         assert(link->network);
185         assert(link->state == LINK_STATE_SETTING_ADDRESSES);
186
187         link->state = LINK_STATE_SETTING_ROUTES;
188
189         if (!link->network->static_routes && !link->dhcp_route)
190                 return link_enter_configured(link);
191
192         log_debug("%s: setting routes", link->ifname);
193
194         LIST_FOREACH(static_routes, route, link->network->static_routes) {
195                 r = route_configure(route, link, &route_handler);
196                 if (r < 0) {
197                         log_warning("%s: could not set routes", link->ifname);
198                         link_enter_failed(link);
199                         return r;
200                 }
201
202                 link->route_messages ++;
203         }
204
205         if (link->dhcp_route) {
206                 r = route_configure(link->dhcp_route, link, &route_handler);
207                 if (r < 0) {
208                         log_warning("%s: could not set routes", link->ifname);
209                         link_enter_failed(link);
210                         return r;
211                 }
212
213                 link->route_messages ++;
214         }
215
216         return 0;
217 }
218
219 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
220         Link *link = userdata;
221         int r;
222
223         assert(m);
224         assert(link);
225         assert(link->ifname);
226         assert(link->addr_messages > 0);
227         assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
228
229         link->addr_messages --;
230
231         if (link->state == LINK_STATE_FAILED)
232                 return 1;
233
234         r = sd_rtnl_message_get_errno(m);
235         if (r < 0 && r != -EEXIST)
236                 log_warning("%s: could not set address: %s",
237                             link->ifname, strerror(-r));
238
239         if (link->addr_messages == 0) {
240                 log_debug("%s: addresses set", link->ifname);
241                 link_enter_set_routes(link);
242         }
243
244         return 1;
245 }
246
247 static int link_enter_set_addresses(Link *link) {
248         Address *address;
249         int r;
250
251         assert(link);
252         assert(link->network);
253         assert(link->state != _LINK_STATE_INVALID);
254
255         link->state = LINK_STATE_SETTING_ADDRESSES;
256
257         if (!link->network->static_addresses && !link->dhcp_address)
258                 return link_enter_set_routes(link);
259
260         log_debug("%s: setting addresses", link->ifname);
261
262         LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
263                 r = address_configure(address, link, &address_handler);
264                 if (r < 0) {
265                         log_warning("%s: could not set addresses", link->ifname);
266                         link_enter_failed(link);
267                         return r;
268                 }
269
270                 link->addr_messages ++;
271         }
272
273         if (link->dhcp_address) {
274                 r = address_configure(link->dhcp_address, link, &address_handler);
275                 if (r < 0) {
276                         log_warning("%s: could not set addresses", link->ifname);
277                         link_enter_failed(link);
278                         return r;
279                 }
280
281                 link->addr_messages ++;
282         }
283
284         return 0;
285 }
286
287 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
288         Link *link = userdata;
289         int r;
290
291         assert(link);
292
293         if (link->state == LINK_STATE_FAILED)
294                 return 1;
295
296         r = sd_rtnl_message_get_errno(m);
297         if (r < 0) {
298                 log_warning("%s: could not bring up interface: %s",
299                             link->ifname, strerror(-r));
300                 link_enter_failed(link);
301         }
302
303         log_debug("%s: brought up interface", link->ifname);
304
305         return 1;
306 }
307
308 static int link_up(Link *link) {
309         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
310         int r;
311
312         assert(link);
313         assert(link->manager);
314         assert(link->manager->rtnl);
315
316         log_debug("%s: bringing up link", link->ifname);
317
318         r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
319         if (r < 0) {
320                 log_error("Could not allocate RTM_SETLINK message");
321                 return r;
322         }
323
324         r = sd_rtnl_message_link_set_flags(req, IFF_UP);
325         if (r < 0) {
326                 log_error("Could not set link flags");
327                 return r;
328         }
329
330         r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
331         if (r < 0) {
332                 log_error("Could not send rtnetlink message: %s", strerror(-r));
333                 return r;
334         }
335
336         return 0;
337 }
338
339 static int link_bridge_joined(Link *link) {
340         int r;
341
342         assert(link);
343         assert(link->state == LINK_STATE_JOINING_BRIDGE);
344         assert(link->network);
345
346         r = link_up(link);
347         if (r < 0) {
348                 link_enter_failed(link);
349                 return r;
350         }
351
352         if (!link->network->dhcp)
353                 return link_enter_set_addresses(link);
354
355         return 0;
356 }
357
358 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
359         Link *link = userdata;
360         int r;
361
362         assert(link);
363         assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
364         assert(link->network);
365
366         if (link->state == LINK_STATE_FAILED)
367                 return 1;
368
369         r = sd_rtnl_message_get_errno(m);
370         if (r < 0) {
371                 log_warning("%s: could not join bridge '%s': %s",
372                             link->ifname, link->network->bridge->name, strerror(-r));
373                 link_enter_failed(link);
374                 return 1;
375         } else
376                 log_debug("%s: joined bridge '%s'",
377                             link->ifname, link->network->bridge->name);
378
379         link_bridge_joined(link);
380
381         return 1;
382 }
383
384 static int link_enter_join_bridge(Link *link) {
385         int r;
386
387         assert(link);
388         assert(link->network);
389         assert(link->state == _LINK_STATE_INVALID);
390
391         link->state = LINK_STATE_JOINING_BRIDGE;
392
393         if (!link->network->bridge)
394                 return link_bridge_joined(link);
395
396         log_debug("%s: joining bridge", link->ifname);
397
398         r = bridge_join(link->network->bridge, link, &bridge_handler);
399         if (r < 0) {
400                 log_warning("%s: could not join bridge '%s'", link->ifname,
401                             link->network->bridge->name);
402                 link_enter_failed(link);
403                 return r;
404         }
405
406         return 0;
407 }
408
409 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
410         Link *link = userdata;
411         int r;
412
413         assert(link);
414
415         if (link->state == LINK_STATE_FAILED)
416                 return 1;
417
418         r = sd_rtnl_message_get_errno(m);
419         if (r < 0) {
420                 log_warning("%s: could not get state: %s",
421                             link->ifname, strerror(-r));
422                 link_enter_failed(link);
423         }
424
425         log_debug("%s: got link state", link->ifname);
426
427         link_update(link, m);
428
429         return 1;
430 }
431
432 static int link_get(Link *link) {
433         _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
434         int r;
435
436         assert(link);
437         assert(link->manager);
438         assert(link->manager->rtnl);
439
440         log_debug("%s: requesting link status", link->ifname);
441
442         r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
443         if (r < 0) {
444                 log_error("Could not allocate RTM_GETLINK message");
445                 return r;
446         }
447
448         r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
449         if (r < 0) {
450                 log_error("Could not send rtnetlink message: %s", strerror(-r));
451                 return r;
452         }
453
454         return 0;
455 }
456
457 int link_configure(Link *link) {
458         int r;
459
460         assert(link);
461         assert(link->network);
462         assert(link->state == _LINK_STATE_INVALID);
463
464         r = link_get(link);
465         if (r < 0) {
466                 link_enter_failed(link);
467                 return r;
468         }
469
470         return link_enter_join_bridge(link);
471 }
472
473 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
474         Link *link = userdata;
475         int r;
476
477         assert(m);
478         assert(link);
479         assert(link->ifname);
480
481         if (link->state == LINK_STATE_FAILED)
482                 return 1;
483
484         r = sd_rtnl_message_get_errno(m);
485         if (r < 0 && r != -EEXIST)
486                 log_warning("%s: could not drop address: %s",
487                             link->ifname, strerror(-r));
488
489         return 1;
490 }
491
492 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
493         Link *link = userdata;
494         struct in_addr address;
495         struct in_addr netmask;
496         struct in_addr gateway;
497         int prefixlen;
498         int r;
499
500         assert(link);
501
502         if (link->state == LINK_STATE_FAILED)
503                 return;
504
505         if (event < 0) {
506                 log_warning("%s: DHCP error: %s", link->ifname, strerror(-event));
507                 link_enter_failed(link);
508                 return;
509         }
510
511         if (event == DHCP_EVENT_NO_LEASE)
512                 log_debug("%s: IP address in use.", link->ifname);
513
514         if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
515             event == DHCP_EVENT_STOP) {
516                 address_drop(link->dhcp_address, link, address_drop_handler);
517
518                 address_free(link->dhcp_address);
519                 link->dhcp_address = NULL;
520
521                 route_free(link->dhcp_route);
522                 link->dhcp_route = NULL;
523         }
524
525         r = sd_dhcp_client_get_address(client, &address);
526         if (r < 0) {
527                 log_warning("%s: DHCP error: no address", link->ifname);
528                 link_enter_failed(link);
529                 return;
530         }
531
532         r = sd_dhcp_client_get_netmask(client, &netmask);
533         if (r < 0) {
534                 log_warning("%s: DHCP error: no netmask", link->ifname);
535                 link_enter_failed(link);
536                 return;
537         }
538
539         prefixlen = sd_dhcp_client_prefixlen(&netmask);
540         if (prefixlen < 0) {
541                 log_warning("%s: DHCP error: no prefixlen", link->ifname);
542                 link_enter_failed(link);
543                 return;
544         }
545
546         r = sd_dhcp_client_get_router(client, &gateway);
547         if (r < 0) {
548                 log_warning("%s: DHCP error: no router", link->ifname);
549                 link_enter_failed(link);
550                 return;
551         }
552
553         if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
554                 _cleanup_address_free_ Address *addr = NULL;
555                 _cleanup_route_free_ Route *rt = NULL;
556
557                 log_info("%s: received config over DHCPv4", link->ifname);
558
559                 r = address_new_dynamic(&addr);
560                 if (r < 0) {
561                         log_error("Could not allocate address");
562                         link_enter_failed(link);
563                         return;
564                 }
565
566                 addr->family = AF_INET;
567                 addr->in_addr.in = address;
568                 addr->prefixlen = prefixlen;
569                 addr->netmask = netmask;
570
571                 r = route_new_dynamic(&rt);
572                 if (r < 0) {
573                         log_error("Could not allocate route");
574                         link_enter_failed(link);
575                         return;
576                 }
577
578                 rt->family = AF_INET;
579                 rt->in_addr.in = gateway;
580
581                 link->dhcp_address = addr;
582                 link->dhcp_route = rt;
583                 addr = NULL;
584                 rt = NULL;
585
586                 link_enter_set_addresses(link);
587         }
588
589         return;
590 }
591
592 static int link_acquire_conf(Link *link) {
593         int r;
594
595         assert(link);
596         assert(link->network);
597         assert(link->network->dhcp);
598         assert(link->manager);
599         assert(link->manager->event);
600
601         if (!link->dhcp) {
602                 link->dhcp = sd_dhcp_client_new(link->manager->event);
603                 if (!link->dhcp)
604                         return -ENOMEM;
605
606                 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
607                 if (r < 0)
608                         return r;
609
610                 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
611                 if (r < 0)
612                         return r;
613
614                 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
615                 if (r < 0)
616                         return r;
617         }
618
619         r = sd_dhcp_client_start(link->dhcp);
620         if (r < 0)
621                 return r;
622
623         return 0;
624 }
625
626 int link_update(Link *link, sd_rtnl_message *m) {
627         unsigned flags;
628         int r;
629
630         assert(link);
631         assert(link->network);
632         assert(m);
633
634         if (link->state == LINK_STATE_FAILED)
635                 return 0;
636
637         r = sd_rtnl_message_link_get_flags(m, &flags);
638         if (r < 0) {
639                 log_warning("%s: could not get link flags", link->ifname);
640                 return r;
641         }
642
643         if (link->flags & IFF_UP && !(flags & IFF_UP))
644                 log_info("%s: interface is down", link->ifname);
645         else if (!(link->flags & IFF_UP) && flags & IFF_UP)
646                 log_info("%s: interface is up", link->ifname);
647
648         if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
649                 log_info("%s: disconnected", link->ifname);
650
651                 if (link->network->dhcp) {
652                         r = sd_dhcp_client_stop(link->dhcp);
653                         if (r < 0) {
654                                 link_enter_failed(link);
655                                 return r;
656                         }
657                 }
658         } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
659                 log_info("%s: connected", link->ifname);
660
661                 if (link->network->dhcp) {
662                         r = link_acquire_conf(link);
663                         if (r < 0) {
664                                 link_enter_failed(link);
665                                 return r;
666                         }
667                 }
668         }
669
670         link->flags = flags;
671
672         log_debug("%s: updated link state", link->ifname);
673
674         return 0;
675 }