diff --git a/src/network/networkd-neighbor-proxy.c b/src/network/networkd-neighbor-proxy.c index a2b050f34b..49899af6a4 100644 --- a/src/network/networkd-neighbor-proxy.c +++ b/src/network/networkd-neighbor-proxy.c @@ -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(); } } } diff --git a/src/network/networkd-neighbor-proxy.h b/src/network/networkd-neighbor-proxy.h index b7e4bb0f6a..49ee2008ae 100644 --- a/src/network/networkd-neighbor-proxy.h +++ b/src/network/networkd-neighbor-proxy.h @@ -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); diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index d627ade828..3c0b8d31b9 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -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) { diff --git a/test/test-network/conf/25-ipv4-proxy-arp-disabled.network b/test/test-network/conf/25-ipv4-proxy-arp-disabled.network index 08e4e8ccc7..e0ca8c4e50 100644 --- a/test/test-network/conf/25-ipv4-proxy-arp-disabled.network +++ b/test/test-network/conf/25-ipv4-proxy-arp-disabled.network @@ -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 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 77b55e84bb..961a3f49a7 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -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):