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