1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <netinet/ether.h>
26 #include "libudev-private.h"
27 #include "udev-util.h"
31 #include "network-internal.h"
33 #include "network-util.h"
34 #include "dhcp-lease-internal.h"
36 static int ipv4ll_address_update(Link *link, bool deprecate);
37 static bool ipv4ll_is_bound(sd_ipv4ll *ll);
39 static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
40 _cleanup_link_unref_ Link *link = NULL;
46 assert(manager->links);
50 r = sd_rtnl_message_get_type(message, &type);
53 else if (type != RTM_NEWLINK)
56 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
59 else if (ifindex <= 0)
62 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
71 link->manager = manager;
72 link->state = LINK_STATE_INITIALIZING;
73 link->ifindex = ifindex;
74 link->ifname = strdup(ifname);
78 r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
82 r = asprintf(&link->state_file, "/run/systemd/netif/links/%"PRIu64,
87 r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%"PRIu64,
92 r = hashmap_put(manager->links, &link->ifindex, link);
102 static void link_free(Link *link) {
108 assert(link->manager);
110 while ((address = link->addresses)) {
111 LIST_REMOVE(addresses, link->addresses, address);
112 address_free(address);
115 sd_dhcp_client_unref(link->dhcp_client);
116 sd_dhcp_lease_unref(link->dhcp_lease);
118 unlink(link->lease_file);
119 free(link->lease_file);
121 sd_ipv4ll_unref(link->ipv4ll);
123 hashmap_remove(link->manager->links, &link->ifindex);
127 unlink(link->state_file);
128 free(link->state_file);
130 udev_device_unref(link->udev_device);
135 Link *link_unref(Link *link) {
136 if (link && (-- link->n_ref <= 0))
142 Link *link_ref(Link *link) {
144 assert_se(++ link->n_ref >= 2);
149 int link_get(Manager *m, int ifindex, Link **ret) {
158 ifindex_64 = ifindex;
159 link = hashmap_get(m->links, &ifindex_64);
168 void link_drop(Link *link) {
169 if (!link || link->state == LINK_STATE_LINGER)
172 link->state = LINK_STATE_LINGER;
174 log_debug_link(link, "link removed");
181 static int link_enter_configured(Link *link) {
183 assert(link->state == LINK_STATE_SETTING_ROUTES);
185 log_info_link(link, "link configured");
187 link->state = LINK_STATE_CONFIGURED;
194 static void link_enter_unmanaged(Link *link) {
197 log_debug_link(link, "unmanaged");
199 link->state = LINK_STATE_UNMANAGED;
204 static int link_stop_clients(Link *link) {
208 assert(link->manager);
209 assert(link->manager->event);
214 if (link->network->dhcp) {
215 assert(link->dhcp_client);
217 k = sd_dhcp_client_stop(link->dhcp_client);
219 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
224 if (link->network->ipv4ll) {
225 assert(link->ipv4ll);
227 k = sd_ipv4ll_stop(link->ipv4ll);
229 log_warning_link(link, "Could not stop IPv4 link-local: %s", strerror(-r));
237 static void link_enter_failed(Link *link) {
240 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
243 log_warning_link(link, "failed");
245 link->state = LINK_STATE_FAILED;
247 link_stop_clients(link);
252 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
253 Link *link = userdata;
256 assert(link->route_messages > 0);
257 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
258 LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
261 link->route_messages --;
263 if (IN_SET(LINK_STATE_FAILED, LINK_STATE_LINGER)) {
268 r = sd_rtnl_message_get_errno(m);
269 if (r < 0 && r != -EEXIST)
270 log_struct_link(LOG_WARNING, link,
271 "MESSAGE=%*s: could not set route: %s",
273 link->ifname, strerror(-r),
277 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
279 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
280 log_debug_link(link, "routes set");
281 link_enter_configured(link);
289 static int link_enter_set_routes(Link *link) {
294 assert(link->network);
295 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
297 link->state = LINK_STATE_SETTING_ROUTES;
299 if (!link->network->static_routes && !link->dhcp_lease &&
300 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
301 return link_enter_configured(link);
303 log_debug_link(link, "setting routes");
305 LIST_FOREACH(routes, rt, link->network->static_routes) {
306 r = route_configure(rt, link, &route_handler);
308 log_warning_link(link,
309 "could not set routes: %s", strerror(-r));
310 link_enter_failed(link);
315 link->route_messages ++;
318 if (link->ipv4ll && !link->dhcp_lease) {
319 _cleanup_route_free_ Route *route = NULL;
322 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
323 if (r < 0 && r != -ENOENT) {
324 log_warning_link(link, "IPV4LL error: no address: %s",
330 r = route_new_dynamic(&route);
332 log_error_link(link, "Could not allocate route: %s",
337 route->family = AF_INET;
338 route->scope = RT_SCOPE_LINK;
341 r = route_configure(route, link, &route_handler);
343 log_warning_link(link,
344 "could not set routes: %s", strerror(-r));
345 link_enter_failed(link);
350 link->route_messages ++;
354 if (link->dhcp_lease) {
355 _cleanup_route_free_ Route *route = NULL;
356 _cleanup_route_free_ Route *route_gw = NULL;
357 struct in_addr gateway;
359 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
360 if (r < 0 && r != -ENOENT) {
361 log_warning_link(link, "DHCP error: %s", strerror(-r));
366 r = route_new_dynamic(&route);
368 log_error_link(link, "Could not allocate route: %s",
373 r = route_new_dynamic(&route_gw);
375 log_error_link(link, "Could not allocate route: %s",
380 /* The dhcp netmask may mask out the gateway. Add an explicit
381 * route for the gw host so that we can route no matter the
382 * netmask or existing kernel route tables. */
383 route_gw->family = AF_INET;
384 route_gw->dst_addr.in = gateway;
385 route_gw->dst_prefixlen = 32;
386 route_gw->scope = RT_SCOPE_LINK;
388 r = route_configure(route_gw, link, &route_handler);
390 log_warning_link(link,
391 "could not set host route: %s", strerror(-r));
396 link->route_messages ++;
398 route->family = AF_INET;
399 route->in_addr.in = gateway;
401 r = route_configure(route, link, &route_handler);
403 log_warning_link(link,
404 "could not set routes: %s", strerror(-r));
405 link_enter_failed(link);
410 link->route_messages ++;
414 if (link->route_messages == 0) {
415 link_enter_configured(link);
421 static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
422 Link *link = userdata;
427 assert(link->ifname);
429 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
434 r = sd_rtnl_message_get_errno(m);
435 if (r < 0 && r != -ESRCH)
436 log_struct_link(LOG_WARNING, link,
437 "MESSAGE=%*s: could not drop route: %s",
439 link->ifname, strerror(-r),
448 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
449 Link *link = userdata;
454 assert(link->ifname);
455 assert(link->addr_messages > 0);
456 assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
457 LINK_STATE_FAILED, LINK_STATE_LINGER));
459 link->addr_messages --;
461 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
466 r = sd_rtnl_message_get_errno(m);
467 if (r < 0 && r != -EEXIST)
468 log_struct_link(LOG_WARNING, link,
469 "MESSAGE=%*s: could not set address: %s",
471 link->ifname, strerror(-r),
475 if (link->addr_messages == 0) {
476 log_debug_link(link, "addresses set");
477 link_enter_set_routes(link);
485 static int link_enter_set_addresses(Link *link) {
490 assert(link->network);
491 assert(link->state != _LINK_STATE_INVALID);
493 link->state = LINK_STATE_SETTING_ADDRESSES;
495 if (!link->network->static_addresses && !link->dhcp_lease &&
496 (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
497 return link_enter_set_routes(link);
499 log_debug_link(link, "setting addresses");
501 LIST_FOREACH(addresses, ad, link->network->static_addresses) {
502 r = address_configure(ad, link, &address_handler);
504 log_warning_link(link,
505 "could not set addresses: %s", strerror(-r));
506 link_enter_failed(link);
511 link->addr_messages ++;
514 if (link->ipv4ll && !link->dhcp_lease) {
515 _cleanup_address_free_ Address *ll_addr = NULL;
518 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
519 if (r < 0 && r != -ENOENT) {
520 log_warning_link(link, "IPV4LL error: no address: %s",
526 r = address_new_dynamic(&ll_addr);
528 log_error_link(link, "Could not allocate address: %s", strerror(-r));
532 ll_addr->family = AF_INET;
533 ll_addr->in_addr.in = addr;
534 ll_addr->prefixlen = 16;
535 ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
536 ll_addr->scope = RT_SCOPE_LINK;
538 r = address_configure(ll_addr, link, &address_handler);
540 log_warning_link(link,
541 "could not set addresses: %s", strerror(-r));
542 link_enter_failed(link);
547 link->addr_messages ++;
551 if (link->dhcp_lease) {
552 _cleanup_address_free_ Address *address = NULL;
554 struct in_addr netmask;
557 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
559 log_warning_link(link, "DHCP error: no address: %s",
564 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
566 log_warning_link(link, "DHCP error: no netmask: %s",
571 prefixlen = net_netmask_to_prefixlen(&netmask);
573 r = address_new_dynamic(&address);
575 log_error_link(link, "Could not allocate address: %s",
580 address->family = AF_INET;
581 address->in_addr.in = addr;
582 address->prefixlen = prefixlen;
583 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
585 r = address_configure(address, link, &address_handler);
587 log_warning_link(link,
588 "could not set addresses: %s", strerror(-r));
589 link_enter_failed(link);
594 link->addr_messages ++;
600 static int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
601 Link *link = userdata;
606 assert(link->ifname);
608 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
613 r = sd_rtnl_message_get_errno(m);
614 if (r < 0 && r != -ENOENT)
615 log_struct_link(LOG_WARNING, link,
616 "MESSAGE=%*s: could not update address: %s",
618 link->ifname, strerror(-r),
627 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
628 Link *link = userdata;
633 assert(link->ifname);
635 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
640 r = sd_rtnl_message_get_errno(m);
641 if (r < 0 && r != -EADDRNOTAVAIL)
642 log_struct_link(LOG_WARNING, link,
643 "MESSAGE=%*s: could not drop address: %s",
645 link->ifname, strerror(-r),
654 static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
655 Link *link = userdata;
660 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
665 r = sd_bus_message_get_errno(m);
667 log_warning_link(link, "Could not set hostname: %s", strerror(-r));
674 static int link_set_hostname(Link *link, const char *hostname) {
675 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
679 assert(link->manager);
682 log_debug_link(link, "Setting transient hostname: '%s'", hostname);
684 if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */
685 log_info_link(link, "Not connected to system bus, ignoring transient hostname.");
689 r = sd_bus_message_new_method_call(
692 "org.freedesktop.hostname1",
693 "/org/freedesktop/hostname1",
694 "org.freedesktop.hostname1",
699 r = sd_bus_message_append(m, "sb", hostname, false);
703 r = sd_bus_call_async(link->manager->bus, NULL, m, set_hostname_handler, link, 0);
705 log_error_link(link, "Could not set transient hostname: %s", strerror(-r));
712 static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
713 Link *link = userdata;
718 assert(link->ifname);
720 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
725 r = sd_rtnl_message_get_errno(m);
727 log_struct_link(LOG_WARNING, link,
728 "MESSAGE=%s: could not set MTU: %s",
729 link->ifname, strerror(-r),
738 static int link_set_mtu(Link *link, uint32_t mtu) {
739 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
743 assert(link->manager);
744 assert(link->manager->rtnl);
746 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
748 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
749 RTM_SETLINK, link->ifindex);
751 log_error_link(link, "Could not allocate RTM_SETLINK message");
755 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
757 log_error_link(link, "Could not append MTU: %s", strerror(-r));
761 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
764 "Could not send rtnetlink message: %s", strerror(-r));
773 static int dhcp_lease_lost(Link *link) {
774 _cleanup_address_free_ Address *address = NULL;
775 _cleanup_route_free_ Route *route_gw = NULL;
776 _cleanup_route_free_ Route *route = NULL;
778 struct in_addr netmask;
779 struct in_addr gateway;
784 assert(link->dhcp_lease);
786 log_warning_link(link, "DHCP lease lost");
788 r = address_new_dynamic(&address);
790 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
792 r = route_new_dynamic(&route_gw);
794 route_gw->family = AF_INET;
795 route_gw->dst_addr.in = gateway;
796 route_gw->dst_prefixlen = 32;
797 route_gw->scope = RT_SCOPE_LINK;
799 route_drop(route_gw, link, &route_drop_handler);
803 r = route_new_dynamic(&route);
805 route->family = AF_INET;
806 route->in_addr.in = gateway;
808 route_drop(route, link, &route_drop_handler);
813 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
814 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
815 prefixlen = net_netmask_to_prefixlen(&netmask);
817 address->family = AF_INET;
818 address->in_addr.in = addr;
819 address->prefixlen = prefixlen;
821 address_drop(address, link, &address_drop_handler);
825 if (link->network->dhcp_mtu) {
828 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
829 if (r >= 0 && link->original_mtu != mtu) {
830 r = link_set_mtu(link, link->original_mtu);
832 log_warning_link(link, "DHCP error: could not reset MTU");
833 link_enter_failed(link);
839 if (link->network->dhcp_hostname) {
840 const char *hostname = NULL;
842 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
843 if (r >= 0 && hostname) {
844 r = link_set_hostname(link, "");
846 log_error_link(link, "Failed to reset transient hostname");
850 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
855 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
856 sd_dhcp_lease *lease;
857 struct in_addr address;
858 struct in_addr netmask;
859 struct in_addr gateway;
866 r = sd_dhcp_client_get_lease(client, &lease);
868 log_warning_link(link, "DHCP error: no lease: %s",
873 r = sd_dhcp_lease_get_address(lease, &address);
875 log_warning_link(link, "DHCP error: no address: %s",
880 r = sd_dhcp_lease_get_netmask(lease, &netmask);
882 log_warning_link(link, "DHCP error: no netmask: %s",
887 prefixlen = net_netmask_to_prefixlen(&netmask);
889 r = sd_dhcp_lease_get_router(lease, &gateway);
890 if (r < 0 && r != -ENOENT) {
891 log_warning_link(link, "DHCP error: %s", strerror(-r));
896 log_struct_link(LOG_INFO, link,
897 "MESSAGE=%*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
900 ADDRESS_FMT_VAL(address),
902 ADDRESS_FMT_VAL(gateway),
903 "ADDRESS=%u.%u.%u.%u",
904 ADDRESS_FMT_VAL(address),
907 "GATEWAY=%u.%u.%u.%u",
908 ADDRESS_FMT_VAL(gateway),
911 log_struct_link(LOG_INFO, link,
912 "MESSAGE=%*s: DHCPv4 address %u.%u.%u.%u/%u",
915 ADDRESS_FMT_VAL(address),
917 "ADDRESS=%u.%u.%u.%u",
918 ADDRESS_FMT_VAL(address),
923 link->dhcp_lease = lease;
925 if (link->network->dhcp_mtu) {
928 r = sd_dhcp_lease_get_mtu(lease, &mtu);
930 r = link_set_mtu(link, mtu);
932 log_error_link(link, "Failed to set MTU "
937 if (link->network->dhcp_hostname) {
938 const char *hostname;
940 r = sd_dhcp_lease_get_hostname(lease, &hostname);
942 r = link_set_hostname(link, hostname);
944 log_error_link(link, "Failed to set transient hostname "
945 "to '%s'", hostname);
949 link_enter_set_addresses(link);
954 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
955 Link *link = userdata;
959 assert(link->network);
960 assert(link->manager);
962 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
966 case DHCP_EVENT_NO_LEASE:
967 log_debug_link(link, "IP address in use.");
969 case DHCP_EVENT_EXPIRED:
970 case DHCP_EVENT_STOP:
971 case DHCP_EVENT_IP_CHANGE:
972 if (link->network->dhcp_critical) {
973 log_error_link(link, "DHCPv4 connection considered system critical, "
974 "ignoring request to reconfigure it.");
978 if (link->dhcp_lease) {
979 r = dhcp_lease_lost(link);
981 link_enter_failed(link);
986 if (event == DHCP_EVENT_IP_CHANGE) {
987 r = dhcp_lease_acquired(client, link);
989 link_enter_failed(link);
994 if (event == DHCP_EVENT_EXPIRED && link->network->ipv4ll) {
995 if (!sd_ipv4ll_is_running(link->ipv4ll))
996 r = sd_ipv4ll_start(link->ipv4ll);
997 else if (ipv4ll_is_bound(link->ipv4ll))
998 r = ipv4ll_address_update(link, false);
1000 link_enter_failed(link);
1006 case DHCP_EVENT_IP_ACQUIRE:
1007 r = dhcp_lease_acquired(client, link);
1009 link_enter_failed(link);
1013 if (ipv4ll_is_bound(link->ipv4ll))
1014 r = ipv4ll_address_update(link, true);
1016 r = sd_ipv4ll_stop(link->ipv4ll);
1018 link_enter_failed(link);
1025 log_warning_link(link, "DHCP error: %s", strerror(-event));
1027 log_warning_link(link, "DHCP unknown event: %d", event);
1034 static int ipv4ll_address_update(Link *link, bool deprecate) {
1036 struct in_addr addr;
1040 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
1042 _cleanup_address_free_ Address *address = NULL;
1044 log_debug_link(link, "IPv4 link-local %s %u.%u.%u.%u",
1045 deprecate ? "deprecate" : "approve",
1046 ADDRESS_FMT_VAL(addr));
1048 r = address_new_dynamic(&address);
1050 log_error_link(link, "Could not allocate address: %s", strerror(-r));
1054 address->family = AF_INET;
1055 address->in_addr.in = addr;
1056 address->prefixlen = 16;
1057 address->scope = RT_SCOPE_LINK;
1058 address->cinfo.ifa_prefered = deprecate ? 0 : CACHE_INFO_INFINITY_LIFE_TIME;
1059 address->broadcast.s_addr = address->in_addr.in.s_addr | htonl(0xfffffffflu >> address->prefixlen);
1061 address_update(address, link, &address_update_handler);
1069 static int ipv4ll_address_lost(Link *link) {
1071 struct in_addr addr;
1075 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
1077 _cleanup_address_free_ Address *address = NULL;
1078 _cleanup_route_free_ Route *route = NULL;
1080 log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u",
1081 ADDRESS_FMT_VAL(addr));
1083 r = address_new_dynamic(&address);
1085 log_error_link(link, "Could not allocate address: %s", strerror(-r));
1089 address->family = AF_INET;
1090 address->in_addr.in = addr;
1091 address->prefixlen = 16;
1092 address->scope = RT_SCOPE_LINK;
1094 address_drop(address, link, &address_drop_handler);
1097 r = route_new_dynamic(&route);
1099 log_error_link(link, "Could not allocate route: %s",
1104 route->family = AF_INET;
1105 route->scope = RT_SCOPE_LINK;
1106 route->metrics = 99;
1108 route_drop(route, link, &route_drop_handler);
1115 static bool ipv4ll_is_bound(sd_ipv4ll *ll) {
1117 struct in_addr addr;
1121 r = sd_ipv4ll_get_address(ll, &addr);
1127 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
1128 struct in_addr address;
1134 r = sd_ipv4ll_get_address(ll, &address);
1138 log_struct_link(LOG_INFO, link,
1139 "MESSAGE=%*s: IPv4 link-local address %u.%u.%u.%u",
1142 ADDRESS_FMT_VAL(address),
1145 link_enter_set_addresses(link);
1150 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
1151 Link *link = userdata;
1155 assert(link->network);
1156 assert(link->manager);
1158 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1162 case IPV4LL_EVENT_STOP:
1163 case IPV4LL_EVENT_CONFLICT:
1164 r = ipv4ll_address_lost(link);
1166 link_enter_failed(link);
1170 case IPV4LL_EVENT_BIND:
1171 r = ipv4ll_address_claimed(ll, link);
1173 link_enter_failed(link);
1179 log_warning_link(link, "IPv4 link-local error: %s", strerror(-event));
1181 log_warning_link(link, "IPv4 link-local unknown event: %d", event);
1186 static int link_acquire_conf(Link *link) {
1190 assert(link->network);
1191 assert(link->manager);
1192 assert(link->manager->event);
1194 if (link->network->ipv4ll) {
1195 assert(link->ipv4ll);
1197 log_debug_link(link, "acquiring IPv4 link-local address");
1199 r = sd_ipv4ll_start(link->ipv4ll);
1201 log_warning_link(link, "could not acquire IPv4 "
1202 "link-local address");
1207 if (link->network->dhcp) {
1208 assert(link->dhcp_client);
1210 log_debug_link(link, "acquiring DHCPv4 lease");
1212 r = sd_dhcp_client_start(link->dhcp_client);
1214 log_warning_link(link, "could not acquire DHCPv4 "
1223 bool link_has_carrier(unsigned flags, uint8_t operstate) {
1224 /* see Documentation/networking/operstates.txt in the kernel sources */
1226 if (operstate == IF_OPER_UP)
1229 if (operstate == IF_OPER_UNKNOWN)
1230 /* operstate may not be implemented, so fall back to flags */
1231 if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT))
1237 #define FLAG_STRING(string, flag, old, new) \
1238 (((old ^ new) & flag) \
1239 ? ((old & flag) ? (" -" string) : (" +" string)) \
1242 static int link_update_flags(Link *link, sd_rtnl_message *m) {
1243 unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags;
1245 bool carrier_gained = false, carrier_lost = false;
1250 r = sd_rtnl_message_link_get_flags(m, &flags);
1252 log_warning_link(link, "Could not get link flags");
1256 r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate);
1258 /* if we got a message without operstate, take it to mean
1259 the state was unchanged */
1260 operstate = link->kernel_operstate;
1262 if ((link->flags == flags) && (link->kernel_operstate == operstate))
1265 if (link->flags != flags) {
1266 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",
1267 FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags),
1268 FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags),
1269 FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags),
1270 FLAG_STRING("UP", IFF_UP, link->flags, flags),
1271 FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags),
1272 FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags),
1273 FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags),
1274 FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags),
1275 FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags),
1276 FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags),
1277 FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags),
1278 FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags),
1279 FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags),
1280 FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags),
1281 FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags),
1282 FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags),
1283 FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags),
1284 FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags),
1285 FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags));
1287 unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP |
1288 IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING |
1289 IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT |
1290 IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL |
1291 IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP |
1292 IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO);
1293 unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags);
1294 unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags);
1296 /* link flags are currently at most 18 bits, let's align to printing 20 */
1297 if (unknown_flags_added)
1298 log_debug_link(link, "unknown link flags gained: %#.5x (ignoring)",
1299 unknown_flags_added);
1301 if (unknown_flags_removed)
1302 log_debug_link(link, "unknown link flags lost: %#.5x (ignoring)",
1303 unknown_flags_removed);
1306 carrier_gained = !link_has_carrier(link->flags, link->kernel_operstate) &&
1307 link_has_carrier(flags, operstate);
1308 carrier_lost = link_has_carrier(link->flags, link->kernel_operstate) &&
1309 !link_has_carrier(flags, operstate);
1311 link->flags = flags;
1312 link->kernel_operstate = operstate;
1316 if (link->state == LINK_STATE_FAILED ||
1317 link->state == LINK_STATE_UNMANAGED)
1320 if (carrier_gained) {
1321 log_info_link(link, "gained carrier");
1323 if (link->network) {
1324 r = link_acquire_conf(link);
1326 link_enter_failed(link);
1330 } else if (carrier_lost) {
1331 log_info_link(link, "lost carrier");
1333 r = link_stop_clients(link);
1335 link_enter_failed(link);
1343 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
1344 Link *link = userdata;
1349 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
1354 r = sd_rtnl_message_get_errno(m);
1356 /* we warn but don't fail the link, as it may
1357 be brought up later */
1358 log_struct_link(LOG_WARNING, link,
1359 "MESSAGE=%*s: could not bring up interface: %s",
1361 link->ifname, strerror(-r),
1371 static int link_up(Link *link) {
1372 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
1376 assert(link->manager);
1377 assert(link->manager->rtnl);
1379 log_debug_link(link, "bringing link up");
1381 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
1382 RTM_SETLINK, link->ifindex);
1384 log_error_link(link, "Could not allocate RTM_SETLINK message");
1388 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
1390 log_error_link(link, "Could not set link flags: %s", strerror(-r));
1394 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
1396 log_error_link(link,
1397 "Could not send rtnetlink message: %s", strerror(-r));
1406 static int link_enslaved(Link *link) {
1410 assert(link->state == LINK_STATE_ENSLAVING);
1411 assert(link->network);
1413 if (!(link->flags & IFF_UP)) {
1416 link_enter_failed(link);
1421 if (!link->network->dhcp && !link->network->ipv4ll)
1422 return link_enter_set_addresses(link);
1427 static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
1428 Link *link = userdata;
1432 assert(IN_SET(link->state, LINK_STATE_ENSLAVING, LINK_STATE_FAILED,
1433 LINK_STATE_LINGER));
1434 assert(link->network);
1438 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) {
1443 r = sd_rtnl_message_get_errno(m);
1445 log_struct_link(LOG_ERR, link,
1446 "MESSAGE=%*s: could not enslave: %s",
1448 link->ifname, strerror(-r),
1451 link_enter_failed(link);
1456 log_debug_link(link, "enslaved");
1458 if (link->enslaving == 0)
1459 link_enslaved(link);
1466 static int link_enter_enslave(Link *link) {
1467 NetDev *vlan, *macvlan;
1472 assert(link->network);
1473 assert(link->state == LINK_STATE_INITIALIZING);
1475 link->state = LINK_STATE_ENSLAVING;
1479 if (!link->network->bridge &&
1480 !link->network->bond &&
1481 !link->network->tunnel &&
1482 hashmap_isempty(link->network->vlans) &&
1483 hashmap_isempty(link->network->macvlans))
1484 return link_enslaved(link);
1486 if (link->network->bond) {
1487 log_struct_link(LOG_DEBUG, link,
1488 "MESSAGE=%*s: enslaving by '%s'",
1490 link->ifname, link->network->bond->ifname,
1491 NETDEV(link->network->bond),
1494 r = netdev_enslave(link->network->bond, link, &enslave_handler);
1496 log_struct_link(LOG_WARNING, link,
1497 "MESSAGE=%*s: could not enslave by '%s': %s",
1499 link->ifname, link->network->bond->ifname, strerror(-r),
1500 NETDEV(link->network->bond),
1502 link_enter_failed(link);
1510 if (link->network->bridge) {
1511 log_struct_link(LOG_DEBUG, link,
1512 "MESSAGE=%*s: enslaving by '%s'",
1514 link->ifname, link->network->bridge->ifname,
1515 NETDEV(link->network->bridge),
1518 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
1520 log_struct_link(LOG_WARNING, link,
1521 "MESSAGE=%*s: could not enslave by '%s': %s",
1523 link->ifname, link->network->bridge->ifname, strerror(-r),
1524 NETDEV(link->network->bridge),
1526 link_enter_failed(link);
1534 if (link->network->tunnel) {
1535 log_struct_link(LOG_DEBUG, link,
1536 "MESSAGE=%*s: enslaving by '%s'",
1538 link->ifname, link->network->tunnel->ifname,
1539 NETDEV(link->network->tunnel),
1542 r = netdev_enslave(link->network->tunnel, link, &enslave_handler);
1544 log_struct_link(LOG_WARNING, link,
1545 "MESSAGE=%*s: could not enslave by '%s': %s",
1547 link->ifname, link->network->tunnel->ifname, strerror(-r),
1548 NETDEV(link->network->tunnel),
1550 link_enter_failed(link);
1558 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
1559 log_struct_link(LOG_DEBUG, link,
1560 "MESSAGE=%*s: enslaving by '%s'",
1562 link->ifname, vlan->ifname, NETDEV(vlan), NULL);
1564 r = netdev_enslave(vlan, link, &enslave_handler);
1566 log_struct_link(LOG_WARNING, link,
1567 "MESSAGE=%*s: could not enslave by '%s': %s",
1569 link->ifname, vlan->ifname, strerror(-r),
1570 NETDEV(vlan), NULL);
1571 link_enter_failed(link);
1579 HASHMAP_FOREACH(macvlan, link->network->macvlans, i) {
1580 log_struct_link(LOG_DEBUG, link,
1581 "MESSAGE=%*s: enslaving by '%s'",
1583 link->ifname, macvlan->ifname, NETDEV(macvlan), NULL);
1585 r = netdev_enslave(macvlan, link, &enslave_handler);
1587 log_struct_link(LOG_WARNING, link,
1588 "MESSAGE=%*s: could not enslave by '%s': %s",
1590 link->ifname, macvlan->ifname, strerror(-r),
1591 NETDEV(macvlan), NULL);
1592 link_enter_failed(link);
1603 static int link_configure(Link *link) {
1607 assert(link->state == LINK_STATE_INITIALIZING);
1609 if (link->network->ipv4ll) {
1612 r = sd_ipv4ll_new(&link->ipv4ll);
1616 if (link->udev_device) {
1617 r = net_get_unique_predictable_data(link->udev_device, seed);
1619 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
1625 r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0);
1629 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1633 r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex);
1637 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
1642 if (link->network->dhcp) {
1643 r = sd_dhcp_client_new(&link->dhcp_client);
1647 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
1651 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
1655 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
1659 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
1663 if (link->network->dhcp_mtu) {
1664 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
1670 if (link_has_carrier(link->flags, link->kernel_operstate)) {
1671 r = link_acquire_conf(link);
1676 return link_enter_enslave(link);
1679 int link_initialized(Link *link, struct udev_device *device) {
1684 assert(link->ifname);
1685 assert(link->manager);
1687 if (link->state != LINK_STATE_INITIALIZING)
1691 link->udev_device = udev_device_ref(device);
1693 log_debug_link(link, "udev initialized link");
1695 r = network_get(link->manager, device, link->ifname, &link->mac, &network);
1697 link_enter_unmanaged(link);
1702 r = network_apply(link->manager, network, link);
1706 r = link_configure(link);
1713 int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
1714 Manager *m = userdata;
1717 _cleanup_address_free_ Address *address = NULL;
1719 char buf[INET6_ADDRSTRLEN];
1720 bool address_dropped = false;
1727 r = sd_rtnl_message_get_type(message, &type);
1729 log_warning("rtnl: could not get message type");
1733 r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
1734 if (r < 0 || ifindex <= 0) {
1735 log_warning("rtnl: received address message without valid ifindex, ignoring");
1738 r = link_get(m, ifindex, &link);
1739 if (r < 0 || !link) {
1740 log_warning("rtnl: received address for a nonexistent link, ignoring");
1745 r = address_new_dynamic(&address);
1749 r = sd_rtnl_message_addr_get_family(message, &address->family);
1750 if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
1751 log_warning_link(link, "rtnl: received address with invalid family, ignoring");
1755 r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
1757 log_warning_link(link, "rtnl: received address with invalid prefixlen, ignoring");
1761 r = sd_rtnl_message_addr_get_scope(message, &address->scope);
1763 log_warning_link(link, "rtnl: received address with invalid scope, ignoring");
1767 switch (address->family) {
1769 r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
1771 log_warning_link(link, "rtnl: received address without valid address, ignoring");
1778 r = sd_rtnl_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
1780 log_warning_link(link, "rtnl: received address without valid address, ignoring");
1787 assert_not_reached("invalid address family");
1790 if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
1791 log_warning_link(link, "could not print address");
1795 LIST_FOREACH(addresses, ad, link->addresses) {
1796 if (address_equal(ad, address)) {
1797 LIST_REMOVE(addresses, link->addresses, ad);
1801 address_dropped = true;
1809 if (!address_dropped)
1810 log_debug_link(link, "added address: %s/%u", buf,
1811 address->prefixlen);
1813 LIST_PREPEND(addresses, link->addresses, address);
1820 if (address_dropped) {
1821 log_debug_link(link, "removed address: %s/%u", buf,
1822 address->prefixlen);
1829 assert_not_reached("Received invalid RTNL message type");
1835 static int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
1836 Link *link = userdata;
1843 for (; m; m = sd_rtnl_message_next(m)) {
1844 r = sd_rtnl_message_get_errno(m);
1846 log_debug_link(link, "getting address failed: %s", strerror(-r));
1850 r = link_rtnl_process_address(rtnl, m, link->manager);
1852 log_warning_link(link, "could not process address: %s", strerror(-r));
1858 int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
1860 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
1861 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
1862 char ifindex_str[2 + DECIMAL_STR_MAX(int)];
1870 r = link_new(m, message, ret);
1876 log_debug_link(link, "link %"PRIu64" added", link->ifindex);
1878 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, link->ifindex, 0);
1882 r = sd_rtnl_call_async(m->rtnl, req, link_get_address_handler, link, 0, NULL);
1886 if (detect_container(NULL) <= 0) {
1887 /* not in a container, udev will be around */
1888 sprintf(ifindex_str, "n%"PRIu64, link->ifindex);
1889 device = udev_device_new_from_device_id(m->udev, ifindex_str);
1891 log_warning_link(link, "could not find udev device");
1895 if (udev_device_get_is_initialized(device) <= 0) {
1897 log_debug_link(link, "udev initializing link...");
1902 r = link_initialized(link, device);
1909 int link_update(Link *link, sd_rtnl_message *m) {
1910 struct ether_addr mac;
1915 assert(link->ifname);
1918 if (link->state == LINK_STATE_LINGER) {
1920 log_info_link(link, "link readded");
1921 link->state = LINK_STATE_ENSLAVING;
1924 r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
1925 if (r >= 0 && !streq(ifname, link->ifname)) {
1926 log_info_link(link, "renamed to %s", ifname);
1929 link->ifname = strdup(ifname);
1934 if (!link->original_mtu) {
1935 r = sd_rtnl_message_read_u16(m, IFLA_MTU, &link->original_mtu);
1937 log_debug_link(link, "saved original MTU: %"
1938 PRIu16, link->original_mtu);
1941 /* The kernel may broadcast NEWLINK messages without the MAC address
1942 set, simply ignore them. */
1943 r = sd_rtnl_message_read_ether_addr(m, IFLA_ADDRESS, &mac);
1945 if (memcmp(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN)) {
1947 memcpy(link->mac.ether_addr_octet, mac.ether_addr_octet, ETH_ALEN);
1949 log_debug_link(link, "MAC address: "
1950 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
1951 mac.ether_addr_octet[0],
1952 mac.ether_addr_octet[1],
1953 mac.ether_addr_octet[2],
1954 mac.ether_addr_octet[3],
1955 mac.ether_addr_octet[4],
1956 mac.ether_addr_octet[5]);
1959 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac);
1961 log_warning_link(link, "Could not update MAC "
1962 "address in IPv4LL client: %s",
1968 if (link->dhcp_client) {
1969 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
1971 log_warning_link(link, "Could not update MAC "
1972 "address in DHCP client: %s",
1980 return link_update_flags(link, m);
1983 static void serialize_addresses(FILE *f, const char *key, Address *address) {
1992 fprintf(f, "%s=", key);
1994 LIST_FOREACH(addresses, ad, address) {
1995 char buf[INET6_ADDRSTRLEN];
1997 if (inet_ntop(ad->family, &ad->in_addr, buf, INET6_ADDRSTRLEN))
1998 fprintf(f, "%s%s", buf, (ad->addresses_next) ? " ": "");
2004 static void link_update_operstate(Link *link) {
2008 if (link->kernel_operstate == IF_OPER_DORMANT)
2009 link->operstate = LINK_OPERSTATE_DORMANT;
2010 else if (link_has_carrier(link->flags, link->kernel_operstate)) {
2012 uint8_t scope = RT_SCOPE_NOWHERE;
2014 /* if we have carrier, check what addresses we have */
2015 LIST_FOREACH(addresses, address, link->addresses) {
2016 if (address->scope < scope)
2017 scope = address->scope;
2020 if (scope < RT_SCOPE_SITE)
2021 /* universally accessible addresses found */
2022 link->operstate = LINK_OPERSTATE_ROUTABLE;
2023 else if (scope < RT_SCOPE_HOST)
2024 /* only link or site local addresses found */
2025 link->operstate = LINK_OPERSTATE_DEGRADED;
2027 /* no useful addresses found */
2028 link->operstate = LINK_OPERSTATE_CARRIER;
2030 link->operstate = LINK_OPERSTATE_UNKNOWN;
2033 int link_save(Link *link) {
2034 _cleanup_free_ char *temp_path = NULL;
2035 _cleanup_fclose_ FILE *f = NULL;
2036 const char *admin_state, *oper_state;
2040 assert(link->state_file);
2041 assert(link->lease_file);
2042 assert(link->manager);
2044 link_update_operstate(link);
2046 r = manager_save(link->manager);
2050 if (link->state == LINK_STATE_LINGER) {
2051 unlink(link->state_file);
2055 admin_state = link_state_to_string(link->state);
2056 assert(admin_state);
2058 oper_state = link_operstate_to_string(link->operstate);
2061 r = fopen_temporary(link->state_file, &f, &temp_path);
2065 fchmod(fileno(f), 0644);
2068 "# This is private data. Do not parse.\n"
2072 admin_state, oper_state, link->flags);
2074 if (link->network) {
2075 serialize_addresses(f, "DNS", link->network->dns);
2076 serialize_addresses(f, "NTP", link->network->ntp);
2079 if (link->dhcp_lease) {
2080 r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
2087 "DHCP_USE_NTP=%s\n",
2089 yes_no(link->network->dhcp_dns),
2090 yes_no(link->network->dhcp_ntp));
2092 unlink(link->lease_file);
2096 if (ferror(f) || rename(temp_path, link->state_file) < 0) {
2098 unlink(link->state_file);
2104 log_error_link(link, "Failed to save link data to %s: %s", link->state_file, strerror(-r));
2109 static const char* const link_state_table[_LINK_STATE_MAX] = {
2110 [LINK_STATE_INITIALIZING] = "initializing",
2111 [LINK_STATE_ENSLAVING] = "configuring",
2112 [LINK_STATE_SETTING_ADDRESSES] = "configuring",
2113 [LINK_STATE_SETTING_ROUTES] = "configuring",
2114 [LINK_STATE_CONFIGURED] = "configured",
2115 [LINK_STATE_UNMANAGED] = "unmanaged",
2116 [LINK_STATE_FAILED] = "failed",
2117 [LINK_STATE_LINGER] = "linger",
2120 DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
2122 static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
2123 [LINK_OPERSTATE_UNKNOWN] = "unknown",
2124 [LINK_OPERSTATE_DORMANT] = "dormant",
2125 [LINK_OPERSTATE_CARRIER] = "carrier",
2126 [LINK_OPERSTATE_DEGRADED] = "degraded",
2127 [LINK_OPERSTATE_ROUTABLE] = "routable",
2130 DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);