]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
zsh-completions: kernel-install - only show existing kernels for 'remove'
[thirdparty/systemd.git] / src / network / networkd-link.c
CommitLineData
f579559b
TG
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"
1346b1f0 28#include "bus-util.h"
377a218f 29#include "net-util.h"
f579559b
TG
30
31int link_new(Manager *manager, struct udev_device *device, Link **ret) {
32 _cleanup_link_free_ Link *link = NULL;
8cd11a0f 33 const char *mac;
602cc437 34 struct ether_addr *mac_addr;
c166a070 35 const char *ifname;
f579559b
TG
36 int r;
37
38 assert(device);
39 assert(ret);
40
41 link = new0(Link, 1);
42 if (!link)
43 return -ENOMEM;
44
5a3eb5a7
TG
45 link->manager = manager;
46 link->state = _LINK_STATE_INVALID;
47
0617ffab
TG
48 link->ifindex = udev_device_get_ifindex(device);
49 if (link->ifindex <= 0)
f579559b
TG
50 return -EINVAL;
51
8cd11a0f 52 mac = udev_device_get_sysattr_value(device, "address");
5a3eb5a7
TG
53 if (mac) {
54 mac_addr = ether_aton(mac);
55 if (mac_addr)
56 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
57 }
f579559b 58
c166a070
TG
59 ifname = udev_device_get_sysname(device);
60 link->ifname = strdup(ifname);
61
0617ffab 62 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
63 if (r < 0)
64 return r;
65
66 *ret = link;
67 link = NULL;
68
69 return 0;
70}
71
72void link_free(Link *link) {
73 if (!link)
74 return;
75
0617ffab 76 assert(link->manager);
f579559b 77
f5be5601
TG
78 if (link->dhcp)
79 sd_dhcp_client_free(link->dhcp);
80
81 route_free(link->dhcp_route);
82 link->dhcp_route = NULL;
83
84 address_free(link->dhcp_address);
85 link->dhcp_address = NULL;
86
0617ffab 87 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 88
c166a070
TG
89 free(link->ifname);
90
f579559b
TG
91 free(link);
92}
93
aa3437a5 94int link_add(Manager *m, struct udev_device *device, Link **ret) {
f579559b
TG
95 Link *link;
96 Network *network;
97 int r;
98 uint64_t ifindex;
99
100 assert(m);
101 assert(device);
102
103 ifindex = udev_device_get_ifindex(device);
104 link = hashmap_get(m->links, &ifindex);
aa3437a5
TG
105 if (link) {
106 *ret = link;
2672953b 107 return -EEXIST;
aa3437a5 108 }
f579559b
TG
109
110 r = link_new(m, device, &link);
2672953b 111 if (r < 0)
f579559b 112 return r;
f579559b 113
aa3437a5
TG
114 *ret = link;
115
f579559b
TG
116 r = network_get(m, device, &network);
117 if (r < 0)
118 return r == -ENOENT ? 0 : r;
119
120 r = network_apply(m, network, link);
121 if (r < 0)
122 return r;
123
124 return 0;
125}
126
f882c247 127static int link_enter_configured(Link *link) {
ef1ba606
TG
128 assert(link);
129 assert(link->state == LINK_STATE_SETTING_ROUTES);
130
39032b87 131 log_info_link(link, "link configured");
f882c247
TG
132
133 link->state = LINK_STATE_CONFIGURED;
134
135 return 0;
136}
137
ef1ba606
TG
138static void link_enter_failed(Link *link) {
139 assert(link);
f882c247 140
39032b87 141 log_warning_link(link, "failed");
449f7554 142
ef1ba606 143 link->state = LINK_STATE_FAILED;
f882c247
TG
144}
145
f882c247
TG
146static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
147 Link *link = userdata;
148 int r;
149
f5be5601
TG
150 assert(link->route_messages > 0);
151 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
152 link->state == LINK_STATE_SETTING_ROUTES ||
153 link->state == LINK_STATE_FAILED);
f882c247 154
f5be5601 155 link->route_messages --;
f882c247
TG
156
157 if (link->state == LINK_STATE_FAILED)
158 return 1;
159
160 r = sd_rtnl_message_get_errno(m);
c166a070 161 if (r < 0 && r != -EEXIST)
c9ccc19f
TG
162 log_struct_link(LOG_WARNING, link,
163 "MESSAGE=%s: could not set route: %s",
164 link->ifname, strerror(-r),
165 "ERRNO=%d", -r,
166 NULL);
f882c247 167
f5be5601
TG
168 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
169 * ignore it */
170 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 171 log_debug_link(link, "routes set");
dd3efc09
TG
172 link_enter_configured(link);
173 }
f882c247
TG
174
175 return 1;
176}
177
178static int link_enter_set_routes(Link *link) {
179 Route *route;
180 int r;
181
182 assert(link);
183 assert(link->network);
ef1ba606 184 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 185
ef1ba606 186 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 187
f5be5601 188 if (!link->network->static_routes && !link->dhcp_route)
dd3efc09 189 return link_enter_configured(link);
f882c247 190
39032b87 191 log_debug_link(link, "setting routes");
449f7554 192
f048a16b 193 LIST_FOREACH(static_routes, route, link->network->static_routes) {
f882c247 194 r = route_configure(route, link, &route_handler);
dd3efc09 195 if (r < 0) {
3333d748
ZJS
196 log_warning_link(link,
197 "could not set routes: %s", strerror(-r));
ef1ba606
TG
198 link_enter_failed(link);
199 return r;
dd3efc09 200 }
c166a070 201
f5be5601
TG
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) {
3333d748
ZJS
208 log_warning_link(link,
209 "could not set routes: %s", strerror(-r));
f5be5601
TG
210 link_enter_failed(link);
211 return r;
212 }
213
214 link->route_messages ++;
f882c247
TG
215 }
216
217 return 0;
218}
219
f882c247
TG
220static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
221 Link *link = userdata;
222 int r;
223
f5be5601
TG
224 assert(m);
225 assert(link);
226 assert(link->ifname);
227 assert(link->addr_messages > 0);
ef1ba606 228 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
f882c247 229
f5be5601 230 link->addr_messages --;
f882c247
TG
231
232 if (link->state == LINK_STATE_FAILED)
233 return 1;
234
235 r = sd_rtnl_message_get_errno(m);
c166a070 236 if (r < 0 && r != -EEXIST)
c9ccc19f 237 log_struct_link(LOG_WARNING, link,
3333d748
ZJS
238 "MESSAGE=%s: could not set address: %s",
239 link->ifname, strerror(-r),
240 "ERRNO=%d", -r,
241 NULL);
f882c247 242
f5be5601 243 if (link->addr_messages == 0) {
39032b87 244 log_debug_link(link, "addresses set");
ef1ba606 245 link_enter_set_routes(link);
dd3efc09 246 }
f882c247
TG
247
248 return 1;
249}
250
251static int link_enter_set_addresses(Link *link) {
252 Address *address;
253 int r;
254
255 assert(link);
256 assert(link->network);
f5be5601 257 assert(link->state != _LINK_STATE_INVALID);
f882c247 258
ef1ba606 259 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 260
f5be5601 261 if (!link->network->static_addresses && !link->dhcp_address)
ef1ba606 262 return link_enter_set_routes(link);
f882c247 263
39032b87 264 log_debug_link(link, "setting addresses");
449f7554 265
f048a16b 266 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
f882c247 267 r = address_configure(address, link, &address_handler);
dd3efc09 268 if (r < 0) {
3333d748
ZJS
269 log_warning_link(link,
270 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
271 link_enter_failed(link);
272 return r;
dd3efc09 273 }
c166a070 274
f5be5601
TG
275 link->addr_messages ++;
276 }
277
278 if (link->dhcp_address) {
279 r = address_configure(link->dhcp_address, link, &address_handler);
280 if (r < 0) {
3333d748
ZJS
281 log_warning_link(link,
282 "could not set addresses: %s", strerror(-r));
f5be5601
TG
283 link_enter_failed(link);
284 return r;
285 }
286
287 link->addr_messages ++;
f882c247
TG
288 }
289
290 return 0;
291}
292
ff254138
TG
293static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
294 Link *link = userdata;
295 int r;
296
297 assert(m);
298 assert(link);
299 assert(link->ifname);
300
301 if (link->state == LINK_STATE_FAILED)
302 return 1;
303
304 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
305 if (r < 0 && r != -ENOENT)
306 log_struct_link(LOG_WARNING, link,
307 "MESSAGE=%s: could not drop address: %s",
308 link->ifname, strerror(-r),
309 "ERRNO=%d", -r,
310 NULL);
ff254138
TG
311
312 return 1;
313}
314
1346b1f0
TG
315static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
316 int r;
317
318 r = sd_bus_message_get_errno(m);
319 if (r < 0)
320 log_warning("Could not set hostname: %s", strerror(-r));
321
322 return 1;
323}
324
325static int set_hostname(sd_bus *bus, const char *hostname) {
326 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
327 int r = 0;
328
1346b1f0
TG
329 assert(hostname);
330
331 log_debug("Setting transient hostname: '%s'", hostname);
332
bcbca829
TG
333 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
334 log_info("Not connected to system bus, ignoring transient hostname.");
335 return 0;
336 }
337
1346b1f0
TG
338 r = sd_bus_message_new_method_call(
339 bus,
340 "org.freedesktop.hostname1",
341 "/org/freedesktop/hostname1",
342 "org.freedesktop.hostname1",
343 "SetHostname",
344 &m);
345 if (r < 0)
346 return r;
347
348 r = sd_bus_message_append(m, "sb", hostname, false);
349 if (r < 0)
350 return r;
351
352 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
353 if (r < 0)
354 log_error("Could not set transient hostname: %s", strerror(-r));
355
356 return r;
357}
358
4f882b2a
TG
359static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
360 Link *link = userdata;
361 int r;
362
363 assert(m);
364 assert(link);
365 assert(link->ifname);
366
367 if (link->state == LINK_STATE_FAILED)
368 return 1;
369
370 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
371 if (r < 0)
372 log_struct_link(LOG_WARNING, link,
373 "MESSAGE=%s: could not set MTU: %s",
374 link->ifname, strerror(-r),
375 "ERRNO=%d", -r,
376 NULL);
4f882b2a
TG
377
378 return 1;
379}
380
381static int link_set_mtu(Link *link, uint32_t mtu) {
382 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
383 int r;
384
385 assert(link);
386 assert(link->manager);
387 assert(link->manager->rtnl);
388
389 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
390
391 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
392 if (r < 0) {
393 log_error_link(link, "Could not allocate RTM_SETLINK message");
394 return r;
395 }
396
397 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
398 if (r < 0) {
399 log_error_link(link, "Could not append MTU: %s", strerror(-r));
400 return r;
401 }
402
403 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
404 if (r < 0) {
405 log_error_link(link,
406 "Could not send rtnetlink message: %s", strerror(-r));
407 return r;
408 }
409
410 return 0;
411}
412
c07aeadf 413static int dhcp_lease_lost(sd_dhcp_client *client, Link *link) {
ff254138
TG
414 int r;
415
c07aeadf 416 assert(client);
ff254138
TG
417 assert(link);
418
c07aeadf
TG
419 if (link->dhcp_address) {
420 address_drop(link->dhcp_address, link, address_drop_handler);
ff254138 421
c07aeadf
TG
422 address_free(link->dhcp_address);
423 link->dhcp_address = NULL;
ff254138
TG
424 }
425
c07aeadf
TG
426 if (link->dhcp_route) {
427 route_free(link->dhcp_route);
428 link->dhcp_route = NULL;
429 }
eb27aeca 430
c07aeadf
TG
431 if (link->network->dhcp_mtu) {
432 uint16_t mtu;
ff254138 433
c07aeadf
TG
434 r = sd_dhcp_client_get_mtu(client, &mtu);
435 if (r >= 0 && link->original_mtu != mtu) {
436 r = link_set_mtu(link, link->original_mtu);
437 if (r < 0) {
438 log_warning_link(link, "DHCP error: could not reset MTU");
439 link_enter_failed(link);
440 return r;
441 }
ff254138 442 }
c07aeadf 443 }
ff254138 444
c07aeadf
TG
445 if (link->network->dhcp_hostname) {
446 r = set_hostname(link->manager->bus, "");
447 if (r < 0)
448 log_error("Failed to reset transient hostname");
449 }
4f882b2a 450
c07aeadf
TG
451 return 0;
452}
4f882b2a 453
c07aeadf
TG
454static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
455 struct in_addr address;
456 struct in_addr netmask;
457 struct in_addr gateway;
458 unsigned prefixlen;
459 _cleanup_address_free_ Address *addr = NULL;
460 _cleanup_route_free_ Route *rt = NULL;
461 struct in_addr *nameservers;
462 size_t nameservers_size;
463 int r;
1346b1f0 464
c07aeadf
TG
465 assert(client);
466 assert(link);
ff254138
TG
467
468 r = sd_dhcp_client_get_address(client, &address);
469 if (r < 0) {
c07aeadf
TG
470 log_warning_link(link, "DHCP error: no address: %s",
471 strerror(-r));
472 return r;
ff254138
TG
473 }
474
475 r = sd_dhcp_client_get_netmask(client, &netmask);
476 if (r < 0) {
c07aeadf
TG
477 log_warning_link(link, "DHCP error: no netmask: %s",
478 strerror(-r));
479 return r;
ff254138
TG
480 }
481
377a218f 482 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138
TG
483
484 r = sd_dhcp_client_get_router(client, &gateway);
485 if (r < 0) {
c07aeadf
TG
486 log_warning_link(link, "DHCP error: no router: %s",
487 strerror(-r));
488 return r;
ff254138
TG
489 }
490
ff254138 491
c07aeadf
TG
492 log_struct_link(LOG_INFO, link,
493 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
494 link->ifname,
495 ADDRESS_FMT_VAL(address),
496 prefixlen,
497 ADDRESS_FMT_VAL(gateway),
498 "ADDRESS=%u.%u.%u.%u",
499 ADDRESS_FMT_VAL(address),
500 "PREFIXLEN=%u",
501 prefixlen,
502 "GATEWAY=%u.%u.%u.%u",
503 ADDRESS_FMT_VAL(gateway),
504 NULL);
505
506 r = address_new_dynamic(&addr);
507 if (r < 0) {
508 log_error_link(link, "Could not allocate address: %s",
509 strerror(-r));
510 return r;
511 }
ff254138 512
c07aeadf
TG
513 addr->family = AF_INET;
514 addr->in_addr.in = address;
515 addr->prefixlen = prefixlen;
516 addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
ff254138 517
c07aeadf
TG
518 r = route_new_dynamic(&rt);
519 if (r < 0) {
520 log_error_link(link, "Could not allocate route: %s",
521 strerror(-r));
522 return r;
523 }
524
525 rt->family = AF_INET;
526 rt->in_addr.in = gateway;
527
528 link->dhcp_address = addr;
529 link->dhcp_route = rt;
530 addr = NULL;
531 rt = NULL;
532
533 if (link->network->dhcp_dns) {
534 r = sd_dhcp_client_get_dns(client, &nameservers, &nameservers_size);
535 if (r >= 0) {
536 r = manager_update_resolv_conf(link->manager);
537 if (r < 0)
538 log_error("Failed to update resolv.conf");
ff254138 539 }
c07aeadf 540 }
ff254138 541
c07aeadf
TG
542 if (link->network->dhcp_mtu) {
543 uint16_t mtu;
544
545 r = sd_dhcp_client_get_mtu(client, &mtu);
546 if (r >= 0) {
547 r = link_set_mtu(link, mtu);
548 if (r < 0)
549 log_error_link(link, "Failed to set MTU "
550 "to %" PRIu16, mtu);
551 }
552 }
ff254138 553
c07aeadf
TG
554 if (link->network->dhcp_hostname) {
555 const char *hostname;
ff254138 556
c07aeadf
TG
557 r = sd_dhcp_client_get_hostname(client, &hostname);
558 if (r >= 0) {
559 r = set_hostname(link->manager->bus, hostname);
560 if (r < 0)
561 log_error("Failed to set transient hostname "
562 "to '%s'", hostname);
3bef724f 563 }
c07aeadf 564 }
3bef724f 565
c07aeadf
TG
566 link_enter_set_addresses(link);
567
568 return 0;
569}
570
571static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
572 Link *link = userdata;
573 int r;
574
575 assert(link);
576 assert(link->network);
577 assert(link->manager);
578
579 if (link->state == LINK_STATE_FAILED)
580 return;
581
582 switch (event) {
583 case DHCP_EVENT_NO_LEASE:
584 log_debug_link(link, "IP address in use.");
585 break;
586 case DHCP_EVENT_EXPIRED:
587 case DHCP_EVENT_STOP:
588 case DHCP_EVENT_IP_CHANGE:
589 if (link->network->dhcp_critical) {
590 log_error_link(link, "DHCPv4 connection considered system critical, "
591 "ignoring request to reconfigure it.");
592 return;
4f882b2a 593 }
4f882b2a 594
c07aeadf
TG
595 r = dhcp_lease_lost(client, link);
596 if (r < 0) {
597 link_enter_failed(link);
598 return;
599 }
1346b1f0 600
c07aeadf
TG
601 if (event == DHCP_EVENT_IP_CHANGE) {
602 r = dhcp_lease_acquired(client, link);
603 if (r < 0) {
604 link_enter_failed(link);
605 return;
606 }
1346b1f0 607 }
1346b1f0 608
c07aeadf
TG
609 break;
610 case DHCP_EVENT_IP_ACQUIRE:
611 r = dhcp_lease_acquired(client, link);
612 if (r < 0) {
613 link_enter_failed(link);
614 return;
615 }
616 break;
617 default:
618 if (event < 0)
619 log_warning_link(link, "DHCP error: %s", strerror(-event));
620 else
621 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 622 break;
ff254138
TG
623 }
624
625 return;
626}
627
628static int link_acquire_conf(Link *link) {
629 int r;
630
631 assert(link);
632 assert(link->network);
633 assert(link->network->dhcp);
634 assert(link->manager);
635 assert(link->manager->event);
636
637 if (!link->dhcp) {
b25ef18b
TG
638 r = sd_dhcp_client_new(&link->dhcp);
639 if (r < 0)
640 return r;
641
642 r = sd_dhcp_client_attach_event(link->dhcp, NULL, 0);
643 if (r < 0)
644 return r;
ff254138
TG
645
646 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
647 if (r < 0)
648 return r;
649
650 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
651 if (r < 0)
652 return r;
653
654 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
655 if (r < 0)
656 return r;
6fc73498
TG
657
658 if (link->network->dhcp_mtu) {
659 r = sd_dhcp_client_set_request_option(link->dhcp, 26);
660 if (r < 0)
661 return r;
662 }
ff254138
TG
663 }
664
ab47d620
TG
665 log_debug_link(link, "acquiring DHCPv4 lease");
666
ff254138
TG
667 r = sd_dhcp_client_start(link->dhcp);
668 if (r < 0)
669 return r;
670
671 return 0;
672}
673
674static int link_update_flags(Link *link, unsigned flags) {
675 int r;
676
677 assert(link);
678 assert(link->network);
679
680 if (link->state == LINK_STATE_FAILED)
681 return 0;
682
efbc88b8 683 if (link->flags == flags) {
ab47d620 684 log_debug_link(link, "link status unchanged: %#.8x", flags);
efbc88b8
TG
685 return 0;
686 }
687
3333d748
ZJS
688 if ((link->flags & IFF_UP) != (flags & IFF_UP))
689 log_info_link(link,
e6674986 690 "link is %s", flags & IFF_UP ? "up": "down");
efbc88b8
TG
691
692 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
693 if (flags & IFF_LOWER_UP) {
39032b87 694 log_info_link(link, "carrier on");
efbc88b8
TG
695
696 if (link->network->dhcp) {
697 r = link_acquire_conf(link);
698 if (r < 0) {
1f6d9bc9 699 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
efbc88b8
TG
700 link_enter_failed(link);
701 return r;
702 }
ff254138 703 }
efbc88b8 704 } else {
39032b87 705 log_info_link(link, "carrier off");
efbc88b8
TG
706
707 if (link->network->dhcp) {
708 r = sd_dhcp_client_stop(link->dhcp);
709 if (r < 0) {
1f6d9bc9 710 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
efbc88b8
TG
711 link_enter_failed(link);
712 return r;
713 }
ff254138
TG
714 }
715 }
716 }
717
3333d748 718 log_debug_link(link,
ab47d620 719 "link status updated: %#.8x -> %#.8x", link->flags, flags);
efbc88b8 720
ff254138
TG
721 link->flags = flags;
722
723 return 0;
724}
725
dd3efc09
TG
726static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
727 Link *link = userdata;
728 int r;
729
1746cf2a
TG
730 assert(link);
731
732 if (link->state == LINK_STATE_FAILED)
733 return 1;
734
dd3efc09
TG
735 r = sd_rtnl_message_get_errno(m);
736 if (r < 0) {
c9ccc19f
TG
737 log_struct_link(LOG_ERR, link,
738 "MESSAGE=%s: could not bring up interface: %s",
739 link->ifname, strerror(-r),
740 "ERRNO=%d", -r,
741 NULL);
dd3efc09 742 link_enter_failed(link);
c9ccc19f 743 return 1;
dd3efc09 744 }
f882c247 745
ff254138 746 link_update_flags(link, link->flags | IFF_UP);
1746cf2a 747
f882c247
TG
748 return 1;
749}
750
751static int link_up(Link *link) {
f579559b
TG
752 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
753 int r;
754
f882c247
TG
755 assert(link);
756 assert(link->manager);
757 assert(link->manager->rtnl);
758
39032b87 759 log_debug_link(link, "bringing link up");
449f7554 760
0f49a5f7 761 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
f579559b 762 if (r < 0) {
39032b87 763 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
764 return r;
765 }
766
5d4795f3 767 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 768 if (r < 0) {
3333d748 769 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
770 return r;
771 }
772
dd3efc09 773 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 774 if (r < 0) {
3333d748
ZJS
775 log_error_link(link,
776 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
777 return r;
778 }
779
f882c247
TG
780 return 0;
781}
782
52433f6b 783static int link_enslaved(Link *link) {
f882c247
TG
784 int r;
785
ef1ba606 786 assert(link);
52433f6b 787 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 788 assert(link->network);
dd3efc09 789
f882c247 790 r = link_up(link);
ef1ba606
TG
791 if (r < 0) {
792 link_enter_failed(link);
793 return r;
794 }
f882c247 795
1746cf2a
TG
796 if (!link->network->dhcp)
797 return link_enter_set_addresses(link);
ef1ba606
TG
798
799 return 0;
02b59d57
TG
800}
801
52433f6b 802static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
803 Link *link = userdata;
804 int r;
805
1746cf2a 806 assert(link);
52433f6b 807 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
ef1ba606 808 assert(link->network);
02b59d57 809
52433f6b
TG
810 link->enslaving --;
811
02b59d57
TG
812 if (link->state == LINK_STATE_FAILED)
813 return 1;
814
815 r = sd_rtnl_message_get_errno(m);
ef1ba606 816 if (r < 0) {
c9ccc19f
TG
817 log_struct_link(LOG_ERR, link,
818 "MESSAGE=%s: could not enslave: %s",
819 link->ifname, strerror(-r),
820 "ERRNO=%d", -r,
821 NULL);
ef1ba606
TG
822 link_enter_failed(link);
823 return 1;
3333d748 824 }
02b59d57 825
52433f6b 826 log_debug_link(link, "enslaved");
ab47d620 827
52433f6b
TG
828 if (link->enslaving == 0)
829 link_enslaved(link);
02b59d57
TG
830
831 return 1;
832}
833
52433f6b 834static int link_enter_enslave(Link *link) {
02b59d57
TG
835 int r;
836
837 assert(link);
838 assert(link->network);
ef1ba606 839 assert(link->state == _LINK_STATE_INVALID);
02b59d57 840
52433f6b 841 link->state = LINK_STATE_ENSLAVING;
02b59d57 842
54abf461 843 if (!link->network->bridge && !link->network->bond && !link->network->vlan)
52433f6b 844 return link_enslaved(link);
02b59d57 845
52433f6b
TG
846 if (link->network->bridge) {
847 log_struct_link(LOG_DEBUG, link,
848 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 849 link->ifname, link->network->bridge->name,
52433f6b
TG
850 NETDEV(link->network->bridge),
851 NULL);
449f7554 852
52433f6b
TG
853 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
854 if (r < 0) {
855 log_struct_link(LOG_WARNING, link,
856 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f 857 link->ifname, link->network->bridge->name, strerror(-r),
52433f6b
TG
858 NETDEV(link->network->bridge),
859 NULL);
860 link_enter_failed(link);
861 return r;
862 }
863
864 link->enslaving ++;
865 }
866
54abf461 867 if (link->network->vlan) {
52433f6b
TG
868 log_struct_link(LOG_DEBUG, link,
869 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 870 link->ifname, link->network->vlan->name,
54abf461 871 NETDEV(link->network->vlan),
3333d748 872 NULL);
52433f6b 873
54abf461 874 r = netdev_enslave(link->network->vlan, link, &enslave_handler);
52433f6b
TG
875 if (r < 0) {
876 log_struct_link(LOG_WARNING, link,
877 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f
TG
878 link->ifname, link->network->vlan->name,
879 strerror(-r), NETDEV(link->network->vlan),
52433f6b
TG
880 NULL);
881 link_enter_failed(link);
882 return r;
883 }
884
885 link->enslaving ++;
ef1ba606
TG
886 }
887
888 return 0;
889}
890
891static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
892 Link *link = userdata;
893 int r;
894
1746cf2a
TG
895 assert(link);
896
897 if (link->state == LINK_STATE_FAILED)
898 return 1;
899
ef1ba606
TG
900 r = sd_rtnl_message_get_errno(m);
901 if (r < 0) {
c9ccc19f
TG
902 log_struct_link(LOG_ERR, link,
903 "MESSAGE=%s: could not get state: %s",
904 link->ifname, strerror(-r),
905 "ERRNO=%d", -r,
906 NULL);
ef1ba606 907 link_enter_failed(link);
c9ccc19f 908 return 1;
ef1ba606
TG
909 }
910
39032b87 911 log_debug_link(link, "got link state");
1746cf2a 912
5eb036ca
TG
913 link_update(link, m);
914
ef1ba606
TG
915 return 1;
916}
917
918static int link_get(Link *link) {
919 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
920 int r;
921
922 assert(link);
923 assert(link->manager);
924 assert(link->manager->rtnl);
925
39032b87 926 log_debug_link(link, "requesting link status");
449f7554 927
ef1ba606
TG
928 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
929 if (r < 0) {
39032b87 930 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
931 return r;
932 }
933
934 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
935 if (r < 0) {
3333d748
ZJS
936 log_error_link(link,
937 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 938 return r;
dd3efc09 939 }
02b59d57
TG
940
941 return 0;
942}
943
944int link_configure(Link *link) {
945 int r;
946
ef1ba606
TG
947 assert(link);
948 assert(link->network);
949 assert(link->state == _LINK_STATE_INVALID);
950
dd3efc09 951 r = link_get(link);
ef1ba606
TG
952 if (r < 0) {
953 link_enter_failed(link);
954 return r;
955 }
dd3efc09 956
52433f6b 957 return link_enter_enslave(link);
f579559b 958}
dd3efc09 959
22936833
TG
960int link_update(Link *link, sd_rtnl_message *m) {
961 unsigned flags;
4f882b2a
TG
962 void *data;
963 uint16_t type;
22936833
TG
964 int r;
965
dd3efc09 966 assert(link);
22936833
TG
967 assert(m);
968
1746cf2a
TG
969 if (link->state == LINK_STATE_FAILED)
970 return 0;
971
22936833
TG
972 r = sd_rtnl_message_link_get_flags(m, &flags);
973 if (r < 0) {
4f882b2a 974 log_warning_link(link, "Could not get link flags");
22936833
TG
975 return r;
976 }
dd3efc09 977
4f882b2a 978 while (sd_rtnl_message_read(m, &type, &data) > 0) {
396945dc
TG
979 if (type == IFLA_MTU && link->network->dhcp &&
980 link->network->dhcp_mtu && !link->original_mtu) {
4f882b2a 981 link->original_mtu = *(uint16_t *) data;
396945dc
TG
982 log_debug_link(link, "saved original MTU: %" PRIu16,
983 link->original_mtu);
4f882b2a
TG
984 }
985 }
986
ff254138 987 return link_update_flags(link, flags);
dd3efc09 988}