diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index bbfc9a7af0..b9f49a43a8 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 4f27ccc81b..94b87d2179 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 0000000000..0dba1892bd
--- /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 7ee6ee1112..beaefbdc89 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