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