network: adjust sysctl setting in network_adjust_neighbor_proxy()

This also makes IPv4 proxy neighbor entries independent of proxy_arp
sysctl. We can configure IPv4 proxy neighbor entries even if proxy_arp
is disabled.
This commit is contained in:
Yu Watanabe
2026-08-17 17:17:18 +09:00
parent 78ca255140
commit a9e74be13c
5 changed files with 42 additions and 80 deletions
+25 -49
View File
@@ -15,61 +15,37 @@
#include "socket-util.h"
#include "string-util.h"
bool network_has_neighbor_proxy_address(const Network *network, int family) {
struct in_addr_data *a;
assert(network);
assert(IN_SET(family, AF_INET, AF_INET6));
SET_FOREACH(a, network->neighbor_proxy_addresses)
if (a->family == family)
return true;
return false;
}
static void network_drop_neighbor_proxy_addresses(Network *network, int family) {
struct in_addr_data *a;
assert(network);
assert(IN_SET(family, AF_INET, AF_INET6));
SET_FOREACH(a, network->neighbor_proxy_addresses)
if (a->family == family)
free(set_remove(network->neighbor_proxy_addresses, a));
if (set_isempty(network->neighbor_proxy_addresses))
network->neighbor_proxy_addresses = set_free(network->neighbor_proxy_addresses);
}
void network_adjust_neighbor_proxy(Network *network) {
assert(network);
if (set_isempty(network->neighbor_proxy_addresses))
return;
struct in_addr_data *a;
SET_FOREACH(a, network->neighbor_proxy_addresses) {
switch (a->family) {
case AF_INET6:
if (!socket_ipv6_is_supported()) {
log_warning("%s: Specified IPv6 proxy NDP address %s, but IPv6 is not supported by the kernel, ignoring.",
network->filename, IN_ADDR_TO_STRING(a->family, &a->address));
free(set_remove(network->neighbor_proxy_addresses, a));
continue;
}
/* If IPv6 is not supported by the kernel, drop any IPv6 entries up front. */
if (!socket_ipv6_is_supported() &&
network_has_neighbor_proxy_address(network, AF_INET6)) {
log_once(LOG_WARNING,
"%s: IPv6 proxy NDP addresses are set, but IPv6 is not supported by kernel, "
"ignoring IPv6 proxy NDP addresses.", network->filename);
network_drop_neighbor_proxy_addresses(network, AF_INET6);
}
if (network->ipv6_proxy_ndp == 0) {
log_warning("%s: Specified IPv6 proxy NDP address %s, but IPv6ProxyNDP= is disabled, ignoring.",
network->filename, IN_ADDR_TO_STRING(a->family, &a->address));
free(set_remove(network->neighbor_proxy_addresses, a));
continue;
}
/* Drop per-family entries when the corresponding proxy sysctl was explicitly disabled.
* For IPv6 the proxy_ndp sysctl is required for manual entries to take effect; for IPv4 we
* apply the same rule for consistency so that an explicit IPv4ProxyARP=no is respected. */
int family;
FOREACH_ARGUMENT(family, AF_INET, AF_INET6) {
int tristate = family == AF_INET ? network->proxy_arp : network->ipv6_proxy_ndp;
/* IPv6 proxy NDP entry requires that proxy_ndp sysctl is enabled. */
network->ipv6_proxy_ndp = true;
break;
if (tristate == 0 && network_has_neighbor_proxy_address(network, family)) {
log_warning("%s: %s is disabled. Ignoring %s.",
network->filename,
family == AF_INET ? "IPv4ProxyARP=" : "IPv6ProxyNDP=",
family == AF_INET ? "IPv4ProxyARPAddress=" : "IPv6ProxyNDPAddress=");
network_drop_neighbor_proxy_addresses(network, family);
case AF_INET:
/* IPv4 proxy ARP entry does NOT require that proxy_arp sysctl is enabled. */
break;
default:
assert_not_reached();
}
}
}
-2
View File
@@ -3,8 +3,6 @@
#include "networkd-forward.h"
bool network_has_neighbor_proxy_address(const Network *network, int family);
void network_adjust_neighbor_proxy(Network *network);
int link_request_static_neighbor_proxy_addresses(Link *link);
+8 -20
View File
@@ -18,7 +18,6 @@
#include "networkd-lldp-tx.h"
#include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-neighbor-proxy.h"
#include "networkd-network.h"
#include "networkd-sysctl.h"
#include "path-util.h"
@@ -271,25 +270,18 @@ static int link_update_ipv6_sysctl(Link *link) {
}
static int link_set_proxy_arp(Link *link) {
bool v;
assert(link);
assert(link->manager);
if (!link_is_configured_for_family(link, AF_INET))
return 0;
if (link->network->proxy_arp >= 0)
v = link->network->proxy_arp;
else if (network_has_neighbor_proxy_address(link->network, AF_INET))
/* If IPv4ProxyARP= is not explicitly set, but per-address IPv4ProxyARPAddress=
* entries are configured, implicitly enable the proxy_arp sysctl. This matches
* the behavior of IPv6ProxyNDPAddress= which implies IPv6ProxyNDP=yes. */
v = true;
else
if (link->network->proxy_arp < 0)
return 0;
return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", v, manager_get_sysctl_shadow(link->manager));
return sysctl_write_ip_property_boolean(
AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp,
manager_get_sysctl_shadow(link->manager));
}
static int link_set_proxy_arp_pvlan(Link *link) {
@@ -512,22 +504,18 @@ static int link_set_ipv6_retransmission_time(Link *link) {
}
static int link_set_ipv6_proxy_ndp(Link *link) {
bool v;
assert(link);
assert(link->manager);
if (!link_is_configured_for_family(link, AF_INET6))
return 0;
if (link->network->ipv6_proxy_ndp >= 0)
v = link->network->ipv6_proxy_ndp;
else if (network_has_neighbor_proxy_address(link->network, AF_INET6))
v = true;
else
if (link->network->ipv6_proxy_ndp < 0)
return 0;
return sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v, manager_get_sysctl_shadow(link->manager));
return sysctl_write_ip_property_boolean(
AF_INET6, link->ifname, "proxy_ndp", link->network->ipv6_proxy_ndp,
manager_get_sysctl_shadow(link->manager));
}
int link_set_ipv6_mtu(Link *link, int log_level) {
@@ -4,7 +4,7 @@ Name=dummy98
[Network]
IPv4ProxyARP=no
ProxyNeighbor=192.0.2.1
ProxyNeighbor=192.0.2.2
ProxyNeighbor=192.0.3.1
ProxyNeighbor=192.0.3.2
IPv6AcceptRA=no
Address=10.0.0.1/24
+7 -7
View File
@@ -5384,13 +5384,9 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
for i in range(1, 6):
self.assertRegex(output, f'192.0.2.{i} *proxy')
# When a proxy ARP address is specified, IPv4ProxyARP=yes is implied.
self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '1')
# Even if a proxy ARP address is specified, IPv4ProxyARP=yes is NOT implied.
self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '0')
# Explicit IPv4ProxyARP=no must suppress all IPv4 proxy ARP address entries and
# must not force proxy_arp=1. The module is add-only (no reconcile/remove pass),
# so phase 2 starts from a clean interface: stop networkd, delete the dummy to
# flush the kernel neighbor-proxy table, swap the .network file, and restart.
stop_networkd()
remove_link('dummy98')
remove_network_unit('25-ipv4-proxy-arp.network')
@@ -5398,10 +5394,14 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online('dummy98:routable')
# Even if IPv4ProxyARP= is disabled, proxy ARP addresses can be configured.
output = check_output('ip -4 neighbor show proxy dev dummy98')
print(output)
for i in range(1, 6):
self.assertNotIn(f'192.0.2.{i}', output)
self.assertNotRegex(output, f'192.0.2.{i} *proxy')
for i in range(1, 3):
self.assertRegex(output, f'192.0.3.{i} *proxy')
self.check_ipv4_sysctl_attr('dummy98', 'proxy_arp', '0')
def test_ipv6_neigh_retrans_time(self):