From 07021ed4f5ee5e34b06fcba97cab2c6214f601c9 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 20 Apr 2025 09:31:32 +0900 Subject: [PATCH 1/3] network/link: move logging --- src/network/networkd-link.c | 40 +++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9cc19fb4d3..64db17c3d3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1747,6 +1747,8 @@ static int link_carrier_gained(Link *link) { assert(link); + log_link_info(link, "Gained carrier"); + r = event_source_disable(link->carrier_lost_timer); if (r < 0) log_link_warning_errno(link, r, "Failed to disable carrier lost timer, ignoring: %m"); @@ -1849,6 +1851,8 @@ static int link_carrier_lost(Link *link) { assert(link); + log_link_info(link, "Lost carrier"); + if (link->iftype == ARPHRD_CAN) /* let's shortcut things for CAN which doesn't need most of what's done below. */ usec = 0; @@ -1902,6 +1906,8 @@ static int link_admin_state_up(Link *link) { /* This is called every time an interface admin state changes to up; * specifically, when IFF_UP flag changes from unset to set. */ + log_link_info(link, "Link UP"); + if (!link->network) return 0; @@ -1920,6 +1926,8 @@ static int link_admin_state_up(Link *link) { static int link_admin_state_down(Link *link) { assert(link); + log_link_info(link, "Link DOWN"); + link_forget_nexthops(link); link_forget_routes(link); @@ -2167,33 +2175,21 @@ static int link_update_flags(Link *link, sd_netlink_message *message) { link_update_operstate(link, true); - if (!link_was_admin_up && (link->flags & IFF_UP)) { - log_link_info(link, "Link UP"); + r = 0; + if (!link_was_admin_up && (link->flags & IFF_UP)) r = link_admin_state_up(link); - if (r < 0) - return r; - } else if (link_was_admin_up && !(link->flags & IFF_UP)) { - log_link_info(link, "Link DOWN"); - + else if (link_was_admin_up && !(link->flags & IFF_UP)) r = link_admin_state_down(link); - if (r < 0) - return r; - } - - if (!had_carrier && link_has_carrier(link)) { - log_link_info(link, "Gained carrier"); + if (r < 0) + return r; + if (!had_carrier && link_has_carrier(link)) r = link_carrier_gained(link); - if (r < 0) - return r; - } else if (had_carrier && !link_has_carrier(link)) { - log_link_info(link, "Lost carrier"); - - r = link_carrier_lost(link); - if (r < 0) - return r; - } + else if (had_carrier && !link_has_carrier(link)) + link_carrier_lost(link); + if (r < 0) + return r; return 0; } From b5c83cd5a7ec3f5154106478301dd855ae706107 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 20 Apr 2025 10:46:36 +0900 Subject: [PATCH 2/3] network/ipv4ll: introduce ipv4ll_start() helper function No effective functional change. Just refactoring. --- src/network/networkd-dhcp4.c | 24 ++++++++++-------------- src/network/networkd-ipv4ll.c | 28 ++++++++++++++++++++++++++++ src/network/networkd-ipv4ll.h | 1 + src/network/networkd-link.c | 6 +++--- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 85493334f5..d793d60362 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -16,7 +16,7 @@ #include "networkd-dhcp-prefix-delegation.h" #include "networkd-dhcp4-bus.h" #include "networkd-dhcp4.h" -#include "networkd-ipv4acd.h" +#include "networkd-ipv4ll.h" #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-network.h" @@ -1192,13 +1192,11 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { return 0; } - if (link->ipv4ll && !sd_ipv4ll_is_running(link->ipv4ll)) { - log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address"); - - r = sd_ipv4ll_start(link->ipv4ll); - if (r < 0 && r != -ESTALE) /* On exit, we cannot and should not start sd-ipv4ll. */ - return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); - } + r = ipv4ll_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); + if (r > 0) + log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address."); if (link->dhcp_lease) { if (link->network->dhcp_send_release) { @@ -1270,13 +1268,11 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { break; case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE: - if (link->ipv4ll && !sd_ipv4ll_is_running(link->ipv4ll)) { + r = ipv4ll_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); + if (r > 0) log_link_debug(link, "Problems acquiring DHCP lease, acquiring IPv4 link-local address"); - - r = sd_ipv4ll_start(link->ipv4ll); - if (r < 0) - return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); - } break; default: diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index ef8b0876b5..7522bca0aa 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -264,6 +264,34 @@ int ipv4ll_configure(Link *link) { return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager); } +int ipv4ll_start(Link *link) { + int r; + + assert(link); + + if (!link->ipv4ll) + return 0; + + if (sd_ipv4ll_is_running(link->ipv4ll)) + return 0; + + if (!link_has_carrier(link)) + return 0; + + /* On exit, we cannot and should not start sd-ipv4ll. */ + r = sd_event_get_state(link->manager->event); + if (r < 0) + return r; + if (r == SD_EVENT_FINISHED) + return 0; + + r = sd_ipv4ll_start(link->ipv4ll); + if (r < 0) + return r; + + return 1; /* started */ +} + int link_drop_ipv4ll_config(Link *link, Network *network) { int ret = 0; diff --git a/src/network/networkd-ipv4ll.h b/src/network/networkd-ipv4ll.h index f380afe9ec..71cddbdd5b 100644 --- a/src/network/networkd-ipv4ll.h +++ b/src/network/networkd-ipv4ll.h @@ -11,6 +11,7 @@ typedef struct Network Network; bool link_ipv4ll_enabled(Link *link); int ipv4ll_configure(Link *link); +int ipv4ll_start(Link *link); int link_drop_ipv4ll_config(Link *link, Network *network); int ipv4ll_update_mac(Link *link); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 64db17c3d3..b13b668c1a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -728,11 +728,11 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) { return log_link_warning_errno(link, r, "Could not set IPv4 link-local start address: %m"); } - r = sd_ipv4ll_start(link->ipv4ll); + r = ipv4ll_start(link); if (r < 0) return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); - - log_link_debug(link, "Acquiring IPv4 link-local address."); + if (r > 0) + log_link_debug(link, "Acquiring IPv4 link-local address."); } r = link_start_dhcp4_server(link); From a06e88426444ac50fde712e426ec9a4234ae5576 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 20 Apr 2025 10:23:32 +0900 Subject: [PATCH 3/3] network: enable ARP= when IPv4LL/IPv4ACD is enabled We can run sd-ipv4ll/sd-ipv4acd also on an interface with IFF_NOARP flag, but that may cause address conflict with other hosts. Let's enable ARPing when sd-ipv4ll/sd-ipv4acd are enabled unless ARP= is explicitly disabled. --- man/systemd.network.xml | 21 ++++++++++++++------- src/network/networkd-ipv4acd.c | 12 ++++++++++++ src/network/networkd-ipv4acd.h | 1 + src/network/networkd-setlink.c | 34 +++++++++++++++++++++++++++++++--- 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 40aa1b449b..d77ce61160 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -189,13 +189,14 @@ ARP= - Takes a boolean. If set to true, the IPv4 ARP (low-level Address Resolution Protocol) - and IPv6 NDP (Neighbor Discovery Protocol) for this interface are enabled. When unset, the - kernel's default will be used. - For example, disabling ARP is useful when creating multiple MACVLAN or VLAN virtual - interfaces atop a single lower-level physical interface, which will then only serve as a - link/"bridge" device aggregating traffic to the same physical link and not participate in - the network otherwise. Defaults to unset. + Takes a boolean. If set to true, the IPv4 ARP (low-level Address Resolution Protocol) and + IPv6 NDP (Neighbor Discovery Protocol) for this interface are enabled. For example, disabling ARP + is useful when creating multiple MACVLAN or VLAN virtual interfaces atop a single lower-level + physical interface, which will then only serve as a link/"bridge" device aggregating traffic to the + same physical link and not participate in the network otherwise. Defaults to unset, and enabled + when the IPv4 link-local addressing is enabled in LinkLocalAddressing= or an + IPv4 address with DuplicateAddressDetection= enabled is requested. Otherwise, + the kernel's default will be used. @@ -459,6 +460,9 @@ MACVLAN=/MACVTAP= has Mode=passthru, or otherwise. + When IPv4 link-local addressing is enabled, ARP= is enabled unless if it + is explicitly configured. + @@ -1439,6 +1443,9 @@ DuplicateAddressDetection=none ipv4 for IPv4 link-local addresses (169.254.0.0/16), ipv6 for IPv6 addresses, and none otherwise. + When enabled, regradless implicitly or not, ARP= is enabled unless it is + explicitly configured. + diff --git a/src/network/networkd-ipv4acd.c b/src/network/networkd-ipv4acd.c index 4785b96f9f..0ecdee0893 100644 --- a/src/network/networkd-ipv4acd.c +++ b/src/network/networkd-ipv4acd.c @@ -66,6 +66,18 @@ static bool address_ipv4acd_enabled(Link *link, const Address *address) { return link_ipv4acd_supported(link); } +bool link_ipv4acd_enabled(Link *link) { + assert(link); + assert(link->network); + + Address *address; + ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section) + if (address_ipv4acd_enabled(link, address)) + return true; + + return false; +} + bool ipv4acd_bound(Link *link, const Address *address) { sd_ipv4acd *acd; diff --git a/src/network/networkd-ipv4acd.h b/src/network/networkd-ipv4acd.h index 54da435679..fc9f92d4f4 100644 --- a/src/network/networkd-ipv4acd.h +++ b/src/network/networkd-ipv4acd.h @@ -5,6 +5,7 @@ typedef struct Address Address; typedef struct Link Link; bool link_ipv4acd_supported(Link *link); +bool link_ipv4acd_enabled(Link *link); bool ipv4acd_bound(Link *link, const Address *address); int ipv4acd_configure(Link *link, const Address *address); void ipv4acd_detach(Link *link, const Address *address); diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c index c0c1da1b16..d4606533a7 100644 --- a/src/network/networkd-setlink.c +++ b/src/network/networkd-setlink.c @@ -12,6 +12,8 @@ #include "netlink-util.h" #include "networkd-address.h" #include "networkd-can.h" +#include "networkd-ipv4acd.h" +#include "networkd-ipv4ll.h" #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-queue.h" @@ -178,6 +180,30 @@ static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Request return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler); } +static int link_get_arp(Link *link) { + assert(link); + + /* This returns tristate. */ + + if (!link->network) + return -1; + + /* If ARP= is explicitly specified, use the setting. */ + if (link->network->arp >= 0) + return link->network->arp; + + /* Enable ARP when IPv4ACD is enabled. */ + if (link_ipv4acd_enabled(link)) + return true; + + /* Similary, enable ARP when IPv4LL is enabled. */ + if (link_ipv4ll_enabled(link)) + return true; + + /* Otherwise, do not change the flag. */ + return -1; +} + static int link_configure_fill_message( Link *link, sd_netlink_message *req, @@ -360,9 +386,11 @@ static int link_configure_fill_message( case REQUEST_TYPE_SET_LINK_FLAGS: { unsigned ifi_change = 0, ifi_flags = 0; - if (link->network->arp >= 0) { + int arp = link_get_arp(link); + + if (arp >= 0) { ifi_change |= IFF_NOARP; - SET_FLAG(ifi_flags, IFF_NOARP, link->network->arp == 0); + SET_FLAG(ifi_flags, IFF_NOARP, arp == 0); } if (link->network->multicast >= 0) { @@ -844,7 +872,7 @@ int link_request_to_set_flags(Link *link) { assert(link); assert(link->network); - if (link->network->arp < 0 && + if (link_get_arp(link) < 0 && link->network->multicast < 0 && link->network->allmulticast < 0 && link->network->promiscuous < 0)