diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index 971247714a..2059567ef8 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -135,3 +135,23 @@ int parse_operational_state_range(const char *str, LinkOperationalStateRange *ou return 0; } + +int network_link_get_operational_state(int ifindex, LinkOperationalState *ret) { + _cleanup_free_ char *str = NULL; + LinkOperationalState s; + int r; + + assert(ifindex > 0); + assert(ret); + + r = sd_network_link_get_operational_state(ifindex, &str); + if (r < 0) + return r; + + s = link_operstate_from_string(str); + if (s < 0) + return s; + + *ret = s; + return 0; +} diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h index 6e2ad28426..c47e271a76 100644 --- a/src/libsystemd/sd-network/network-util.h +++ b/src/libsystemd/sd-network/network-util.h @@ -83,3 +83,4 @@ typedef struct LinkOperationalStateRange { LINK_OPERSTATE_ROUTABLE } int parse_operational_state_range(const char *str, LinkOperationalStateRange *out); +int network_link_get_operational_state(int ifindex, LinkOperationalState *ret); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 89ee8c8367..1f5f4bd41a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1802,21 +1802,6 @@ static int link_admin_state_down(Link *link) { return 0; } -bool link_has_carrier(Link *link) { - /* see Documentation/networking/operstates.txt in the kernel sources */ - - if (link->kernel_operstate == IF_OPER_UP) - return true; - - if (link->kernel_operstate == IF_OPER_UNKNOWN) - /* operstate may not be implemented, so fall back to flags */ - if (FLAGS_SET(link->flags, IFF_LOWER_UP | IFF_RUNNING) && - !FLAGS_SET(link->flags, IFF_DORMANT)) - return true; - - return false; -} - static bool link_is_enslaved(Link *link) { if (link->flags & IFF_SLAVE) return true; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 8bf1cc67f7..7ccb31df79 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -19,6 +19,7 @@ #include "ether-addr-util.h" #include "log-link.h" +#include "netif-util.h" #include "network-util.h" #include "networkd-util.h" #include "ordered-set.h" @@ -212,7 +213,10 @@ void link_check_ready(Link *link); void link_update_operstate(Link *link, bool also_update_bond_master); -bool link_has_carrier(Link *link); +static inline bool link_has_carrier(Link *link) { + assert(link); + return netif_has_carrier(link->kernel_operstate, link->flags); +} bool link_ipv6_enabled(Link *link); bool link_ipv6ll_enabled(Link *link); diff --git a/src/network/wait-online/link.c b/src/network/wait-online/link.c index 5a33d563c2..a1ad16db47 100644 --- a/src/network/wait-online/link.c +++ b/src/network/wait-online/link.c @@ -97,7 +97,7 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) { } int link_update_monitor(Link *l) { - _cleanup_free_ char *operstate = NULL, *required_operstate = NULL, *required_family = NULL, + _cleanup_free_ char *required_operstate = NULL, *required_family = NULL, *ipv4_address_state = NULL, *ipv6_address_state = NULL, *state = NULL; int r, ret = 0; @@ -123,18 +123,9 @@ int link_update_monitor(Link *l) { "Failed to parse required operational state, ignoring: %m"); } - r = sd_network_link_get_operational_state(l->ifindex, &operstate); + r = network_link_get_operational_state(l->ifindex, &l->operational_state); if (r < 0) ret = log_link_debug_errno(l, r, "Failed to get operational state, ignoring: %m"); - else { - LinkOperationalState s; - - s = link_operstate_from_string(operstate); - if (s < 0) - ret = log_link_debug_errno(l, s, "Failed to parse operational state, ignoring: %m"); - else - l->operational_state = s; - } r = sd_network_link_get_required_family_for_online(l->ifindex, &required_family); if (r < 0) diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 6c910498a2..9eb0ccefd1 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -11,6 +11,7 @@ #include "fileio.h" #include "log-link.h" #include "mkdir.h" +#include "netif-util.h" #include "parse-util.h" #include "resolved-link.h" #include "resolved-llmnr.h" @@ -133,7 +134,7 @@ void link_allocate_scopes(Link *l) { r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC); if (r < 0) - log_warning_errno(r, "Failed to allocate DNS scope: %m"); + log_link_warning_errno(l, r, "Failed to allocate DNS scope, ignoring: %m"); } } else l->unicast_scope = dns_scope_free(l->unicast_scope); @@ -144,7 +145,7 @@ void link_allocate_scopes(Link *l) { if (!l->llmnr_ipv4_scope) { r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET); if (r < 0) - log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m"); + log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv4 scope, ignoring: %m"); } } else l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope); @@ -156,7 +157,7 @@ void link_allocate_scopes(Link *l) { if (!l->llmnr_ipv6_scope) { r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6); if (r < 0) - log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m"); + log_link_warning_errno(l, r, "Failed to allocate LLMNR IPv6 scope, ignoring: %m"); } } else l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope); @@ -167,7 +168,7 @@ void link_allocate_scopes(Link *l) { if (!l->mdns_ipv4_scope) { r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET); if (r < 0) - log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m"); + log_link_warning_errno(l, r, "Failed to allocate mDNS IPv4 scope, ignoring: %m"); } } else l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope); @@ -178,7 +179,7 @@ void link_allocate_scopes(Link *l) { if (!l->mdns_ipv6_scope) { r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6); if (r < 0) - log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m"); + log_link_warning_errno(l, r, "Failed to allocate mDNS IPv6 scope, ignoring: %m"); } } else l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope); @@ -198,13 +199,13 @@ void link_add_rrs(Link *l, bool force_remove) { if (l->mdns_ipv4_scope) { r = dns_scope_add_dnssd_services(l->mdns_ipv4_scope); if (r < 0) - log_warning_errno(r, "Failed to add IPv4 DNS-SD services: %m"); + log_link_warning_errno(l, r, "Failed to add IPv4 DNS-SD services, ignoring: %m"); } if (l->mdns_ipv6_scope) { r = dns_scope_add_dnssd_services(l->mdns_ipv6_scope); if (r < 0) - log_warning_errno(r, "Failed to add IPv6 DNS-SD services: %m"); + log_link_warning_errno(l, r, "Failed to add IPv6 DNS-SD services, ignoring: %m"); } } else { @@ -212,13 +213,13 @@ void link_add_rrs(Link *l, bool force_remove) { if (l->mdns_ipv4_scope) { r = dns_scope_remove_dnssd_services(l->mdns_ipv4_scope); if (r < 0) - log_warning_errno(r, "Failed to remove IPv4 DNS-SD services: %m"); + log_link_warning_errno(l, r, "Failed to remove IPv4 DNS-SD services, ignoring: %m"); } if (l->mdns_ipv6_scope) { r = dns_scope_remove_dnssd_services(l->mdns_ipv6_scope); if (r < 0) - log_warning_errno(r, "Failed to remove IPv6 DNS-SD services: %m"); + log_link_warning_errno(l, r, "Failed to remove IPv6 DNS-SD services, ignoring: %m"); } } } @@ -237,15 +238,16 @@ int link_process_rtnl(Link *l, sd_netlink_message *m) { (void) sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu); (void) sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &l->operstate); - if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) { + if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0 && + !streq_ptr(l->ifname, n)) { + if (l->ifname) + log_link_debug(l, "Interface name change detected: %s -> %s", l->ifname, n); + r = free_and_strdup(&l->ifname, n); if (r < 0) return r; } - link_allocate_scopes(l); - link_add_rrs(l, false); - return 0; } @@ -382,7 +384,10 @@ void link_set_dns_over_tls_mode(Link *l, DnsOverTlsMode mode) { #if ! ENABLE_DNS_OVER_TLS if (mode != DNS_OVER_TLS_NO) - log_warning("DNS-over-TLS option for the link cannot be enabled or set to opportunistic when systemd-resolved is built without DNS-over-TLS support. Turning off DNS-over-TLS support."); + log_link_warning(l, + "DNS-over-TLS option for the link cannot be enabled or set to opportunistic " + "when systemd-resolved is built without DNS-over-TLS support. " + "Turning off DNS-over-TLS support."); return; #endif @@ -417,7 +422,10 @@ void link_set_dnssec_mode(Link *l, DnssecMode mode) { #if !HAVE_OPENSSL_OR_GCRYPT if (IN_SET(mode, DNSSEC_YES, DNSSEC_ALLOW_DOWNGRADE)) - log_warning("DNSSEC option for the link cannot be enabled or set to allow-downgrade when systemd-resolved is built without a cryptographic library. Turning off DNSSEC support."); + log_link_warning(l, + "DNSSEC option for the link cannot be enabled or set to allow-downgrade " + "when systemd-resolved is built without a cryptographic library. " + "Turning off DNSSEC support."); return; #endif @@ -608,6 +616,10 @@ static void link_read_settings(Link *l) { l->is_managed = true; + r = network_link_get_operational_state(l->ifindex, &l->networkd_operstate); + if (r < 0) + log_link_warning_errno(l, r, "Failed to read networkd's link operational state, ignoring: %m"); + r = link_update_dns_servers(l); if (r < 0) log_link_warning_errno(l, r, "Failed to read DNS servers for the interface, ignoring: %m"); @@ -670,7 +682,6 @@ int link_update(Link *l) { } bool link_relevant(Link *l, int family, bool local_multicast) { - _cleanup_free_ char *state = NULL; LinkAddress *a; assert(l); @@ -681,24 +692,21 @@ bool link_relevant(Link *l, int family, bool local_multicast) { * A link is relevant for non-multicast traffic if it isn't a loopback device, has a link beat, and has at * least one routable address. */ - if (l->flags & (IFF_LOOPBACK|IFF_DORMANT)) + if ((l->flags & (IFF_LOOPBACK | IFF_DORMANT)) != 0) return false; - if ((l->flags & (IFF_UP|IFF_LOWER_UP)) != (IFF_UP|IFF_LOWER_UP)) + if (!FLAGS_SET(l->flags, IFF_UP | IFF_LOWER_UP)) return false; - if (local_multicast) { - if ((l->flags & IFF_MULTICAST) != IFF_MULTICAST) - return false; - } - - /* Check kernel operstate - * https://www.kernel.org/doc/Documentation/networking/operstates.txt */ - if (!IN_SET(l->operstate, IF_OPER_UNKNOWN, IF_OPER_UP)) + if (local_multicast && + !FLAGS_SET(l->flags, IFF_MULTICAST)) return false; - (void) sd_network_link_get_operational_state(l->ifindex, &state); - if (state && !STR_IN_SET(state, "unknown", "degraded", "degraded-carrier", "routable")) + if (!netif_has_carrier(l->operstate, l->flags)) + return false; + + if (l->is_managed && + !IN_SET(l->networkd_operstate, LINK_OPERSTATE_DEGRADED_CARRIER, LINK_OPERSTATE_DEGRADED, LINK_OPERSTATE_ROUTABLE)) return false; LIST_FOREACH(addresses, a, l->addresses) @@ -733,7 +741,7 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) { return s; if (s) - log_debug("Switching to DNS server %s for interface %s.", strna(dns_server_string_full(s)), l->ifname); + log_link_debug(l, "Switching to DNS server %s.", strna(dns_server_string_full(s))); dns_server_unref(l->current_dns_server); l->current_dns_server = dns_server_ref(s); @@ -925,11 +933,11 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true); if (r < 0) - log_warning_errno(r, "Failed to add A record to LLMNR zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add A record to LLMNR zone, ignoring: %m"); r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false); if (r < 0) - log_warning_errno(r, "Failed to add IPv4 PTR record to LLMNR zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add IPv4 PTR record to LLMNR zone, ignoring: %m"); } else { if (a->llmnr_address_rr) { if (a->link->llmnr_ipv4_scope) @@ -978,11 +986,11 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { r = dns_zone_put(&a->link->mdns_ipv4_scope->zone, a->link->mdns_ipv4_scope, a->mdns_address_rr, true); if (r < 0) - log_warning_errno(r, "Failed to add A record to MDNS zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add A record to MDNS zone, ignoring: %m"); r = dns_zone_put(&a->link->mdns_ipv4_scope->zone, a->link->mdns_ipv4_scope, a->mdns_ptr_rr, false); if (r < 0) - log_warning_errno(r, "Failed to add IPv4 PTR record to MDNS zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add IPv4 PTR record to MDNS zone, ignoring: %m"); } else { if (a->mdns_address_rr) { if (a->link->mdns_ipv4_scope) @@ -1035,11 +1043,11 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true); if (r < 0) - log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add AAAA record to LLMNR zone, ignoring: %m"); r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false); if (r < 0) - log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add IPv6 PTR record to LLMNR zone, ignoring: %m"); } else { if (a->llmnr_address_rr) { if (a->link->llmnr_ipv6_scope) @@ -1089,11 +1097,11 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { r = dns_zone_put(&a->link->mdns_ipv6_scope->zone, a->link->mdns_ipv6_scope, a->mdns_address_rr, true); if (r < 0) - log_warning_errno(r, "Failed to add AAAA record to MDNS zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add AAAA record to MDNS zone, ignoring: %m"); r = dns_zone_put(&a->link->mdns_ipv6_scope->zone, a->link->mdns_ipv6_scope, a->mdns_ptr_rr, false); if (r < 0) - log_warning_errno(r, "Failed to add IPv6 PTR record to MDNS zone: %m"); + log_link_warning_errno(a->link, r, "Failed to add IPv6 PTR record to MDNS zone, ignoring: %m"); } else { if (a->mdns_address_rr) { if (a->link->mdns_ipv6_scope) @@ -1112,7 +1120,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { return; fail: - log_debug_errno(r, "Failed to update address RRs: %m"); + log_link_debug_errno(a->link, r, "Failed to update address RRs, ignoring: %m"); } int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) { @@ -1284,7 +1292,7 @@ fail: if (temp_path) (void) unlink(temp_path); - return log_error_errno(r, "Failed to save link data %s: %m", l->state_file); + return log_link_error_errno(l, r, "Failed to save link data %s: %m", l->state_file); } int link_load_user(Link *l) { @@ -1354,7 +1362,7 @@ int link_load_user(Link *l) { r = link_update_dns_server_one(l, word); if (r < 0) { - log_debug_errno(r, "Failed to load DNS server '%s', ignoring: %m", word); + log_link_debug_errno(l, r, "Failed to load DNS server '%s', ignoring: %m", word); continue; } } @@ -1375,7 +1383,7 @@ int link_load_user(Link *l) { r = link_update_search_domain_one(l, n, is_route); if (r < 0) { - log_debug_errno(r, "Failed to load search domain '%s', ignoring: %m", word); + log_link_debug_errno(l, r, "Failed to load search domain '%s', ignoring: %m", word); continue; } } @@ -1399,7 +1407,7 @@ int link_load_user(Link *l) { return 0; fail: - return log_error_errno(r, "Failed to load link data %s: %m", l->state_file); + return log_link_error_errno(l, r, "Failed to load link data %s: %m", l->state_file); } void link_remove_user(Link *l) { diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index f65718ce31..b5299e0b5b 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -6,6 +6,7 @@ #include "sd-netlink.h" #include "in-addr-util.h" +#include "network-util.h" #include "ratelimit.h" #include "resolve-util.h" @@ -68,6 +69,7 @@ struct Link { DnsScope *mdns_ipv6_scope; struct stat networkd_state_file_stat; + LinkOperationalState networkd_operstate; bool is_managed; char *ifname; diff --git a/src/shared/netif-util.c b/src/shared/netif-util.c index 603d4de109..69d7cc2b10 100644 --- a/src/shared/netif-util.c +++ b/src/shared/netif-util.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include #include "arphrd-util.h" @@ -11,6 +12,20 @@ #include "sparse-endian.h" #include "strv.h" +bool netif_has_carrier(uint8_t operstate, unsigned flags) { + /* see Documentation/networking/operstates.txt in the kernel sources */ + + if (operstate == IF_OPER_UP) + return true; + + if (operstate != IF_OPER_UNKNOWN) + return false; + + /* operstate may not be implemented, so fall back to flags */ + return FLAGS_SET(flags, IFF_LOWER_UP | IFF_RUNNING) && + !FLAGS_SET(flags, IFF_DORMANT); +} + int net_get_type_string(sd_device *device, uint16_t iftype, char **ret) { const char *t; char *p; diff --git a/src/shared/netif-util.h b/src/shared/netif-util.h index c26dab63cf..fb6a27cce1 100644 --- a/src/shared/netif-util.h +++ b/src/shared/netif-util.h @@ -9,6 +9,7 @@ #include "ether-addr-util.h" +bool netif_has_carrier(uint8_t operstate, unsigned flags); int net_get_type_string(sd_device *device, uint16_t iftype, char **ret); const char *net_get_persistent_name(sd_device *device); int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *ret);