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