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