From: Quentin Deslandes Date: Tue, 18 Nov 2025 20:36:49 +0000 (+0100) Subject: network: clear existing routes if Gateway= is empty in [Network] X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5b0e262f451af6b5cab0fdb239512c3ae89c25d0;p=thirdparty%2Fsystemd.git network: clear existing routes if Gateway= is empty in [Network] Add support for an empty Gateway= in [Network] to clear the existing routes. This change will allow users to remove the default route from a drop-in file. --- diff --git a/man/systemd.network.xml b/man/systemd.network.xml index bbfc9a7af09..b9f49a43a80 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -747,6 +747,9 @@ DuplicateAddressDetection=none This is a short-hand for a [Route] section only containing a Gateway= key. This option may be specified more than once. + If an empty string is specified, then the all previous assignments in both [Network] and + [Route] sections are cleared. + diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 4f27ccc81be..94b87d21799 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -2008,6 +2008,12 @@ int config_parse_route_section( if (streq(section, "Network")) { assert(streq_ptr(lvalue, "Gateway")); + /* Clear all previously defined routes when Gateway= (empty) is set in [Network] section */ + if (isempty(rvalue)) { + network->routes_by_section = hashmap_free(network->routes_by_section); + return 0; + } + /* we are not in an Route section, so use line number instead */ r = route_new_static(network, filename, line, &route); } else diff --git a/test/test-network/conf/25-gateway-clear-routes.network b/test/test-network/conf/25-gateway-clear-routes.network new file mode 100644 index 00000000000..0dba1892bd8 --- /dev/null +++ b/test/test-network/conf/25-gateway-clear-routes.network @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=dummy98 + +[Network] +Address=10.0.0.1/24 +Gateway=10.0.0.2 + +[Route] +Destination=192.168.1.0/24 +Gateway=10.0.0.254 + +[Route] +Destination=192.168.2.0/24 +Gateway=10.0.0.253 + +[Network] +Gateway= diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 7ee6ee11129..beaefbdc895 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -4633,6 +4633,21 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertNotIn('149.10.124.59', output) self.assertIn('default via 149.10.124.60 proto static', output) + def test_gateway_clear_routes(self): + copy_network_unit('25-gateway-clear-routes.network', '12-dummy.netdev') + start_networkd() + self.wait_online('dummy98:routable') + + print('### ip -4 route show dev dummy98') + output = check_output('ip -4 route show dev dummy98') + print(output) + # All routes should be cleared - no default gateway, no [Route] section routes + self.assertNotIn('default via 10.0.0.2', output) + self.assertNotIn('192.168.1.0/24', output) + self.assertNotIn('192.168.2.0/24', output) + # Only the directly connected network should remain + self.assertIn('10.0.0.0/24 proto kernel scope link src 10.0.0.1', output) + def test_ip_route_ipv6_src_route(self): # a dummy device does not make the addresses go through tentative state, so we # reuse a bond from an earlier test, which does make the addresses go through