From 39f4185c698fb2c41502ee16700a625144678292 Mon Sep 17 00:00:00 2001 From: r-vdp Date: Mon, 13 Apr 2026 19:03:27 +0200 Subject: [PATCH] network: honour static IPv6LL addresses in network_adjust_*() link_radv_enabled() and link_ndisc_enabled() use link_ipv6ll_enabled_harder(), which considers a static fe80:: address in [Address] sufficient to run radv/ndisc even when LinkLocalAddressing= (or IPv6LinkLocalAddressGenerationMode=none, which network_verify() folds into the same flag) disables the kernel-generated link-local. network_adjust_radv()/ndisc()/dhcp() however only check the raw link_local flag and zero router_prefix_delegation / ndisc / dhcp&IPV6 at parse time, so the runtime gate never gets a chance to fire. Factor the static-LL lookup out of link_ipv6ll_enabled_harder() into a Network-level helper and use it in the three network_adjust_*() functions, bringing parse-time and runtime behaviour in line. --- src/network/networkd-dhcp-common.c | 2 ++ src/network/networkd-ipv6ll.c | 28 +++++++++++++++++----------- src/network/networkd-ipv6ll.h | 1 + src/network/networkd-ndisc.c | 4 +++- src/network/networkd-radv.c | 4 +++- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 5d83835580..d2e51e7e91 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -19,6 +19,7 @@ #include "iovec-util.h" #include "networkd-dhcp-common.h" #include "networkd-dhcp-prefix-delegation.h" +#include "networkd-ipv6ll.h" #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-network.h" @@ -100,6 +101,7 @@ void network_adjust_dhcp(Network *network) { } if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6) && + !network_has_static_ipv6ll_address(network) && FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV6)) { log_warning("%s: DHCPv6 client is enabled but IPv6 link-local addressing is disabled. " "Disabling DHCPv6 client.", network->filename); diff --git a/src/network/networkd-ipv6ll.c b/src/network/networkd-ipv6ll.c index 546229a2e2..654fbdb6a8 100644 --- a/src/network/networkd-ipv6ll.c +++ b/src/network/networkd-ipv6ll.c @@ -42,6 +42,22 @@ bool link_ipv6ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV6; } +bool network_has_static_ipv6ll_address(const Network *network) { + assert(network); + + Address *a; + ORDERED_HASHMAP_FOREACH(a, network->addresses_by_section) { + if (a->family != AF_INET6) + continue; + if (in6_addr_is_set(&a->in_addr_peer.in6)) + continue; + if (in6_addr_is_link_local(&a->in_addr.in6)) + return true; + } + + return false; +} + bool link_ipv6ll_enabled_harder(Link *link) { assert(link); @@ -54,17 +70,7 @@ bool link_ipv6ll_enabled_harder(Link *link) { if (!link->network) return false; - Address *a; - ORDERED_HASHMAP_FOREACH(a, link->network->addresses_by_section) { - if (a->family != AF_INET6) - continue; - if (in6_addr_is_set(&a->in_addr_peer.in6)) - continue; - if (in6_addr_is_link_local(&a->in_addr.in6)) - return true; - } - - return false; + return network_has_static_ipv6ll_address(link->network); } IPv6LinkLocalAddressGenMode link_get_ipv6ll_addrgen_mode(Link *link) { diff --git a/src/network/networkd-ipv6ll.h b/src/network/networkd-ipv6ll.h index 62ce9d957e..73fa51fbef 100644 --- a/src/network/networkd-ipv6ll.h +++ b/src/network/networkd-ipv6ll.h @@ -16,6 +16,7 @@ typedef enum IPv6LinkLocalAddressGenMode { bool link_ipv6ll_enabled(Link *link); bool link_ipv6ll_enabled_harder(Link *link); +bool network_has_static_ipv6ll_address(const Network *network); IPv6LinkLocalAddressGenMode link_get_ipv6ll_addrgen_mode(Link *link); int ipv6ll_addrgen_mode_fill_message(sd_netlink_message *message, IPv6LinkLocalAddressGenMode mode); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index e6b03c0826..4e15da9588 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -17,6 +17,7 @@ #include "networkd-address.h" #include "networkd-address-generation.h" #include "networkd-dhcp6.h" +#include "networkd-ipv6ll.h" #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-ndisc.h" @@ -91,7 +92,8 @@ bool link_ndisc_enabled(Link *link) { void network_adjust_ndisc(Network *network) { assert(network); - if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) { + if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6) && + !network_has_static_ipv6ll_address(network)) { if (network->ndisc > 0) log_warning("%s: IPv6AcceptRA= is enabled but IPv6 link-local addressing is disabled or not supported. " "Disabling IPv6AcceptRA=.", network->filename); diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index a71e01dfbf..02322d4dab 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -14,6 +14,7 @@ #include "networkd-address.h" #include "networkd-address-generation.h" #include "networkd-dhcp-prefix-delegation.h" +#include "networkd-ipv6ll.h" #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-network.h" @@ -815,7 +816,8 @@ void network_adjust_radv(Network *network) { /* For backward compatibility. */ network->dhcp_pd = FLAGS_SET(network->router_prefix_delegation, RADV_PREFIX_DELEGATION_DHCP6); - if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6)) { + if (!FLAGS_SET(network->link_local, ADDRESS_FAMILY_IPV6) && + !network_has_static_ipv6ll_address(network)) { if (network->router_prefix_delegation != RADV_PREFIX_DELEGATION_NONE) log_warning("%s: IPv6PrefixDelegation= is enabled but IPv6 link-local addressing is disabled. " "Disabling IPv6PrefixDelegation=.", network->filename);