]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
networkd: link - improve link tracking logging
[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>
4cc7a82c 24#include <unistd.h>
f579559b
TG
25
26#include "networkd.h"
27#include "libudev-private.h"
505f8da7 28#include "udev-util.h"
f579559b 29#include "util.h"
505f8da7 30#include "virt.h"
1346b1f0 31#include "bus-util.h"
c6f7c917 32#include "network-internal.h"
ed942a9e 33#include "conf-parser.h"
f579559b 34
3a67e927 35#include "network-util.h"
fe8db0c5
TG
36#include "dhcp-lease-internal.h"
37
aba496a5
UTL
38static int ipv4ll_address_update(Link *link, bool deprecate);
39static bool ipv4ll_is_bound(sd_ipv4ll *ll);
40
505f8da7 41static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
14b746f7 42 _cleanup_link_unref_ Link *link = NULL;
505f8da7
TG
43 uint16_t type;
44 char *ifname;
45 int r, ifindex;
f579559b 46
0c2f9b84
TG
47 assert(manager);
48 assert(manager->links);
505f8da7 49 assert(message);
f579559b
TG
50 assert(ret);
51
505f8da7
TG
52 r = sd_rtnl_message_get_type(message, &type);
53 if (r < 0)
54 return r;
55 else if (type != RTM_NEWLINK)
56 return -EINVAL;
57
58 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
59 if (r < 0)
60 return r;
61 else if (ifindex <= 0)
62 return -EINVAL;
63
64 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
65 if (r < 0)
66 return r;
67
f579559b
TG
68 link = new0(Link, 1);
69 if (!link)
70 return -ENOMEM;
71
14b746f7 72 link->n_ref = 1;
5a3eb5a7 73 link->manager = manager;
505f8da7
TG
74 link->state = LINK_STATE_INITIALIZING;
75 link->ifindex = ifindex;
76 link->ifname = strdup(ifname);
77 if (!link->ifname)
78 return -ENOMEM;
f579559b 79
512922f8
TG
80 r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
81 if (r < 0)
1a941ac4 82 log_debug_link(link, "MAC address not found for new device, continuing without");
512922f8 83
85b5673b 84 r = asprintf(&link->state_file, "/run/systemd/netif/links/%"PRIu64,
315db1a8 85 link->ifindex);
fe8db0c5 86 if (r < 0)
315db1a8 87 return -ENOMEM;
fe8db0c5 88
85b5673b 89 r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%"PRIu64,
68a8723c
TG
90 link->ifindex);
91 if (r < 0)
92 return -ENOMEM;
93
0617ffab 94 r = hashmap_put(manager->links, &link->ifindex, link);
f579559b
TG
95 if (r < 0)
96 return r;
97
98 *ret = link;
99 link = NULL;
100
101 return 0;
102}
103
14b746f7 104static void link_free(Link *link) {
428fd0a7
TG
105 Address *address;
106
f579559b
TG
107 if (!link)
108 return;
109
428fd0a7
TG
110 while ((address = link->addresses)) {
111 LIST_REMOVE(addresses, link->addresses, address);
112 address_free(address);
113 }
114
11bf3cce
LP
115 while ((address = link->pool_addresses)) {
116 LIST_REMOVE(addresses, link->pool_addresses, address);
117 address_free(address);
118 }
119
e5b04c8d 120 sd_dhcp_client_unref(link->dhcp_client);
a6cc569e 121 sd_dhcp_lease_unref(link->dhcp_lease);
f5be5601 122
68a8723c
TG
123 unlink(link->lease_file);
124 free(link->lease_file);
125
56cd007a 126 sd_ipv4ll_unref(link->ipv4ll);
4138fb2c 127 sd_dhcp6_client_unref(link->dhcp6_client);
6b66097b 128 sd_icmp6_nd_unref(link->icmp6_router_discovery);
4138fb2c 129
28aeb07f
TG
130 if (link->manager)
131 hashmap_remove(link->manager->links, &link->ifindex);
f579559b 132
c166a070 133 free(link->ifname);
68a8723c
TG
134
135 unlink(link->state_file);
fe8db0c5 136 free(link->state_file);
c166a070 137
b5db00e5
UTL
138 udev_device_unref(link->udev_device);
139
f579559b
TG
140 free(link);
141}
142
14b746f7
TG
143Link *link_unref(Link *link) {
144 if (link && (-- link->n_ref <= 0))
145 link_free(link);
146
147 return NULL;
148}
149
150Link *link_ref(Link *link) {
151 if (link)
152 assert_se(++ link->n_ref >= 2);
153
154 return link;
155}
156
11a7f229
TG
157int link_get(Manager *m, int ifindex, Link **ret) {
158 Link *link;
159 uint64_t ifindex_64;
160
161 assert(m);
162 assert(m->links);
163 assert(ifindex);
164 assert(ret);
165
166 ifindex_64 = ifindex;
167 link = hashmap_get(m->links, &ifindex_64);
168 if (!link)
169 return -ENODEV;
170
171 *ret = link;
172
173 return 0;
174}
175
370e9930
TG
176void link_drop(Link *link) {
177 if (!link || link->state == LINK_STATE_LINGER)
178 return;
179
180 link->state = LINK_STATE_LINGER;
181
7619683b 182 log_debug_link(link, "link removed");
370e9930
TG
183
184 link_unref(link);
185
186 return;
187}
188
57bd6899
TG
189static void link_enter_unmanaged(Link *link) {
190 assert(link);
191
df9aa406 192 log_debug_link(link, "unmanaged");
57bd6899
TG
193
194 link->state = LINK_STATE_UNMANAGED;
195
196 link_save(link);
197}
198
111bb8f9
TG
199static int link_stop_clients(Link *link) {
200 int r = 0, k;
201
202 assert(link);
203 assert(link->manager);
204 assert(link->manager->event);
205
206 if (!link->network)
207 return 0;
208
ed942a9e 209 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
111bb8f9
TG
210 assert(link->dhcp_client);
211
212 k = sd_dhcp_client_stop(link->dhcp_client);
213 if (k < 0) {
214 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
215 r = k;
216 }
217 }
218
219 if (link->network->ipv4ll) {
220 assert(link->ipv4ll);
221
222 k = sd_ipv4ll_stop(link->ipv4ll);
223 if (k < 0) {
224 log_warning_link(link, "Could not stop IPv4 link-local: %s", strerror(-r));
225 r = k;
226 }
227 }
228
dd43110f
TG
229 if (link->network->dhcp_server) {
230 assert(link->dhcp_server);
231
232 k = sd_dhcp_server_stop(link->dhcp_server);
233 if (k < 0) {
234 log_warning_link(link, "Could not stop DHCPv4 server: %s", strerror(-r));
235 r = k;
236 }
237 }
238
ed942a9e 239 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
1873a3d3
PF
240 assert(link->icmp6_router_discovery);
241
242 if (link->dhcp6_client) {
243 k = sd_dhcp6_client_stop(link->dhcp6_client);
244 if (k < 0) {
245 log_warning_link(link, "Could not stop DHCPv6 client: %s", strerror(-r));
246 r = k;
247 }
248 }
4138fb2c 249
1873a3d3 250 k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
4138fb2c 251 if (k < 0) {
1873a3d3 252 log_warning_link(link, "Could not stop ICMPv6 router discovery: %s", strerror(-r));
4138fb2c
PF
253 r = k;
254 }
255 }
256
111bb8f9
TG
257 return r;
258}
259
ef1ba606
TG
260static void link_enter_failed(Link *link) {
261 assert(link);
f882c247 262
370e9930 263 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
2139694e
TG
264 return;
265
39032b87 266 log_warning_link(link, "failed");
449f7554 267
ef1ba606 268 link->state = LINK_STATE_FAILED;
fe8db0c5 269
111bb8f9
TG
270 link_stop_clients(link);
271
fe8db0c5 272 link_save(link);
f882c247
TG
273}
274
4f434938
LP
275static Address* link_find_dhcp_server_address(Link *link) {
276 Address *address;
277
278 assert(link);
279 assert(link->network);
280
281 /* The the first statically configured address if there is any */
282 LIST_FOREACH(addresses, address, link->network->static_addresses) {
283
284 if (address->family != AF_INET)
285 continue;
286
287 if (in_addr_null(address->family, &address->in_addr))
288 continue;
289
290 return address;
291 }
292
293 /* If that didn't work, find a suitable address we got from the pool */
294 LIST_FOREACH(addresses, address, link->pool_addresses) {
295 if (address->family != AF_INET)
296 continue;
297
298 return address;
299 }
300
301 return NULL;
302}
303
dd43110f
TG
304static int link_enter_configured(Link *link) {
305 int r;
306
307 assert(link);
308 assert(link->network);
309 assert(link->state == LINK_STATE_SETTING_ROUTES);
310
7c16313f
TG
311 if (link->network->dhcp_server &&
312 !sd_dhcp_server_is_running(link->dhcp_server)) {
4f434938
LP
313 struct in_addr pool_start;
314 Address *address;
315
316 address = link_find_dhcp_server_address(link);
317 if (!address) {
318 log_warning_link(link, "Failed to find suitable address for DHCPv4 server instance.");
319 link_enter_failed(link);
320 return 0;
321 }
322
dd43110f
TG
323 log_debug_link(link, "offering DHCPv4 leases");
324
4f434938
LP
325 r = sd_dhcp_server_set_address(link->dhcp_server, &address->in_addr.in);
326 if (r < 0)
327 return r;
328
329 /* offer 32 addresses starting from the address following the server address */
330 pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1);
331 r = sd_dhcp_server_set_lease_pool(link->dhcp_server,
332 &pool_start, 32);
333 if (r < 0)
334 return r;
335
336 /* TODO:
337 r = sd_dhcp_server_set_router(link->dhcp_server,
338 &main_address->in_addr.in);
339 if (r < 0)
340 return r;
341
342 r = sd_dhcp_server_set_prefixlen(link->dhcp_server,
343 main_address->prefixlen);
344 if (r < 0)
345 return r;
346 */
347
dd43110f
TG
348 r = sd_dhcp_server_start(link->dhcp_server);
349 if (r < 0) {
350 log_warning_link(link, "could not start DHCPv4 server "
351 "instance: %s", strerror(-r));
352
353 link_enter_failed(link);
354
355 return 0;
356 }
357 }
358
359 log_info_link(link, "link configured");
360
361 link->state = LINK_STATE_CONFIGURED;
362
363 link_save(link);
364
365 return 0;
366}
367
f882c247 368static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 369 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
370 int r;
371
f5be5601 372 assert(link->route_messages > 0);
370e9930
TG
373 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
374 LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
375 LINK_STATE_LINGER));
f882c247 376
f5be5601 377 link->route_messages --;
f882c247 378
5da8149f 379 if (IN_SET(LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
380 return 1;
381
382 r = sd_rtnl_message_get_errno(m);
c166a070 383 if (r < 0 && r != -EEXIST)
c9ccc19f 384 log_struct_link(LOG_WARNING, link,
97578344 385 "MESSAGE=%-*s: could not set route: %s",
987efa17 386 IFNAMSIZ,
c9ccc19f
TG
387 link->ifname, strerror(-r),
388 "ERRNO=%d", -r,
389 NULL);
f882c247 390
f5be5601
TG
391 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
392 * ignore it */
393 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
39032b87 394 log_debug_link(link, "routes set");
dd3efc09
TG
395 link_enter_configured(link);
396 }
f882c247
TG
397
398 return 1;
399}
400
e1ea665e
EY
401static int link_set_dhcp_routes(Link *link) {
402 struct sd_dhcp_route *static_routes;
403 size_t static_routes_size;
404 int r;
405 unsigned i;
406
407 assert(link);
408
409 r = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes, &static_routes_size);
410 if (r < 0) {
411 if (r != -ENOENT)
b1666580 412 log_warning_link(link, "DHCP error: could not get routes: %s", strerror(-r));
e1ea665e
EY
413 return r;
414 }
415
416 for (i = 0; i < static_routes_size; i++) {
417 _cleanup_route_free_ Route *route = NULL;
418
419 r = route_new_dynamic(&route);
420 if (r < 0) {
421 log_error_link(link, "Could not allocate route: %s",
422 strerror(-r));
423 return r;
424 }
425
426 route->family = AF_INET;
427 route->in_addr.in = static_routes[i].gw_addr;
428 route->dst_addr.in = static_routes[i].dst_addr;
429 route->dst_prefixlen = static_routes[i].dst_prefixlen;
430 route->metrics = DHCP_STATIC_ROUTE_METRIC;
431
432 r = route_configure(route, link, &route_handler);
433 if (r < 0) {
434 log_warning_link(link,
435 "could not set host route: %s", strerror(-r));
436 return r;
437 }
438
e1ea665e
EY
439 link->route_messages ++;
440 }
441
442 return 0;
443}
444
f882c247 445static int link_enter_set_routes(Link *link) {
a6cc569e 446 Route *rt;
f882c247
TG
447 int r;
448
449 assert(link);
450 assert(link->network);
ef1ba606 451 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 452
ef1ba606 453 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 454
5c1d3fc9 455 if (!link->network->static_routes && !link->dhcp_lease &&
370e9930 456 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
dd3efc09 457 return link_enter_configured(link);
f882c247 458
39032b87 459 log_debug_link(link, "setting routes");
449f7554 460
3d3d4255 461 LIST_FOREACH(routes, rt, link->network->static_routes) {
a6cc569e 462 r = route_configure(rt, link, &route_handler);
dd3efc09 463 if (r < 0) {
3333d748
ZJS
464 log_warning_link(link,
465 "could not set routes: %s", strerror(-r));
ef1ba606
TG
466 link_enter_failed(link);
467 return r;
dd3efc09 468 }
c166a070 469
f5be5601
TG
470 link->route_messages ++;
471 }
472
5c1d3fc9
UTL
473 if (link->ipv4ll && !link->dhcp_lease) {
474 _cleanup_route_free_ Route *route = NULL;
475 struct in_addr addr;
476
477 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
478 if (r < 0 && r != -ENOENT) {
479 log_warning_link(link, "IPV4LL error: no address: %s",
480 strerror(-r));
481 return r;
482 }
483
484 if (r != -ENOENT) {
485 r = route_new_dynamic(&route);
486 if (r < 0) {
487 log_error_link(link, "Could not allocate route: %s",
488 strerror(-r));
489 return r;
490 }
491
492 route->family = AF_INET;
493 route->scope = RT_SCOPE_LINK;
494 route->metrics = 99;
495
496 r = route_configure(route, link, &route_handler);
497 if (r < 0) {
498 log_warning_link(link,
499 "could not set routes: %s", strerror(-r));
500 link_enter_failed(link);
501 return r;
502 }
503
504 link->route_messages ++;
505 }
506 }
507
a6cc569e
TG
508 if (link->dhcp_lease) {
509 _cleanup_route_free_ Route *route = NULL;
9765ce69 510 _cleanup_route_free_ Route *route_gw = NULL;
a6cc569e
TG
511 struct in_addr gateway;
512
513 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
8ddbeaa2 514 if (r < 0 && r != -ENOENT) {
b1666580
TG
515 log_warning_link(link, "DHCP error: could not get gateway: %s",
516 strerror(-r));
a6cc569e
TG
517 return r;
518 }
519
8ddbeaa2
UTL
520 if (r >= 0) {
521 r = route_new_dynamic(&route);
522 if (r < 0) {
523 log_error_link(link, "Could not allocate route: %s",
524 strerror(-r));
525 return r;
526 }
a6cc569e 527
8ddbeaa2
UTL
528 r = route_new_dynamic(&route_gw);
529 if (r < 0) {
530 log_error_link(link, "Could not allocate route: %s",
531 strerror(-r));
532 return r;
533 }
9765ce69 534
8ddbeaa2
UTL
535 /* The dhcp netmask may mask out the gateway. Add an explicit
536 * route for the gw host so that we can route no matter the
537 * netmask or existing kernel route tables. */
538 route_gw->family = AF_INET;
539 route_gw->dst_addr.in = gateway;
540 route_gw->dst_prefixlen = 32;
541 route_gw->scope = RT_SCOPE_LINK;
3e53303e 542 route_gw->metrics = DHCP_STATIC_ROUTE_METRIC;
9765ce69 543
8ddbeaa2
UTL
544 r = route_configure(route_gw, link, &route_handler);
545 if (r < 0) {
546 log_warning_link(link,
547 "could not set host route: %s", strerror(-r));
548 return r;
549 }
9765ce69 550
8ddbeaa2 551 link->route_messages ++;
9765ce69 552
8ddbeaa2
UTL
553 route->family = AF_INET;
554 route->in_addr.in = gateway;
3e53303e 555 route->metrics = DHCP_STATIC_ROUTE_METRIC;
a6cc569e 556
8ddbeaa2
UTL
557 r = route_configure(route, link, &route_handler);
558 if (r < 0) {
559 log_warning_link(link,
560 "could not set routes: %s", strerror(-r));
561 link_enter_failed(link);
562 return r;
563 }
564
565 link->route_messages ++;
f5be5601 566 }
e1ea665e
EY
567
568 if (link->network->dhcp_routes)
569 link_set_dhcp_routes(link);
8ddbeaa2 570 }
f5be5601 571
8ddbeaa2
UTL
572 if (link->route_messages == 0) {
573 link_enter_configured(link);
f882c247
TG
574 }
575
576 return 0;
577}
578
5c1d3fc9 579static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 580 _cleanup_link_unref_ Link *link = userdata;
5c1d3fc9
UTL
581 int r;
582
583 assert(m);
584 assert(link);
585 assert(link->ifname);
586
5da8149f 587 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
5c1d3fc9
UTL
588 return 1;
589
590 r = sd_rtnl_message_get_errno(m);
b90b025a 591 if (r < 0 && r != -ESRCH)
5c1d3fc9 592 log_struct_link(LOG_WARNING, link,
97578344 593 "MESSAGE=%-*s: could not drop route: %s",
987efa17 594 IFNAMSIZ,
5c1d3fc9
UTL
595 link->ifname, strerror(-r),
596 "ERRNO=%d", -r,
597 NULL);
598
599 return 0;
600}
601
f882c247 602static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 603 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
604 int r;
605
f5be5601
TG
606 assert(m);
607 assert(link);
608 assert(link->ifname);
609 assert(link->addr_messages > 0);
370e9930
TG
610 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
611 LINK_STATE_FAILED, LINK_STATE_LINGER));
f882c247 612
f5be5601 613 link->addr_messages --;
f882c247 614
5da8149f 615 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
616 return 1;
617
618 r = sd_rtnl_message_get_errno(m);
c166a070 619 if (r < 0 && r != -EEXIST)
c9ccc19f 620 log_struct_link(LOG_WARNING, link,
97578344 621 "MESSAGE=%-*s: could not set address: %s",
987efa17 622 IFNAMSIZ,
3333d748
ZJS
623 link->ifname, strerror(-r),
624 "ERRNO=%d", -r,
625 NULL);
f882c247 626
f5be5601 627 if (link->addr_messages == 0) {
39032b87 628 log_debug_link(link, "addresses set");
ef1ba606 629 link_enter_set_routes(link);
dd3efc09 630 }
f882c247
TG
631
632 return 1;
633}
634
635static int link_enter_set_addresses(Link *link) {
a6cc569e 636 Address *ad;
f882c247 637 int r;
68ceb9df 638 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
f882c247
TG
639
640 assert(link);
641 assert(link->network);
f5be5601 642 assert(link->state != _LINK_STATE_INVALID);
f882c247 643
ef1ba606 644 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 645
5c1d3fc9 646 if (!link->network->static_addresses && !link->dhcp_lease &&
aba496a5 647 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
ef1ba606 648 return link_enter_set_routes(link);
f882c247 649
39032b87 650 log_debug_link(link, "setting addresses");
449f7554 651
3d3d4255 652 LIST_FOREACH(addresses, ad, link->network->static_addresses) {
a6cc569e 653 r = address_configure(ad, link, &address_handler);
dd3efc09 654 if (r < 0) {
3333d748
ZJS
655 log_warning_link(link,
656 "could not set addresses: %s", strerror(-r));
ef1ba606
TG
657 link_enter_failed(link);
658 return r;
dd3efc09 659 }
c166a070 660
f5be5601
TG
661 link->addr_messages ++;
662 }
663
5c1d3fc9
UTL
664 if (link->ipv4ll && !link->dhcp_lease) {
665 _cleanup_address_free_ Address *ll_addr = NULL;
666 struct in_addr addr;
667
668 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
669 if (r < 0 && r != -ENOENT) {
670 log_warning_link(link, "IPV4LL error: no address: %s",
671 strerror(-r));
672 return r;
673 }
674
675 if (r != -ENOENT) {
676 r = address_new_dynamic(&ll_addr);
677 if (r < 0) {
678 log_error_link(link, "Could not allocate address: %s", strerror(-r));
679 return r;
680 }
681
682 ll_addr->family = AF_INET;
683 ll_addr->in_addr.in = addr;
684 ll_addr->prefixlen = 16;
685 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
686 ll_addr->scope = RT_SCOPE_LINK;
687
688 r = address_configure(ll_addr, link, &address_handler);
689 if (r < 0) {
690 log_warning_link(link,
691 "could not set addresses: %s", strerror(-r));
692 link_enter_failed(link);
693 return r;
694 }
695
696 link->addr_messages ++;
697 }
698 }
699
a6cc569e
TG
700 if (link->dhcp_lease) {
701 _cleanup_address_free_ Address *address = NULL;
702 struct in_addr addr;
703 struct in_addr netmask;
704 unsigned prefixlen;
705
706 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
707 if (r < 0) {
708 log_warning_link(link, "DHCP error: no address: %s",
709 strerror(-r));
710 return r;
711 }
712
68ceb9df
PF
713 if (!link->network->dhcp_critical) {
714 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
715 &lifetime);
716 if (r < 0) {
717 log_warning_link(link, "DHCP error: no lifetime: %s",
718 strerror(-r));
719 return r;
720 }
721 }
722
a6cc569e
TG
723 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
724 if (r < 0) {
725 log_warning_link(link, "DHCP error: no netmask: %s",
726 strerror(-r));
727 return r;
728 }
729
730 prefixlen = net_netmask_to_prefixlen(&netmask);
731
732 r = address_new_dynamic(&address);
733 if (r < 0) {
734 log_error_link(link, "Could not allocate address: %s",
735 strerror(-r));
736 return r;
737 }
738
739 address->family = AF_INET;
740 address->in_addr.in = addr;
68ceb9df
PF
741 address->cinfo.ifa_prefered = lifetime;
742 address->cinfo.ifa_valid = lifetime;
a6cc569e
TG
743 address->prefixlen = prefixlen;
744 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
745
46ba9fba
TG
746 /* use update rather than configure so that we will update the lifetime
747 of an existing address if it has already been configured */
748 r = address_update(address, link, &address_handler);
f5be5601 749 if (r < 0) {
3333d748
ZJS
750 log_warning_link(link,
751 "could not set addresses: %s", strerror(-r));
f5be5601
TG
752 link_enter_failed(link);
753 return r;
754 }
755
756 link->addr_messages ++;
f882c247
TG
757 }
758
759 return 0;
760}
761
aba496a5 762static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 763 _cleanup_link_unref_ Link *link = userdata;
aba496a5
UTL
764 int r;
765
766 assert(m);
767 assert(link);
768 assert(link->ifname);
769
5da8149f 770 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
aba496a5
UTL
771 return 1;
772
773 r = sd_rtnl_message_get_errno(m);
774 if (r < 0 && r != -ENOENT)
775 log_struct_link(LOG_WARNING, link,
97578344 776 "MESSAGE=%-*s: could not update address: %s",
987efa17 777 IFNAMSIZ,
aba496a5
UTL
778 link->ifname, strerror(-r),
779 "ERRNO=%d", -r,
780 NULL);
781
782 return 0;
783}
784
ff254138 785static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 786 _cleanup_link_unref_ Link *link = userdata;
ff254138
TG
787 int r;
788
789 assert(m);
790 assert(link);
791 assert(link->ifname);
792
5da8149f 793 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
ff254138
TG
794 return 1;
795
796 r = sd_rtnl_message_get_errno(m);
b90b025a 797 if (r < 0 && r != -EADDRNOTAVAIL)
c9ccc19f 798 log_struct_link(LOG_WARNING, link,
97578344 799 "MESSAGE=%-*s: could not drop address: %s",
987efa17 800 IFNAMSIZ,
c9ccc19f
TG
801 link->ifname, strerror(-r),
802 "ERRNO=%d", -r,
803 NULL);
ff254138 804
5c1d3fc9 805 return 0;
ff254138
TG
806}
807
1346b1f0 808static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
5da8149f 809 _cleanup_link_unref_ Link *link = userdata;
1346b1f0
TG
810 int r;
811
b226d99b
TG
812 assert(link);
813
5da8149f 814 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
370e9930 815 return 1;
370e9930 816
1346b1f0
TG
817 r = sd_bus_message_get_errno(m);
818 if (r < 0)
987efa17 819 log_warning_link(link, "Could not set hostname: %s", strerror(-r));
1346b1f0
TG
820
821 return 1;
822}
823
b226d99b 824static int link_set_hostname(Link *link, const char *hostname) {
1346b1f0
TG
825 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
826 int r = 0;
827
b226d99b
TG
828 assert(link);
829 assert(link->manager);
1346b1f0
TG
830 assert(hostname);
831
b226d99b 832 log_debug_link(link, "Setting transient hostname: '%s'", hostname);
1346b1f0 833
b226d99b
TG
834 if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */
835 log_info_link(link, "Not connected to system bus, ignoring transient hostname.");
bcbca829
TG
836 return 0;
837 }
838
1346b1f0 839 r = sd_bus_message_new_method_call(
b226d99b 840 link->manager->bus,
151b9b96 841 &m,
1346b1f0
TG
842 "org.freedesktop.hostname1",
843 "/org/freedesktop/hostname1",
844 "org.freedesktop.hostname1",
151b9b96 845 "SetHostname");
1346b1f0
TG
846 if (r < 0)
847 return r;
848
849 r = sd_bus_message_append(m, "sb", hostname, false);
850 if (r < 0)
851 return r;
852
19befb2d 853 r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler, link, 0);
5da8149f 854 if (r < 0) {
b226d99b 855 log_error_link(link, "Could not set transient hostname: %s", strerror(-r));
5da8149f
TG
856 return r;
857 }
b226d99b
TG
858
859 link_ref(link);
1346b1f0 860
5da8149f 861 return 0;
1346b1f0
TG
862}
863
4f882b2a 864static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 865 _cleanup_link_unref_ Link *link = userdata;
4f882b2a
TG
866 int r;
867
868 assert(m);
869 assert(link);
870 assert(link->ifname);
871
5da8149f 872 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
4f882b2a
TG
873 return 1;
874
875 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
876 if (r < 0)
877 log_struct_link(LOG_WARNING, link,
97578344
TG
878 "MESSAGE=%-*s: could not set MTU: %s",
879 IFNAMSIZ, link->ifname, strerror(-r),
c9ccc19f
TG
880 "ERRNO=%d", -r,
881 NULL);
4f882b2a
TG
882
883 return 1;
884}
885
886static int link_set_mtu(Link *link, uint32_t mtu) {
cf6a8911 887 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
4f882b2a
TG
888 int r;
889
890 assert(link);
891 assert(link->manager);
892 assert(link->manager->rtnl);
893
894 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
895
151b9b96
LP
896 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
897 RTM_SETLINK, link->ifindex);
4f882b2a
TG
898 if (r < 0) {
899 log_error_link(link, "Could not allocate RTM_SETLINK message");
900 return r;
901 }
902
903 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
904 if (r < 0) {
905 log_error_link(link, "Could not append MTU: %s", strerror(-r));
906 return r;
907 }
908
909 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
910 if (r < 0) {
911 log_error_link(link,
912 "Could not send rtnetlink message: %s", strerror(-r));
913 return r;
914 }
915
ae941762 916 link_ref(link);
b226d99b 917
4f882b2a
TG
918 return 0;
919}
920
a6cc569e
TG
921static int dhcp_lease_lost(Link *link) {
922 _cleanup_address_free_ Address *address = NULL;
923 struct in_addr addr;
924 struct in_addr netmask;
3e790eae 925 struct in_addr gateway;
a6cc569e 926 unsigned prefixlen;
e1ea665e 927 unsigned i;
ff254138
TG
928 int r;
929
930 assert(link);
a6cc569e 931 assert(link->dhcp_lease);
ff254138 932
14efd761
TG
933 log_warning_link(link, "DHCP lease lost");
934
e1ea665e
EY
935 if (link->network->dhcp_routes) {
936 struct sd_dhcp_route *routes;
937 size_t routes_size;
938
939 r = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes, &routes_size);
940 if (r >= 0) {
941 for (i = 0; i < routes_size; i++) {
942 _cleanup_route_free_ Route *route = NULL;
943
944 r = route_new_dynamic(&route);
945 if (r >= 0) {
946 route->family = AF_INET;
947 route->in_addr.in = routes[i].gw_addr;
948 route->dst_addr.in = routes[i].dst_addr;
949 route->dst_prefixlen = routes[i].dst_prefixlen;
950
951 route_drop(route, link, &route_drop_handler);
e1ea665e
EY
952 }
953 }
954 }
955 }
956
a6cc569e
TG
957 r = address_new_dynamic(&address);
958 if (r >= 0) {
8ddbeaa2 959 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
3e790eae 960 if (r >= 0) {
e1ea665e
EY
961 _cleanup_route_free_ Route *route_gw = NULL;
962 _cleanup_route_free_ Route *route = NULL;
963
8ddbeaa2
UTL
964 r = route_new_dynamic(&route_gw);
965 if (r >= 0) {
966 route_gw->family = AF_INET;
967 route_gw->dst_addr.in = gateway;
968 route_gw->dst_prefixlen = 32;
969 route_gw->scope = RT_SCOPE_LINK;
970
971 route_drop(route_gw, link, &route_drop_handler);
972 }
3e790eae 973
8ddbeaa2
UTL
974 r = route_new_dynamic(&route);
975 if (r >= 0) {
976 route->family = AF_INET;
977 route->in_addr.in = gateway;
3e790eae 978
8ddbeaa2
UTL
979 route_drop(route, link, &route_drop_handler);
980 }
3e790eae
UTL
981 }
982
8ddbeaa2
UTL
983 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
984 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
985 prefixlen = net_netmask_to_prefixlen(&netmask);
986
a6cc569e
TG
987 address->family = AF_INET;
988 address->in_addr.in = addr;
989 address->prefixlen = prefixlen;
ff254138 990
5c1d3fc9 991 address_drop(address, link, &address_drop_handler);
c07aeadf 992 }
eb27aeca 993
c07aeadf
TG
994 if (link->network->dhcp_mtu) {
995 uint16_t mtu;
ff254138 996
a6cc569e 997 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
c07aeadf
TG
998 if (r >= 0 && link->original_mtu != mtu) {
999 r = link_set_mtu(link, link->original_mtu);
1000 if (r < 0) {
1001 log_warning_link(link, "DHCP error: could not reset MTU");
1002 link_enter_failed(link);
1003 return r;
1004 }
ff254138 1005 }
c07aeadf 1006 }
ff254138 1007
c07aeadf 1008 if (link->network->dhcp_hostname) {
216816c6
TG
1009 const char *hostname = NULL;
1010
1011 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
1012 if (r >= 0 && hostname) {
b226d99b 1013 r = link_set_hostname(link, "");
216816c6 1014 if (r < 0)
987efa17 1015 log_error_link(link, "Failed to reset transient hostname");
216816c6 1016 }
c07aeadf 1017 }
4f882b2a 1018
a6cc569e
TG
1019 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
1020
c07aeadf
TG
1021 return 0;
1022}
4f882b2a 1023
68ceb9df
PF
1024static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
1025 sd_dhcp_lease *lease;
1026 int r;
1027
1028 r = sd_dhcp_client_get_lease(client, &lease);
1029 if (r < 0) {
1030 log_warning_link(link, "DHCP error: no lease %s",
1031 strerror(-r));
1032 return r;
1033 }
1034
1035 sd_dhcp_lease_unref(link->dhcp_lease);
1036 link->dhcp_lease = lease;
1037
1038 link_enter_set_addresses(link);
1039
1040 return 0;
1041}
1042
c07aeadf 1043static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
a6cc569e 1044 sd_dhcp_lease *lease;
c07aeadf
TG
1045 struct in_addr address;
1046 struct in_addr netmask;
1047 struct in_addr gateway;
1048 unsigned prefixlen;
c07aeadf 1049 int r;
1346b1f0 1050
c07aeadf
TG
1051 assert(client);
1052 assert(link);
ff254138 1053
a6cc569e
TG
1054 r = sd_dhcp_client_get_lease(client, &lease);
1055 if (r < 0) {
1056 log_warning_link(link, "DHCP error: no lease: %s",
1057 strerror(-r));
1058 return r;
1059 }
1060
1061 r = sd_dhcp_lease_get_address(lease, &address);
ff254138 1062 if (r < 0) {
c07aeadf
TG
1063 log_warning_link(link, "DHCP error: no address: %s",
1064 strerror(-r));
1065 return r;
ff254138
TG
1066 }
1067
a6cc569e 1068 r = sd_dhcp_lease_get_netmask(lease, &netmask);
ff254138 1069 if (r < 0) {
c07aeadf
TG
1070 log_warning_link(link, "DHCP error: no netmask: %s",
1071 strerror(-r));
1072 return r;
ff254138
TG
1073 }
1074
377a218f 1075 prefixlen = net_netmask_to_prefixlen(&netmask);
ff254138 1076
a6cc569e 1077 r = sd_dhcp_lease_get_router(lease, &gateway);
8ddbeaa2 1078 if (r < 0 && r != -ENOENT) {
b1666580
TG
1079 log_warning_link(link, "DHCP error: could not get gateway: %s",
1080 strerror(-r));
c07aeadf 1081 return r;
ff254138
TG
1082 }
1083
8ddbeaa2
UTL
1084 if (r >= 0)
1085 log_struct_link(LOG_INFO, link,
97578344 1086 "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
987efa17 1087 IFNAMSIZ,
8ddbeaa2
UTL
1088 link->ifname,
1089 ADDRESS_FMT_VAL(address),
1090 prefixlen,
1091 ADDRESS_FMT_VAL(gateway),
1092 "ADDRESS=%u.%u.%u.%u",
1093 ADDRESS_FMT_VAL(address),
1094 "PREFIXLEN=%u",
1095 prefixlen,
1096 "GATEWAY=%u.%u.%u.%u",
1097 ADDRESS_FMT_VAL(gateway),
1098 NULL);
1099 else
1100 log_struct_link(LOG_INFO, link,
97578344 1101 "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u",
987efa17 1102 IFNAMSIZ,
8ddbeaa2
UTL
1103 link->ifname,
1104 ADDRESS_FMT_VAL(address),
1105 prefixlen,
1106 "ADDRESS=%u.%u.%u.%u",
1107 ADDRESS_FMT_VAL(address),
1108 "PREFIXLEN=%u",
1109 prefixlen,
1110 NULL);
c07aeadf 1111
d50cf59b
TG
1112 link->dhcp_lease = lease;
1113
c07aeadf
TG
1114 if (link->network->dhcp_mtu) {
1115 uint16_t mtu;
1116
a6cc569e 1117 r = sd_dhcp_lease_get_mtu(lease, &mtu);
c07aeadf
TG
1118 if (r >= 0) {
1119 r = link_set_mtu(link, mtu);
1120 if (r < 0)
1121 log_error_link(link, "Failed to set MTU "
1122 "to %" PRIu16, mtu);
1123 }
1124 }
ff254138 1125
c07aeadf
TG
1126 if (link->network->dhcp_hostname) {
1127 const char *hostname;
ff254138 1128
a6cc569e 1129 r = sd_dhcp_lease_get_hostname(lease, &hostname);
c07aeadf 1130 if (r >= 0) {
b226d99b 1131 r = link_set_hostname(link, hostname);
c07aeadf 1132 if (r < 0)
987efa17 1133 log_error_link(link, "Failed to set transient hostname "
c07aeadf 1134 "to '%s'", hostname);
3bef724f 1135 }
c07aeadf 1136 }
3bef724f 1137
c07aeadf
TG
1138 link_enter_set_addresses(link);
1139
1140 return 0;
1141}
1142
1143static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
1144 Link *link = userdata;
aba496a5 1145 int r = 0;
c07aeadf
TG
1146
1147 assert(link);
1148 assert(link->network);
1149 assert(link->manager);
1150
370e9930 1151 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
c07aeadf
TG
1152 return;
1153
1154 switch (event) {
1155 case DHCP_EVENT_NO_LEASE:
1156 log_debug_link(link, "IP address in use.");
1157 break;
1158 case DHCP_EVENT_EXPIRED:
1159 case DHCP_EVENT_STOP:
1160 case DHCP_EVENT_IP_CHANGE:
1161 if (link->network->dhcp_critical) {
1162 log_error_link(link, "DHCPv4 connection considered system critical, "
1163 "ignoring request to reconfigure it.");
1164 return;
4f882b2a 1165 }
4f882b2a 1166
17256461
UTL
1167 if (link->dhcp_lease) {
1168 r = dhcp_lease_lost(link);
1169 if (r < 0) {
1170 link_enter_failed(link);
1171 return;
1172 }
c07aeadf 1173 }
1346b1f0 1174
c07aeadf
TG
1175 if (event == DHCP_EVENT_IP_CHANGE) {
1176 r = dhcp_lease_acquired(client, link);
1177 if (r < 0) {
1178 link_enter_failed(link);
1179 return;
1180 }
1346b1f0 1181 }
1346b1f0 1182
5c1d3fc9 1183 if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
aba496a5
UTL
1184 if (!sd_ipv4ll_is_running(link->ipv4ll))
1185 r = sd_ipv4ll_start(link->ipv4ll);
1186 else if (ipv4ll_is_bound(link->ipv4ll))
1187 r = ipv4ll_address_update(link, false);
5c1d3fc9
UTL
1188 if (r < 0) {
1189 link_enter_failed(link);
1190 return;
1191 }
1192 }
1193
68ceb9df
PF
1194 break;
1195 case DHCP_EVENT_RENEW:
1196 r = dhcp_lease_renew(client, link);
1197 if (r < 0) {
1198 link_enter_failed(link);
1199 return;
1200 }
c07aeadf
TG
1201 break;
1202 case DHCP_EVENT_IP_ACQUIRE:
1203 r = dhcp_lease_acquired(client, link);
1204 if (r < 0) {
1205 link_enter_failed(link);
1206 return;
1207 }
5c1d3fc9 1208 if (link->ipv4ll) {
aba496a5
UTL
1209 if (ipv4ll_is_bound(link->ipv4ll))
1210 r = ipv4ll_address_update(link, true);
1211 else
1212 r = sd_ipv4ll_stop(link->ipv4ll);
5c1d3fc9
UTL
1213 if (r < 0) {
1214 link_enter_failed(link);
1215 return;
1216 }
1217 }
c07aeadf
TG
1218 break;
1219 default:
1220 if (event < 0)
b1666580 1221 log_warning_link(link, "DHCP error: client failed: %s", strerror(-event));
c07aeadf
TG
1222 else
1223 log_warning_link(link, "DHCP unknown event: %d", event);
c07aeadf 1224 break;
ff254138
TG
1225 }
1226
1227 return;
1228}
1229
aba496a5
UTL
1230static int ipv4ll_address_update(Link *link, bool deprecate) {
1231 int r;
1232 struct in_addr addr;
1233
1234 assert(link);
1235
1236 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
1237 if (r >= 0) {
1238 _cleanup_address_free_ Address *address = NULL;
1239
1240 log_debug_link(link, "IPv4 link-local %s %u.%u.%u.%u",
1241 deprecate ? "deprecate" : "approve",
1242 ADDRESS_FMT_VAL(addr));
1243
1244 r = address_new_dynamic(&address);
1245 if (r < 0) {
1246 log_error_link(link, "Could not allocate address: %s", strerror(-r));
1247 return r;
1248 }
1249
1250 address->family = AF_INET;
1251 address->in_addr.in = addr;
1252 address->prefixlen = 16;
1253 address->scope = RT_SCOPE_LINK;
1254 address->cinfo.ifa_prefered = deprecate ? 0 : CACHE_INFO_INFINITY_LIFE_TIME;
1255 address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen);
1256
1257 address_update(address, link, &address_update_handler);
1258 }
1259
1260 return 0;
1261
1262}
1263
1264static int ipv4ll_address_lost(Link *link) {
5c1d3fc9
UTL
1265 int r;
1266 struct in_addr addr;
1267
5c1d3fc9
UTL
1268 assert(link);
1269
1270 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
1271 if (r >= 0) {
1272 _cleanup_address_free_ Address *address = NULL;
1273 _cleanup_route_free_ Route *route = NULL;
1274
1275 log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u",
1276 ADDRESS_FMT_VAL(addr));
1277
1278 r = address_new_dynamic(&address);
1279 if (r < 0) {
1280 log_error_link(link, "Could not allocate address: %s", strerror(-r));
1281 return r;
1282 }
1283
1284 address->family = AF_INET;
1285 address->in_addr.in = addr;
1286 address->prefixlen = 16;
1287 address->scope = RT_SCOPE_LINK;
1288
1289 address_drop(address, link, &address_drop_handler);
1290
1291 r = route_new_dynamic(&route);
1292 if (r < 0) {
1293 log_error_link(link, "Could not allocate route: %s",
1294 strerror(-r));
1295 return r;
1296 }
1297
1298 route->family = AF_INET;
1299 route->scope = RT_SCOPE_LINK;
1300 route->metrics = 99;
1301
1302 route_drop(route, link, &route_drop_handler);
1303 }
1304
1305 return 0;
1306}
1307
aba496a5
UTL
1308static bool ipv4ll_is_bound(sd_ipv4ll *ll) {
1309 int r;
1310 struct in_addr addr;
1311
1312 assert(ll);
1313
1314 r = sd_ipv4ll_get_address(ll, &addr);
1315 if (r < 0)
1316 return false;
1317 return true;
1318}
1319
5c1d3fc9
UTL
1320static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
1321 struct in_addr address;
1322 int r;
1323
1324 assert(ll);
1325 assert(link);
1326
1327 r = sd_ipv4ll_get_address(ll, &address);
1328 if (r < 0)
1329 return r;
1330
1331 log_struct_link(LOG_INFO, link,
97578344 1332 "MESSAGE=%-*s: IPv4 link-local address %u.%u.%u.%u",
987efa17 1333 IFNAMSIZ,
5c1d3fc9
UTL
1334 link->ifname,
1335 ADDRESS_FMT_VAL(address),
1336 NULL);
1337
1338 link_enter_set_addresses(link);
1339
1340 return 0;
1341}
1342
1343static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
1344 Link *link = userdata;
1345 int r;
1346
1347 assert(link);
1348 assert(link->network);
1349 assert(link->manager);
1350
370e9930
TG
1351 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1352 return;
1353
5c1d3fc9
UTL
1354 switch(event) {
1355 case IPV4LL_EVENT_STOP:
1356 case IPV4LL_EVENT_CONFLICT:
aba496a5 1357 r = ipv4ll_address_lost(link);
5c1d3fc9
UTL
1358 if (r < 0) {
1359 link_enter_failed(link);
1360 return;
1361 }
1362 break;
1363 case IPV4LL_EVENT_BIND:
1364 r = ipv4ll_address_claimed(ll, link);
1365 if (r < 0) {
1366 link_enter_failed(link);
1367 return;
1368 }
1369 break;
1370 default:
1371 if (event < 0)
1372 log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
1373 else
1374 log_warning_link(link, "IPv4 link-local unknown event: %d", event);
1375 break;
1376 }
1377}
1378
4138fb2c
PF
1379static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
1380 Link *link = userdata;
1381
1382 assert(link);
1383 assert(link->network);
1384 assert(link->manager);
1385
1386 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1387 return;
1388
1389 switch(event) {
1390 case DHCP6_EVENT_STOP:
1391 case DHCP6_EVENT_RESEND_EXPIRE:
1392 case DHCP6_EVENT_RETRANS_MAX:
1393 case DHCP6_EVENT_IP_ACQUIRE:
1394 log_debug_link(link, "DHCPv6 event %d", event);
1395
1396 break;
1397
1398 default:
1399 if (event < 0)
1400 log_warning_link(link, "DHCPv6 error: %s",
1401 strerror(-event));
1402 else
1403 log_warning_link(link, "DHCPv6 unknown event: %d",
1404 event);
1405 return;
1406 }
1407}
1408
1409static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
1410 Link *link = userdata;
1411 int r;
1412
1413 assert(link);
1414 assert(link->network);
1415 assert(link->manager);
1416
1417 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1418 return;
1419
1420 switch(event) {
1421 case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
1422 case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
1423 return;
1424
1425 case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
1426 case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
1427 break;
1428
1429 default:
1430 if (event < 0)
1431 log_warning_link(link, "ICMPv6 error: %s",
1432 strerror(-event));
1433 else
1434 log_warning_link(link, "ICMPv6 unknown event: %d",
1435 event);
1436
1437 return;
1438 }
1439
1440 if (link->dhcp6_client)
1441 return;
1442
1443 r = sd_dhcp6_client_new(&link->dhcp6_client);
1444 if (r < 0)
1445 return;
1446
1447 r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
1448 if (r < 0) {
1449 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1450 return;
1451 }
1452
1453 r = sd_dhcp6_client_set_mac(link->dhcp6_client, &link->mac);
1454 if (r < 0) {
1455 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1456 return;
1457 }
1458
1459 r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
1460 if (r < 0) {
1461 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1462 return;
1463 }
1464
1465 r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
1466 link);
1467 if (r < 0) {
1468 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1469 return;
1470 }
1471
1472 r = sd_dhcp6_client_start(link->dhcp6_client);
1473 if (r < 0)
1474 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
1475}
1476
ff254138
TG
1477static int link_acquire_conf(Link *link) {
1478 int r;
1479
1480 assert(link);
1481 assert(link->network);
ff254138
TG
1482 assert(link->manager);
1483 assert(link->manager->event);
1484
5c1d3fc9 1485 if (link->network->ipv4ll) {
eb34d4af 1486 assert(link->ipv4ll);
ff254138 1487
5c1d3fc9
UTL
1488 log_debug_link(link, "acquiring IPv4 link-local address");
1489
1490 r = sd_ipv4ll_start(link->ipv4ll);
124fa2c6
TG
1491 if (r < 0) {
1492 log_warning_link(link, "could not acquire IPv4 "
1493 "link-local address");
ff254138 1494 return r;
124fa2c6 1495 }
5c1d3fc9
UTL
1496 }
1497
ed942a9e 1498 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) {
eb34d4af 1499 assert(link->dhcp_client);
ff254138 1500
5c1d3fc9 1501 log_debug_link(link, "acquiring DHCPv4 lease");
ab47d620 1502
5c1d3fc9 1503 r = sd_dhcp_client_start(link->dhcp_client);
124fa2c6
TG
1504 if (r < 0) {
1505 log_warning_link(link, "could not acquire DHCPv4 "
1506 "lease");
5c1d3fc9 1507 return r;
124fa2c6 1508 }
5c1d3fc9 1509 }
ff254138 1510
ed942a9e 1511 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
4138fb2c
PF
1512 assert(link->icmp6_router_discovery);
1513
1514 log_debug_link(link, "discovering IPv6 routers");
1515
1516 r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
1517 if (r < 0) {
1518 log_warning_link(link, "could not start IPv6 router discovery");
1519 return r;
1520 }
1521 }
1522
ff254138
TG
1523 return 0;
1524}
1525
bbf7c048 1526bool link_has_carrier(unsigned flags, uint8_t operstate) {
deb2e523
TG
1527 /* see Documentation/networking/operstates.txt in the kernel sources */
1528
1529 if (operstate == IF_OPER_UP)
1530 return true;
1531
1532 if (operstate == IF_OPER_UNKNOWN)
1533 /* operstate may not be implemented, so fall back to flags */
1534 if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT))
1535 return true;
1536
1537 return false;
1538}
1539
389cc5f7
TG
1540#define FLAG_STRING(string, flag, old, new) \
1541 (((old ^ new) & flag) \
1542 ? ((old & flag) ? (" -" string) : (" +" string)) \
1543 : "")
1544
1e9be60b 1545static int link_update_flags(Link *link, sd_rtnl_message *m) {
389cc5f7 1546 unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
1e9be60b
TG
1547 uint8_t operstate;
1548 bool carrier_gained = false, carrier_lost = false;
ff254138
TG
1549 int r;
1550
1551 assert(link);
ff254138 1552
1e9be60b
TG
1553 r = sd_rtnl_message_link_get_flags(m, &flags);
1554 if (r < 0) {
1555 log_warning_link(link, "Could not get link flags");
1556 return r;
1557 }
1558
1559 r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate);
1560 if (r < 0)
1561 /* if we got a message without operstate, take it to mean
1562 the state was unchanged */
e375dcde 1563 operstate = link->kernel_operstate;
1e9be60b 1564
e375dcde 1565 if ((link->flags == flags) && (link->kernel_operstate == operstate))
efbc88b8 1566 return 0;
efbc88b8 1567
389cc5f7
TG
1568 if (link->flags != flags) {
1569 log_debug_link(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1570 FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
1571 FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
1572 FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
1573 FLAG_STRING("UP", IFF_UP, link->flags, flags),
1574 FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags),
1575 FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags),
1576 FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags),
1577 FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags),
1578 FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags),
1579 FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags),
1580 FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags),
1581 FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags),
1582 FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags),
1583 FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags),
1584 FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags),
1585 FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags),
1586 FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags),
1587 FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags),
1588 FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags));
1589
1590 unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP |
1591 IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING |
1592 IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT |
1593 IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL |
1594 IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP |
1595 IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO);
1596 unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags);
1597 unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags);
1598
1599 /* link flags are currently at most 18 bits, let's align to printing 20 */
1600 if (unknown_flags_added)
1601 log_debug_link(link, "unknown link flags gained: %#.5x (ignoring)",
1602 unknown_flags_added);
1603
1604 if (unknown_flags_removed)
1605 log_debug_link(link, "unknown link flags lost: %#.5x (ignoring)",
1606 unknown_flags_removed);
1607 }
505f8da7 1608
e375dcde 1609 carrier_gained = !link_has_carrier(link->flags, link->kernel_operstate) &&
1e9be60b 1610 link_has_carrier(flags, operstate);
e375dcde 1611 carrier_lost = link_has_carrier(link->flags, link->kernel_operstate) &&
1e9be60b
TG
1612 !link_has_carrier(flags, operstate);
1613
1614 link->flags = flags;
e375dcde 1615 link->kernel_operstate = operstate;
1e9be60b 1616
deb2e523
TG
1617 link_save(link);
1618
99b4cc3e
TG
1619 if (link->state == LINK_STATE_FAILED ||
1620 link->state == LINK_STATE_UNMANAGED)
1621 return 0;
1622
7cc832b9
TG
1623 if (carrier_gained) {
1624 log_info_link(link, "gained carrier");
ffba6166 1625
1e9be60b 1626 if (link->network) {
ffba6166
TG
1627 r = link_acquire_conf(link);
1628 if (r < 0) {
ffba6166
TG
1629 link_enter_failed(link);
1630 return r;
ff254138 1631 }
ffba6166 1632 }
7cc832b9
TG
1633 } else if (carrier_lost) {
1634 log_info_link(link, "lost carrier");
efbc88b8 1635
1e9be60b
TG
1636 r = link_stop_clients(link);
1637 if (r < 0) {
1638 link_enter_failed(link);
1639 return r;
ff254138
TG
1640 }
1641 }
1642
ff254138
TG
1643 return 0;
1644}
1645
dd3efc09 1646static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 1647 _cleanup_link_unref_ Link *link = userdata;
dd3efc09
TG
1648 int r;
1649
1746cf2a
TG
1650 assert(link);
1651
5da8149f 1652 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1746cf2a
TG
1653 return 1;
1654
dd3efc09 1655 r = sd_rtnl_message_get_errno(m);
45ad2c13 1656 if (r < 0) {
9b86b393
TG
1657 /* we warn but don't fail the link, as it may
1658 be brought up later */
76800848 1659 log_struct_link(LOG_WARNING, link,
97578344 1660 "MESSAGE=%-*s: could not bring up interface: %s",
987efa17 1661 IFNAMSIZ,
c9ccc19f
TG
1662 link->ifname, strerror(-r),
1663 "ERRNO=%d", -r,
1664 NULL);
45ad2c13
TG
1665 }
1666
f882c247
TG
1667 return 1;
1668}
1669
1670static int link_up(Link *link) {
cf6a8911 1671 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
1672 int r;
1673
f882c247
TG
1674 assert(link);
1675 assert(link->manager);
1676 assert(link->manager->rtnl);
1677
39032b87 1678 log_debug_link(link, "bringing link up");
449f7554 1679
151b9b96
LP
1680 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1681 RTM_SETLINK, link->ifindex);
f579559b 1682 if (r < 0) {
39032b87 1683 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
1684 return r;
1685 }
1686
5d4795f3 1687 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 1688 if (r < 0) {
3333d748 1689 log_error_link(link, "Could not set link flags: %s", strerror(-r));
fc25d7f8
TG
1690 return r;
1691 }
1692
dd3efc09 1693 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
f579559b 1694 if (r < 0) {
3333d748
ZJS
1695 log_error_link(link,
1696 "Could not send rtnetlink message: %s", strerror(-r));
f579559b
TG
1697 return r;
1698 }
1699
b226d99b
TG
1700 link_ref(link);
1701
f882c247
TG
1702 return 0;
1703}
1704
52433f6b 1705static int link_enslaved(Link *link) {
f882c247
TG
1706 int r;
1707
ef1ba606 1708 assert(link);
52433f6b 1709 assert(link->state == LINK_STATE_ENSLAVING);
f5be5601 1710 assert(link->network);
dd3efc09 1711
856f962c
TG
1712 log_debug_link(link, "enslaved");
1713
505f8da7
TG
1714 if (!(link->flags & IFF_UP)) {
1715 r = link_up(link);
1716 if (r < 0) {
1717 link_enter_failed(link);
1718 return r;
1719 }
ef1ba606 1720 }
f882c247 1721
fb6730c4 1722 return link_enter_set_addresses(link);
02b59d57
TG
1723}
1724
52433f6b 1725static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 1726 _cleanup_link_unref_ Link *link = userdata;
02b59d57
TG
1727 int r;
1728
1746cf2a 1729 assert(link);
370e9930
TG
1730 assert(IN_SET(link->state, LINK_STATE_ENSLAVING, LINK_STATE_FAILED,
1731 LINK_STATE_LINGER));
ef1ba606 1732 assert(link->network);
02b59d57 1733
52433f6b
TG
1734 link->enslaving --;
1735
5da8149f 1736 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
02b59d57
TG
1737 return 1;
1738
1739 r = sd_rtnl_message_get_errno(m);
856f962c 1740 if (r < 0 && r != -EEXIST) {
c9ccc19f 1741 log_struct_link(LOG_ERR, link,
97578344 1742 "MESSAGE=%-*s: could not enslave: %s",
987efa17 1743 IFNAMSIZ,
c9ccc19f
TG
1744 link->ifname, strerror(-r),
1745 "ERRNO=%d", -r,
1746 NULL);
ef1ba606
TG
1747 link_enter_failed(link);
1748 return 1;
3333d748 1749 }
02b59d57 1750
856f962c 1751 if (link->enslaving <= 0)
52433f6b 1752 link_enslaved(link);
02b59d57
TG
1753
1754 return 1;
1755}
1756
52433f6b 1757static int link_enter_enslave(Link *link) {
326cb406 1758 NetDev *vlan, *macvlan, *vxlan;
672682a6 1759 Iterator i;
02b59d57
TG
1760 int r;
1761
1762 assert(link);
1763 assert(link->network);
505f8da7 1764 assert(link->state == LINK_STATE_INITIALIZING);
02b59d57 1765
52433f6b 1766 link->state = LINK_STATE_ENSLAVING;
02b59d57 1767
fe8db0c5
TG
1768 link_save(link);
1769
7951dea2
SS
1770 if (!link->network->bridge &&
1771 !link->network->bond &&
1772 !link->network->tunnel &&
fe6b2d55 1773 hashmap_isempty(link->network->vlans) &&
326cb406
SS
1774 hashmap_isempty(link->network->macvlans) &&
1775 hashmap_isempty(link->network->vxlans))
52433f6b 1776 return link_enslaved(link);
02b59d57 1777
d9c67ea1 1778 if (link->network->bond) {
52433f6b 1779 log_struct_link(LOG_DEBUG, link,
97578344 1780 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1781 IFNAMSIZ,
af4e9e2c 1782 link->ifname, link->network->bond->ifname,
d9c67ea1 1783 NETDEV(link->network->bond),
52433f6b 1784 NULL);
449f7554 1785
d9c67ea1 1786 r = netdev_enslave(link->network->bond, link, &enslave_handler);
52433f6b
TG
1787 if (r < 0) {
1788 log_struct_link(LOG_WARNING, link,
97578344 1789 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1790 IFNAMSIZ,
af4e9e2c 1791 link->ifname, link->network->bond->ifname, strerror(-r),
d9c67ea1 1792 NETDEV(link->network->bond),
52433f6b
TG
1793 NULL);
1794 link_enter_failed(link);
1795 return r;
1796 }
1797
0ad6148e
MO
1798 link->enslaving ++;
1799 }
1800
d9c67ea1 1801 if (link->network->bridge) {
0ad6148e 1802 log_struct_link(LOG_DEBUG, link,
97578344 1803 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1804 IFNAMSIZ,
af4e9e2c 1805 link->ifname, link->network->bridge->ifname,
d9c67ea1 1806 NETDEV(link->network->bridge),
0ad6148e
MO
1807 NULL);
1808
d9c67ea1 1809 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
0ad6148e
MO
1810 if (r < 0) {
1811 log_struct_link(LOG_WARNING, link,
97578344 1812 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1813 IFNAMSIZ,
af4e9e2c 1814 link->ifname, link->network->bridge->ifname, strerror(-r),
d9c67ea1 1815 NETDEV(link->network->bridge),
0ad6148e
MO
1816 NULL);
1817 link_enter_failed(link);
1818 return r;
1819 }
1820
52433f6b
TG
1821 link->enslaving ++;
1822 }
1823
7951dea2
SS
1824 if (link->network->tunnel) {
1825 log_struct_link(LOG_DEBUG, link,
97578344 1826 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1827 IFNAMSIZ,
af4e9e2c 1828 link->ifname, link->network->tunnel->ifname,
7951dea2
SS
1829 NETDEV(link->network->tunnel),
1830 NULL);
1831
1832 r = netdev_enslave(link->network->tunnel, link, &enslave_handler);
1833 if (r < 0) {
1834 log_struct_link(LOG_WARNING, link,
97578344 1835 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1836 IFNAMSIZ,
af4e9e2c 1837 link->ifname, link->network->tunnel->ifname, strerror(-r),
7951dea2
SS
1838 NETDEV(link->network->tunnel),
1839 NULL);
1840 link_enter_failed(link);
1841 return r;
1842 }
1843
7951dea2
SS
1844 link->enslaving ++;
1845 }
1846
672682a6 1847 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
52433f6b 1848 log_struct_link(LOG_DEBUG, link,
97578344 1849 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1850 IFNAMSIZ,
af4e9e2c 1851 link->ifname, vlan->ifname, NETDEV(vlan), NULL);
52433f6b 1852
672682a6 1853 r = netdev_enslave(vlan, link, &enslave_handler);
52433f6b
TG
1854 if (r < 0) {
1855 log_struct_link(LOG_WARNING, link,
97578344 1856 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1857 IFNAMSIZ,
af4e9e2c 1858 link->ifname, vlan->ifname, strerror(-r),
672682a6 1859 NETDEV(vlan), NULL);
52433f6b
TG
1860 link_enter_failed(link);
1861 return r;
1862 }
1863
1864 link->enslaving ++;
ef1ba606
TG
1865 }
1866
fe6b2d55
TG
1867 HASHMAP_FOREACH(macvlan, link->network->macvlans, i) {
1868 log_struct_link(LOG_DEBUG, link,
97578344 1869 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1870 IFNAMSIZ,
af4e9e2c 1871 link->ifname, macvlan->ifname, NETDEV(macvlan), NULL);
fe6b2d55
TG
1872
1873 r = netdev_enslave(macvlan, link, &enslave_handler);
1874 if (r < 0) {
1875 log_struct_link(LOG_WARNING, link,
97578344 1876 "MESSAGE=%-*s: could not enslave by '%s': %s",
987efa17 1877 IFNAMSIZ,
af4e9e2c 1878 link->ifname, macvlan->ifname, strerror(-r),
fe6b2d55
TG
1879 NETDEV(macvlan), NULL);
1880 link_enter_failed(link);
1881 return r;
1882 }
1883
1884 link->enslaving ++;
1885 }
1886
326cb406
SS
1887 HASHMAP_FOREACH(vxlan, link->network->vxlans, i) {
1888 log_struct_link(LOG_DEBUG, link,
1889 "MESSAGE=%*s: enslaving by '%s'",
1890 IFNAMSIZ,
1891 link->ifname, vxlan->ifname, NETDEV(vxlan), NULL);
1892
1893 r = netdev_enslave(vxlan, link, &enslave_handler);
1894 if (r < 0) {
1895 log_struct_link(LOG_WARNING, link,
1896 "MESSAGE=%*s: could not enslave by '%s': %s",
1897 IFNAMSIZ,
1898 link->ifname, vxlan->ifname, strerror(-r),
1899 NETDEV(vxlan), NULL);
1900 link_enter_failed(link);
1901 return r;
1902 }
1903
326cb406
SS
1904 link->enslaving ++;
1905 }
1906
ef1ba606
TG
1907 return 0;
1908}
1909
a748b692 1910static int link_configure(Link *link) {
02b59d57
TG
1911 int r;
1912
ef1ba606 1913 assert(link);
505f8da7 1914 assert(link->state == LINK_STATE_INITIALIZING);
a748b692 1915
eb34d4af 1916 if (link->network->ipv4ll) {
b5db00e5 1917 uint8_t seed[8];
45ad2c13 1918
eb34d4af
TG
1919 r = sd_ipv4ll_new(&link->ipv4ll);
1920 if (r < 0)
1921 return r;
1922
505f8da7
TG
1923 if (link->udev_device) {
1924 r = net_get_unique_predictable_data(link->udev_device, seed);
1925 if (r >= 0) {
1926 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
1927 if (r < 0)
1928 return r;
1929 }
b5db00e5
UTL
1930 }
1931
eb34d4af
TG
1932 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
1933 if (r < 0)
1934 return r;
1935
4bb40e81
TG
1936 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1937 if (r < 0)
1938 return r;
1939
eb34d4af
TG
1940 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
1941 if (r < 0)
1942 return r;
1943
1944 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
1945 if (r < 0)
1946 return r;
1947 }
1948
ed942a9e 1949 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) {
eb34d4af
TG
1950 r = sd_dhcp_client_new(&link->dhcp_client);
1951 if (r < 0)
1952 return r;
1953
1954 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
1955 if (r < 0)
1956 return r;
1957
4bb40e81
TG
1958 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
1959 if (r < 0)
1960 return r;
1961
eb34d4af
TG
1962 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
1963 if (r < 0)
1964 return r;
1965
1966 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
1967 if (r < 0)
1968 return r;
1969
1970 if (link->network->dhcp_mtu) {
1971 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
1972 if (r < 0)
1973 return r;
1974 }
4cc7a82c 1975
e1ea665e
EY
1976 if (link->network->dhcp_routes) {
1977 r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_STATIC_ROUTE);
1978 if (r < 0)
1979 return r;
1980 r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
1981 if (r < 0)
1982 return r;
1983 }
4cc7a82c
EY
1984
1985 if (link->network->dhcp_sendhost) {
1986 _cleanup_free_ char *hostname = gethostname_malloc();
1987 if (!hostname)
1988 return -ENOMEM;
1989
1990 if (!is_localhost(hostname)) {
1991 r = sd_dhcp_client_set_hostname(link->dhcp_client, hostname);
1992 if (r < 0)
1993 return r;
1994 }
1995 }
eb34d4af
TG
1996 }
1997
dd43110f 1998 if (link->network->dhcp_server) {
dd43110f
TG
1999 r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
2000 if (r < 0)
2001 return r;
2002
2003 r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
2004 if (r < 0)
2005 return r;
dd43110f
TG
2006 }
2007
ed942a9e 2008 if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
4138fb2c
PF
2009 r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
2010 if (r < 0)
2011 return r;
2012
2013 r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery,
2014 NULL, 0);
2015 if (r < 0)
2016 return r;
2017
2018 r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery,
2019 &link->mac);
2020 if (r < 0)
2021 return r;
2022
2023 r = sd_icmp6_nd_set_index(link->icmp6_router_discovery,
2024 link->ifindex);
2025 if (r < 0)
2026 return r;
2027
2028 r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
2029 icmp6_router_handler, link);
2030 if (r < 0)
2031 return r;
2032 }
2033
bf0308cb 2034 if (link_has_carrier(link->flags, link->kernel_operstate)) {
1e9be60b
TG
2035 r = link_acquire_conf(link);
2036 if (r < 0)
2037 return r;
cc544d5f 2038 }
1e9be60b 2039
505f8da7
TG
2040 return link_enter_enslave(link);
2041}
2042
4f561e8e 2043static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 2044 _cleanup_link_unref_ Link *link = userdata;
505f8da7 2045 Network *network;
505f8da7
TG
2046 int r;
2047
2048 assert(link);
2049 assert(link->ifname);
2050 assert(link->manager);
2051
2052 if (link->state != LINK_STATE_INITIALIZING)
5da8149f 2053 return 1;
505f8da7 2054
4f561e8e 2055 log_debug_link(link, "link state is up-to-date");
505f8da7 2056
4f561e8e 2057 r = network_get(link->manager, link->udev_device, link->ifname, &link->mac, &network);
57bd6899
TG
2058 if (r == -ENOENT) {
2059 link_enter_unmanaged(link);
5da8149f 2060 return 1;
57bd6899
TG
2061 } else if (r < 0)
2062 return r;
505f8da7
TG
2063
2064 r = network_apply(link->manager, network, link);
2065 if (r < 0)
2066 return r;
2067
a748b692
TG
2068 r = link_configure(link);
2069 if (r < 0)
2070 return r;
2071
5da8149f 2072 return 1;
505f8da7
TG
2073}
2074
4f561e8e
TG
2075int link_initialized(Link *link, struct udev_device *device) {
2076 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
2077 int r;
2078
2079 assert(link);
2080 assert(link->manager);
2081 assert(link->manager->rtnl);
2082 assert(device);
2083
2084 if (link->state != LINK_STATE_INITIALIZING)
2085 return 0;
2086
2087 log_debug_link(link, "udev initialized link");
2088
2089 link->udev_device = udev_device_ref(device);
2090
2091 /* udev has initialized the link, but we don't know if we have yet processed
2092 the NEWLINK messages with the latest state. Do a GETLINK, when it returns
2093 we know that the pending NEWLINKs have already been processed and that we
2094 are up-to-date */
2095
2096 r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK, link->ifindex);
2097 if (r < 0)
2098 return r;
2099
2100 r = sd_rtnl_call_async(link->manager->rtnl, req, link_initialized_and_synced, link, 0, NULL);
2101 if (r < 0)
2102 return r;
2103
5da8149f
TG
2104 link_ref(link);
2105
4f561e8e
TG
2106 return 0;
2107}
2108
fbbeb65a
TG
2109int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
2110 Manager *m = userdata;
2111 Link *link = NULL;
2112 uint16_t type;
2113 _cleanup_address_free_ Address *address = NULL;
428fd0a7 2114 Address *ad;
fbbeb65a 2115 char buf[INET6_ADDRSTRLEN];
428fd0a7 2116 bool address_dropped = false;
fbbeb65a
TG
2117 int r, ifindex;
2118
2119 assert(rtnl);
2120 assert(message);
2121 assert(m);
2122
2123 r = sd_rtnl_message_get_type(message, &type);
2124 if (r < 0) {
2125 log_warning("rtnl: could not get message type");
2126 return 0;
2127 }
2128
2129 r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
2130 if (r < 0 || ifindex <= 0) {
5ea846cc 2131 log_warning("rtnl: received address message without valid ifindex, ignoring");
fbbeb65a
TG
2132 return 0;
2133 } else {
2134 r = link_get(m, ifindex, &link);
2135 if (r < 0 || !link) {
5ea846cc 2136 log_warning("rtnl: received address for a nonexistent link, ignoring");
fbbeb65a
TG
2137 return 0;
2138 }
2139 }
2140
2141 r = address_new_dynamic(&address);
2142 if (r < 0)
393c0c5e 2143 return r;
fbbeb65a
TG
2144
2145 r = sd_rtnl_message_addr_get_family(message, &address->family);
2146 if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
987efa17 2147 log_warning_link(link, "rtnl: received address with invalid family, ignoring");
fbbeb65a
TG
2148 return 0;
2149 }
2150
2151 r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
2152 if (r < 0) {
e375dcde
TG
2153 log_warning_link(link, "rtnl: received address with invalid prefixlen, ignoring");
2154 return 0;
2155 }
2156
2157 r = sd_rtnl_message_addr_get_scope(message, &address->scope);
2158 if (r < 0) {
2159 log_warning_link(link, "rtnl: received address with invalid scope, ignoring");
fbbeb65a
TG
2160 return 0;
2161 }
2162
2163 switch (address->family) {
2164 case AF_INET:
2165 r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
2166 if (r < 0) {
987efa17 2167 log_warning_link(link, "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
2168 return 0;
2169 }
2170
2171 break;
2172
2173 case AF_INET6:
2174 r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
2175 if (r < 0) {
987efa17 2176 log_warning_link(link, "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
2177 return 0;
2178 }
2179
2180 break;
2181
2182 default:
2183 assert_not_reached("invalid address family");
2184 }
2185
2186 if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
987efa17 2187 log_warning_link(link, "could not print address");
fbbeb65a
TG
2188 return 0;
2189 }
2190
428fd0a7
TG
2191 LIST_FOREACH(addresses, ad, link->addresses) {
2192 if (address_equal(ad, address)) {
2193 LIST_REMOVE(addresses, link->addresses, ad);
2194
2195 address_free(ad);
2196
2197 address_dropped = true;
2198
2199 break;
2200 }
2201 }
2202
fbbeb65a
TG
2203 switch (type) {
2204 case RTM_NEWADDR:
428fd0a7
TG
2205 if (!address_dropped)
2206 log_debug_link(link, "added address: %s/%u", buf,
393c0c5e
TG
2207 address->prefixlen);
2208 else
2209 log_debug_link(link, "updated address: %s/%u", buf,
2210 address->prefixlen);
fbbeb65a 2211
428fd0a7
TG
2212 LIST_PREPEND(addresses, link->addresses, address);
2213 address = NULL;
2214
f5602be9
TG
2215 link_save(link);
2216
428fd0a7 2217 break;
fbbeb65a 2218 case RTM_DELADDR:
f5602be9 2219 if (address_dropped) {
428fd0a7 2220 log_debug_link(link, "removed address: %s/%u", buf,
393c0c5e 2221 address->prefixlen);
428fd0a7 2222
f5602be9 2223 link_save(link);
393c0c5e
TG
2224 } else
2225 log_warning_link(link, "removing non-existent address: %s/%u",
2226 buf, address->prefixlen);
f5602be9 2227
fbbeb65a
TG
2228 break;
2229 default:
2230 assert_not_reached("Received invalid RTNL message type");
2231 }
2232
2233 return 1;
2234}
2235
2236static int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 2237 _cleanup_link_unref_ Link *link = userdata;
fbbeb65a
TG
2238 int r;
2239
2240 assert(rtnl);
2241 assert(m);
2242 assert(link);
5da8149f 2243 assert(link->manager);
fbbeb65a
TG
2244
2245 for (; m; m = sd_rtnl_message_next(m)) {
2246 r = sd_rtnl_message_get_errno(m);
2247 if (r < 0) {
2248 log_debug_link(link, "getting address failed: %s", strerror(-r));
2249 continue;
2250 }
2251
2252 r = link_rtnl_process_address(rtnl, m, link->manager);
2253 if (r < 0)
2254 log_warning_link(link, "could not process address: %s", strerror(-r));
2255 }
2256
2257 return 1;
2258}
2259
505f8da7
TG
2260int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
2261 Link *link;
fbbeb65a 2262 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
505f8da7
TG
2263 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
2264 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
2265 int r;
2266
2267 assert(m);
fbbeb65a 2268 assert(m->rtnl);
505f8da7
TG
2269 assert(message);
2270 assert(ret);
2271
2272 r = link_new(m, message, ret);
2273 if (r < 0)
2274 return r;
2275
2276 link = *ret;
2277
5261692f 2278 log_debug_link(link, "link %"PRIu64" added", link->ifindex);
505f8da7 2279
fbbeb65a
TG
2280 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex, 0);
2281 if (r < 0)
2282 return r;
2283
2284 r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0, NULL);
2285 if (r < 0)
2286 return r;
2287
5da8149f
TG
2288 link_ref(link);
2289
505f8da7
TG
2290 if (detect_container(NULL) <= 0) {
2291 /* not in a container, udev will be around */
2292 sprintf(ifindex_str, "n%"PRIu64, link->ifindex);
2293 device = udev_device_new_from_device_id(m->udev, ifindex_str);
2294 if (!device) {
2295 log_warning_link(link, "could not find udev device");
2296 return -errno;
2297 }
2298
3c4cb064 2299 if (udev_device_get_is_initialized(device) <= 0) {
505f8da7 2300 /* not yet ready */
16cd414b 2301 log_debug_link(link, "udev initializing link...");
505f8da7 2302 return 0;
3c4cb064 2303 }
505f8da7 2304
4f561e8e
TG
2305 r = link_initialized(link, device);
2306 if (r < 0)
2307 return r;
2308 } else {
5da8149f
TG
2309 /* we are calling a callback directly, so must take a ref */
2310 link_ref(link);
2311
4f561e8e
TG
2312 r = link_initialized_and_synced(m->rtnl, NULL, link);
2313 if (r < 0)
2314 return r;
2315 }
505f8da7 2316
a748b692
TG
2317 return 0;
2318}
2319
22936833 2320int link_update(Link *link, sd_rtnl_message *m) {
c49b33ac 2321 struct ether_addr mac;
b8941f74 2322 char *ifname;
22936833
TG
2323 int r;
2324
dd3efc09 2325 assert(link);
b8941f74 2326 assert(link->ifname);
22936833
TG
2327 assert(m);
2328
7619683b
TG
2329 if (link->state == LINK_STATE_LINGER) {
2330 link_ref(link);
2331 log_info_link(link, "link readded");
2332 link->state = LINK_STATE_ENSLAVING;
2333 }
2334
b8941f74
TG
2335 r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
2336 if (r >= 0 && !streq(ifname, link->ifname)) {
2337 log_info_link(link, "renamed to %s", ifname);
2338
2339 free(link->ifname);
2340 link->ifname = strdup(ifname);
2341 if (!link->ifname)
2342 return -ENOMEM;
2343 }
2344
505f8da7 2345 if (!link->original_mtu) {
9842de0d
TG
2346 r = sd_rtnl_message_read_u16(m, IFLA_MTU, &link->original_mtu);
2347 if (r >= 0)
2348 log_debug_link(link, "saved original MTU: %"
2349 PRIu16, link->original_mtu);
2350 }
69629de9 2351
e9189a1f
TG
2352 /* The kernel may broadcast NEWLINK messages without the MAC address
2353 set, simply ignore them. */
c49b33ac 2354 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
e9189a1f 2355 if (r >= 0) {
20861203 2356 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN)) {
c49b33ac 2357
20861203 2358 memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);
c49b33ac 2359
20861203
TG
2360 log_debug_link(link, "MAC address: "
2361 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
2362 mac.ether_addr_octet[0],
2363 mac.ether_addr_octet[1],
2364 mac.ether_addr_octet[2],
2365 mac.ether_addr_octet[3],
2366 mac.ether_addr_octet[4],
2367 mac.ether_addr_octet[5]);
c49b33ac 2368
20861203
TG
2369 if (link->ipv4ll) {
2370 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
2371 if (r < 0) {
2372 log_warning_link(link, "Could not update MAC "
2373 "address in IPv4LL client: %s",
2374 strerror(-r));
2375 return r;
2376 }
c49b33ac 2377 }
c49b33ac 2378
20861203
TG
2379 if (link->dhcp_client) {
2380 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
2381 if (r < 0) {
2382 log_warning_link(link, "Could not update MAC "
2383 "address in DHCP client: %s",
2384 strerror(-r));
2385 return r;
2386 }
c49b33ac 2387 }
4138fb2c
PF
2388
2389 if (link->dhcp6_client) {
2390 r = sd_dhcp6_client_set_mac(link->dhcp6_client,
2391 &link->mac);
2392 if (r < 0) {
2393 log_warning_link(link, "Could not update MAC address in DHCPv6 client: %s",
2394 strerror(-r));
2395 return r;
2396 }
2397 }
c49b33ac 2398 }
4f882b2a
TG
2399 }
2400
1e9be60b 2401 return link_update_flags(link, m);
dd3efc09 2402}
fe8db0c5 2403
7374f9d8
TG
2404static void serialize_addresses(FILE *f, const char *key, Address *address) {
2405 Address *ad;
2406
2407 assert(f);
2408 assert(key);
2409
2410 if (!address)
2411 return;
2412
2413 fprintf(f, "%s=", key);
2414
2415 LIST_FOREACH(addresses, ad, address) {
2416 char buf[INET6_ADDRSTRLEN];
2417
d408b506 2418 if (inet_ntop(ad->family, &ad->in_addr, buf, INET6_ADDRSTRLEN))
7374f9d8
TG
2419 fprintf(f, "%s%s", buf, (ad->addresses_next) ? " ": "");
2420 }
2421
2422 fputs("\n", f);
2423}
2424
e375dcde
TG
2425static void link_update_operstate(Link *link) {
2426
2427 assert(link);
2428
2429 if (link->kernel_operstate == IF_OPER_DORMANT)
2430 link->operstate = LINK_OPERSTATE_DORMANT;
2431 else if (link_has_carrier(link->flags, link->kernel_operstate)) {
2432 Address *address;
2433 uint8_t scope = RT_SCOPE_NOWHERE;
2434
2435 /* if we have carrier, check what addresses we have */
2436 LIST_FOREACH(addresses, address, link->addresses) {
2437 if (address->scope < scope)
2438 scope = address->scope;
2439 }
2440
2441 if (scope < RT_SCOPE_SITE)
2442 /* universally accessible addresses found */
2443 link->operstate = LINK_OPERSTATE_ROUTABLE;
2444 else if (scope < RT_SCOPE_HOST)
2445 /* only link or site local addresses found */
2446 link->operstate = LINK_OPERSTATE_DEGRADED;
2447 else
2448 /* no useful addresses found */
2449 link->operstate = LINK_OPERSTATE_CARRIER;
2450 } else
2451 link->operstate = LINK_OPERSTATE_UNKNOWN;
2452}
2453
fe8db0c5 2454int link_save(Link *link) {
68a8723c 2455 _cleanup_free_ char *temp_path = NULL;
fe8db0c5 2456 _cleanup_fclose_ FILE *f = NULL;
e375dcde 2457 const char *admin_state, *oper_state;
fe8db0c5
TG
2458 int r;
2459
2460 assert(link);
2461 assert(link->state_file);
68a8723c 2462 assert(link->lease_file);
bbf7c048
TG
2463 assert(link->manager);
2464
e375dcde
TG
2465 link_update_operstate(link);
2466
bbf7c048
TG
2467 r = manager_save(link->manager);
2468 if (r < 0)
2469 return r;
fe8db0c5 2470
370e9930
TG
2471 if (link->state == LINK_STATE_LINGER) {
2472 unlink(link->state_file);
2473 return 0;
2474 }
2475
deb2e523
TG
2476 admin_state = link_state_to_string(link->state);
2477 assert(admin_state);
2478
e375dcde
TG
2479 oper_state = link_operstate_to_string(link->operstate);
2480 assert(oper_state);
deb2e523 2481
fe8db0c5
TG
2482 r = fopen_temporary(link->state_file, &f, &temp_path);
2483 if (r < 0)
2484 goto finish;
2485
2486 fchmod(fileno(f), 0644);
2487
2488 fprintf(f,
2489 "# This is private data. Do not parse.\n"
deb2e523
TG
2490 "ADMIN_STATE=%s\n"
2491 "OPER_STATE=%s\n"
2492 "FLAGS=%u\n",
2493 admin_state, oper_state, link->flags);
fe8db0c5 2494
bcb7a07e 2495 if (link->network) {
7374f9d8 2496 serialize_addresses(f, "DNS", link->network->dns);
bcb7a07e
TG
2497 serialize_addresses(f, "NTP", link->network->ntp);
2498 }
7374f9d8 2499
fe8db0c5 2500 if (link->dhcp_lease) {
d9876a52
TG
2501 assert(link->network);
2502
68a8723c 2503 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
fe8db0c5
TG
2504 if (r < 0)
2505 goto finish;
2506
7374f9d8
TG
2507 fprintf(f,
2508 "DHCP_LEASE=%s\n"
bcb7a07e
TG
2509 "DHCP_USE_DNS=%s\n"
2510 "DHCP_USE_NTP=%s\n",
2511 link->lease_file,
2512 yes_no(link->network->dhcp_dns),
2513 yes_no(link->network->dhcp_ntp));
deb2e523 2514 } else
68a8723c 2515 unlink(link->lease_file);
fe8db0c5
TG
2516
2517 fflush(f);
2518
2519 if (ferror(f) || rename(temp_path, link->state_file) < 0) {
2520 r = -errno;
2521 unlink(link->state_file);
2522 unlink(temp_path);
2523 }
2524
2525finish:
2526 if (r < 0)
987efa17 2527 log_error_link(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
fe8db0c5
TG
2528
2529 return r;
2530}
2531
2532static const char* const link_state_table[_LINK_STATE_MAX] = {
deb2e523 2533 [LINK_STATE_INITIALIZING] = "initializing",
fe8db0c5
TG
2534 [LINK_STATE_ENSLAVING] = "configuring",
2535 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
2536 [LINK_STATE_SETTING_ROUTES] = "configuring",
2537 [LINK_STATE_CONFIGURED] = "configured",
57bd6899 2538 [LINK_STATE_UNMANAGED] = "unmanaged",
fe8db0c5 2539 [LINK_STATE_FAILED] = "failed",
370e9930 2540 [LINK_STATE_LINGER] = "linger",
fe8db0c5
TG
2541};
2542
2543DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
e375dcde
TG
2544
2545static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
2546 [LINK_OPERSTATE_UNKNOWN] = "unknown",
2547 [LINK_OPERSTATE_DORMANT] = "dormant",
2548 [LINK_OPERSTATE_CARRIER] = "carrier",
2549 [LINK_OPERSTATE_DEGRADED] = "degraded",
2550 [LINK_OPERSTATE_ROUTABLE] = "routable",
2551};
2552
2553DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
ed942a9e
TG
2554
2555static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = {
2556 [DHCP_SUPPORT_NONE] = "none",
2557 [DHCP_SUPPORT_BOTH] = "both",
2558 [DHCP_SUPPORT_V4] = "v4",
2559 [DHCP_SUPPORT_V6] = "v6",
2560};
2561
2562DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport);
2563
2564int config_parse_dhcp(
2565 const char* unit,
2566 const char *filename,
2567 unsigned line,
2568 const char *section,
2569 unsigned section_line,
2570 const char *lvalue,
2571 int ltype,
2572 const char *rvalue,
2573 void *data,
2574 void *userdata) {
2575
2576 DHCPSupport *dhcp = data;
2577 int k;
2578
2579 assert(filename);
2580 assert(lvalue);
2581 assert(rvalue);
2582 assert(data);
2583
2584 /* Our enum shall be a superset of booleans, hence first try
2585 * to parse as boolean, and then as enum */
2586
2587 k = parse_boolean(rvalue);
2588 if (k > 0)
2589 *dhcp = DHCP_SUPPORT_BOTH;
2590 else if (k == 0)
2591 *dhcp = DHCP_SUPPORT_NONE;
2592 else {
2593 DHCPSupport s;
2594
2595 s = dhcp_support_from_string(rvalue);
2596 if (s < 0){
2597 log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue);
2598 return 0;
2599 }
2600
2601 *dhcp = s;
2602 }
2603
2604 return 0;
2605}