]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-link.c
Report aa_change_onexec error code
[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 25
0b1831c2 26#include "networkd-link.h"
3be1d7e0 27#include "networkd-netdev.h"
f579559b 28#include "libudev-private.h"
505f8da7 29#include "udev-util.h"
f579559b 30#include "util.h"
505f8da7 31#include "virt.h"
1346b1f0 32#include "bus-util.h"
c6f7c917 33#include "network-internal.h"
ed942a9e 34#include "conf-parser.h"
f579559b 35
fe8db0c5
TG
36#include "dhcp-lease-internal.h"
37
78c958f8
TG
38static bool link_dhcp6_enabled(Link *link) {
39 if (link->flags & IFF_LOOPBACK)
40 return false;
41
42 if (!link->network)
43 return false;
44
45 return IN_SET(link->network->dhcp, DHCP_SUPPORT_V6, DHCP_SUPPORT_BOTH);
46}
47
48static bool link_dhcp4_enabled(Link *link) {
49 if (link->flags & IFF_LOOPBACK)
50 return false;
51
52 if (!link->network)
53 return false;
54
55 return IN_SET(link->network->dhcp, DHCP_SUPPORT_V4, DHCP_SUPPORT_BOTH);
56}
57
58static bool link_dhcp4_server_enabled(Link *link) {
59 if (link->flags & IFF_LOOPBACK)
60 return false;
61
62 if (!link->network)
63 return false;
64
65 return link->network->dhcp_server;
66}
67
68static bool link_ipv4ll_enabled(Link *link) {
69 if (link->flags & IFF_LOOPBACK)
70 return false;
71
72 if (!link->network)
73 return false;
74
75 return link->network->ipv4ll;
76}
77
51d18171
TG
78#define FLAG_STRING(string, flag, old, new) \
79 (((old ^ new) & flag) \
80 ? ((old & flag) ? (" -" string) : (" +" string)) \
81 : "")
82
83static int link_update_flags(Link *link, sd_rtnl_message *m) {
84 unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
85 uint8_t operstate;
86 int r;
87
88 assert(link);
89
90 r = sd_rtnl_message_link_get_flags(m, &flags);
91 if (r < 0) {
92 log_warning_link(link, "Could not get link flags");
93 return r;
94 }
95
96 r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate);
97 if (r < 0)
98 /* if we got a message without operstate, take it to mean
99 the state was unchanged */
100 operstate = link->kernel_operstate;
101
102 if ((link->flags == flags) && (link->kernel_operstate == operstate))
103 return 0;
104
105 if (link->flags != flags) {
106 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",
107 FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
108 FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
109 FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
110 FLAG_STRING("UP", IFF_UP, link->flags, flags),
111 FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags),
112 FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags),
113 FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags),
114 FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags),
115 FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags),
116 FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags),
117 FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags),
118 FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags),
119 FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags),
120 FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags),
121 FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags),
122 FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags),
123 FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags),
124 FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags),
125 FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags));
126
127 unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP |
128 IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING |
129 IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT |
130 IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL |
131 IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP |
132 IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO);
133 unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags);
134 unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags);
135
136 /* link flags are currently at most 18 bits, let's align to
137 * printing 20 */
138 if (unknown_flags_added)
139 log_debug_link(link,
140 "unknown link flags gained: %#.5x (ignoring)",
141 unknown_flags_added);
142
143 if (unknown_flags_removed)
144 log_debug_link(link,
145 "unknown link flags lost: %#.5x (ignoring)",
146 unknown_flags_removed);
147 }
148
149 link->flags = flags;
150 link->kernel_operstate = operstate;
151
152 link_save(link);
153
154 return 0;
155}
156
505f8da7 157static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
14b746f7 158 _cleanup_link_unref_ Link *link = NULL;
505f8da7 159 uint16_t type;
ca4e095a 160 const char *ifname;
505f8da7 161 int r, ifindex;
f579559b 162
0c2f9b84 163 assert(manager);
505f8da7 164 assert(message);
f579559b
TG
165 assert(ret);
166
505f8da7
TG
167 r = sd_rtnl_message_get_type(message, &type);
168 if (r < 0)
169 return r;
170 else if (type != RTM_NEWLINK)
171 return -EINVAL;
172
173 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
174 if (r < 0)
175 return r;
176 else if (ifindex <= 0)
177 return -EINVAL;
178
179 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
180 if (r < 0)
181 return r;
182
f579559b
TG
183 link = new0(Link, 1);
184 if (!link)
185 return -ENOMEM;
186
14b746f7 187 link->n_ref = 1;
5a3eb5a7 188 link->manager = manager;
8434fd5c 189 link->state = LINK_STATE_PENDING;
505f8da7
TG
190 link->ifindex = ifindex;
191 link->ifname = strdup(ifname);
192 if (!link->ifname)
193 return -ENOMEM;
f579559b 194
512922f8
TG
195 r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
196 if (r < 0)
1a941ac4 197 log_debug_link(link, "MAC address not found for new device, continuing without");
512922f8 198
3c9b8860
TG
199 r = asprintf(&link->state_file, "/run/systemd/netif/links/%d",
200 link->ifindex);
fe8db0c5 201 if (r < 0)
315db1a8 202 return -ENOMEM;
fe8db0c5 203
3c9b8860
TG
204 r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d",
205 link->ifindex);
68a8723c
TG
206 if (r < 0)
207 return -ENOMEM;
208
d5099efc 209 r = hashmap_ensure_allocated(&manager->links, NULL);
ae06ab10
TG
210 if (r < 0)
211 return r;
212
213 r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link);
f579559b
TG
214 if (r < 0)
215 return r;
216
51d18171
TG
217 r = link_update_flags(link, message);
218 if (r < 0)
219 return r;
220
f579559b
TG
221 *ret = link;
222 link = NULL;
223
224 return 0;
225}
226
14b746f7 227static void link_free(Link *link) {
428fd0a7
TG
228 Address *address;
229
f579559b
TG
230 if (!link)
231 return;
232
428fd0a7
TG
233 while ((address = link->addresses)) {
234 LIST_REMOVE(addresses, link->addresses, address);
235 address_free(address);
236 }
237
11bf3cce
LP
238 while ((address = link->pool_addresses)) {
239 LIST_REMOVE(addresses, link->pool_addresses, address);
240 address_free(address);
241 }
242
e5b04c8d 243 sd_dhcp_client_unref(link->dhcp_client);
a6cc569e 244 sd_dhcp_lease_unref(link->dhcp_lease);
f5be5601 245
68a8723c
TG
246 unlink(link->lease_file);
247 free(link->lease_file);
248
56cd007a 249 sd_ipv4ll_unref(link->ipv4ll);
4138fb2c 250 sd_dhcp6_client_unref(link->dhcp6_client);
6b66097b 251 sd_icmp6_nd_unref(link->icmp6_router_discovery);
4138fb2c 252
28aeb07f 253 if (link->manager)
ae06ab10 254 hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
f579559b 255
c166a070 256 free(link->ifname);
68a8723c
TG
257
258 unlink(link->state_file);
fe8db0c5 259 free(link->state_file);
c166a070 260
b5db00e5
UTL
261 udev_device_unref(link->udev_device);
262
f579559b
TG
263 free(link);
264}
265
14b746f7
TG
266Link *link_unref(Link *link) {
267 if (link && (-- link->n_ref <= 0))
268 link_free(link);
269
270 return NULL;
271}
272
273Link *link_ref(Link *link) {
274 if (link)
275 assert_se(++ link->n_ref >= 2);
276
277 return link;
278}
279
11a7f229
TG
280int link_get(Manager *m, int ifindex, Link **ret) {
281 Link *link;
11a7f229
TG
282
283 assert(m);
11a7f229
TG
284 assert(ifindex);
285 assert(ret);
286
ae06ab10 287 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
11a7f229
TG
288 if (!link)
289 return -ENODEV;
290
291 *ret = link;
292
293 return 0;
294}
295
370e9930
TG
296void link_drop(Link *link) {
297 if (!link || link->state == LINK_STATE_LINGER)
298 return;
299
300 link->state = LINK_STATE_LINGER;
301
7619683b 302 log_debug_link(link, "link removed");
370e9930
TG
303
304 link_unref(link);
305
306 return;
307}
308
57bd6899
TG
309static void link_enter_unmanaged(Link *link) {
310 assert(link);
311
df9aa406 312 log_debug_link(link, "unmanaged");
57bd6899
TG
313
314 link->state = LINK_STATE_UNMANAGED;
315
316 link_save(link);
317}
318
111bb8f9
TG
319static int link_stop_clients(Link *link) {
320 int r = 0, k;
321
322 assert(link);
323 assert(link->manager);
324 assert(link->manager->event);
325
326 if (!link->network)
327 return 0;
328
ba179154 329 if (link->dhcp_client) {
111bb8f9
TG
330 k = sd_dhcp_client_stop(link->dhcp_client);
331 if (k < 0) {
3c9b8860
TG
332 log_warning_link(link, "Could not stop DHCPv4 client: %s",
333 strerror(-r));
111bb8f9
TG
334 r = k;
335 }
336 }
337
ba179154 338 if (link->ipv4ll) {
111bb8f9
TG
339 k = sd_ipv4ll_stop(link->ipv4ll);
340 if (k < 0) {
3c9b8860
TG
341 log_warning_link(link, "Could not stop IPv4 link-local: %s",
342 strerror(-r));
111bb8f9
TG
343 r = k;
344 }
345 }
346
ba179154 347 if (link->dhcp_server) {
dd43110f
TG
348 k = sd_dhcp_server_stop(link->dhcp_server);
349 if (k < 0) {
3c9b8860
TG
350 log_warning_link(link, "Could not stop DHCPv4 server: %s",
351 strerror(-r));
dd43110f
TG
352 r = k;
353 }
354 }
355
ba179154 356 if(link->icmp6_router_discovery) {
1873a3d3
PF
357
358 if (link->dhcp6_client) {
359 k = sd_dhcp6_client_stop(link->dhcp6_client);
360 if (k < 0) {
3c9b8860
TG
361 log_warning_link(link, "Could not stop DHCPv6 client: %s",
362 strerror(-r));
1873a3d3
PF
363 r = k;
364 }
365 }
4138fb2c 366
1873a3d3 367 k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
4138fb2c 368 if (k < 0) {
3c9b8860
TG
369 log_warning_link(link,
370 "Could not stop ICMPv6 router discovery: %s",
371 strerror(-r));
4138fb2c
PF
372 r = k;
373 }
374 }
375
111bb8f9
TG
376 return r;
377}
378
b22d8a00 379void link_enter_failed(Link *link) {
ef1ba606 380 assert(link);
f882c247 381
370e9930 382 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
2139694e
TG
383 return;
384
39032b87 385 log_warning_link(link, "failed");
449f7554 386
ef1ba606 387 link->state = LINK_STATE_FAILED;
fe8db0c5 388
111bb8f9
TG
389 link_stop_clients(link);
390
fe8db0c5 391 link_save(link);
f882c247
TG
392}
393
4f434938
LP
394static Address* link_find_dhcp_server_address(Link *link) {
395 Address *address;
396
397 assert(link);
398 assert(link->network);
399
400 /* The the first statically configured address if there is any */
401 LIST_FOREACH(addresses, address, link->network->static_addresses) {
402
403 if (address->family != AF_INET)
404 continue;
405
af93291c 406 if (in_addr_is_null(address->family, &address->in_addr))
4f434938
LP
407 continue;
408
409 return address;
410 }
411
412 /* If that didn't work, find a suitable address we got from the pool */
413 LIST_FOREACH(addresses, address, link->pool_addresses) {
414 if (address->family != AF_INET)
415 continue;
416
417 return address;
418 }
419
420 return NULL;
421}
422
dd43110f
TG
423static int link_enter_configured(Link *link) {
424 int r;
425
426 assert(link);
427 assert(link->network);
428 assert(link->state == LINK_STATE_SETTING_ROUTES);
429
78c958f8 430 if (link_dhcp4_server_enabled(link) &&
7c16313f 431 !sd_dhcp_server_is_running(link->dhcp_server)) {
4f434938
LP
432 struct in_addr pool_start;
433 Address *address;
434
435 address = link_find_dhcp_server_address(link);
436 if (!address) {
3c9b8860
TG
437 log_warning_link(link,
438 "Failed to find suitable address for DHCPv4 server instance.");
4f434938
LP
439 link_enter_failed(link);
440 return 0;
441 }
442
dd43110f
TG
443 log_debug_link(link, "offering DHCPv4 leases");
444
3c9b8860
TG
445 r = sd_dhcp_server_set_address(link->dhcp_server,
446 &address->in_addr.in,
447 address->prefixlen);
4f434938
LP
448 if (r < 0)
449 return r;
450
451 /* offer 32 addresses starting from the address following the server address */
452 pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1);
453 r = sd_dhcp_server_set_lease_pool(link->dhcp_server,
454 &pool_start, 32);
455 if (r < 0)
456 return r;
457
458 /* TODO:
459 r = sd_dhcp_server_set_router(link->dhcp_server,
460 &main_address->in_addr.in);
461 if (r < 0)
462 return r;
463
464 r = sd_dhcp_server_set_prefixlen(link->dhcp_server,
465 main_address->prefixlen);
466 if (r < 0)
467 return r;
468 */
469
dd43110f
TG
470 r = sd_dhcp_server_start(link->dhcp_server);
471 if (r < 0) {
472 log_warning_link(link, "could not start DHCPv4 server "
473 "instance: %s", strerror(-r));
474
475 link_enter_failed(link);
476
477 return 0;
478 }
479 }
480
481 log_info_link(link, "link configured");
482
483 link->state = LINK_STATE_CONFIGURED;
484
485 link_save(link);
486
487 return 0;
488}
489
3c9b8860
TG
490void link_client_handler(Link *link) {
491 assert(link);
492 assert(link->network);
493
494 if (!link->static_configured)
495 return;
496
78c958f8 497 if (link_ipv4ll_enabled(link))
3c9b8860
TG
498 if (!link->ipv4ll_address ||
499 !link->ipv4ll_route)
500 return;
501
78c958f8 502 if (link_dhcp4_enabled(link) && !link->dhcp4_configured)
3c9b8860
TG
503 return;
504
9fdaa992
TG
505 if (link->state != LINK_STATE_CONFIGURED)
506 link_enter_configured(link);
3c9b8860
TG
507
508 return;
509}
510
f882c247 511static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 512 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
513 int r;
514
3c9b8860 515 assert(link->link_messages > 0);
370e9930
TG
516 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
517 LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
518 LINK_STATE_LINGER));
f882c247 519
3c9b8860 520 link->link_messages --;
f882c247 521
77a008c0 522 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
523 return 1;
524
525 r = sd_rtnl_message_get_errno(m);
c166a070 526 if (r < 0 && r != -EEXIST)
c9ccc19f 527 log_struct_link(LOG_WARNING, link,
97578344 528 "MESSAGE=%-*s: could not set route: %s",
987efa17 529 IFNAMSIZ,
c9ccc19f
TG
530 link->ifname, strerror(-r),
531 "ERRNO=%d", -r,
532 NULL);
f882c247 533
3c9b8860 534 if (link->link_messages == 0) {
39032b87 535 log_debug_link(link, "routes set");
3c9b8860
TG
536 link->static_configured = true;
537 link_client_handler(link);
dd3efc09 538 }
f882c247
TG
539
540 return 1;
541}
542
543static int link_enter_set_routes(Link *link) {
a6cc569e 544 Route *rt;
f882c247
TG
545 int r;
546
547 assert(link);
548 assert(link->network);
ef1ba606 549 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
f882c247 550
ef1ba606 551 link->state = LINK_STATE_SETTING_ROUTES;
f882c247 552
3d3d4255 553 LIST_FOREACH(routes, rt, link->network->static_routes) {
a6cc569e 554 r = route_configure(rt, link, &route_handler);
dd3efc09 555 if (r < 0) {
3333d748 556 log_warning_link(link,
3c9b8860 557 "could not set routes: %s",
b1666580 558 strerror(-r));
3c9b8860 559 link_enter_failed(link);
a6cc569e
TG
560 return r;
561 }
562
3c9b8860 563 link->link_messages ++;
8ddbeaa2 564 }
f5be5601 565
3c9b8860
TG
566 if (link->link_messages == 0) {
567 link->static_configured = true;
568 link_client_handler(link);
431ca2ce
TG
569 } else
570 log_debug_link(link, "setting routes");
f882c247
TG
571
572 return 0;
573}
574
b22d8a00 575int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 576 _cleanup_link_unref_ Link *link = userdata;
5c1d3fc9
UTL
577 int r;
578
579 assert(m);
580 assert(link);
581 assert(link->ifname);
582
5da8149f 583 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
5c1d3fc9
UTL
584 return 1;
585
586 r = sd_rtnl_message_get_errno(m);
b90b025a 587 if (r < 0 && r != -ESRCH)
5c1d3fc9 588 log_struct_link(LOG_WARNING, link,
97578344 589 "MESSAGE=%-*s: could not drop route: %s",
987efa17 590 IFNAMSIZ,
5c1d3fc9
UTL
591 link->ifname, strerror(-r),
592 "ERRNO=%d", -r,
593 NULL);
594
5bdd314c 595 return 1;
5c1d3fc9
UTL
596}
597
b22d8a00 598int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
4958aee4
TG
599 _cleanup_link_unref_ Link *link = userdata;
600 int r;
601
602 assert(rtnl);
603 assert(m);
604 assert(link);
605 assert(link->manager);
606
607 for (; m; m = sd_rtnl_message_next(m)) {
608 r = sd_rtnl_message_get_errno(m);
609 if (r < 0) {
3c9b8860
TG
610 log_debug_link(link, "getting address failed: %s",
611 strerror(-r));
4958aee4
TG
612 continue;
613 }
614
615 r = link_rtnl_process_address(rtnl, m, link->manager);
616 if (r < 0)
3c9b8860
TG
617 log_warning_link(link, "could not process address: %s",
618 strerror(-r));
4958aee4
TG
619 }
620
621 return 1;
622}
623
f882c247 624static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 625 _cleanup_link_unref_ Link *link = userdata;
f882c247
TG
626 int r;
627
4958aee4 628 assert(rtnl);
f5be5601
TG
629 assert(m);
630 assert(link);
631 assert(link->ifname);
3c9b8860 632 assert(link->link_messages > 0);
370e9930
TG
633 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
634 LINK_STATE_FAILED, LINK_STATE_LINGER));
f882c247 635
3c9b8860 636 link->link_messages --;
f882c247 637
5da8149f 638 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
f882c247
TG
639 return 1;
640
641 r = sd_rtnl_message_get_errno(m);
c166a070 642 if (r < 0 && r != -EEXIST)
c9ccc19f 643 log_struct_link(LOG_WARNING, link,
97578344 644 "MESSAGE=%-*s: could not set address: %s",
987efa17 645 IFNAMSIZ,
3333d748
ZJS
646 link->ifname, strerror(-r),
647 "ERRNO=%d", -r,
648 NULL);
5bdd314c 649 else if (r >= 0) {
4958aee4
TG
650 /* calling handler directly so take a ref */
651 link_ref(link);
652 link_get_address_handler(rtnl, m, link);
653 }
f882c247 654
3c9b8860 655 if (link->link_messages == 0) {
39032b87 656 log_debug_link(link, "addresses set");
ef1ba606 657 link_enter_set_routes(link);
dd3efc09 658 }
f882c247
TG
659
660 return 1;
661}
662
663static int link_enter_set_addresses(Link *link) {
a6cc569e 664 Address *ad;
f882c247
TG
665 int r;
666
667 assert(link);
668 assert(link->network);
f5be5601 669 assert(link->state != _LINK_STATE_INVALID);
f882c247 670
ef1ba606 671 link->state = LINK_STATE_SETTING_ADDRESSES;
f882c247 672
3d3d4255 673 LIST_FOREACH(addresses, ad, link->network->static_addresses) {
a6cc569e 674 r = address_configure(ad, link, &address_handler);
dd3efc09 675 if (r < 0) {
3333d748 676 log_warning_link(link,
3c9b8860 677 "could not set addresses: %s",
a6cc569e 678 strerror(-r));
f5be5601
TG
679 link_enter_failed(link);
680 return r;
681 }
682
3c9b8860 683 link->link_messages ++;
f882c247
TG
684 }
685
3c9b8860 686 if (link->link_messages == 0) {
431ca2ce
TG
687 link_enter_set_routes(link);
688 } else
689 log_debug_link(link, "setting addresses");
690
f882c247
TG
691 return 0;
692}
693
b22d8a00 694int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 695 _cleanup_link_unref_ Link *link = userdata;
ff254138
TG
696 int r;
697
698 assert(m);
699 assert(link);
700 assert(link->ifname);
701
5da8149f 702 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
ff254138
TG
703 return 1;
704
705 r = sd_rtnl_message_get_errno(m);
b90b025a 706 if (r < 0 && r != -EADDRNOTAVAIL)
c9ccc19f 707 log_struct_link(LOG_WARNING, link,
97578344 708 "MESSAGE=%-*s: could not drop address: %s",
987efa17 709 IFNAMSIZ,
c9ccc19f
TG
710 link->ifname, strerror(-r),
711 "ERRNO=%d", -r,
712 NULL);
ff254138 713
5bdd314c 714 return 1;
ff254138
TG
715}
716
3c9b8860
TG
717static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata,
718 sd_bus_error *ret_error) {
5da8149f 719 _cleanup_link_unref_ Link *link = userdata;
1346b1f0
TG
720 int r;
721
b226d99b
TG
722 assert(link);
723
5da8149f 724 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
370e9930 725 return 1;
370e9930 726
1346b1f0 727 r = sd_bus_message_get_errno(m);
70b34f5d 728 if (r > 0)
3c9b8860
TG
729 log_warning_link(link, "Could not set hostname: %s",
730 strerror(r));
1346b1f0
TG
731
732 return 1;
733}
734
3c9b8860 735int link_set_hostname(Link *link, const char *hostname) {
1346b1f0
TG
736 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
737 int r = 0;
738
b226d99b
TG
739 assert(link);
740 assert(link->manager);
1346b1f0
TG
741 assert(hostname);
742
b226d99b 743 log_debug_link(link, "Setting transient hostname: '%s'", hostname);
1346b1f0 744
3c9b8860
TG
745 if (!link->manager->bus) {
746 /* TODO: replace by assert when we can rely on kdbus */
747 log_info_link(link,
748 "Not connected to system bus, ignoring transient hostname.");
bcbca829
TG
749 return 0;
750 }
751
1346b1f0 752 r = sd_bus_message_new_method_call(
b226d99b 753 link->manager->bus,
151b9b96 754 &m,
1346b1f0
TG
755 "org.freedesktop.hostname1",
756 "/org/freedesktop/hostname1",
757 "org.freedesktop.hostname1",
151b9b96 758 "SetHostname");
1346b1f0
TG
759 if (r < 0)
760 return r;
761
762 r = sd_bus_message_append(m, "sb", hostname, false);
763 if (r < 0)
764 return r;
765
3c9b8860
TG
766 r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler,
767 link, 0);
5da8149f 768 if (r < 0) {
3c9b8860
TG
769 log_error_link(link, "Could not set transient hostname: %s",
770 strerror(-r));
5da8149f
TG
771 return r;
772 }
b226d99b
TG
773
774 link_ref(link);
1346b1f0 775
5da8149f 776 return 0;
1346b1f0
TG
777}
778
4f882b2a 779static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 780 _cleanup_link_unref_ Link *link = userdata;
4f882b2a
TG
781 int r;
782
783 assert(m);
784 assert(link);
785 assert(link->ifname);
786
5da8149f 787 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
4f882b2a
TG
788 return 1;
789
790 r = sd_rtnl_message_get_errno(m);
c9ccc19f
TG
791 if (r < 0)
792 log_struct_link(LOG_WARNING, link,
97578344
TG
793 "MESSAGE=%-*s: could not set MTU: %s",
794 IFNAMSIZ, link->ifname, strerror(-r),
c9ccc19f
TG
795 "ERRNO=%d", -r,
796 NULL);
4f882b2a
TG
797
798 return 1;
799}
800
3c9b8860 801int link_set_mtu(Link *link, uint32_t mtu) {
cf6a8911 802 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
4f882b2a
TG
803 int r;
804
805 assert(link);
806 assert(link->manager);
807 assert(link->manager->rtnl);
808
809 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
810
151b9b96
LP
811 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
812 RTM_SETLINK, link->ifindex);
4f882b2a
TG
813 if (r < 0) {
814 log_error_link(link, "Could not allocate RTM_SETLINK message");
815 return r;
816 }
817
818 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
819 if (r < 0) {
820 log_error_link(link, "Could not append MTU: %s", strerror(-r));
821 return r;
822 }
823
3c9b8860
TG
824 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link,
825 0, NULL);
4f882b2a
TG
826 if (r < 0) {
827 log_error_link(link,
3c9b8860
TG
828 "Could not send rtnetlink message: %s",
829 strerror(-r));
4f882b2a
TG
830 return r;
831 }
832
ae941762 833 link_ref(link);
b226d99b 834
4f882b2a
TG
835 return 0;
836}
837
4138fb2c
PF
838static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
839 Link *link = userdata;
840
841 assert(link);
842 assert(link->network);
843 assert(link->manager);
844
845 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
846 return;
847
848 switch(event) {
849 case DHCP6_EVENT_STOP:
850 case DHCP6_EVENT_RESEND_EXPIRE:
851 case DHCP6_EVENT_RETRANS_MAX:
852 case DHCP6_EVENT_IP_ACQUIRE:
853 log_debug_link(link, "DHCPv6 event %d", event);
854
855 break;
856
857 default:
858 if (event < 0)
859 log_warning_link(link, "DHCPv6 error: %s",
860 strerror(-event));
861 else
862 log_warning_link(link, "DHCPv6 unknown event: %d",
863 event);
864 return;
865 }
866}
867
868static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
869 Link *link = userdata;
870 int r;
871
872 assert(link);
873 assert(link->network);
874 assert(link->manager);
875
876 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
877 return;
878
879 switch(event) {
880 case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
881 case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
882 return;
883
884 case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
885 case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
886 break;
887
888 default:
889 if (event < 0)
890 log_warning_link(link, "ICMPv6 error: %s",
891 strerror(-event));
892 else
893 log_warning_link(link, "ICMPv6 unknown event: %d",
894 event);
895
896 return;
897 }
898
899 if (link->dhcp6_client)
900 return;
901
902 r = sd_dhcp6_client_new(&link->dhcp6_client);
903 if (r < 0)
904 return;
905
906 r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
907 if (r < 0) {
908 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
909 return;
910 }
911
912 r = sd_dhcp6_client_set_mac(link->dhcp6_client, &link->mac);
913 if (r < 0) {
914 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
915 return;
916 }
917
918 r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
919 if (r < 0) {
920 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
921 return;
922 }
923
924 r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
925 link);
926 if (r < 0) {
927 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
928 return;
929 }
930
931 r = sd_dhcp6_client_start(link->dhcp6_client);
932 if (r < 0)
933 link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
934}
935
ff254138
TG
936static int link_acquire_conf(Link *link) {
937 int r;
938
939 assert(link);
940 assert(link->network);
ff254138
TG
941 assert(link->manager);
942 assert(link->manager->event);
943
78c958f8 944 if (link_ipv4ll_enabled(link)) {
eb34d4af 945 assert(link->ipv4ll);
ff254138 946
5c1d3fc9
UTL
947 log_debug_link(link, "acquiring IPv4 link-local address");
948
949 r = sd_ipv4ll_start(link->ipv4ll);
124fa2c6
TG
950 if (r < 0) {
951 log_warning_link(link, "could not acquire IPv4 "
952 "link-local address");
ff254138 953 return r;
124fa2c6 954 }
5c1d3fc9
UTL
955 }
956
78c958f8 957 if (link_dhcp4_enabled(link)) {
eb34d4af 958 assert(link->dhcp_client);
ff254138 959
5c1d3fc9 960 log_debug_link(link, "acquiring DHCPv4 lease");
ab47d620 961
5c1d3fc9 962 r = sd_dhcp_client_start(link->dhcp_client);
124fa2c6
TG
963 if (r < 0) {
964 log_warning_link(link, "could not acquire DHCPv4 "
965 "lease");
5c1d3fc9 966 return r;
124fa2c6 967 }
5c1d3fc9 968 }
ff254138 969
78c958f8 970 if (link_dhcp6_enabled(link)) {
4138fb2c
PF
971 assert(link->icmp6_router_discovery);
972
973 log_debug_link(link, "discovering IPv6 routers");
974
975 r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery);
976 if (r < 0) {
3c9b8860
TG
977 log_warning_link(link,
978 "could not start IPv6 router discovery");
4138fb2c
PF
979 return r;
980 }
981 }
982
ff254138
TG
983 return 0;
984}
985
a61bb41c 986bool link_has_carrier(Link *link) {
deb2e523
TG
987 /* see Documentation/networking/operstates.txt in the kernel sources */
988
a61bb41c 989 if (link->kernel_operstate == IF_OPER_UP)
deb2e523
TG
990 return true;
991
a61bb41c 992 if (link->kernel_operstate == IF_OPER_UNKNOWN)
deb2e523 993 /* operstate may not be implemented, so fall back to flags */
a61bb41c 994 if ((link->flags & IFF_LOWER_UP) && !(link->flags & IFF_DORMANT))
deb2e523
TG
995 return true;
996
997 return false;
998}
999
dd3efc09 1000static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
5da8149f 1001 _cleanup_link_unref_ Link *link = userdata;
dd3efc09
TG
1002 int r;
1003
1746cf2a
TG
1004 assert(link);
1005
5da8149f 1006 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1746cf2a
TG
1007 return 1;
1008
dd3efc09 1009 r = sd_rtnl_message_get_errno(m);
45ad2c13 1010 if (r < 0) {
9b86b393
TG
1011 /* we warn but don't fail the link, as it may
1012 be brought up later */
76800848 1013 log_struct_link(LOG_WARNING, link,
97578344 1014 "MESSAGE=%-*s: could not bring up interface: %s",
987efa17 1015 IFNAMSIZ,
c9ccc19f
TG
1016 link->ifname, strerror(-r),
1017 "ERRNO=%d", -r,
1018 NULL);
45ad2c13
TG
1019 }
1020
f882c247
TG
1021 return 1;
1022}
1023
1024static int link_up(Link *link) {
cf6a8911 1025 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
f579559b
TG
1026 int r;
1027
f882c247
TG
1028 assert(link);
1029 assert(link->manager);
1030 assert(link->manager->rtnl);
1031
39032b87 1032 log_debug_link(link, "bringing link up");
449f7554 1033
151b9b96
LP
1034 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1035 RTM_SETLINK, link->ifindex);
f579559b 1036 if (r < 0) {
39032b87 1037 log_error_link(link, "Could not allocate RTM_SETLINK message");
f579559b
TG
1038 return r;
1039 }
1040
5d4795f3 1041 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
fc25d7f8 1042 if (r < 0) {
3c9b8860
TG
1043 log_error_link(link, "Could not set link flags: %s",
1044 strerror(-r));
fc25d7f8
TG
1045 return r;
1046 }
1047
3c9b8860
TG
1048 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link,
1049 0, NULL);
f579559b 1050 if (r < 0) {
3333d748 1051 log_error_link(link,
3c9b8860
TG
1052 "Could not send rtnetlink message: %s",
1053 strerror(-r));
f579559b
TG
1054 return r;
1055 }
1056
b226d99b
TG
1057 link_ref(link);
1058
f882c247
TG
1059 return 0;
1060}
1061
3f265037 1062static int link_joined(Link *link) {
f882c247
TG
1063 int r;
1064
ef1ba606 1065 assert(link);
f5be5601 1066 assert(link->network);
dd3efc09 1067
505f8da7
TG
1068 if (!(link->flags & IFF_UP)) {
1069 r = link_up(link);
1070 if (r < 0) {
1071 link_enter_failed(link);
1072 return r;
1073 }
ef1ba606 1074 }
f882c247 1075
fb6730c4 1076 return link_enter_set_addresses(link);
02b59d57
TG
1077}
1078
3c9b8860
TG
1079static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
1080 void *userdata) {
5da8149f 1081 _cleanup_link_unref_ Link *link = userdata;
02b59d57
TG
1082 int r;
1083
1746cf2a 1084 assert(link);
ef1ba606 1085 assert(link->network);
02b59d57 1086
52433f6b
TG
1087 link->enslaving --;
1088
5da8149f 1089 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
02b59d57
TG
1090 return 1;
1091
1092 r = sd_rtnl_message_get_errno(m);
856f962c 1093 if (r < 0 && r != -EEXIST) {
c9ccc19f 1094 log_struct_link(LOG_ERR, link,
3f265037 1095 "MESSAGE=%-*s: could not join netdev: %s",
987efa17 1096 IFNAMSIZ,
c9ccc19f
TG
1097 link->ifname, strerror(-r),
1098 "ERRNO=%d", -r,
1099 NULL);
ef1ba606
TG
1100 link_enter_failed(link);
1101 return 1;
ba179154
TG
1102 } else
1103 log_debug_link(link, "joined netdev");
02b59d57 1104
856f962c 1105 if (link->enslaving <= 0)
3f265037 1106 link_joined(link);
02b59d57
TG
1107
1108 return 1;
1109}
1110
3f265037 1111static int link_enter_join_netdev(Link *link) {
6a0a2f86 1112 NetDev *netdev;
672682a6 1113 Iterator i;
02b59d57
TG
1114 int r;
1115
1116 assert(link);
1117 assert(link->network);
8434fd5c 1118 assert(link->state == LINK_STATE_PENDING);
02b59d57 1119
52433f6b 1120 link->state = LINK_STATE_ENSLAVING;
02b59d57 1121
fe8db0c5
TG
1122 link_save(link);
1123
7951dea2
SS
1124 if (!link->network->bridge &&
1125 !link->network->bond &&
6a0a2f86 1126 hashmap_isempty(link->network->stacked_netdevs))
3f265037 1127 return link_joined(link);
02b59d57 1128
d9c67ea1 1129 if (link->network->bond) {
52433f6b 1130 log_struct_link(LOG_DEBUG, link,
97578344 1131 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1132 IFNAMSIZ,
af4e9e2c 1133 link->ifname, link->network->bond->ifname,
aa9f1140 1134 NETDEVIF(link->network->bond),
52433f6b 1135 NULL);
449f7554 1136
3f265037 1137 r = netdev_join(link->network->bond, link, &netdev_join_handler);
52433f6b
TG
1138 if (r < 0) {
1139 log_struct_link(LOG_WARNING, link,
3f265037 1140 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1141 IFNAMSIZ,
3c9b8860
TG
1142 link->ifname, link->network->bond->ifname,
1143 strerror(-r),
aa9f1140 1144 NETDEVIF(link->network->bond),
52433f6b
TG
1145 NULL);
1146 link_enter_failed(link);
1147 return r;
1148 }
1149
0ad6148e
MO
1150 link->enslaving ++;
1151 }
1152
d9c67ea1 1153 if (link->network->bridge) {
0ad6148e 1154 log_struct_link(LOG_DEBUG, link,
97578344 1155 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1156 IFNAMSIZ,
af4e9e2c 1157 link->ifname, link->network->bridge->ifname,
aa9f1140 1158 NETDEVIF(link->network->bridge),
0ad6148e
MO
1159 NULL);
1160
3c9b8860
TG
1161 r = netdev_join(link->network->bridge, link,
1162 &netdev_join_handler);
0ad6148e
MO
1163 if (r < 0) {
1164 log_struct_link(LOG_WARNING, link,
3f265037 1165 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1166 IFNAMSIZ,
3c9b8860
TG
1167 link->ifname, link->network->bridge->ifname,
1168 strerror(-r),
aa9f1140 1169 NETDEVIF(link->network->bridge),
0ad6148e
MO
1170 NULL);
1171 link_enter_failed(link);
1172 return r;
1173 }
1174
52433f6b
TG
1175 link->enslaving ++;
1176 }
1177
6a0a2f86 1178 HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
7951dea2 1179 log_struct_link(LOG_DEBUG, link,
97578344 1180 "MESSAGE=%-*s: enslaving by '%s'",
987efa17 1181 IFNAMSIZ,
3c9b8860
TG
1182 link->ifname, netdev->ifname, NETDEVIF(netdev),
1183 NULL);
7951dea2 1184
6a0a2f86 1185 r = netdev_join(netdev, link, &netdev_join_handler);
7951dea2
SS
1186 if (r < 0) {
1187 log_struct_link(LOG_WARNING, link,
3f265037 1188 "MESSAGE=%-*s: could not join netdev '%s': %s",
987efa17 1189 IFNAMSIZ,
3c9b8860
TG
1190 link->ifname, netdev->ifname,
1191 strerror(-r),
6a0a2f86 1192 NETDEVIF(netdev), NULL);
326cb406
SS
1193 link_enter_failed(link);
1194 return r;
1195 }
1196
326cb406
SS
1197 link->enslaving ++;
1198 }
1199
ef1ba606
TG
1200 return 0;
1201}
1202
a748b692 1203static int link_configure(Link *link) {
02b59d57
TG
1204 int r;
1205
ef1ba606 1206 assert(link);
b22d8a00 1207 assert(link->network);
8434fd5c 1208 assert(link->state == LINK_STATE_PENDING);
a748b692 1209
78c958f8 1210 if (link_ipv4ll_enabled(link)) {
b22d8a00 1211 r = ipv4ll_configure(link);
eb34d4af
TG
1212 if (r < 0)
1213 return r;
1214 }
1215
78c958f8 1216 if (link_dhcp4_enabled(link)) {
3c9b8860 1217 r = dhcp4_configure(link);
eb34d4af
TG
1218 if (r < 0)
1219 return r;
eb34d4af
TG
1220 }
1221
78c958f8 1222 if (link_dhcp4_server_enabled(link)) {
dd43110f
TG
1223 r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
1224 if (r < 0)
1225 return r;
1226
1227 r = sd_dhcp_server_attach_event(link->dhcp_server, NULL, 0);
1228 if (r < 0)
1229 return r;
dd43110f
TG
1230 }
1231
78c958f8 1232 if (link_dhcp6_enabled(link)) {
4138fb2c
PF
1233 r = sd_icmp6_nd_new(&link->icmp6_router_discovery);
1234 if (r < 0)
1235 return r;
1236
1237 r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery,
1238 NULL, 0);
1239 if (r < 0)
1240 return r;
1241
1242 r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery,
1243 &link->mac);
1244 if (r < 0)
1245 return r;
1246
1247 r = sd_icmp6_nd_set_index(link->icmp6_router_discovery,
1248 link->ifindex);
1249 if (r < 0)
1250 return r;
1251
1252 r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery,
1253 icmp6_router_handler, link);
1254 if (r < 0)
1255 return r;
1256 }
1257
a61bb41c 1258 if (link_has_carrier(link)) {
1e9be60b
TG
1259 r = link_acquire_conf(link);
1260 if (r < 0)
1261 return r;
cc544d5f 1262 }
1e9be60b 1263
3f265037 1264 return link_enter_join_netdev(link);
505f8da7
TG
1265}
1266
3c9b8860
TG
1267static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m,
1268 void *userdata) {
5da8149f 1269 _cleanup_link_unref_ Link *link = userdata;
505f8da7 1270 Network *network;
505f8da7
TG
1271 int r;
1272
1273 assert(link);
1274 assert(link->ifname);
1275 assert(link->manager);
1276
8434fd5c 1277 if (link->state != LINK_STATE_PENDING)
5da8149f 1278 return 1;
505f8da7 1279
4f561e8e 1280 log_debug_link(link, "link state is up-to-date");
505f8da7 1281
3c9b8860
TG
1282 r = network_get(link->manager, link->udev_device, link->ifname,
1283 &link->mac, &network);
57bd6899
TG
1284 if (r == -ENOENT) {
1285 link_enter_unmanaged(link);
5da8149f 1286 return 1;
57bd6899
TG
1287 } else if (r < 0)
1288 return r;
505f8da7 1289
bd2efe92 1290 if (link->flags & IFF_LOOPBACK) {
78c958f8
TG
1291 if (network->ipv4ll)
1292 log_debug_link(link, "ignoring IPv4LL for loopback link");
1293
1294 if (network->dhcp != DHCP_SUPPORT_NONE)
1295 log_debug_link(link, "ignoring DHCP clients for loopback link");
1296
1297 if (network->dhcp_server)
1298 log_debug_link(link, "ignoring DHCP server for loopback link");
bd2efe92
TG
1299 }
1300
505f8da7
TG
1301 r = network_apply(link->manager, network, link);
1302 if (r < 0)
1303 return r;
1304
a748b692
TG
1305 r = link_configure(link);
1306 if (r < 0)
1307 return r;
1308
5da8149f 1309 return 1;
505f8da7
TG
1310}
1311
4f561e8e
TG
1312int link_initialized(Link *link, struct udev_device *device) {
1313 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
1314 int r;
1315
1316 assert(link);
1317 assert(link->manager);
1318 assert(link->manager->rtnl);
1319 assert(device);
1320
8434fd5c 1321 if (link->state != LINK_STATE_PENDING)
4f561e8e
TG
1322 return 0;
1323
679b3605
TG
1324 if (link->udev_device)
1325 return 0;
1326
4f561e8e
TG
1327 log_debug_link(link, "udev initialized link");
1328
1329 link->udev_device = udev_device_ref(device);
1330
3c9b8860
TG
1331 /* udev has initialized the link, but we don't know if we have yet
1332 * processed the NEWLINK messages with the latest state. Do a GETLINK,
1333 * when it returns we know that the pending NEWLINKs have already been
1334 * processed and that we are up-to-date */
4f561e8e 1335
3c9b8860
TG
1336 r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK,
1337 link->ifindex);
4f561e8e
TG
1338 if (r < 0)
1339 return r;
1340
3c9b8860
TG
1341 r = sd_rtnl_call_async(link->manager->rtnl, req,
1342 link_initialized_and_synced, link, 0, NULL);
4f561e8e
TG
1343 if (r < 0)
1344 return r;
1345
5da8149f
TG
1346 link_ref(link);
1347
4f561e8e
TG
1348 return 0;
1349}
1350
3c9b8860
TG
1351int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message,
1352 void *userdata) {
fbbeb65a
TG
1353 Manager *m = userdata;
1354 Link *link = NULL;
1355 uint16_t type;
1356 _cleanup_address_free_ Address *address = NULL;
428fd0a7 1357 Address *ad;
fbbeb65a 1358 char buf[INET6_ADDRSTRLEN];
c6d3b303
TG
1359 char valid_buf[FORMAT_TIMESPAN_MAX];
1360 const char *valid_str = NULL;
428fd0a7 1361 bool address_dropped = false;
fbbeb65a
TG
1362 int r, ifindex;
1363
1364 assert(rtnl);
1365 assert(message);
1366 assert(m);
1367
1368 r = sd_rtnl_message_get_type(message, &type);
1369 if (r < 0) {
1370 log_warning("rtnl: could not get message type");
1371 return 0;
1372 }
1373
1374 r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
1375 if (r < 0 || ifindex <= 0) {
5ea846cc 1376 log_warning("rtnl: received address message without valid ifindex, ignoring");
fbbeb65a
TG
1377 return 0;
1378 } else {
1379 r = link_get(m, ifindex, &link);
1380 if (r < 0 || !link) {
a821cbb0 1381 log_warning("rtnl: received address for a nonexistent link (%d), ignoring", ifindex);
fbbeb65a
TG
1382 return 0;
1383 }
1384 }
1385
1386 r = address_new_dynamic(&address);
1387 if (r < 0)
393c0c5e 1388 return r;
fbbeb65a
TG
1389
1390 r = sd_rtnl_message_addr_get_family(message, &address->family);
1391 if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
3c9b8860
TG
1392 log_warning_link(link,
1393 "rtnl: received address with invalid family, ignoring");
fbbeb65a
TG
1394 return 0;
1395 }
1396
1397 r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
1398 if (r < 0) {
3c9b8860
TG
1399 log_warning_link(link,
1400 "rtnl: received address with invalid prefixlen, ignoring");
e375dcde
TG
1401 return 0;
1402 }
1403
1404 r = sd_rtnl_message_addr_get_scope(message, &address->scope);
1405 if (r < 0) {
3c9b8860
TG
1406 log_warning_link(link,
1407 "rtnl: received address with invalid scope, ignoring");
fbbeb65a
TG
1408 return 0;
1409 }
1410
81163121
TG
1411 r = sd_rtnl_message_addr_get_flags(message, &address->flags);
1412 if (r < 0) {
1413 log_warning_link(link,
1414 "rtnl: received address with invalid flags, ignoring");
1415 return 0;
1416 }
1417
fbbeb65a
TG
1418 switch (address->family) {
1419 case AF_INET:
3c9b8860
TG
1420 r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL,
1421 &address->in_addr.in);
fbbeb65a 1422 if (r < 0) {
3c9b8860
TG
1423 log_warning_link(link,
1424 "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
1425 return 0;
1426 }
1427
1428 break;
1429
1430 case AF_INET6:
3c9b8860
TG
1431 r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS,
1432 &address->in_addr.in6);
fbbeb65a 1433 if (r < 0) {
3c9b8860
TG
1434 log_warning_link(link,
1435 "rtnl: received address without valid address, ignoring");
fbbeb65a
TG
1436 return 0;
1437 }
1438
1439 break;
1440
1441 default:
1442 assert_not_reached("invalid address family");
1443 }
1444
3c9b8860
TG
1445 if (!inet_ntop(address->family, &address->in_addr, buf,
1446 INET6_ADDRSTRLEN)) {
987efa17 1447 log_warning_link(link, "could not print address");
fbbeb65a
TG
1448 return 0;
1449 }
1450
c6d3b303
TG
1451 r = sd_rtnl_message_read_cache_info(message, IFA_CACHEINFO,
1452 &address->cinfo);
1453 if (r >= 0) {
1454 if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
1455 valid_str = "ever";
1456 else
1457 valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
1458 address->cinfo.ifa_valid * USEC_PER_SEC,
1459 USEC_PER_SEC);
1460 }
1461
428fd0a7
TG
1462 LIST_FOREACH(addresses, ad, link->addresses) {
1463 if (address_equal(ad, address)) {
1464 LIST_REMOVE(addresses, link->addresses, ad);
1465
1466 address_free(ad);
1467
1468 address_dropped = true;
1469
1470 break;
1471 }
1472 }
1473
fbbeb65a
TG
1474 switch (type) {
1475 case RTM_NEWADDR:
428fd0a7 1476 if (!address_dropped)
c6d3b303 1477 log_debug_link(link, "added address: %s/%u (valid for %s)",
b1d6dcf5 1478 buf, address->prefixlen, valid_str);
393c0c5e 1479 else
c6d3b303 1480 log_debug_link(link, "updated address: %s/%u (valid for %s)",
b1d6dcf5 1481 buf, address->prefixlen, valid_str);
fbbeb65a 1482
428fd0a7
TG
1483 LIST_PREPEND(addresses, link->addresses, address);
1484 address = NULL;
1485
f5602be9
TG
1486 link_save(link);
1487
428fd0a7 1488 break;
fbbeb65a 1489 case RTM_DELADDR:
f5602be9 1490 if (address_dropped) {
c6d3b303 1491 log_debug_link(link, "removed address: %s/%u (valid for %s)",
b1d6dcf5 1492 buf, address->prefixlen, valid_str);
428fd0a7 1493
f5602be9 1494 link_save(link);
393c0c5e 1495 } else
3c9b8860 1496 log_warning_link(link,
c6d3b303 1497 "removing non-existent address: %s/%u (valid for %s)",
b1d6dcf5 1498 buf, address->prefixlen, valid_str);
f5602be9 1499
fbbeb65a
TG
1500 break;
1501 default:
1502 assert_not_reached("Received invalid RTNL message type");
1503 }
1504
1505 return 1;
1506}
1507
505f8da7
TG
1508int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
1509 Link *link;
fbbeb65a 1510 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
505f8da7
TG
1511 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
1512 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
1513 int r;
1514
1515 assert(m);
fbbeb65a 1516 assert(m->rtnl);
505f8da7
TG
1517 assert(message);
1518 assert(ret);
1519
1520 r = link_new(m, message, ret);
1521 if (r < 0)
1522 return r;
1523
1524 link = *ret;
1525
ae06ab10 1526 log_debug_link(link, "link %d added", link->ifindex);
505f8da7 1527
3c9b8860
TG
1528 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex,
1529 0);
fbbeb65a
TG
1530 if (r < 0)
1531 return r;
1532
3c9b8860
TG
1533 r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0,
1534 NULL);
fbbeb65a
TG
1535 if (r < 0)
1536 return r;
1537
5da8149f
TG
1538 link_ref(link);
1539
505f8da7
TG
1540 if (detect_container(NULL) <= 0) {
1541 /* not in a container, udev will be around */
ae06ab10 1542 sprintf(ifindex_str, "n%d", link->ifindex);
505f8da7
TG
1543 device = udev_device_new_from_device_id(m->udev, ifindex_str);
1544 if (!device) {
3c9b8860
TG
1545 log_warning_link(link,
1546 "could not find udev device: %m");
9fecce80 1547 return -errno;
505f8da7
TG
1548 }
1549
3c4cb064 1550 if (udev_device_get_is_initialized(device) <= 0) {
505f8da7 1551 /* not yet ready */
8434fd5c 1552 log_debug_link(link, "link pending udev initialization...");
505f8da7 1553 return 0;
3c4cb064 1554 }
505f8da7 1555
4f561e8e
TG
1556 r = link_initialized(link, device);
1557 if (r < 0)
1558 return r;
1559 } else {
5da8149f
TG
1560 /* we are calling a callback directly, so must take a ref */
1561 link_ref(link);
1562
4f561e8e
TG
1563 r = link_initialized_and_synced(m->rtnl, NULL, link);
1564 if (r < 0)
1565 return r;
1566 }
505f8da7 1567
a748b692
TG
1568 return 0;
1569}
1570
22936833 1571int link_update(Link *link, sd_rtnl_message *m) {
c49b33ac 1572 struct ether_addr mac;
ca4e095a 1573 const char *ifname;
afe7fd56 1574 uint32_t mtu;
a61bb41c 1575 bool had_carrier, carrier_gained, carrier_lost;
22936833
TG
1576 int r;
1577
dd3efc09 1578 assert(link);
b8941f74 1579 assert(link->ifname);
22936833
TG
1580 assert(m);
1581
7619683b
TG
1582 if (link->state == LINK_STATE_LINGER) {
1583 link_ref(link);
1584 log_info_link(link, "link readded");
1585 link->state = LINK_STATE_ENSLAVING;
1586 }
1587
b8941f74
TG
1588 r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
1589 if (r >= 0 && !streq(ifname, link->ifname)) {
1590 log_info_link(link, "renamed to %s", ifname);
1591
1592 free(link->ifname);
1593 link->ifname = strdup(ifname);
1594 if (!link->ifname)
1595 return -ENOMEM;
1596 }
1597
afe7fd56
TG
1598 r = sd_rtnl_message_read_u32(m, IFLA_MTU, &mtu);
1599 if (r >= 0 && mtu > 0) {
1600 link->mtu = mtu;
1601 if (!link->original_mtu) {
1602 link->original_mtu = mtu;
9842de0d 1603 log_debug_link(link, "saved original MTU: %"
afe7fd56
TG
1604 PRIu32, link->original_mtu);
1605 }
1606
1607 if (link->dhcp_client) {
3c9b8860
TG
1608 r = sd_dhcp_client_set_mtu(link->dhcp_client,
1609 link->mtu);
afe7fd56 1610 if (r < 0) {
3c9b8860
TG
1611 log_warning_link(link,
1612 "Could not update MTU in DHCP client: %s",
afe7fd56
TG
1613 strerror(-r));
1614 return r;
1615 }
1616 }
9842de0d 1617 }
69629de9 1618
e9189a1f
TG
1619 /* The kernel may broadcast NEWLINK messages without the MAC address
1620 set, simply ignore them. */
c49b33ac 1621 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
e9189a1f 1622 if (r >= 0) {
3c9b8860
TG
1623 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet,
1624 ETH_ALEN)) {
c49b33ac 1625
3c9b8860
TG
1626 memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet,
1627 ETH_ALEN);
c49b33ac 1628
20861203
TG
1629 log_debug_link(link, "MAC address: "
1630 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1631 mac.ether_addr_octet[0],
1632 mac.ether_addr_octet[1],
1633 mac.ether_addr_octet[2],
1634 mac.ether_addr_octet[3],
1635 mac.ether_addr_octet[4],
1636 mac.ether_addr_octet[5]);
c49b33ac 1637
20861203
TG
1638 if (link->ipv4ll) {
1639 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1640 if (r < 0) {
3c9b8860
TG
1641 log_warning_link(link,
1642 "Could not update MAC address in IPv4LL client: %s",
20861203
TG
1643 strerror(-r));
1644 return r;
1645 }
c49b33ac 1646 }
c49b33ac 1647
20861203 1648 if (link->dhcp_client) {
3c9b8860
TG
1649 r = sd_dhcp_client_set_mac(link->dhcp_client,
1650 &link->mac);
20861203 1651 if (r < 0) {
3c9b8860
TG
1652 log_warning_link(link,
1653 "Could not update MAC address in DHCP client: %s",
20861203
TG
1654 strerror(-r));
1655 return r;
1656 }
c49b33ac 1657 }
4138fb2c
PF
1658
1659 if (link->dhcp6_client) {
1660 r = sd_dhcp6_client_set_mac(link->dhcp6_client,
1661 &link->mac);
1662 if (r < 0) {
3c9b8860
TG
1663 log_warning_link(link,
1664 "Could not update MAC address in DHCPv6 client: %s",
4138fb2c
PF
1665 strerror(-r));
1666 return r;
1667 }
1668 }
c49b33ac 1669 }
4f882b2a
TG
1670 }
1671
a61bb41c
TG
1672 had_carrier = link_has_carrier(link);
1673
1674 r = link_update_flags(link, m);
1675 if (r < 0)
1676 return r;
1677
1678 carrier_gained = !had_carrier && link_has_carrier(link);
1679 carrier_lost = had_carrier && !link_has_carrier(link);
1680
1681 if (carrier_gained) {
1682 log_info_link(link, "gained carrier");
1683
1684 if (link->network) {
1685 r = link_acquire_conf(link);
1686 if (r < 0) {
1687 link_enter_failed(link);
1688 return r;
1689 }
1690 }
1691 } else if (carrier_lost) {
1692 log_info_link(link, "lost carrier");
1693
1694 r = link_stop_clients(link);
1695 if (r < 0) {
1696 link_enter_failed(link);
1697 return r;
1698 }
1699 }
1700
1701 return 0;
dd3efc09 1702}
fe8db0c5 1703
e375dcde
TG
1704static void link_update_operstate(Link *link) {
1705
1706 assert(link);
1707
1708 if (link->kernel_operstate == IF_OPER_DORMANT)
1709 link->operstate = LINK_OPERSTATE_DORMANT;
a61bb41c 1710 else if (link_has_carrier(link)) {
e375dcde
TG
1711 Address *address;
1712 uint8_t scope = RT_SCOPE_NOWHERE;
1713
1714 /* if we have carrier, check what addresses we have */
1715 LIST_FOREACH(addresses, address, link->addresses) {
81163121
TG
1716 if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
1717 continue;
1718
e375dcde
TG
1719 if (address->scope < scope)
1720 scope = address->scope;
1721 }
1722
1723 if (scope < RT_SCOPE_SITE)
1724 /* universally accessible addresses found */
1725 link->operstate = LINK_OPERSTATE_ROUTABLE;
1726 else if (scope < RT_SCOPE_HOST)
1727 /* only link or site local addresses found */
1728 link->operstate = LINK_OPERSTATE_DEGRADED;
1729 else
1730 /* no useful addresses found */
1731 link->operstate = LINK_OPERSTATE_CARRIER;
54cba0b1 1732 } else if (link->flags & IFF_UP)
d3df0e39 1733 link->operstate = LINK_OPERSTATE_NO_CARRIER;
54cba0b1 1734 else
d3df0e39 1735 link->operstate = LINK_OPERSTATE_OFF;
e375dcde
TG
1736}
1737
fe8db0c5 1738int link_save(Link *link) {
68a8723c 1739 _cleanup_free_ char *temp_path = NULL;
fe8db0c5 1740 _cleanup_fclose_ FILE *f = NULL;
e375dcde 1741 const char *admin_state, *oper_state;
fe8db0c5
TG
1742 int r;
1743
1744 assert(link);
1745 assert(link->state_file);
68a8723c 1746 assert(link->lease_file);
bbf7c048
TG
1747 assert(link->manager);
1748
e375dcde
TG
1749 link_update_operstate(link);
1750
bbf7c048
TG
1751 r = manager_save(link->manager);
1752 if (r < 0)
1753 return r;
fe8db0c5 1754
370e9930
TG
1755 if (link->state == LINK_STATE_LINGER) {
1756 unlink(link->state_file);
1757 return 0;
1758 }
1759
deb2e523
TG
1760 admin_state = link_state_to_string(link->state);
1761 assert(admin_state);
1762
e375dcde
TG
1763 oper_state = link_operstate_to_string(link->operstate);
1764 assert(oper_state);
deb2e523 1765
fe8db0c5
TG
1766 r = fopen_temporary(link->state_file, &f, &temp_path);
1767 if (r < 0)
c2d6bd61 1768 return r;
fe8db0c5
TG
1769
1770 fchmod(fileno(f), 0644);
1771
1772 fprintf(f,
1773 "# This is private data. Do not parse.\n"
deb2e523 1774 "ADMIN_STATE=%s\n"
6dcaa6f5
TG
1775 "OPER_STATE=%s\n",
1776 admin_state, oper_state);
fe8db0c5 1777
bcb7a07e 1778 if (link->network) {
ea352b40
LP
1779 char **address, **domain;
1780 bool space;
b0e39c82 1781
adc5b2e2
TG
1782 fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
1783
b0e39c82 1784 fputs("DNS=", f);
ea352b40
LP
1785 space = false;
1786 STRV_FOREACH(address, link->network->dns) {
1787 if (space)
1788 fputc(' ', f);
1789 fputs(*address, f);
1790 space = true;
1791 }
d5314fff 1792
b0e39c82
TG
1793 if (link->network->dhcp_dns &&
1794 link->dhcp_lease) {
1795 const struct in_addr *addresses;
1796
1797 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
1798 if (r > 0) {
ea352b40
LP
1799 if (space)
1800 fputc(' ', f);
b0e39c82 1801 serialize_in_addrs(f, addresses, r);
b0e39c82
TG
1802 }
1803 }
1804
b0e39c82
TG
1805 fputs("\n", f);
1806
1807 fprintf(f, "NTP=");
ea352b40
LP
1808 space = false;
1809 STRV_FOREACH(address, link->network->ntp) {
1810 if (space)
1811 fputc(' ', f);
1812 fputs(*address, f);
1813 space = true;
1814 }
d5314fff 1815
b0e39c82
TG
1816 if (link->network->dhcp_ntp &&
1817 link->dhcp_lease) {
1818 const struct in_addr *addresses;
1819
1820 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
1821 if (r > 0) {
ea352b40
LP
1822 if (space)
1823 fputc(' ', f);
b0e39c82 1824 serialize_in_addrs(f, addresses, r);
b0e39c82
TG
1825 }
1826 }
1827
b0e39c82 1828 fputs("\n", f);
bd8f6538 1829
6192b846 1830 fprintf(f, "DOMAINS=");
ea352b40
LP
1831 space = false;
1832 STRV_FOREACH(domain, link->network->domains) {
1833 if (space)
1834 fputc(' ', f);
1835 fputs(*domain, f);
1836 space = true;
1837 }
d5314fff 1838
ad0734e8 1839 if (link->network->dhcp_domains &&
9b4d1882
TG
1840 link->dhcp_lease) {
1841 const char *domainname;
1842
1843 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
6192b846 1844 if (r >= 0) {
ea352b40
LP
1845 if (space)
1846 fputc(' ', f);
6192b846 1847 fputs(domainname, f);
6192b846 1848 }
9b4d1882
TG
1849 }
1850
6192b846
TG
1851 fputs("\n", f);
1852
67272d15
TG
1853 fprintf(f, "WILDCARD_DOMAIN=%s\n",
1854 yes_no(link->network->wildcard_domain));
1855
3c9b8860
TG
1856 fprintf(f, "LLMNR=%s\n",
1857 llmnr_support_to_string(link->network->llmnr));
bcb7a07e 1858 }
7374f9d8 1859
fe8db0c5 1860 if (link->dhcp_lease) {
d9876a52
TG
1861 assert(link->network);
1862
68a8723c 1863 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
fe8db0c5 1864 if (r < 0)
c2d6bd61 1865 goto fail;
fe8db0c5 1866
7374f9d8 1867 fprintf(f,
b0e39c82
TG
1868 "DHCP_LEASE=%s\n",
1869 link->lease_file);
deb2e523 1870 } else
68a8723c 1871 unlink(link->lease_file);
fe8db0c5 1872
c2d6bd61
LP
1873 r = fflush_and_check(f);
1874 if (r < 0)
1875 goto fail;
fe8db0c5 1876
c2d6bd61 1877 if (rename(temp_path, link->state_file) < 0) {
fe8db0c5 1878 r = -errno;
c2d6bd61 1879 goto fail;
fe8db0c5
TG
1880 }
1881
c2d6bd61 1882 return 0;
c2d6bd61
LP
1883fail:
1884 log_error_link(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
1885 unlink(link->state_file);
1886 unlink(temp_path);
fe8db0c5
TG
1887 return r;
1888}
1889
1890static const char* const link_state_table[_LINK_STATE_MAX] = {
8434fd5c 1891 [LINK_STATE_PENDING] = "pending",
fe8db0c5
TG
1892 [LINK_STATE_ENSLAVING] = "configuring",
1893 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
1894 [LINK_STATE_SETTING_ROUTES] = "configuring",
1895 [LINK_STATE_CONFIGURED] = "configured",
57bd6899 1896 [LINK_STATE_UNMANAGED] = "unmanaged",
fe8db0c5 1897 [LINK_STATE_FAILED] = "failed",
370e9930 1898 [LINK_STATE_LINGER] = "linger",
fe8db0c5
TG
1899};
1900
1901DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
e375dcde
TG
1902
1903static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
d3df0e39
TG
1904 [LINK_OPERSTATE_OFF] = "off",
1905 [LINK_OPERSTATE_NO_CARRIER] = "no-carrier",
e375dcde
TG
1906 [LINK_OPERSTATE_DORMANT] = "dormant",
1907 [LINK_OPERSTATE_CARRIER] = "carrier",
1908 [LINK_OPERSTATE_DEGRADED] = "degraded",
1909 [LINK_OPERSTATE_ROUTABLE] = "routable",
1910};
1911
1912DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);