]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
nss-myhostname: port to sd-rtnl
[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"
c6f7c917 29#include "network-internal.h"
f579559b 30
fe8db0c5
TG
31#include "dhcp-lease-internal.h"
32
aba496a5
UTL
33static int ipv4ll_address_update(Link *link, bool deprecate);
34static bool ipv4ll_is_bound(sd_ipv4ll *ll);
35
f579559b
TG
36int link_new(Manager *manager, struct udev_device *device, Link **ret) {
37 _cleanup_link_free_ Link *link = NULL;
c166a070 38 const char *ifname;
f579559b
TG
39 int r;
40
0c2f9b84
TG
41 assert(manager);
42 assert(manager->links);
f579559b
TG
43 assert(device);
44 assert(ret);
45
46 link = new0(Link, 1);
47 if (!link)
48 return -ENOMEM;
49
5a3eb5a7
TG
50 link->manager = manager;
51 link->state = _LINK_STATE_INVALID;
52
0617ffab
TG
53 link->ifindex = udev_device_get_ifindex(device);
54 if (link->ifindex <= 0)
f579559b
TG
55 return -EINVAL;
56
315db1a8
ZJS
57 r = asprintf(&link->state_file, "/run/systemd/network/links/%"PRIu64,
58 link->ifindex);
fe8db0c5 59 if (r < 0)
315db1a8 60 return -ENOMEM;
fe8db0c5 61
c166a070
TG
62 ifname = udev_device_get_sysname(device);
63 link->ifname = strdup(ifname);
64
0617ffab 65 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
66 if (r < 0)
67 return r;
68
b5db00e5
UTL
69 link->udev_device = udev_device_ref(device);
70
f579559b
TG
71 *ret = link;
72 link = NULL;
73
74 return 0;
75}
76
77void link_free(Link *link) {
78 if (!link)
79 return;
80
0617ffab 81 assert(link->manager);
f579559b 82
e5b04c8d 83 sd_dhcp_client_unref(link->dhcp_client);
a6cc569e 84 sd_dhcp_lease_unref(link->dhcp_lease);
f5be5601 85
56cd007a 86 sd_ipv4ll_unref(link->ipv4ll);
5c1d3fc9 87
0617ffab 88 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 89
c166a070 90 free(link->ifname);
fe8db0c5 91 free(link->state_file);
c166a070 92
b5db00e5
UTL
93 udev_device_unref(link->udev_device);
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
f882c247 117static int link_enter_configured(Link *link) {
ef1ba606
TG
118 assert(link);
119 assert(link->state == LINK_STATE_SETTING_ROUTES);
120
39032b87 121 log_info_link(link, "link configured");
f882c247
TG
122
123 link->state = LINK_STATE_CONFIGURED;
124
fe8db0c5
TG
125 link_save(link);
126
f882c247
TG
127 return 0;
128}
129
ef1ba606
TG
130static void link_enter_failed(Link *link) {
131 assert(link);
f882c247 132
39032b87 133 log_warning_link(link, "failed");
449f7554 134
ef1ba606 135 link->state = LINK_STATE_FAILED;
fe8db0c5
TG
136
137 link_save(link);
f882c247
TG
138}
139
f882c247
TG
140static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
141 Link *link = userdata;
142 int r;
143
f5be5601
TG
144 assert(link->route_messages > 0);
145 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
146 link->state == LINK_STATE_SETTING_ROUTES ||
147 link->state == LINK_STATE_FAILED);
f882c247 148
f5be5601 149 link->route_messages --;
f882c247
TG
150
151 if (link->state == LINK_STATE_FAILED)
152 return 1;
153
154 r = sd_rtnl_message_get_errno(m);
c166a070 155 if (r < 0 && r != -EEXIST)
c9ccc19f
TG
156 log_struct_link(LOG_WARNING, link,
157 "MESSAGE=%s: could not set route: %s",
158 link->ifname, strerror(-r),
159 "ERRNO=%d", -r,
160 NULL);
f882c247 161
f5be5601
TG
162 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
163 * ignore it */
164 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 165 log_debug_link(link, "routes set");
dd3efc09
TG
166 link_enter_configured(link);
167 }
f882c247
TG
168
169 return 1;
170}
171
172static int link_enter_set_routes(Link *link) {
a6cc569e 173 Route *rt;
f882c247
TG
174 int r;
175
176 assert(link);
177 assert(link->network);
ef1ba606 178 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 179
ef1ba606 180 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 181
5c1d3fc9 182 if (!link->network->static_routes && !link->dhcp_lease &&
aba496a5 183 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
dd3efc09 184 return link_enter_configured(link);
f882c247 185
39032b87 186 log_debug_link(link, "setting routes");
449f7554 187
a6cc569e
TG
188 LIST_FOREACH(static_routes, rt, link->network->static_routes) {
189 r = route_configure(rt, link, &route_handler);
dd3efc09 190 if (r < 0) {
3333d748
ZJS
191 log_warning_link(link,
192 "could not set routes: %s", strerror(-r));
ef1ba606
TG
193 link_enter_failed(link);
194 return r;
dd3efc09 195 }
c166a070 196
f5be5601
TG
197 link->route_messages ++;
198 }
199
5c1d3fc9
UTL
200 if (link->ipv4ll && !link->dhcp_lease) {
201 _cleanup_route_free_ Route *route = NULL;
202 struct in_addr addr;
203
204 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
205 if (r < 0 && r != -ENOENT) {
206 log_warning_link(link, "IPV4LL error: no address: %s",
207 strerror(-r));
208 return r;
209 }
210
211 if (r != -ENOENT) {
212 r = route_new_dynamic(&route);
213 if (r < 0) {
214 log_error_link(link, "Could not allocate route: %s",
215 strerror(-r));
216 return r;
217 }
218
219 route->family = AF_INET;
220 route->scope = RT_SCOPE_LINK;
221 route->metrics = 99;
222
223 r = route_configure(route, link, &route_handler);
224 if (r < 0) {
225 log_warning_link(link,
226 "could not set routes: %s", strerror(-r));
227 link_enter_failed(link);
228 return r;
229 }
230
231 link->route_messages ++;
232 }
233 }
234
a6cc569e
TG
235 if (link->dhcp_lease) {
236 _cleanup_route_free_ Route *route = NULL;
9765ce69 237 _cleanup_route_free_ Route *route_gw = NULL;
a6cc569e
TG
238 struct in_addr gateway;
239
240 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
241 if (r < 0) {
242 log_warning_link(link, "DHCP error: no router: %s",
243 strerror(-r));
244 return r;
245 }
246
247 r = route_new_dynamic(&route);
248 if (r < 0) {
249 log_error_link(link, "Could not allocate route: %s",
250 strerror(-r));
251 return r;
252 }
253
9765ce69
BP
254 r = route_new_dynamic(&route_gw);
255 if (r < 0) {
256 log_error_link(link, "Could not allocate route: %s",
257 strerror(-r));
258 return r;
259 }
260
261 /* The dhcp netmask may mask out the gateway. Add an explicit
262 * route for the gw host so that we can route no matter the
263 * netmask or existing kernel route tables. */
264 route_gw->family = AF_INET;
265 route_gw->dst_addr.in = gateway;
266 route_gw->dst_prefixlen = 32;
267 route_gw->scope = RT_SCOPE_LINK;
268
269 r = route_configure(route_gw, link, &route_handler);
270 if (r < 0) {
271 log_warning_link(link,
272 "could not set host route: %s", strerror(-r));
273 return r;
274 }
275
276 link->route_messages ++;
277
a6cc569e
TG
278 route->family = AF_INET;
279 route->in_addr.in = gateway;
280
281 r = route_configure(route, link, &route_handler);
f5be5601 282 if (r < 0) {
3333d748
ZJS
283 log_warning_link(link,
284 "could not set routes: %s", strerror(-r));
f5be5601
TG
285 link_enter_failed(link);
286 return r;
287 }
288
289 link->route_messages ++;
f882c247
TG
290 }
291
292 return 0;
293}
294
5c1d3fc9
UTL
295static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
296 Link *link = userdata;
297 int r;
298
299 assert(m);
300 assert(link);
301 assert(link->ifname);
302
303 if (link->state == LINK_STATE_FAILED)
304 return 1;
305
306 r = sd_rtnl_message_get_errno(m);
307 if (r < 0 && r != -ENOENT)
308 log_struct_link(LOG_WARNING, link,
309 "MESSAGE=%s: could not drop route: %s",
310 link->ifname, strerror(-r),
311 "ERRNO=%d", -r,
312 NULL);
313
314 return 0;
315}
316
f882c247
TG
317static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
318 Link *link = userdata;
319 int r;
320
f5be5601
TG
321 assert(m);
322 assert(link);
323 assert(link->ifname);
324 assert(link->addr_messages > 0);
ef1ba606 325 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
f882c247 326
f5be5601 327 link->addr_messages --;
f882c247
TG
328
329 if (link->state == LINK_STATE_FAILED)
330 return 1;
331
332 r = sd_rtnl_message_get_errno(m);
c166a070 333 if (r < 0 && r != -EEXIST)
c9ccc19f 334 log_struct_link(LOG_WARNING, link,
3333d748
ZJS
335 "MESSAGE=%s: could not set address: %s",
336 link->ifname, strerror(-r),
337 "ERRNO=%d", -r,
338 NULL);
f882c247 339
f5be5601 340 if (link->addr_messages == 0) {
39032b87 341 log_debug_link(link, "addresses set");
ef1ba606 342 link_enter_set_routes(link);
dd3efc09 343 }
f882c247
TG
344
345 return 1;
346}
347
348static int link_enter_set_addresses(Link *link) {
a6cc569e 349 Address *ad;
f882c247
TG
350 int r;
351
352 assert(link);
353 assert(link->network);
f5be5601 354 assert(link->state != _LINK_STATE_INVALID);
f882c247 355
ef1ba606 356 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 357
5c1d3fc9 358 if (!link->network->static_addresses && !link->dhcp_lease &&
aba496a5 359 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
ef1ba606 360 return link_enter_set_routes(link);
f882c247 361
39032b87 362 log_debug_link(link, "setting addresses");
449f7554 363
a6cc569e
TG
364 LIST_FOREACH(static_addresses, ad, link->network->static_addresses) {
365 r = address_configure(ad, link, &address_handler);
dd3efc09 366 if (r < 0) {
3333d748
ZJS
367 log_warning_link(link,
368 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
369 link_enter_failed(link);
370 return r;
dd3efc09 371 }
c166a070 372
f5be5601
TG
373 link->addr_messages ++;
374 }
375
5c1d3fc9
UTL
376 if (link->ipv4ll && !link->dhcp_lease) {
377 _cleanup_address_free_ Address *ll_addr = NULL;
378 struct in_addr addr;
379
380 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
381 if (r < 0 && r != -ENOENT) {
382 log_warning_link(link, "IPV4LL error: no address: %s",
383 strerror(-r));
384 return r;
385 }
386
387 if (r != -ENOENT) {
388 r = address_new_dynamic(&ll_addr);
389 if (r < 0) {
390 log_error_link(link, "Could not allocate address: %s", strerror(-r));
391 return r;
392 }
393
394 ll_addr->family = AF_INET;
395 ll_addr->in_addr.in = addr;
396 ll_addr->prefixlen = 16;
397 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
398 ll_addr->scope = RT_SCOPE_LINK;
399
400 r = address_configure(ll_addr, link, &address_handler);
401 if (r < 0) {
402 log_warning_link(link,
403 "could not set addresses: %s", strerror(-r));
404 link_enter_failed(link);
405 return r;
406 }
407
408 link->addr_messages ++;
409 }
410 }
411
a6cc569e
TG
412 if (link->dhcp_lease) {
413 _cleanup_address_free_ Address *address = NULL;
414 struct in_addr addr;
415 struct in_addr netmask;
416 unsigned prefixlen;
417
418 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
419 if (r < 0) {
420 log_warning_link(link, "DHCP error: no address: %s",
421 strerror(-r));
422 return r;
423 }
424
425 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
426 if (r < 0) {
427 log_warning_link(link, "DHCP error: no netmask: %s",
428 strerror(-r));
429 return r;
430 }
431
432 prefixlen = net_netmask_to_prefixlen(&netmask);
433
434 r = address_new_dynamic(&address);
435 if (r < 0) {
436 log_error_link(link, "Could not allocate address: %s",
437 strerror(-r));
438 return r;
439 }
440
441 address->family = AF_INET;
442 address->in_addr.in = addr;
443 address->prefixlen = prefixlen;
444 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
445
446 r = address_configure(address, link, &address_handler);
f5be5601 447 if (r < 0) {
3333d748
ZJS
448 log_warning_link(link,
449 "could not set addresses: %s", strerror(-r));
f5be5601
TG
450 link_enter_failed(link);
451 return r;
452 }
453
454 link->addr_messages ++;
f882c247
TG
455 }
456
457 return 0;
458}
459
aba496a5
UTL
460static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
461 Link *link = userdata;
462 int r;
463
464 assert(m);
465 assert(link);
466 assert(link->ifname);
467
468 if (link->state == LINK_STATE_FAILED)
469 return 1;
470
471 r = sd_rtnl_message_get_errno(m);
472 if (r < 0 && r != -ENOENT)
473 log_struct_link(LOG_WARNING, link,
474 "MESSAGE=%s: could not update address: %s",
475 link->ifname, strerror(-r),
476 "ERRNO=%d", -r,
477 NULL);
478
479 return 0;
480}
481
ff254138
TG
482static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
483 Link *link = userdata;
484 int r;
485
486 assert(m);
487 assert(link);
488 assert(link->ifname);
489
490 if (link->state == LINK_STATE_FAILED)
491 return 1;
492
493 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
494 if (r < 0 && r != -ENOENT)
495 log_struct_link(LOG_WARNING, link,
496 "MESSAGE=%s: could not drop address: %s",
497 link->ifname, strerror(-r),
498 "ERRNO=%d", -r,
499 NULL);
ff254138 500
5c1d3fc9 501 return 0;
ff254138
TG
502}
503
1346b1f0
TG
504static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
505 int r;
506
507 r = sd_bus_message_get_errno(m);
508 if (r < 0)
509 log_warning("Could not set hostname: %s", strerror(-r));
510
511 return 1;
512}
513
514static int set_hostname(sd_bus *bus, const char *hostname) {
515 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
516 int r = 0;
517
1346b1f0
TG
518 assert(hostname);
519
520 log_debug("Setting transient hostname: '%s'", hostname);
521
bcbca829
TG
522 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
523 log_info("Not connected to system bus, ignoring transient hostname.");
524 return 0;
525 }
526
1346b1f0
TG
527 r = sd_bus_message_new_method_call(
528 bus,
151b9b96 529 &m,
1346b1f0
TG
530 "org.freedesktop.hostname1",
531 "/org/freedesktop/hostname1",
532 "org.freedesktop.hostname1",
151b9b96 533 "SetHostname");
1346b1f0
TG
534 if (r < 0)
535 return r;
536
537 r = sd_bus_message_append(m, "sb", hostname, false);
538 if (r < 0)
539 return r;
540
541 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
542 if (r < 0)
543 log_error("Could not set transient hostname: %s", strerror(-r));
544
545 return r;
546}
547
4f882b2a
TG
548static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
549 Link *link = userdata;
550 int r;
551
552 assert(m);
553 assert(link);
554 assert(link->ifname);
555
556 if (link->state == LINK_STATE_FAILED)
557 return 1;
558
559 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
560 if (r < 0)
561 log_struct_link(LOG_WARNING, link,
562 "MESSAGE=%s: could not set MTU: %s",
563 link->ifname, strerror(-r),
564 "ERRNO=%d", -r,
565 NULL);
4f882b2a
TG
566
567 return 1;
568}
569
570static int link_set_mtu(Link *link, uint32_t mtu) {
cf6a8911 571 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
4f882b2a
TG
572 int r;
573
574 assert(link);
575 assert(link->manager);
576 assert(link->manager->rtnl);
577
578 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
579
151b9b96
LP
580 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
581 RTM_SETLINK, link->ifindex);
4f882b2a
TG
582 if (r < 0) {
583 log_error_link(link, "Could not allocate RTM_SETLINK message");
584 return r;
585 }
586
587 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
588 if (r < 0) {
589 log_error_link(link, "Could not append MTU: %s", strerror(-r));
590 return r;
591 }
592
593 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
594 if (r < 0) {
595 log_error_link(link,
596 "Could not send rtnetlink message: %s", strerror(-r));
597 return r;
598 }
599
600 return 0;
601}
602
a6cc569e
TG
603static int dhcp_lease_lost(Link *link) {
604 _cleanup_address_free_ Address *address = NULL;
3e790eae
UTL
605 _cleanup_route_free_ Route *route_gw = NULL;
606 _cleanup_route_free_ Route *route = NULL;
a6cc569e
TG
607 struct in_addr addr;
608 struct in_addr netmask;
3e790eae 609 struct in_addr gateway;
a6cc569e 610 unsigned prefixlen;
ff254138
TG
611 int r;
612
613 assert(link);
a6cc569e 614 assert(link->dhcp_lease);
ff254138 615
14efd761
TG
616 log_warning_link(link, "DHCP lease lost");
617
a6cc569e
TG
618 r = address_new_dynamic(&address);
619 if (r >= 0) {
620 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
621 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
3e790eae 622 sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
a6cc569e 623 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 624
3e790eae
UTL
625 r = route_new_dynamic(&route_gw);
626 if (r >= 0) {
627 route_gw->family = AF_INET;
628 route_gw->dst_addr.in = gateway;
629 route_gw->dst_prefixlen = 32;
630 route_gw->scope = RT_SCOPE_LINK;
631
632 route_drop(route_gw, link, &route_drop_handler);
633 }
634
635 r = route_new_dynamic(&route);
636 if (r >= 0) {
637 route->family = AF_INET;
638 route->in_addr.in = gateway;
639
640 route_drop(route, link, &route_drop_handler);
641 }
642
a6cc569e
TG
643 address->family = AF_INET;
644 address->in_addr.in = addr;
645 address->prefixlen = prefixlen;
ff254138 646
5c1d3fc9 647 address_drop(address, link, &address_drop_handler);
c07aeadf 648 }
eb27aeca 649
c07aeadf
TG
650 if (link->network->dhcp_mtu) {
651 uint16_t mtu;
ff254138 652
a6cc569e 653 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
c07aeadf
TG
654 if (r >= 0 && link->original_mtu != mtu) {
655 r = link_set_mtu(link, link->original_mtu);
656 if (r < 0) {
657 log_warning_link(link, "DHCP error: could not reset MTU");
658 link_enter_failed(link);
659 return r;
660 }
ff254138 661 }
c07aeadf 662 }
ff254138 663
c07aeadf 664 if (link->network->dhcp_hostname) {
216816c6
TG
665 const char *hostname = NULL;
666
667 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
668 if (r >= 0 && hostname) {
669 r = set_hostname(link->manager->bus, "");
670 if (r < 0)
671 log_error("Failed to reset transient hostname");
672 }
c07aeadf 673 }
4f882b2a 674
a6cc569e
TG
675 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
676
c07aeadf
TG
677 return 0;
678}
4f882b2a 679
c07aeadf 680static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
a6cc569e 681 sd_dhcp_lease *lease;
c07aeadf
TG
682 struct in_addr address;
683 struct in_addr netmask;
684 struct in_addr gateway;
685 unsigned prefixlen;
c07aeadf
TG
686 struct in_addr *nameservers;
687 size_t nameservers_size;
688 int r;
1346b1f0 689
c07aeadf
TG
690 assert(client);
691 assert(link);
ff254138 692
a6cc569e
TG
693 r = sd_dhcp_client_get_lease(client, &lease);
694 if (r < 0) {
695 log_warning_link(link, "DHCP error: no lease: %s",
696 strerror(-r));
697 return r;
698 }
699
700 r = sd_dhcp_lease_get_address(lease, &address);
ff254138 701 if (r < 0) {
c07aeadf
TG
702 log_warning_link(link, "DHCP error: no address: %s",
703 strerror(-r));
704 return r;
ff254138
TG
705 }
706
a6cc569e 707 r = sd_dhcp_lease_get_netmask(lease, &netmask);
ff254138 708 if (r < 0) {
c07aeadf
TG
709 log_warning_link(link, "DHCP error: no netmask: %s",
710 strerror(-r));
711 return r;
ff254138
TG
712 }
713
377a218f 714 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 715
a6cc569e 716 r = sd_dhcp_lease_get_router(lease, &gateway);
ff254138 717 if (r < 0) {
c07aeadf
TG
718 log_warning_link(link, "DHCP error: no router: %s",
719 strerror(-r));
720 return r;
ff254138
TG
721 }
722
c07aeadf
TG
723 log_struct_link(LOG_INFO, link,
724 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
725 link->ifname,
726 ADDRESS_FMT_VAL(address),
727 prefixlen,
728 ADDRESS_FMT_VAL(gateway),
729 "ADDRESS=%u.%u.%u.%u",
730 ADDRESS_FMT_VAL(address),
731 "PREFIXLEN=%u",
732 prefixlen,
733 "GATEWAY=%u.%u.%u.%u",
734 ADDRESS_FMT_VAL(gateway),
735 NULL);
736
d50cf59b
TG
737 link->dhcp_lease = lease;
738
c07aeadf 739 if (link->network->dhcp_dns) {
a6cc569e 740 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
c07aeadf
TG
741 if (r >= 0) {
742 r = manager_update_resolv_conf(link->manager);
743 if (r < 0)
744 log_error("Failed to update resolv.conf");
ff254138 745 }
c07aeadf 746 }
ff254138 747
c07aeadf
TG
748 if (link->network->dhcp_mtu) {
749 uint16_t mtu;
750
a6cc569e 751 r = sd_dhcp_lease_get_mtu(lease, &mtu);
c07aeadf
TG
752 if (r >= 0) {
753 r = link_set_mtu(link, mtu);
754 if (r < 0)
755 log_error_link(link, "Failed to set MTU "
756 "to %" PRIu16, mtu);
757 }
758 }
ff254138 759
c07aeadf
TG
760 if (link->network->dhcp_hostname) {
761 const char *hostname;
ff254138 762
a6cc569e 763 r = sd_dhcp_lease_get_hostname(lease, &hostname);
c07aeadf
TG
764 if (r >= 0) {
765 r = set_hostname(link->manager->bus, hostname);
766 if (r < 0)
767 log_error("Failed to set transient hostname "
768 "to '%s'", hostname);
3bef724f 769 }
c07aeadf 770 }
3bef724f 771
c07aeadf
TG
772 link_enter_set_addresses(link);
773
774 return 0;
775}
776
777static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
778 Link *link = userdata;
aba496a5 779 int r = 0;
c07aeadf
TG
780
781 assert(link);
782 assert(link->network);
783 assert(link->manager);
784
785 if (link->state == LINK_STATE_FAILED)
786 return;
787
788 switch (event) {
789 case DHCP_EVENT_NO_LEASE:
790 log_debug_link(link, "IP address in use.");
791 break;
792 case DHCP_EVENT_EXPIRED:
793 case DHCP_EVENT_STOP:
794 case DHCP_EVENT_IP_CHANGE:
795 if (link->network->dhcp_critical) {
796 log_error_link(link, "DHCPv4 connection considered system critical, "
797 "ignoring request to reconfigure it.");
798 return;
4f882b2a 799 }
4f882b2a 800
17256461
UTL
801 if (link->dhcp_lease) {
802 r = dhcp_lease_lost(link);
803 if (r < 0) {
804 link_enter_failed(link);
805 return;
806 }
c07aeadf 807 }
1346b1f0 808
c07aeadf
TG
809 if (event == DHCP_EVENT_IP_CHANGE) {
810 r = dhcp_lease_acquired(client, link);
811 if (r < 0) {
812 link_enter_failed(link);
813 return;
814 }
1346b1f0 815 }
1346b1f0 816
5c1d3fc9 817 if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
aba496a5
UTL
818 if (!sd_ipv4ll_is_running(link->ipv4ll))
819 r = sd_ipv4ll_start(link->ipv4ll);
820 else if (ipv4ll_is_bound(link->ipv4ll))
821 r = ipv4ll_address_update(link, false);
5c1d3fc9
UTL
822 if (r < 0) {
823 link_enter_failed(link);
824 return;
825 }
826 }
827
c07aeadf
TG
828 break;
829 case DHCP_EVENT_IP_ACQUIRE:
830 r = dhcp_lease_acquired(client, link);
831 if (r < 0) {
832 link_enter_failed(link);
833 return;
834 }
5c1d3fc9 835 if (link->ipv4ll) {
aba496a5
UTL
836 if (ipv4ll_is_bound(link->ipv4ll))
837 r = ipv4ll_address_update(link, true);
838 else
839 r = sd_ipv4ll_stop(link->ipv4ll);
5c1d3fc9
UTL
840 if (r < 0) {
841 link_enter_failed(link);
842 return;
843 }
844 }
c07aeadf
TG
845 break;
846 default:
847 if (event < 0)
848 log_warning_link(link, "DHCP error: %s", strerror(-event));
849 else
850 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 851 break;
ff254138
TG
852 }
853
854 return;
855}
856
aba496a5
UTL
857static int ipv4ll_address_update(Link *link, bool deprecate) {
858 int r;
859 struct in_addr addr;
860
861 assert(link);
862
863 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
864 if (r >= 0) {
865 _cleanup_address_free_ Address *address = NULL;
866
867 log_debug_link(link, "IPv4 link-local %s %u.%u.%u.%u",
868 deprecate ? "deprecate" : "approve",
869 ADDRESS_FMT_VAL(addr));
870
871 r = address_new_dynamic(&address);
872 if (r < 0) {
873 log_error_link(link, "Could not allocate address: %s", strerror(-r));
874 return r;
875 }
876
877 address->family = AF_INET;
878 address->in_addr.in = addr;
879 address->prefixlen = 16;
880 address->scope = RT_SCOPE_LINK;
881 address->cinfo.ifa_prefered = deprecate ? 0 : CACHE_INFO_INFINITY_LIFE_TIME;
882 address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen);
883
884 address_update(address, link, &address_update_handler);
885 }
886
887 return 0;
888
889}
890
891static int ipv4ll_address_lost(Link *link) {
5c1d3fc9
UTL
892 int r;
893 struct in_addr addr;
894
5c1d3fc9
UTL
895 assert(link);
896
897 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
898 if (r >= 0) {
899 _cleanup_address_free_ Address *address = NULL;
900 _cleanup_route_free_ Route *route = NULL;
901
902 log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u",
903 ADDRESS_FMT_VAL(addr));
904
905 r = address_new_dynamic(&address);
906 if (r < 0) {
907 log_error_link(link, "Could not allocate address: %s", strerror(-r));
908 return r;
909 }
910
911 address->family = AF_INET;
912 address->in_addr.in = addr;
913 address->prefixlen = 16;
914 address->scope = RT_SCOPE_LINK;
915
916 address_drop(address, link, &address_drop_handler);
917
918 r = route_new_dynamic(&route);
919 if (r < 0) {
920 log_error_link(link, "Could not allocate route: %s",
921 strerror(-r));
922 return r;
923 }
924
925 route->family = AF_INET;
926 route->scope = RT_SCOPE_LINK;
927 route->metrics = 99;
928
929 route_drop(route, link, &route_drop_handler);
930 }
931
932 return 0;
933}
934
aba496a5
UTL
935static bool ipv4ll_is_bound(sd_ipv4ll *ll) {
936 int r;
937 struct in_addr addr;
938
939 assert(ll);
940
941 r = sd_ipv4ll_get_address(ll, &addr);
942 if (r < 0)
943 return false;
944 return true;
945}
946
5c1d3fc9
UTL
947static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
948 struct in_addr address;
949 int r;
950
951 assert(ll);
952 assert(link);
953
954 r = sd_ipv4ll_get_address(ll, &address);
955 if (r < 0)
956 return r;
957
958 log_struct_link(LOG_INFO, link,
959 "MESSAGE=%s: IPv4 link-local address %u.%u.%u.%u",
960 link->ifname,
961 ADDRESS_FMT_VAL(address),
962 NULL);
963
964 link_enter_set_addresses(link);
965
966 return 0;
967}
968
969static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
970 Link *link = userdata;
971 int r;
972
973 assert(link);
974 assert(link->network);
975 assert(link->manager);
976
977 switch(event) {
978 case IPV4LL_EVENT_STOP:
979 case IPV4LL_EVENT_CONFLICT:
aba496a5 980 r = ipv4ll_address_lost(link);
5c1d3fc9
UTL
981 if (r < 0) {
982 link_enter_failed(link);
983 return;
984 }
985 break;
986 case IPV4LL_EVENT_BIND:
987 r = ipv4ll_address_claimed(ll, link);
988 if (r < 0) {
989 link_enter_failed(link);
990 return;
991 }
992 break;
993 default:
994 if (event < 0)
995 log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
996 else
997 log_warning_link(link, "IPv4 link-local unknown event: %d", event);
998 break;
999 }
1000}
1001
ff254138
TG
1002static int link_acquire_conf(Link *link) {
1003 int r;
1004
1005 assert(link);
1006 assert(link->network);
ff254138
TG
1007 assert(link->manager);
1008 assert(link->manager->event);
1009
5c1d3fc9 1010 if (link->network->ipv4ll) {
eb34d4af 1011 assert(link->ipv4ll);
ff254138 1012
5c1d3fc9
UTL
1013 log_debug_link(link, "acquiring IPv4 link-local address");
1014
1015 r = sd_ipv4ll_start(link->ipv4ll);
ff254138
TG
1016 if (r < 0)
1017 return r;
5c1d3fc9
UTL
1018 }
1019
1020 if (link->network->dhcp) {
eb34d4af 1021 assert(link->dhcp_client);
ff254138 1022
5c1d3fc9 1023 log_debug_link(link, "acquiring DHCPv4 lease");
ab47d620 1024
5c1d3fc9
UTL
1025 r = sd_dhcp_client_start(link->dhcp_client);
1026 if (r < 0)
1027 return r;
1028 }
ff254138
TG
1029
1030 return 0;
1031}
1032
1033static int link_update_flags(Link *link, unsigned flags) {
ffba6166 1034 unsigned flags_added, flags_removed, generic_flags;
7cc832b9 1035 bool carrier_gained, carrier_lost;
ff254138
TG
1036 int r;
1037
1038 assert(link);
1039 assert(link->network);
1040
1041 if (link->state == LINK_STATE_FAILED)
1042 return 0;
1043
a748b692 1044 if (link->flags == flags)
efbc88b8 1045 return 0;
efbc88b8 1046
ffba6166
TG
1047 flags_added = (link->flags ^ flags) & flags;
1048 flags_removed = (link->flags ^ flags) & link->flags;
1049 generic_flags = ~(IFF_UP | IFF_LOWER_UP | IFF_RUNNING);
c49b33ac 1050
7cc832b9
TG
1051 /* consider link to have carrier when both RUNNING and LOWER_UP, as RUNNING
1052 may mean that the oper state is unknown, in which case we should fall back to
1053 simply trust LOWER_UP, even thought that is less reliable
1054 */
1055 carrier_gained = ((flags_added & IFF_LOWER_UP) && (flags & IFF_RUNNING)) ||
1056 ((flags_added & IFF_RUNNING) && (flags & IFF_LOWER_UP));
1057 carrier_lost = ((link->flags & (IFF_RUNNING | IFF_LOWER_UP)) ==
1058 (IFF_RUNNING | IFF_LOWER_UP)) &&
1059 (flags_removed & (IFF_LOWER_UP | IFF_RUNNING));
1060
1061 link->flags = flags;
1062
ffba6166
TG
1063 if (flags_added & generic_flags)
1064 log_debug_link(link, "link flags gained: %#.8x",
1065 flags_added & generic_flags);
efbc88b8 1066
ffba6166
TG
1067 if (flags_removed & generic_flags)
1068 log_debug_link(link, "link flags lost: %#.8x",
1069 flags_removed & generic_flags);
efbc88b8 1070
ffba6166
TG
1071 if (flags_added & IFF_UP)
1072 log_info_link(link, "link is up");
1073 else if (flags_removed & IFF_UP)
1074 log_info_link(link, "link is down");
1075
1076 if (flags_added & IFF_LOWER_UP)
3379e257 1077 log_debug_link(link, "link is lower up");
ffba6166 1078 else if (flags_removed & IFF_LOWER_UP)
3379e257 1079 log_debug_link(link, "link is lower down");
ffba6166 1080
7cc832b9 1081 if (flags_added & IFF_RUNNING)
3379e257 1082 log_debug_link(link, "link is running");
7cc832b9 1083 else if (flags_removed & IFF_RUNNING)
3379e257 1084 log_debug_link(link, "link is not running");
ffba6166 1085
7cc832b9
TG
1086 if (carrier_gained) {
1087 log_info_link(link, "gained carrier");
ffba6166
TG
1088
1089 if (link->network->dhcp || link->network->ipv4ll) {
1090 r = link_acquire_conf(link);
1091 if (r < 0) {
1092 log_warning_link(link, "Could not acquire configuration: %s", strerror(-r));
1093 link_enter_failed(link);
1094 return r;
ff254138 1095 }
ffba6166 1096 }
7cc832b9
TG
1097 } else if (carrier_lost) {
1098 log_info_link(link, "lost carrier");
efbc88b8 1099
ffba6166
TG
1100 if (link->network->dhcp) {
1101 r = sd_dhcp_client_stop(link->dhcp_client);
1102 if (r < 0) {
1103 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
1104 link_enter_failed(link);
1105 return r;
ff254138 1106 }
ffba6166 1107 }
5c1d3fc9 1108
ffba6166
TG
1109 if (link->network->ipv4ll) {
1110 r = sd_ipv4ll_stop(link->ipv4ll);
1111 if (r < 0) {
1112 log_warning_link(link, "Could not stop IPv4 link-local: %s", strerror(-r));
1113 link_enter_failed(link);
1114 return r;
5c1d3fc9 1115 }
ff254138
TG
1116 }
1117 }
1118
ff254138
TG
1119 return 0;
1120}
1121
dd3efc09
TG
1122static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
1123 Link *link = userdata;
1124 int r;
1125
1746cf2a
TG
1126 assert(link);
1127
1128 if (link->state == LINK_STATE_FAILED)
1129 return 1;
1130
dd3efc09 1131 r = sd_rtnl_message_get_errno(m);
58b12917
ZJS
1132 if (r >= 0)
1133 link_update_flags(link, link->flags | IFF_UP);
1134 else
76800848 1135 log_struct_link(LOG_WARNING, link,
c9ccc19f
TG
1136 "MESSAGE=%s: could not bring up interface: %s",
1137 link->ifname, strerror(-r),
1138 "ERRNO=%d", -r,
1139 NULL);
f882c247
TG
1140 return 1;
1141}
1142
1143static int link_up(Link *link) {
cf6a8911 1144 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
1145 int r;
1146
f882c247
TG
1147 assert(link);
1148 assert(link->manager);
1149 assert(link->manager->rtnl);
1150
39032b87 1151 log_debug_link(link, "bringing link up");
449f7554 1152
151b9b96
LP
1153 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1154 RTM_SETLINK, link->ifindex);
f579559b 1155 if (r < 0) {
39032b87 1156 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
1157 return r;
1158 }
1159
5d4795f3 1160 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 1161 if (r < 0) {
3333d748 1162 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
1163 return r;
1164 }
1165
dd3efc09 1166 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 1167 if (r < 0) {
3333d748
ZJS
1168 log_error_link(link,
1169 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
1170 return r;
1171 }
1172
f882c247
TG
1173 return 0;
1174}
1175
52433f6b 1176static int link_enslaved(Link *link) {
f882c247
TG
1177 int r;
1178
ef1ba606 1179 assert(link);
52433f6b 1180 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 1181 assert(link->network);
dd3efc09 1182
f882c247 1183 r = link_up(link);
ef1ba606
TG
1184 if (r < 0) {
1185 link_enter_failed(link);
1186 return r;
1187 }
f882c247 1188
5c1d3fc9 1189 if (!link->network->dhcp && !link->network->ipv4ll)
1746cf2a 1190 return link_enter_set_addresses(link);
ef1ba606
TG
1191
1192 return 0;
02b59d57
TG
1193}
1194
52433f6b 1195static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
02b59d57
TG
1196 Link *link = userdata;
1197 int r;
1198
1746cf2a 1199 assert(link);
52433f6b 1200 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
ef1ba606 1201 assert(link->network);
02b59d57 1202
52433f6b
TG
1203 link->enslaving --;
1204
02b59d57
TG
1205 if (link->state == LINK_STATE_FAILED)
1206 return 1;
1207
1208 r = sd_rtnl_message_get_errno(m);
ef1ba606 1209 if (r < 0) {
c9ccc19f
TG
1210 log_struct_link(LOG_ERR, link,
1211 "MESSAGE=%s: could not enslave: %s",
1212 link->ifname, strerror(-r),
1213 "ERRNO=%d", -r,
1214 NULL);
ef1ba606
TG
1215 link_enter_failed(link);
1216 return 1;
3333d748 1217 }
02b59d57 1218
52433f6b 1219 log_debug_link(link, "enslaved");
ab47d620 1220
52433f6b
TG
1221 if (link->enslaving == 0)
1222 link_enslaved(link);
02b59d57
TG
1223
1224 return 1;
1225}
1226
52433f6b 1227static int link_enter_enslave(Link *link) {
fe6b2d55 1228 NetDev *vlan, *macvlan;
672682a6 1229 Iterator i;
02b59d57
TG
1230 int r;
1231
1232 assert(link);
1233 assert(link->network);
ef1ba606 1234 assert(link->state == _LINK_STATE_INVALID);
02b59d57 1235
52433f6b 1236 link->state = LINK_STATE_ENSLAVING;
02b59d57 1237
fe8db0c5
TG
1238 link_save(link);
1239
63ffa720 1240 if (!link->network->bridge && !link->network->bond &&
fe6b2d55
TG
1241 hashmap_isempty(link->network->vlans) &&
1242 hashmap_isempty(link->network->macvlans))
52433f6b 1243 return link_enslaved(link);
02b59d57 1244
52433f6b
TG
1245 if (link->network->bridge) {
1246 log_struct_link(LOG_DEBUG, link,
1247 "MESSAGE=%s: enslaving by '%s'",
c9ccc19f 1248 link->ifname, link->network->bridge->name,
52433f6b
TG
1249 NETDEV(link->network->bridge),
1250 NULL);
449f7554 1251
52433f6b
TG
1252 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
1253 if (r < 0) {
1254 log_struct_link(LOG_WARNING, link,
1255 "MESSAGE=%s: could not enslave by '%s': %s",
c9ccc19f 1256 link->ifname, link->network->bridge->name, strerror(-r),
52433f6b
TG
1257 NETDEV(link->network->bridge),
1258 NULL);
1259 link_enter_failed(link);
1260 return r;
1261 }
1262
0ad6148e
MO
1263 link->enslaving ++;
1264 }
1265
1266 if (link->network->bond) {
1267 log_struct_link(LOG_DEBUG, link,
1268 "MESSAGE=%s: enslaving by '%s'",
1269 link->ifname, link->network->bond->name,
1270 NETDEV(link->network->bond),
1271 NULL);
1272
1273 r = netdev_enslave(link->network->bond, link, &enslave_handler);
1274 if (r < 0) {
1275 log_struct_link(LOG_WARNING, link,
1276 "MESSAGE=%s: could not enslave by '%s': %s",
1277 link->ifname, link->network->bond->name, strerror(-r),
1278 NETDEV(link->network->bond),
1279 NULL);
1280 link_enter_failed(link);
1281 return r;
1282 }
1283
52433f6b
TG
1284 link->enslaving ++;
1285 }
1286
672682a6 1287 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
52433f6b
TG
1288 log_struct_link(LOG_DEBUG, link,
1289 "MESSAGE=%s: enslaving by '%s'",
672682a6 1290 link->ifname, vlan->name, NETDEV(vlan), NULL);
52433f6b 1291
672682a6 1292 r = netdev_enslave(vlan, link, &enslave_handler);
52433f6b
TG
1293 if (r < 0) {
1294 log_struct_link(LOG_WARNING, link,
1295 "MESSAGE=%s: could not enslave by '%s': %s",
672682a6
TG
1296 link->ifname, vlan->name, strerror(-r),
1297 NETDEV(vlan), NULL);
52433f6b
TG
1298 link_enter_failed(link);
1299 return r;
1300 }
1301
1302 link->enslaving ++;
ef1ba606
TG
1303 }
1304
fe6b2d55
TG
1305 HASHMAP_FOREACH(macvlan, link->network->macvlans, i) {
1306 log_struct_link(LOG_DEBUG, link,
1307 "MESSAGE=%s: enslaving by '%s'",
1308 link->ifname, macvlan->name, NETDEV(macvlan), NULL);
1309
1310 r = netdev_enslave(macvlan, link, &enslave_handler);
1311 if (r < 0) {
1312 log_struct_link(LOG_WARNING, link,
1313 "MESSAGE=%s: could not enslave by '%s': %s",
1314 link->ifname, macvlan->name, strerror(-r),
1315 NETDEV(macvlan), NULL);
1316 link_enter_failed(link);
1317 return r;
1318 }
1319
1320 link->enslaving ++;
1321 }
1322
ef1ba606
TG
1323 return 0;
1324}
1325
11a7f229
TG
1326static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
1327 void *userdata) {
ef1ba606
TG
1328 Link *link = userdata;
1329 int r;
1330
1746cf2a 1331 assert(link);
7ff8f4b5 1332 assert(link->ifname);
1746cf2a
TG
1333
1334 if (link->state == LINK_STATE_FAILED)
1335 return 1;
1336
ef1ba606
TG
1337 r = sd_rtnl_message_get_errno(m);
1338 if (r < 0) {
c9ccc19f
TG
1339 log_struct_link(LOG_ERR, link,
1340 "MESSAGE=%s: could not get state: %s",
1341 link->ifname, strerror(-r),
1342 "ERRNO=%d", -r,
1343 NULL);
ef1ba606 1344 link_enter_failed(link);
c9ccc19f 1345 return 1;
ef1ba606
TG
1346 }
1347
5eb036ca
TG
1348 link_update(link, m);
1349
ef1ba606
TG
1350 return 1;
1351}
1352
11a7f229 1353static int link_getlink(Link *link) {
cf6a8911 1354 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
ef1ba606
TG
1355 int r;
1356
1357 assert(link);
1358 assert(link->manager);
1359 assert(link->manager->rtnl);
1360
39032b87 1361 log_debug_link(link, "requesting link status");
449f7554 1362
151b9b96
LP
1363 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1364 RTM_GETLINK, link->ifindex);
ef1ba606 1365 if (r < 0) {
39032b87 1366 log_error_link(link, "Could not allocate RTM_GETLINK message");
ef1ba606
TG
1367 return r;
1368 }
1369
11a7f229
TG
1370 r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
1371 link, 0, NULL);
ef1ba606 1372 if (r < 0) {
3333d748
ZJS
1373 log_error_link(link,
1374 "Could not send rtnetlink message: %s", strerror(-r));
ef1ba606 1375 return r;
dd3efc09 1376 }
02b59d57
TG
1377
1378 return 0;
1379}
1380
a748b692 1381static int link_configure(Link *link) {
02b59d57
TG
1382 int r;
1383
ef1ba606 1384 assert(link);
ef1ba606
TG
1385 assert(link->state == _LINK_STATE_INVALID);
1386
11a7f229 1387 r = link_getlink(link);
a748b692 1388 if (r < 0)
ef1ba606 1389 return r;
dd3efc09 1390
52433f6b 1391 return link_enter_enslave(link);
f579559b 1392}
dd3efc09 1393
a748b692
TG
1394int link_add(Manager *m, struct udev_device *device, Link **ret) {
1395 Link *link = NULL;
1396 Network *network;
1397 int r;
1398
1399 assert(m);
1400 assert(device);
1401
1402 r = link_new(m, device, &link);
1403 if (r < 0)
1404 return r;
1405
1406 *ret = link;
1407
1408 r = network_get(m, device, &network);
1409 if (r < 0)
1410 return r == -ENOENT ? 0 : r;
1411
1412 r = network_apply(m, network, link);
1413 if (r < 0)
1414 return r;
1415
eb34d4af 1416 if (link->network->ipv4ll) {
b5db00e5 1417 uint8_t seed[8];
eb34d4af
TG
1418 r = sd_ipv4ll_new(&link->ipv4ll);
1419 if (r < 0)
1420 return r;
1421
b5db00e5
UTL
1422 r = net_get_unique_predictable_data(link->udev_device, seed);
1423 if (r >= 0) {
1424 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
1425 if (r < 0)
1426 return r;
1427 }
1428
eb34d4af
TG
1429 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
1430 if (r < 0)
1431 return r;
1432
1433 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
1434 if (r < 0)
1435 return r;
1436
1437 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
1438 if (r < 0)
1439 return r;
1440 }
1441
1442 if (link->network->dhcp) {
1443 r = sd_dhcp_client_new(&link->dhcp_client);
1444 if (r < 0)
1445 return r;
1446
1447 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
1448 if (r < 0)
1449 return r;
1450
1451 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
1452 if (r < 0)
1453 return r;
1454
1455 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
1456 if (r < 0)
1457 return r;
1458
1459 if (link->network->dhcp_mtu) {
1460 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
1461 if (r < 0)
1462 return r;
1463 }
1464 }
1465
a748b692
TG
1466 r = link_configure(link);
1467 if (r < 0)
1468 return r;
1469
1470 return 0;
1471}
1472
22936833
TG
1473int link_update(Link *link, sd_rtnl_message *m) {
1474 unsigned flags;
c49b33ac 1475 struct ether_addr mac;
22936833
TG
1476 int r;
1477
dd3efc09 1478 assert(link);
a748b692 1479 assert(link->network);
22936833
TG
1480 assert(m);
1481
1746cf2a
TG
1482 if (link->state == LINK_STATE_FAILED)
1483 return 0;
1484
9842de0d
TG
1485 if (link->network->dhcp && link->network->dhcp_mtu &&
1486 !link->original_mtu) {
1487 r = sd_rtnl_message_read_u16(m, IFLA_MTU, &link->original_mtu);
1488 if (r >= 0)
1489 log_debug_link(link, "saved original MTU: %"
1490 PRIu16, link->original_mtu);
1491 }
69629de9 1492
e9189a1f
TG
1493 /* The kernel may broadcast NEWLINK messages without the MAC address
1494 set, simply ignore them. */
c49b33ac 1495 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
e9189a1f 1496 if (r >= 0) {
20861203 1497 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN)) {
c49b33ac 1498
20861203 1499 memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);
c49b33ac 1500
20861203
TG
1501 log_debug_link(link, "MAC address: "
1502 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1503 mac.ether_addr_octet[0],
1504 mac.ether_addr_octet[1],
1505 mac.ether_addr_octet[2],
1506 mac.ether_addr_octet[3],
1507 mac.ether_addr_octet[4],
1508 mac.ether_addr_octet[5]);
c49b33ac 1509
20861203
TG
1510 if (link->ipv4ll) {
1511 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1512 if (r < 0) {
1513 log_warning_link(link, "Could not update MAC "
1514 "address in IPv4LL client: %s",
1515 strerror(-r));
1516 return r;
1517 }
c49b33ac 1518 }
c49b33ac 1519
20861203
TG
1520 if (link->dhcp_client) {
1521 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
1522 if (r < 0) {
1523 log_warning_link(link, "Could not update MAC "
1524 "address in DHCP client: %s",
1525 strerror(-r));
1526 return r;
1527 }
c49b33ac
TG
1528 }
1529 }
4f882b2a
TG
1530 }
1531
a748b692
TG
1532 r = sd_rtnl_message_link_get_flags(m, &flags);
1533 if (r < 0) {
1534 log_warning_link(link, "Could not get link flags");
1535 return r;
1536 }
1537
ff254138 1538 return link_update_flags(link, flags);
dd3efc09 1539}
fe8db0c5
TG
1540
1541int link_save(Link *link) {
1542 _cleanup_free_ char *temp_path = NULL;
1543 _cleanup_fclose_ FILE *f = NULL;
7ff8f4b5 1544 const char *state;
fe8db0c5
TG
1545 int r;
1546
1547 assert(link);
1548 assert(link->state_file);
1549
7ff8f4b5 1550 state = link_state_to_string(link->state);
70280736 1551 assert(state);
7ff8f4b5 1552
fe8db0c5
TG
1553 r = fopen_temporary(link->state_file, &f, &temp_path);
1554 if (r < 0)
1555 goto finish;
1556
1557 fchmod(fileno(f), 0644);
1558
1559 fprintf(f,
1560 "# This is private data. Do not parse.\n"
7ff8f4b5 1561 "STATE=%s\n", state);
fe8db0c5
TG
1562
1563 if (link->dhcp_lease) {
fd88eb8a 1564 _cleanup_free_ char *lease_file = NULL;
2a1763ed 1565
315db1a8
ZJS
1566 r = asprintf(&lease_file, "/run/systemd/network/leases/%"PRIu64,
1567 link->ifindex);
2a1763ed 1568 if (r < 0)
315db1a8 1569 return -ENOMEM;
fe8db0c5
TG
1570
1571 r = dhcp_lease_save(link->dhcp_lease, lease_file);
1572 if (r < 0)
1573 goto finish;
1574
1575 fprintf(f, "DHCP_LEASE=%s\n", lease_file);
1576 }
1577
1578 fflush(f);
1579
1580 if (ferror(f) || rename(temp_path, link->state_file) < 0) {
1581 r = -errno;
1582 unlink(link->state_file);
1583 unlink(temp_path);
1584 }
1585
1586finish:
1587 if (r < 0)
1588 log_error("Failed to save link data %s: %s", link->state_file, strerror(-r));
1589
1590 return r;
1591}
1592
1593static const char* const link_state_table[_LINK_STATE_MAX] = {
1594 [LINK_STATE_ENSLAVING] = "configuring",
1595 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
1596 [LINK_STATE_SETTING_ROUTES] = "configuring",
1597 [LINK_STATE_CONFIGURED] = "configured",
1598 [LINK_STATE_FAILED] = "failed",
1599};
1600
1601DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);