diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 2d9596dfe4..db9a9ac25d 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1617,6 +1617,13 @@ allow my_server_t localnet_peer_t:peer recv;
+
+ HopLimit=
+
+ Configures per route hop limit. See also IPv6HopLimit=.
+
+
+
Protocol=
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index d0214d131a..c3f286e8bd 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -197,6 +197,7 @@ Route.IPv6Preference, config_parse_ipv6_route_preference,
Route.Protocol, config_parse_route_protocol, 0, 0
Route.Type, config_parse_route_type, 0, 0
Route.TCPRetransmissionTimeOutSec, config_parse_route_tcp_rto, 0, 0
+Route.HopLimit, config_parse_route_hop_limit, 0, 0
Route.InitialCongestionWindow, config_parse_route_tcp_window, 0, 0
Route.InitialAdvertisedReceiveWindow, config_parse_route_tcp_window, 0, 0
Route.TCPAdvertisedMaximumSegmentSize, config_parse_tcp_advmss, 0, 0
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index a13ec81806..7af697c16d 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -2532,6 +2532,67 @@ int config_parse_route_type(
return 0;
}
+int config_parse_route_hop_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
+ Network *network = userdata;
+ uint32_t k;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = route_new_static(network, filename, section_line, &n);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to allocate route, ignoring assignment: %m");
+ return 0;
+ }
+
+ if (isempty(rvalue)) {
+ n->hop_limit = 0;
+ TAKE_PTR(n);
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Could not parse route hop limit %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
+ return 0;
+ }
+ if (k > 255) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Specified route hop limit %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
+ return 0;
+ }
+ if (k == 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Invalid route hop limit %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
+ return 0;
+ }
+
+ n->hop_limit = k;
+
+ TAKE_PTR(n);
+ return 0;
+}
+
int config_parse_tcp_congestion(
const char *unit,
const char *filename,
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index f64d081fe2..3d85889a2f 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -125,6 +125,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_route_preference);
CONFIG_PARSER_PROTOTYPE(config_parse_route_protocol);
CONFIG_PARSER_PROTOTYPE(config_parse_route_type);
CONFIG_PARSER_PROTOTYPE(config_parse_route_tcp_window);
+CONFIG_PARSER_PROTOTYPE(config_parse_route_hop_limit);
CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window);
CONFIG_PARSER_PROTOTYPE(config_parse_route_tcp_rto);
CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu);
diff --git a/test/test-network/conf/25-route-static.network b/test/test-network/conf/25-route-static.network
index 6aa3ec66dc..44acb19f34 100644
--- a/test/test-network/conf/25-route-static.network
+++ b/test/test-network/conf/25-route-static.network
@@ -44,6 +44,10 @@ InitialAdvertisedReceiveWindow=30
Destination=192.168.1.3
TCPAdvertisedMaximumSegmentSize=30
+[Route]
+Destination=192.168.1.4
+HopLimit=122
+
[Route]
Type=blackhole
Destination=202.54.1.2
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 2257003c0b..5910d0d8da 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -2946,6 +2946,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
self.assertIn('192.168.1.1 proto static scope link initcwnd 20', output)
self.assertIn('192.168.1.2 proto static scope link initrwnd 30', output)
self.assertIn('192.168.1.3 proto static scope link advmss 30', output)
+ self.assertIn('192.168.1.4 proto static scope link hoplimit 122', output)
self.assertIn('multicast 149.10.123.4 proto static', output)
print('### ip -4 route show dev dummy98 default')