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