diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml
index 018bde0fbf..6d1dfc78ce 100644
--- a/man/networkd.conf.xml
+++ b/man/networkd.conf.xml
@@ -90,6 +90,17 @@
+
+ ManageForeignNextHops=
+ A boolean. When true, systemd-networkd will remove nexthops
+ that are not configured in .network files (except for routes with protocol
+ kernel). When false, it will
+ not remove any foreign nexthops, keeping them even if they are not configured in a .network file.
+ Defaults to yes.
+
+
+
+
RouteTable=
Defines the route table name. Takes a whitespace-separated list of the pairs of
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 3436a32b11..0bad731b0d 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1715,8 +1715,10 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix
Id=
- The id of the next hop. Takes an integer in the range 1…4294967295. If unspecified,
- then automatically chosen by kernel.
+ The id of the next hop. Takes an integer in the range 1…4294967295.
+ This is mandatory if ManageForeignNextHops=no is specified in
+ networkd.conf5.
+ Otherwise, if unspecified, an unused ID will be automatically picked.
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
index 8542ffa6b5..c9e3c937f4 100644
--- a/src/network/networkd-gperf.gperf
+++ b/src/network/networkd-gperf.gperf
@@ -25,6 +25,7 @@ Network.SpeedMeter, config_parse_bool,
Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec)
Network.ManageForeignRoutingPolicyRules, config_parse_bool, 0, offsetof(Manager, manage_foreign_rules)
Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes)
+Network.ManageForeignNextHops, config_parse_bool, 0, offsetof(Manager, manage_foreign_nexthops)
Network.RouteTable, config_parse_route_table_names, 0, 0
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Manager, ipv6_privacy_extensions)
DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp_duid)
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index fca5d76618..6ee01b28e0 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -591,6 +591,7 @@ int manager_new(Manager **ret, bool test_mode) {
.online_state = _LINK_ONLINE_STATE_INVALID,
.manage_foreign_routes = true,
.manage_foreign_rules = true,
+ .manage_foreign_nexthops = true,
.ethtool_fd = -EBADF,
.dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN,
@@ -867,6 +868,9 @@ static int manager_enumerate_nexthop(Manager *m) {
assert(m);
assert(m->rtnl);
+ if (!m->manage_foreign_nexthops)
+ return 0;
+
r = sd_rtnl_message_new_nexthop(m->rtnl, &req, RTM_GETNEXTHOP, 0, 0);
if (r < 0)
return r;
diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h
index fbef5289d2..a4eb7d78af 100644
--- a/src/network/networkd-manager.h
+++ b/src/network/networkd-manager.h
@@ -38,6 +38,7 @@ struct Manager {
bool restarting;
bool manage_foreign_routes;
bool manage_foreign_rules;
+ bool manage_foreign_nexthops;
Set *dirty_links;
Set *new_wlan_ifindices;
diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c
index e2ded28197..442e16b026 100644
--- a/src/network/networkd-nexthop.c
+++ b/src/network/networkd-nexthop.c
@@ -318,6 +318,10 @@ static int nexthop_acquire_id(Manager *manager, NextHop *nexthop) {
if (nexthop->id > 0)
return 0;
+ /* If ManageForeignNextHops=no, nexthop with id == 0 should be already filtered by
+ * nexthop_section_verify(). */
+ assert(manager->manage_foreign_nexthops);
+
/* Find the lowest unused ID. */
ORDERED_HASHMAP_FOREACH(network, manager->networks) {
@@ -988,6 +992,13 @@ static int nexthop_section_verify(NextHop *nh) {
if (section_is_invalid(nh->section))
return -EINVAL;
+ if (!nh->network->manager->manage_foreign_nexthops && nh->id == 0)
+ return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+ "%s: [NextHop] section without specifying Id= is not supported "
+ "if ManageForeignNextHops=no is set in networkd.conf. "
+ "Ignoring [NextHop] section from line %u.",
+ nh->section->filename, nh->section->line);
+
if (!hashmap_isempty(nh->group)) {
if (in_addr_is_set(nh->family, &nh->gw))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
diff --git a/src/network/networkd.conf b/src/network/networkd.conf
index e5a5e88926..2994b8b70c 100644
--- a/src/network/networkd.conf
+++ b/src/network/networkd.conf
@@ -21,6 +21,7 @@
#SpeedMeterIntervalSec=10sec
#ManageForeignRoutingPolicyRules=yes
#ManageForeignRoutes=yes
+#ManageForeignNextHops=yes
#RouteTable=
#IPv6PrivacyExtensions=no