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