X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-link.c;h=c5857da8fc456b47020c0f5778363b416cd6a786;hb=8e54db83e2837247bec2fc9f27a62877921c9f18;hp=9e3cd71a095896f415afd8a64b2acfb7083364c0;hpb=299ad32d48c01d1529affddc612198c60733f23c;p=thirdparty%2Fsystemd.git diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9e3cd71a095..c5857da8fc4 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1,10 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ -#include +#include #include #include #include -#include #include "alloc-util.h" #include "bus-util.h" @@ -111,7 +110,7 @@ static bool link_dhcp4_server_enabled(Link *link) { return link->network->dhcp_server; } -static bool link_ipv4ll_enabled(Link *link) { +bool link_ipv4ll_enabled(Link *link) { assert(link); if (link->flags & IFF_LOOPBACK) @@ -129,6 +128,24 @@ static bool link_ipv4ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV4; } +bool link_ipv4ll_fallback_enabled(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return false; + + if (!link->network) + return false; + + if (STRPTR_IN_SET(link->kind, "vrf", "wireguard")) + return false; + + if (link->network->bond) + return false; + + return link->network->link_local & ADDRESS_FAMILY_FALLBACK_IPV4; +} + static bool link_ipv6ll_enabled(Link *link) { assert(link); @@ -178,42 +195,6 @@ static bool link_radv_enabled(Link *link) { return link->network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE; } -static bool link_lldp_rx_enabled(Link *link) { - assert(link); - - if (link->flags & IFF_LOOPBACK) - return false; - - if (link->iftype != ARPHRD_ETHER) - return false; - - if (!link->network) - return false; - - /* LLDP should be handled on bridge slaves as those have a direct - * connection to their peers not on the bridge master. Linux doesn't - * even (by default) forward lldp packets to the bridge master.*/ - if (streq_ptr("bridge", link->kind)) - return false; - - return link->network->lldp_mode != LLDP_MODE_NO; -} - -static bool link_lldp_emit_enabled(Link *link) { - assert(link); - - if (link->flags & IFF_LOOPBACK) - return false; - - if (link->iftype != ARPHRD_ETHER) - return false; - - if (!link->network) - return false; - - return link->network->lldp_emit != LLDP_EMIT_NO; -} - static bool link_ipv4_forward_enabled(Link *link) { assert(link); @@ -321,8 +302,7 @@ static int link_enable_ipv6(Link *link) { r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", disabled); if (r < 0) - log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m", - enable_disable(!disabled), link->ifname); + log_link_warning_errno(link, r, "Cannot %s IPv6: %m", enable_disable(!disabled)); else log_link_info(link, "IPv6 successfully %sd", enable_disable(!disabled)); @@ -407,15 +387,14 @@ void link_update_operstate(Link *link, bool also_update_master) { link_is_enslaved(link)) operstate = LINK_OPERSTATE_ENSLAVED; - if (IN_SET(operstate, LINK_OPERSTATE_CARRIER, LINK_OPERSTATE_ENSLAVED, LINK_OPERSTATE_ROUTABLE)) { + if (operstate >= LINK_OPERSTATE_CARRIER) { Link *slave; - HASHMAP_FOREACH(slave, link->slaves, i) { + SET_FOREACH(slave, link->slaves, i) { link_update_operstate(slave, false); - if (IN_SET(slave->operstate, - LINK_OPERSTATE_OFF, LINK_OPERSTATE_NO_CARRIER, LINK_OPERSTATE_DORMANT)) - operstate = LINK_OPERSTATE_DEGRADED; + if (slave->operstate < LINK_OPERSTATE_CARRIER) + operstate = LINK_OPERSTATE_DEGRADED_CARRIER; } } @@ -508,8 +487,6 @@ static int link_update_flags(Link *link, sd_netlink_message *m) { return 0; } -DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref); - static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { _cleanup_(link_unrefp) Link *link = NULL; uint16_t type; @@ -607,40 +584,16 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { return 0; } -static void link_detach_from_manager(Link *link) { - if (!link || !link->manager) - return; - - hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)); - set_remove(link->manager->links_requesting_uuid, link); - link_clean(link); -} - static Link *link_free(Link *link) { - Link *carrier, *master; Address *address; - Route *route; - Iterator i; assert(link); - while ((route = set_first(link->routes))) - route_free(route); - - while ((route = set_first(link->routes_foreign))) - route_free(route); - - link->routes = set_free(link->routes); - link->routes_foreign = set_free(link->routes_foreign); + link->routes = set_free_with_destructor(link->routes, route_free); + link->routes_foreign = set_free_with_destructor(link->routes_foreign, route_free); - while ((address = set_first(link->addresses))) - address_free(address); - - while ((address = set_first(link->addresses_foreign))) - address_free(address); - - link->addresses = set_free(link->addresses); - link->addresses_foreign = set_free(link->addresses_foreign); + link->addresses = set_free_with_destructor(link->addresses, address_free); + link->addresses_foreign = set_free_with_destructor(link->addresses_foreign, address_free); while ((address = link->pool_addresses)) { LIST_REMOVE(addresses, link->pool_addresses, address); @@ -665,10 +618,7 @@ static Link *link_free(Link *link) { sd_ndisc_unref(link->ndisc); sd_radv_unref(link->radv); - link_detach_from_manager(link); - free(link->ifname); - free(link->kind); (void) unlink(link->state_file); @@ -676,25 +626,12 @@ static Link *link_free(Link *link) { sd_device_unref(link->sd_device); - HASHMAP_FOREACH (carrier, link->bound_to_links, i) - hashmap_remove(link->bound_to_links, INT_TO_PTR(carrier->ifindex)); hashmap_free(link->bound_to_links); - - HASHMAP_FOREACH (carrier, link->bound_by_links, i) - hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex)); hashmap_free(link->bound_by_links); - hashmap_free(link->slaves); - - if (link->network) { - if (link->network->bond && - link_get(link->manager, link->network->bond->ifindex, &master) >= 0) - (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex)); + set_free_with_destructor(link->slaves, link_unref); - if (link->network->bridge && - link_get(link->manager, link->network->bridge->ifindex, &master) >= 0) - (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex)); - } + network_unref(link->network); return mfree(link); } @@ -723,6 +660,10 @@ static void link_set_state(Link *link, LinkState state) { if (link->state == state) return; + log_link_debug(link, "State changed: %s -> %s", + link_state_to_string(link->state), + link_state_to_string(state)); + link->state = state; link_send_changed(link, "AdministrativeState", NULL); @@ -738,7 +679,7 @@ static void link_enter_unmanaged(Link *link) { link_dirty(link); } -static int link_stop_clients(Link *link) { +int link_stop_clients(Link *link) { int r = 0, k; assert(link); @@ -823,6 +764,35 @@ static Address* link_find_dhcp_server_address(Link *link) { return NULL; } +static int link_join_netdevs_after_configured(Link *link) { + NetDev *netdev; + Iterator i; + int r; + + HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { + if (netdev->ifindex > 0) + /* Assume already enslaved. */ + continue; + + if (netdev_get_create_type(netdev) != NETDEV_CREATE_AFTER_CONFIGURED) + continue; + + log_struct(LOG_DEBUG, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(netdev), + LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname)); + + r = netdev_join(netdev, link, NULL); + if (r < 0) + return log_struct_errno(LOG_WARNING, r, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(netdev), + LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", netdev->ifname)); + } + + return 0; +} + static void link_enter_configured(Link *link) { assert(link); assert(link->network); @@ -834,6 +804,8 @@ static void link_enter_configured(Link *link) { link_set_state(link, LINK_STATE_CONFIGURED); + (void) link_join_netdevs_after_configured(link); + link_dirty(link); } @@ -902,7 +874,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { return 1; } -static int link_request_set_routes(Link *link) { +int link_request_set_routes(Link *link) { enum { PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */ PHASE_GATEWAY, /* Second phase: Routes with a gateway */ @@ -983,21 +955,18 @@ void link_check_ready(Link *link) { if (!link->routing_policy_rules_configured) return; - if (link_ipv4ll_enabled(link)) - if (!link->ipv4ll_address || - !link->ipv4ll_route) - return; + if (link_ipv4ll_enabled(link) && !(link->ipv4ll_address && link->ipv4ll_route)) + return; if (link_ipv6ll_enabled(link) && in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) return; - if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && - !link->dhcp4_configured) || - (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && - !link->dhcp6_configured) || - (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && - !link->dhcp4_configured && !link->dhcp6_configured)) + if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && + !(link->dhcp4_configured || link->dhcp6_configured) && + !(link_ipv4ll_fallback_enabled(link) && link->ipv4ll_address && link->ipv4ll_route)) + /* When DHCP is enabled, at least one protocol must provide an address, or + * an IPv4ll fallback address must be configured. */ return; if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured) @@ -1131,20 +1100,20 @@ static int link_push_uplink_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) { log_debug("Copying NTP server information from %s", link->ifname); STRV_FOREACH(a, link->network->ntp) { - struct in_addr ia; + union in_addr_union ia; /* Only look for IPv4 addresses */ - if (inet_pton(AF_INET, *a, &ia) <= 0) + if (in_addr_from_string(AF_INET, *a, &ia) <= 0) continue; /* Never propagate obviously borked data */ - if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia)) + if (in4_addr_is_null(&ia.in) || in4_addr_is_localhost(&ia.in)) continue; if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) return log_oom(); - addresses[n_addresses++] = ia; + addresses[n_addresses++] = ia.in; } if (link->network->dhcp_use_ntp && link->dhcp_lease) { @@ -1422,7 +1391,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) log_link_debug(link, "Setting MTU done."); - if (link->state == LINK_STATE_PENDING) + if (link->state == LINK_STATE_INITIALIZED) (void) link_configure_after_setting_mtu(link); return 1; @@ -1587,7 +1556,6 @@ static int link_set_bridge(Link *link) { r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->allow_port_to_be_root); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m"); - } if (link->network->unicast_flood >= 0) { @@ -1596,12 +1564,42 @@ static int link_set_bridge(Link *link) { return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m"); } + if (link->network->multicast_flood >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_FLOOD, link->network->multicast_flood); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_FLOOD attribute: %m"); + } + if (link->network->multicast_to_unicast >= 0) { r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m"); } + if (link->network->neighbor_suppression >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_NEIGH_SUPPRESS, link->network->neighbor_suppression); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_NEIGH_SUPPRESS attribute: %m"); + } + + if (link->network->learning >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_LEARNING, link->network->learning); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_LEARNING attribute: %m"); + } + + if (link->network->bridge_proxy_arp >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP, link->network->bridge_proxy_arp); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP attribute: %m"); + } + + if (link->network->bridge_proxy_arp_wifi >= 0) { + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROXYARP_WIFI, link->network->bridge_proxy_arp_wifi); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROXYARP_WIFI attribute: %m"); + } + if (link->network->cost != 0) { r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); if (r < 0) @@ -1614,6 +1612,12 @@ static int link_set_bridge(Link *link) { return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PRIORITY attribute: %m"); } + if (link->network->multicast_router != _MULTICAST_ROUTER_INVALID) { + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MULTICAST_ROUTER, link->network->multicast_router); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MULTICAST_ROUTER attribute: %m"); + } + r = sd_netlink_message_close_container(req); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_LINKINFO attribute: %m"); @@ -1700,118 +1704,6 @@ static int link_set_bond(Link *link) { return r; } -static int link_append_to_master(Link *link, NetDev *netdev) { - Link *master; - int r; - - assert(link); - assert(netdev); - - r = link_get(link->manager, netdev->ifindex, &master); - if (r < 0) - return r; - - r = hashmap_ensure_allocated(&master->slaves, NULL); - if (r < 0) - return r; - - r = hashmap_put(master->slaves, INT_TO_PTR(link->ifindex), link); - if (r < 0) - return r; - - return 0; -} - -static int link_lldp_save(Link *link) { - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - sd_lldp_neighbor **l = NULL; - int n = 0, r, i; - - assert(link); - assert(link->lldp_file); - - if (!link->lldp) { - (void) unlink(link->lldp_file); - return 0; - } - - r = sd_lldp_get_neighbors(link->lldp, &l); - if (r < 0) - goto finish; - if (r == 0) { - (void) unlink(link->lldp_file); - goto finish; - } - - n = r; - - r = fopen_temporary(link->lldp_file, &f, &temp_path); - if (r < 0) - goto finish; - - fchmod(fileno(f), 0644); - - for (i = 0; i < n; i++) { - const void *p; - le64_t u; - size_t sz; - - r = sd_lldp_neighbor_get_raw(l[i], &p, &sz); - if (r < 0) - goto finish; - - u = htole64(sz); - (void) fwrite(&u, 1, sizeof(u), f); - (void) fwrite(p, 1, sz, f); - } - - r = fflush_and_check(f); - if (r < 0) - goto finish; - - if (rename(temp_path, link->lldp_file) < 0) { - r = -errno; - goto finish; - } - -finish: - if (r < 0) { - (void) unlink(link->lldp_file); - if (temp_path) - (void) unlink(temp_path); - - log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file); - } - - if (l) { - for (i = 0; i < n; i++) - sd_lldp_neighbor_unref(l[i]); - free(l); - } - - return r; -} - -static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { - Link *link = userdata; - int r; - - assert(link); - - (void) link_lldp_save(link); - - if (link_lldp_emit_enabled(link) && event == SD_LLDP_EVENT_ADDED) { - /* If we received information about a new neighbor, restart the LLDP "fast" logic */ - - log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission."); - - r = link_lldp_emit_start(link); - if (r < 0) - log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m"); - } -} - static int link_acquire_ipv6_conf(Link *link) { int r; @@ -1847,7 +1739,6 @@ static int link_acquire_ipv4_conf(Link *link) { int r; assert(link); - assert(link->network); assert(link->manager); assert(link->manager->event); @@ -2031,6 +1922,8 @@ static int link_up(Link *link) { } if (link_ipv6_enabled(link)) { + uint8_t ipv6ll_mode; + r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); if (r < 0) return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m"); @@ -2046,6 +1939,19 @@ static int link_up(Link *link) { return log_link_error_errno(link, r, "Could not append IFLA_INET6_TOKEN: %m"); } + if (!link_ipv6ll_enabled(link)) + ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE; + else if (sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL) < 0) + /* The file may not exist. And event if it exists, when stable_secret is unset, + * reading the file fails with EIO. */ + ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64; + else + ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; + + r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_INET6_ADDR_GEN_MODE: %m"); + r = sd_netlink_message_close_container(req); if (r < 0) return log_link_error_errno(link, r, "Could not close AF_INET6 container: %m"); @@ -2163,6 +2069,19 @@ static int link_set_can(Link *link) { return log_link_error_errno(link, r, "Could not append IFLA_CAN_RESTART_MS attribute: %m"); } + if (link->network->can_triple_sampling >= 0) { + struct can_ctrlmode cm = { + .mask = CAN_CTRLMODE_3_SAMPLES, + .flags = link->network->can_triple_sampling ? CAN_CTRLMODE_3_SAMPLES : 0, + }; + + log_link_debug(link, "%sabling triple-sampling", link->network->can_triple_sampling ? "En" : "Dis"); + + r = sd_netlink_message_append_data(m, IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_CAN_CTRLMODE attribute: %m"); + } + r = sd_netlink_message_close_container(m); if (r < 0) return log_link_error_errno(link, r, "Failed to close netlink container: %m"); @@ -2209,7 +2128,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link return 1; } -int link_down(Link *link) { +int link_down(Link *link, link_netlink_message_handler_t callback) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -2228,7 +2147,8 @@ int link_down(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not set link flags: %m"); - r = netlink_call_async(link->manager->rtnl, NULL, req, link_down_handler, + r = netlink_call_async(link->manager->rtnl, NULL, req, + callback ?: link_down_handler, link_netlink_destroy_callback, link); if (r < 0) return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); @@ -2260,7 +2180,7 @@ static int link_handle_bound_to_list(Link *link) { } if (!required_up && link_is_up) { - r = link_down(link); + r = link_down(link, NULL); if (r < 0) return r; } else if (required_up && !link_is_up) { @@ -2471,6 +2391,55 @@ static void link_free_carrier_maps(Link *link) { return; } +static int link_append_to_master(Link *link, NetDev *netdev) { + Link *master; + int r; + + assert(link); + assert(netdev); + + r = link_get(link->manager, netdev->ifindex, &master); + if (r < 0) + return r; + + r = set_ensure_allocated(&master->slaves, NULL); + if (r < 0) + return r; + + r = set_put(master->slaves, link); + if (r < 0) + return r; + + link_ref(link); + return 0; +} + +static void link_drop_from_master(Link *link, NetDev *netdev) { + Link *master; + + assert(link); + + if (!link->manager || !netdev) + return; + + if (link_get(link->manager, netdev->ifindex, &master) < 0) + return; + + link_unref(set_remove(master->slaves, link)); +} + +static void link_detach_from_manager(Link *link) { + if (!link || !link->manager) + return; + + link_unref(set_remove(link->manager->links_requesting_uuid, link)); + link_clean(link); + + /* The following must be called at last. */ + assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link); + link_unref(link); +} + void link_drop(Link *link) { if (!link || link->state == LINK_STATE_LINGER) return; @@ -2479,15 +2448,15 @@ void link_drop(Link *link) { link_free_carrier_maps(link); + if (link->network) { + link_drop_from_master(link, link->network->bridge); + link_drop_from_master(link, link->network->bond); + } + log_link_debug(link, "Link removed"); (void) unlink(link->state_file); - link_detach_from_manager(link); - - link_unref(link); - - return; } static int link_joined(Link *link) { @@ -2580,7 +2549,7 @@ static int link_enter_join_netdev(Link *link) { assert(link); assert(link->network); - assert(link->state == LINK_STATE_PENDING); + assert(link->state == LINK_STATE_INITIALIZED); link_set_state(link, LINK_STATE_CONFIGURING); @@ -2651,10 +2620,12 @@ static int link_enter_join_netdev(Link *link) { HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) { - if (netdev->ifindex > 0) { - link_joined(link); + if (netdev->ifindex > 0) + /* Assume already enslaved. */ + continue; + + if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED) continue; - } log_struct(LOG_DEBUG, LOG_LINK_INTERFACE(link), @@ -2936,34 +2907,13 @@ static int link_drop_config(Link *link) { return 0; } -static int link_update_lldp(Link *link) { - int r; - - assert(link); - - if (!link->lldp) - return 0; - - if (link->flags & IFF_UP) { - r = sd_lldp_start(link->lldp); - if (r > 0) - log_link_debug(link, "Started LLDP."); - } else { - r = sd_lldp_stop(link->lldp); - if (r > 0) - log_link_debug(link, "Stopped LLDP."); - } - - return r; -} - static int link_configure_can(Link *link) { int r; if (streq_ptr(link->kind, "can")) { /* The CAN interface must be down to configure bitrate, etc... */ if ((link->flags & IFF_UP)) { - r = link_down(link); + r = link_down(link, NULL); if (r < 0) { link_enter_failed(link); return r; @@ -2991,7 +2941,7 @@ static int link_configure(Link *link) { assert(link); assert(link->network); - assert(link->state == LINK_STATE_PENDING); + assert(link->state == LINK_STATE_INITIALIZED); if (STRPTR_IN_SET(link->kind, "can", "vcan")) return link_configure_can(link); @@ -3044,7 +2994,7 @@ static int link_configure(Link *link) { if (r < 0) return r; - if (link_ipv4ll_enabled(link)) { + if (link_ipv4ll_enabled(link) || link_ipv4ll_fallback_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) return r; @@ -3090,34 +3040,7 @@ static int link_configure(Link *link) { } if (link_lldp_rx_enabled(link)) { - r = sd_lldp_new(&link->lldp); - if (r < 0) - return r; - - r = sd_lldp_set_ifindex(link->lldp, link->ifindex); - if (r < 0) - return r; - - r = sd_lldp_match_capabilities(link->lldp, - link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ? - SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS : - SD_LLDP_SYSTEM_CAPABILITIES_ALL); - if (r < 0) - return r; - - r = sd_lldp_set_filter_address(link->lldp, &link->mac); - if (r < 0) - return r; - - r = sd_lldp_attach_event(link->lldp, NULL, 0); - if (r < 0) - return r; - - r = sd_lldp_set_callback(link->lldp, lldp_handler, link); - if (r < 0) - return r; - - r = link_update_lldp(link); + r = link_lldp_rx_configure(link); if (r < 0) return r; } @@ -3140,7 +3063,7 @@ static int link_configure_after_setting_mtu(Link *link) { assert(link); assert(link->network); - assert(link->state == LINK_STATE_PENDING); + assert(link->state == LINK_STATE_INITIALIZED); if (link->setting_mtu) return 0; @@ -3291,10 +3214,13 @@ static int link_initialized_and_synced(Link *link) { assert(link->ifname); assert(link->manager); - if (link->state != LINK_STATE_PENDING) - return 1; + /* We may get called either from the asynchronous netlink callback, + * or directly for link_add() if running in a container. See link_add(). */ + if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED)) + return 0; log_link_debug(link, "Link state is up-to-date"); + link_set_state(link, LINK_STATE_INITIALIZED); r = link_new_bound_by_list(link); if (r < 0) @@ -3309,7 +3235,7 @@ static int link_initialized_and_synced(Link *link) { &link->mac, &network); if (r == -ENOENT) { link_enter_unmanaged(link); - return 1; + return 0; } else if (r == 0 && network->unmanaged) { link_enter_unmanaged(link); return 0; @@ -3346,7 +3272,7 @@ static int link_initialized_and_synced(Link *link) { if (r < 0) return r; - return 1; + return 0; } static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { @@ -3370,6 +3296,7 @@ int link_initialized(Link *link, sd_device *device) { return 0; log_link_debug(link, "udev initialized link"); + link_set_state(link, LINK_STATE_INITIALIZED); link->sd_device = sd_device_ref(device); @@ -3660,7 +3587,7 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address) { link->ipv6ll_address = *address; link_check_ready(link); - if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { + if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) { r = link_acquire_ipv6_conf(link); if (r < 0) { link_enter_failed(link); @@ -3676,7 +3603,7 @@ static int link_carrier_gained(Link *link) { assert(link); - if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { + if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) { r = link_acquire_conf(link); if (r < 0) { link_enter_failed(link); @@ -3768,7 +3695,7 @@ int link_update(Link *link, sd_netlink_message *m) { assert(m); if (link->state == LINK_STATE_LINGER) { - log_link_info(link, "Link readded"); + log_link_info(link, "Link re-added"); link_set_state(link, LINK_STATE_CONFIGURING); r = link_new_carrier_maps(link); @@ -3955,7 +3882,7 @@ int link_save(Link *link) { assert(link->manager); if (link->state == LINK_STATE_LINGER) { - unlink(link->state_file); + (void) unlink(link->state_file); return 0; } @@ -3971,7 +3898,6 @@ int link_save(Link *link) { if (r < 0) goto fail; - (void) __fsetlocking(f, FSETLOCKING_BYCALLER); (void) fchmod(fileno(f), 0644); fprintf(f, @@ -3991,6 +3917,9 @@ int link_save(Link *link) { fprintf(f, "REQUIRED_FOR_ONLINE=%s\n", yes_no(link->network->required_for_online)); + fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s\n", + strempty(link_operstate_to_string(link->network->required_operstate_for_online))); + if (link->dhcp6_client) { r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease); if (r < 0 && r != -ENOMSG) @@ -4221,7 +4150,7 @@ int link_save(Link *link) { "DHCP_LEASE=%s\n", link->lease_file); } else - unlink(link->lease_file); + (void) unlink(link->lease_file); if (link->ipv4ll) { struct in_addr address; @@ -4285,6 +4214,7 @@ void link_clean(Link *link) { static const char* const link_state_table[_LINK_STATE_MAX] = { [LINK_STATE_PENDING] = "pending", + [LINK_STATE_INITIALIZED] = "initialized", [LINK_STATE_CONFIGURING] = "configuring", [LINK_STATE_CONFIGURED] = "configured", [LINK_STATE_UNMANAGED] = "unmanaged", @@ -4293,15 +4223,3 @@ static const char* const link_state_table[_LINK_STATE_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState); - -static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = { - [LINK_OPERSTATE_OFF] = "off", - [LINK_OPERSTATE_NO_CARRIER] = "no-carrier", - [LINK_OPERSTATE_DORMANT] = "dormant", - [LINK_OPERSTATE_CARRIER] = "carrier", - [LINK_OPERSTATE_DEGRADED] = "degraded", - [LINK_OPERSTATE_ENSLAVED] = "enslaved", - [LINK_OPERSTATE_ROUTABLE] = "routable", -}; - -DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);