]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
systemctl: remove erroneous return in runlevel_parse_argv()
[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
TG
509 if (link->network->dhcp_hostname) {
510 r = set_hostname(link->manager->bus, "");
511 if (r < 0)
512 log_error("Failed to reset transient hostname");
513 }
4f882b2a 514
a6cc569e
TG
515 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
516
c07aeadf
TG
517 return 0;
518}
4f882b2a 519
c07aeadf 520static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
a6cc569e 521 sd_dhcp_lease *lease;
c07aeadf
TG
522 struct in_addr address;
523 struct in_addr netmask;
524 struct in_addr gateway;
525 unsigned prefixlen;
c07aeadf
TG
526 struct in_addr *nameservers;
527 size_t nameservers_size;
528 int r;
1346b1f0 529
c07aeadf
TG
530 assert(client);
531 assert(link);
ff254138 532
a6cc569e
TG
533 r = sd_dhcp_client_get_lease(client, &lease);
534 if (r < 0) {
535 log_warning_link(link, "DHCP error: no lease: %s",
536 strerror(-r));
537 return r;
538 }
539
540 r = sd_dhcp_lease_get_address(lease, &address);
ff254138 541 if (r < 0) {
c07aeadf
TG
542 log_warning_link(link, "DHCP error: no address: %s",
543 strerror(-r));
544 return r;
ff254138
TG
545 }
546
a6cc569e 547 r = sd_dhcp_lease_get_netmask(lease, &netmask);
ff254138 548 if (r < 0) {
c07aeadf
TG
549 log_warning_link(link, "DHCP error: no netmask: %s",
550 strerror(-r));
551 return r;
ff254138
TG
552 }
553
377a218f 554 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 555
a6cc569e 556 r = sd_dhcp_lease_get_router(lease, &gateway);
ff254138 557 if (r < 0) {
c07aeadf
TG
558 log_warning_link(link, "DHCP error: no router: %s",
559 strerror(-r));
560 return r;
ff254138
TG
561 }
562
c07aeadf
TG
563 log_struct_link(LOG_INFO, link,
564 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
565 link->ifname,
566 ADDRESS_FMT_VAL(address),
567 prefixlen,
568 ADDRESS_FMT_VAL(gateway),
569 "ADDRESS=%u.%u.%u.%u",
570 ADDRESS_FMT_VAL(address),
571 "PREFIXLEN=%u",
572 prefixlen,
573 "GATEWAY=%u.%u.%u.%u",
574 ADDRESS_FMT_VAL(gateway),
575 NULL);
576
d50cf59b
TG
577 link->dhcp_lease = lease;
578
c07aeadf 579 if (link->network->dhcp_dns) {
a6cc569e 580 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
c07aeadf
TG
581 if (r >= 0) {
582 r = manager_update_resolv_conf(link->manager);
583 if (r < 0)
584 log_error("Failed to update resolv.conf");
ff254138 585 }
c07aeadf 586 }
ff254138 587
c07aeadf
TG
588 if (link->network->dhcp_mtu) {
589 uint16_t mtu;
590
a6cc569e 591 r = sd_dhcp_lease_get_mtu(lease, &mtu);
c07aeadf
TG
592 if (r >= 0) {
593 r = link_set_mtu(link, mtu);
594 if (r < 0)
595 log_error_link(link, "Failed to set MTU "
596 "to %" PRIu16, mtu);
597 }
598 }
ff254138 599
c07aeadf
TG
600 if (link->network->dhcp_hostname) {
601 const char *hostname;
ff254138 602
a6cc569e 603 r = sd_dhcp_lease_get_hostname(lease, &hostname);
c07aeadf
TG
604 if (r >= 0) {
605 r = set_hostname(link->manager->bus, hostname);
606 if (r < 0)
607 log_error("Failed to set transient hostname "
608 "to '%s'", hostname);
3bef724f 609 }
c07aeadf 610 }
3bef724f 611
c07aeadf
TG
612 link_enter_set_addresses(link);
613
614 return 0;
615}
616
617static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
618 Link *link = userdata;
619 int r;
620
621 assert(link);
622 assert(link->network);
623 assert(link->manager);
624
625 if (link->state == LINK_STATE_FAILED)
626 return;
627
628 switch (event) {
629 case DHCP_EVENT_NO_LEASE:
630 log_debug_link(link, "IP address in use.");
631 break;
632 case DHCP_EVENT_EXPIRED:
633 case DHCP_EVENT_STOP:
634 case DHCP_EVENT_IP_CHANGE:
635 if (link->network->dhcp_critical) {
636 log_error_link(link, "DHCPv4 connection considered system critical, "
637 "ignoring request to reconfigure it.");
638 return;
4f882b2a 639 }
4f882b2a 640
17256461
UTL
641 if (link->dhcp_lease) {
642 r = dhcp_lease_lost(link);
643 if (r < 0) {
644 link_enter_failed(link);
645 return;
646 }
c07aeadf 647 }
1346b1f0 648
c07aeadf
TG
649 if (event == DHCP_EVENT_IP_CHANGE) {
650 r = dhcp_lease_acquired(client, link);
651 if (r < 0) {
652 link_enter_failed(link);
653 return;
654 }
1346b1f0 655 }
1346b1f0 656
c07aeadf
TG
657 break;
658 case DHCP_EVENT_IP_ACQUIRE:
659 r = dhcp_lease_acquired(client, link);
660 if (r < 0) {
661 link_enter_failed(link);
662 return;
663 }
664 break;
665 default:
666 if (event < 0)
667 log_warning_link(link, "DHCP error: %s", strerror(-event));
668 else
669 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 670 break;
ff254138
TG
671 }
672
673 return;
674}
675
676static int link_acquire_conf(Link *link) {
677 int r;
678
679 assert(link);
680 assert(link->network);
681 assert(link->network->dhcp);
682 assert(link->manager);
683 assert(link->manager->event);
684
a6cc569e
TG
685 if (!link->dhcp_client) {
686 r = sd_dhcp_client_new(&link->dhcp_client);
b25ef18b
TG
687 if (r < 0)
688 return r;
689
a6cc569e 690 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
b25ef18b
TG
691 if (r < 0)
692 return r;
ff254138 693
a6cc569e 694 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
ff254138
TG
695 if (r < 0)
696 return r;
697
a6cc569e 698 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
ff254138
TG
699 if (r < 0)
700 return r;
701
a6cc569e 702 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
ff254138
TG
703 if (r < 0)
704 return r;
6fc73498
TG
705
706 if (link->network->dhcp_mtu) {
a6cc569e 707 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
6fc73498
TG
708 if (r < 0)
709 return r;
710 }
ff254138
TG
711 }
712
ab47d620
TG
713 log_debug_link(link, "acquiring DHCPv4 lease");
714
a6cc569e 715 r = sd_dhcp_client_start(link->dhcp_client);
ff254138
TG
716 if (r < 0)
717 return r;
718
719 return 0;
720}
721
722static int link_update_flags(Link *link, unsigned flags) {
723 int r;
724
725 assert(link);
726 assert(link->network);
727
728 if (link->state == LINK_STATE_FAILED)
729 return 0;
730
efbc88b8 731 if (link->flags == flags) {
ab47d620 732 log_debug_link(link, "link status unchanged: %#.8x", flags);
efbc88b8
TG
733 return 0;
734 }
735
3333d748
ZJS
736 if ((link->flags & IFF_UP) != (flags & IFF_UP))
737 log_info_link(link,
e6674986 738 "link is %s", flags & IFF_UP ? "up": "down");
efbc88b8
TG
739
740 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
741 if (flags & IFF_LOWER_UP) {
39032b87 742 log_info_link(link, "carrier on");
efbc88b8
TG
743
744 if (link->network->dhcp) {
745 r = link_acquire_conf(link);
746 if (r < 0) {
1f6d9bc9 747 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
efbc88b8
TG
748 link_enter_failed(link);
749 return r;
750 }
ff254138 751 }
efbc88b8 752 } else {
39032b87 753 log_info_link(link, "carrier off");
efbc88b8
TG
754
755 if (link->network->dhcp) {
a6cc569e 756 r = sd_dhcp_client_stop(link->dhcp_client);
efbc88b8 757 if (r < 0) {
1f6d9bc9 758 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
efbc88b8
TG
759 link_enter_failed(link);
760 return r;
761 }
ff254138
TG
762 }
763 }
764 }
765
3333d748 766 log_debug_link(link,
ab47d620 767 "link status updated: %#.8x -> %#.8x", link->flags, flags);
efbc88b8 768
ff254138
TG
769 link->flags = flags;
770
771 return 0;
772}
773
dd3efc09
TG
774static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
775 Link *link = userdata;
776 int r;
777
1746cf2a
TG
778 assert(link);
779
780 if (link->state == LINK_STATE_FAILED)
781 return 1;
782
dd3efc09
TG
783 r = sd_rtnl_message_get_errno(m);
784 if (r < 0) {
c9ccc19f
TG
785 log_struct_link(LOG_ERR, link,
786 "MESSAGE=%s: could not bring up interface: %s",
787 link->ifname, strerror(-r),
788 "ERRNO=%d", -r,
789 NULL);
dd3efc09 790 link_enter_failed(link);
c9ccc19f 791 return 1;
dd3efc09 792 }
f882c247 793
ff254138 794 link_update_flags(link, link->flags | IFF_UP);
1746cf2a 795
f882c247
TG
796 return 1;
797}
798
799static int link_up(Link *link) {
cf6a8911 800 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
801 int r;
802
f882c247
TG
803 assert(link);
804 assert(link->manager);
805 assert(link->manager->rtnl);
806
39032b87 807 log_debug_link(link, "bringing link up");
449f7554 808
4fb7242c
TG
809 r = sd_rtnl_message_new_link(link->manager->rtnl, RTM_SETLINK,
810 link->ifindex, &req);
f579559b 811 if (r < 0) {
39032b87 812 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
813 return r;
814 }
815
5d4795f3 816 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 817 if (r < 0) {
3333d748 818 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
819 return r;
820 }
821
dd3efc09 822 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 823 if (r < 0) {
3333d748
ZJS
824 log_error_link(link,
825 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
826 return r;
827 }
828
f882c247
TG
829 return 0;
830}
831
52433f6b 832static int link_enslaved(Link *link) {
f882c247
TG
833 int r;
834
ef1ba606 835 assert(link);
52433f6b 836 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 837 assert(link->network);
dd3efc09 838
f882c247 839 r = link_up(link);
ef1ba606
TG
840 if (r < 0) {
841 link_enter_failed(link);
842 return r;
843 }
f882c247 844
1746cf2a
TG
845 if (!link->network->dhcp)
846 return link_enter_set_addresses(link);
ef1ba606
TG
847
848 return 0;
02b59d57
TG
849}
850
52433f6b 851static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
852 Link *link = userdata;
853 int r;
854
1746cf2a 855 assert(link);
52433f6b 856 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
ef1ba606 857 assert(link->network);
02b59d57 858
52433f6b
TG
859 link->enslaving --;
860
02b59d57
TG
861 if (link->state == LINK_STATE_FAILED)
862 return 1;
863
864 r = sd_rtnl_message_get_errno(m);
ef1ba606 865 if (r < 0) {
c9ccc19f
TG
866 log_struct_link(LOG_ERR, link,
867 "MESSAGE=%s: could not enslave: %s",
868 link->ifname, strerror(-r),
869 "ERRNO=%d", -r,
870 NULL);
ef1ba606
TG
871 link_enter_failed(link);
872 return 1;
3333d748 873 }
02b59d57 874
52433f6b 875 log_debug_link(link, "enslaved");
ab47d620 876
52433f6b
TG
877 if (link->enslaving == 0)
878 link_enslaved(link);
02b59d57
TG
879
880 return 1;
881}
882
52433f6b 883static int link_enter_enslave(Link *link) {
672682a6
TG
884 NetDev *vlan;
885 Iterator i;
02b59d57
TG
886 int r;
887
888 assert(link);
889 assert(link->network);
ef1ba606 890 assert(link->state == _LINK_STATE_INVALID);
02b59d57 891
52433f6b 892 link->state = LINK_STATE_ENSLAVING;
02b59d57 893
63ffa720
TG
894 if (!link->network->bridge && !link->network->bond &&
895 hashmap_isempty(link->network->vlans))
52433f6b 896 return link_enslaved(link);
02b59d57 897
52433f6b
TG
898 if (link->network->bridge) {
899 log_struct_link(LOG_DEBUG, link,
900 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 901 link->ifname, link->network->bridge->name,
52433f6b
TG
902 NETDEV(link->network->bridge),
903 NULL);
449f7554 904
52433f6b
TG
905 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
906 if (r < 0) {
907 log_struct_link(LOG_WARNING, link,
908 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f 909 link->ifname, link->network->bridge->name, strerror(-r),
52433f6b
TG
910 NETDEV(link->network->bridge),
911 NULL);
912 link_enter_failed(link);
913 return r;
914 }
915
916 link->enslaving ++;
917 }
918
672682a6 919 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
52433f6b
TG
920 log_struct_link(LOG_DEBUG, link,
921 "MESSAGE=%s: enslaving by '%s'",
672682a6 922 link->ifname, vlan->name, NETDEV(vlan), NULL);
52433f6b 923
672682a6 924 r = netdev_enslave(vlan, link, &enslave_handler);
52433f6b
TG
925 if (r < 0) {
926 log_struct_link(LOG_WARNING, link,
927 "MESSAGE=%s: could not enslave by '%s': %s",
672682a6
TG
928 link->ifname, vlan->name, strerror(-r),
929 NETDEV(vlan), NULL);
52433f6b
TG
930 link_enter_failed(link);
931 return r;
932 }
933
934 link->enslaving ++;
ef1ba606
TG
935 }
936
937 return 0;
938}
939
11a7f229
TG
940static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
941 void *userdata) {
ef1ba606
TG
942 Link *link = userdata;
943 int r;
944
1746cf2a
TG
945 assert(link);
946
947 if (link->state == LINK_STATE_FAILED)
948 return 1;
949
ef1ba606
TG
950 r = sd_rtnl_message_get_errno(m);
951 if (r < 0) {
c9ccc19f
TG
952 log_struct_link(LOG_ERR, link,
953 "MESSAGE=%s: could not get state: %s",
954 link->ifname, strerror(-r),
955 "ERRNO=%d", -r,
956 NULL);
ef1ba606 957 link_enter_failed(link);
c9ccc19f 958 return 1;
ef1ba606
TG
959 }
960
39032b87 961 log_debug_link(link, "got link state");
1746cf2a 962
5eb036ca
TG
963 link_update(link, m);
964
ef1ba606
TG
965 return 1;
966}
967
11a7f229 968static int link_getlink(Link *link) {
cf6a8911 969 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
ef1ba606
TG
970 int r;
971
972 assert(link);
973 assert(link->manager);
974 assert(link->manager->rtnl);
975
39032b87 976 log_debug_link(link, "requesting link status");
449f7554 977
4fb7242c
TG
978 r = sd_rtnl_message_new_link(link->manager->rtnl, RTM_GETLINK,
979 link->ifindex, &req);
ef1ba606 980 if (r < 0) {
39032b87 981 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
982 return r;
983 }
984
11a7f229
TG
985 r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
986 link, 0, NULL);
ef1ba606 987 if (r < 0) {
3333d748
ZJS
988 log_error_link(link,
989 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 990 return r;
dd3efc09 991 }
02b59d57
TG
992
993 return 0;
994}
995
996int link_configure(Link *link) {
997 int r;
998
ef1ba606
TG
999 assert(link);
1000 assert(link->network);
1001 assert(link->state == _LINK_STATE_INVALID);
1002
11a7f229 1003 r = link_getlink(link);
ef1ba606
TG
1004 if (r < 0) {
1005 link_enter_failed(link);
1006 return r;
1007 }
dd3efc09 1008
52433f6b 1009 return link_enter_enslave(link);
f579559b 1010}
dd3efc09 1011
22936833
TG
1012int link_update(Link *link, sd_rtnl_message *m) {
1013 unsigned flags;
4f882b2a
TG
1014 void *data;
1015 uint16_t type;
22936833
TG
1016 int r;
1017
dd3efc09 1018 assert(link);
22936833
TG
1019 assert(m);
1020
1746cf2a
TG
1021 if (link->state == LINK_STATE_FAILED)
1022 return 0;
1023
22936833
TG
1024 r = sd_rtnl_message_link_get_flags(m, &flags);
1025 if (r < 0) {
4f882b2a 1026 log_warning_link(link, "Could not get link flags");
22936833
TG
1027 return r;
1028 }
dd3efc09 1029
4f882b2a 1030 while (sd_rtnl_message_read(m, &type, &data) > 0) {
396945dc
TG
1031 if (type == IFLA_MTU && link->network->dhcp &&
1032 link->network->dhcp_mtu && !link->original_mtu) {
4f882b2a 1033 link->original_mtu = *(uint16_t *) data;
396945dc
TG
1034 log_debug_link(link, "saved original MTU: %" PRIu16,
1035 link->original_mtu);
4f882b2a
TG
1036 }
1037 }
1038
ff254138 1039 return link_update_flags(link, flags);
dd3efc09 1040}