network: enable ARP when IPv4LL and/or IPv4ACD is enabled (#37190)

This commit is contained in:
Yu Watanabe
2025-04-23 08:53:49 +09:00
committed by GitHub
8 changed files with 118 additions and 49 deletions

View File

@@ -189,13 +189,14 @@
<varlistentry>
<term><varname>ARP=</varname></term>
<listitem>
<para>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.</para>
<para> 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.</para>
<para>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 <varname>LinkLocalAddressing=</varname> or an
IPv4 address with <varname>DuplicateAddressDetection=</varname> enabled is requested. Otherwise,
the kernel's default will be used.</para>
<xi:include href="version-info.xml" xpointer="v232"/>
</listitem>
@@ -459,6 +460,9 @@
<varname>MACVLAN=</varname>/<varname>MACVTAP=</varname> has <varname>Mode=passthru</varname>,
or <option>ipv6</option> otherwise.</para>
<para>When IPv4 link-local addressing is enabled, <varname>ARP=</varname> is enabled unless if it
is explicitly configured.</para>
<xi:include href="version-info.xml" xpointer="v219"/>
</listitem>
</varlistentry>
@@ -1439,6 +1443,9 @@ DuplicateAddressDetection=none</programlisting></para>
<literal>ipv4</literal> for IPv4 link-local addresses (169.254.0.0/16), <literal>ipv6</literal>
for IPv6 addresses, and <literal>none</literal> otherwise.</para>
<para>When enabled, regradless implicitly or not, <varname>ARP=</varname> is enabled unless it is
explicitly configured.</para>
<xi:include href="version-info.xml" xpointer="v232"/>
</listitem>
</varlistentry>

View File

@@ -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:

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
@@ -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;
}

View File

@@ -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)