]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link.c
networkd: improve logging
[thirdparty/systemd.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 r = sd_rtnl_message_get_errno(m);
292 if (r < 0) {
293 log_warning("%s: could not bring up interface: %s",
294 link->ifname, strerror(-r));
295 link_enter_failed(link);
296 }
297
298 return 1;
299 }
300
301 static int link_up(Link *link) {
302 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
303 int r;
304
305 assert(link);
306 assert(link->manager);
307 assert(link->manager->rtnl);
308
309 log_debug("%s: bringing up link", link->ifname);
310
311 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
312 if (r < 0) {
313 log_error("Could not allocate RTM_SETLINK message");
314 return r;
315 }
316
317 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
318 if (r < 0) {
319 log_error("Could not set link flags");
320 return r;
321 }
322
323 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
324 if (r < 0) {
325 log_error("Could not send rtnetlink message: %s", strerror(-r));
326 return r;
327 }
328
329 return 0;
330 }
331
332 static int link_bridge_joined(Link *link) {
333 int r;
334
335 assert(link);
336 assert(link->state == LINK_STATE_JOINING_BRIDGE);
337 assert(link->network);
338
339 r = link_up(link);
340 if (r < 0) {
341 link_enter_failed(link);
342 return r;
343 }
344
345 if (!link->network->dhcp) {
346 r = link_enter_set_addresses(link);
347 if (r < 0)
348 link_enter_failed(link);
349 return r;
350 }
351
352 return 0;
353 }
354
355 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
356 Link *link = userdata;
357 int r;
358
359 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
360 assert(link->network);
361
362 if (link->state == LINK_STATE_FAILED)
363 return 1;
364
365 r = sd_rtnl_message_get_errno(m);
366 if (r < 0) {
367 log_warning("%s: could not join bridge '%s': %s",
368 link->ifname, link->network->bridge->name, strerror(-r));
369 link_enter_failed(link);
370 return 1;
371 } else
372 log_debug("%s: joined bridge '%s'",
373 link->ifname, link->network->bridge->name);
374
375 link_bridge_joined(link);
376
377 return 1;
378 }
379
380 static int link_enter_join_bridge(Link *link) {
381 int r;
382
383 assert(link);
384 assert(link->network);
385 assert(link->state == _LINK_STATE_INVALID);
386
387 link->state = LINK_STATE_JOINING_BRIDGE;
388
389 if (!link->network->bridge)
390 return link_bridge_joined(link);
391
392 log_debug("%s: joining bridge", link->ifname);
393
394 r = bridge_join(link->network->bridge, link, &bridge_handler);
395 if (r < 0) {
396 log_warning("%s: could not join bridge '%s'", link->ifname,
397 link->network->bridge->name);
398 link_enter_failed(link);
399 return r;
400 }
401
402 return 0;
403 }
404
405 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
406 Link *link = userdata;
407 int r;
408
409 r = sd_rtnl_message_get_errno(m);
410 if (r < 0) {
411 log_warning("%s: could not get state: %s",
412 link->ifname, strerror(-r));
413 link_enter_failed(link);
414 }
415
416 link_update(link, m);
417
418 return 1;
419 }
420
421 static int link_get(Link *link) {
422 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
423 int r;
424
425 assert(link);
426 assert(link->manager);
427 assert(link->manager->rtnl);
428
429 log_debug("%s: requesting link status", link->ifname);
430
431 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
432 if (r < 0) {
433 log_error("Could not allocate RTM_GETLINK message");
434 return r;
435 }
436
437 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
438 if (r < 0) {
439 log_error("Could not send rtnetlink message: %s", strerror(-r));
440 return r;
441 }
442
443 return 0;
444 }
445
446 int link_configure(Link *link) {
447 int r;
448
449 assert(link);
450 assert(link->network);
451 assert(link->state == _LINK_STATE_INVALID);
452
453 r = link_get(link);
454 if (r < 0) {
455 link_enter_failed(link);
456 return r;
457 }
458
459 r = link_enter_join_bridge(link);
460 if (r < 0)
461 return r;
462
463 return 0;
464 }
465
466 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
467 Link *link = userdata;
468 int r;
469
470 assert(m);
471 assert(link);
472 assert(link->ifname);
473
474 if (link->state == LINK_STATE_FAILED)
475 return 1;
476
477 r = sd_rtnl_message_get_errno(m);
478 if (r < 0 && r != -EEXIST)
479 log_warning("%s: could not drop address: %s",
480 link->ifname, strerror(-r));
481
482 return 1;
483 }
484
485 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
486 Link *link = userdata;
487 struct in_addr address;
488 struct in_addr netmask;
489 struct in_addr gateway;
490 int prefixlen;
491 int r;
492
493 if (link->state == LINK_STATE_FAILED)
494 return;
495
496 if (event < 0) {
497 log_warning("%s: DHCP error: %s", link->ifname, strerror(-event));
498 link_enter_failed(link);
499 return;
500 }
501
502 if (event == DHCP_EVENT_NO_LEASE)
503 log_debug("%s: IP address in use.", link->ifname);
504
505 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
506 event == DHCP_EVENT_STOP) {
507 address_drop(link->dhcp_address, link, address_drop_handler);
508
509 address_free(link->dhcp_address);
510 link->dhcp_address = NULL;
511
512 route_free(link->dhcp_route);
513 link->dhcp_route = NULL;
514 }
515
516 r = sd_dhcp_client_get_address(client, &address);
517 if (r < 0) {
518 log_warning("%s: DHCP error: no address", link->ifname);
519 link_enter_failed(link);
520 return;
521 }
522
523 r = sd_dhcp_client_get_netmask(client, &netmask);
524 if (r < 0) {
525 log_warning("%s: DHCP error: no netmask", link->ifname);
526 link_enter_failed(link);
527 return;
528 }
529
530 prefixlen = sd_dhcp_client_prefixlen(&netmask);
531 if (prefixlen < 0) {
532 log_warning("%s: DHCP error: no prefixlen", link->ifname);
533 link_enter_failed(link);
534 return;
535 }
536
537 r = sd_dhcp_client_get_router(client, &gateway);
538 if (r < 0) {
539 log_warning("%s: DHCP error: no router", link->ifname);
540 link_enter_failed(link);
541 return;
542 }
543
544 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
545 _cleanup_address_free_ Address *addr = NULL;
546 _cleanup_route_free_ Route *rt = NULL;
547
548 log_info("%s: received config over DHCPv4", link->ifname);
549
550 r = address_new_dynamic(&addr);
551 if (r < 0) {
552 log_error("Could not allocate address");
553 link_enter_failed(link);
554 return;
555 }
556
557 addr->family = AF_INET;
558 addr->in_addr.in = address;
559 addr->prefixlen = prefixlen;
560 addr->netmask = netmask;
561
562 r = route_new_dynamic(&rt);
563 if (r < 0) {
564 log_error("Could not allocate route");
565 link_enter_failed(link);
566 return;
567 }
568
569 rt->family = AF_INET;
570 rt->in_addr.in = gateway;
571
572 link->dhcp_address = addr;
573 link->dhcp_route = rt;
574 addr = NULL;
575 rt = NULL;
576
577 link_enter_set_addresses(link);
578 }
579
580 return;
581 }
582
583 static int link_acquire_conf(Link *link) {
584 int r;
585
586 assert(link);
587 assert(link->network);
588 assert(link->network->dhcp);
589 assert(link->manager);
590 assert(link->manager->event);
591
592 if (!link->dhcp) {
593 link->dhcp = sd_dhcp_client_new(link->manager->event);
594 if (!link->dhcp)
595 return -ENOMEM;
596
597 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
598 if (r < 0)
599 return r;
600
601 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
602 if (r < 0)
603 return r;
604
605 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
606 if (r < 0)
607 return r;
608 }
609
610 r = sd_dhcp_client_start(link->dhcp);
611 if (r < 0)
612 return r;
613
614 return 0;
615 }
616
617 int link_update(Link *link, sd_rtnl_message *m) {
618 unsigned flags;
619 int r;
620
621 assert(link);
622 assert(m);
623
624 r = sd_rtnl_message_link_get_flags(m, &flags);
625 if (r < 0) {
626 log_warning("%s: could not get link flags", link->ifname);
627 return r;
628 }
629
630 if (link->flags & IFF_UP && !(flags & IFF_UP))
631 log_info("%s: interface is down", link->ifname);
632 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
633 log_info("%s: interface is up", link->ifname);
634
635 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
636 log_info("%s: disconnected", link->ifname);
637
638 if (link->network->dhcp) {
639 r = sd_dhcp_client_stop(link->dhcp);
640 if (r < 0) {
641 link_enter_failed(link);
642 return r;
643 }
644 }
645 } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
646 log_info("%s: connected", link->ifname);
647
648 if (link->network && link->network->dhcp) {
649 r = link_acquire_conf(link);
650 if (r < 0) {
651 link_enter_failed(link);
652 return r;
653 }
654 }
655 }
656
657 link->flags = flags;
658
659 log_debug("%s: updated state", link->ifname);
660
661 return 0;
662 }