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