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