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