diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index b4fb051be34..2d9596dfe46 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -1719,6 +1719,15 @@ allow my_server_t localnet_peer_t:peer recv;
+
+ TCPRetransmissionTimeOutSec=
+
+ Specifies the TCP Retransmission Time Out for the route. Takes time values in seconds.
+ This value specifies the timeout of an alive TCP connection, when RTO retransmissions remain unacknowledged.
+ When unset, the kernel's default will be used.
+
+
+
MultiPathRoute=address[@name] [weight]
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 0f87ce24bb4..d0214d131a1 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -196,6 +196,7 @@ Route.GatewayOnlink, config_parse_route_boolean,
Route.IPv6Preference, config_parse_ipv6_route_preference, 0, 0
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.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 5bb2388b410..a13ec818069 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -1247,6 +1247,12 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link
return r;
}
+ if (route->tcp_rto_usec > 0) {
+ r = sd_netlink_message_append_u32(m, RTAX_RTO_MIN, route->tcp_rto_usec / USEC_PER_MSEC);
+ if (r < 0)
+ return r;
+ }
+
r = sd_netlink_message_close_container(m);
if (r < 0)
return r;
@@ -2752,6 +2758,58 @@ int config_parse_route_mtu(
return 0;
}
+int config_parse_route_tcp_rto(
+ 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) {
+
+ Network *network = userdata;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
+ usec_t usec;
+ 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;
+ }
+
+ r = parse_sec(rvalue, &usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to parse route TCP retransmission time out (RTO) sec '%s', ignoring: %m", rvalue);
+ return 0;
+ }
+
+ if (usec != USEC_INFINITY &&
+ DIV_ROUND_UP(usec, USEC_PER_SEC) > UINT32_MAX) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Route TCP retransmission time out (RTO) = must be in the range 0...%"PRIu32"ms, ignoring: %s", UINT32_MAX, rvalue);
+ return 0;
+ }
+
+ n->tcp_rto_usec = usec;
+
+ TAKE_PTR(n);
+ return 0;
+}
+
int config_parse_multipath_route(
const char *unit,
const char *filename,
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index 0ecabc26477..f64d081fe26 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -56,6 +56,7 @@ struct Route {
unsigned flags;
int gateway_onlink; /* Only used in conf parser and route_section_verify(). */
uint32_t nexthop_id;
+ usec_t tcp_rto_usec;
bool scope_set:1;
bool table_set:1;
@@ -125,6 +126,7 @@ 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_tcp_window);
+CONFIG_PARSER_PROTOTYPE(config_parse_route_tcp_rto);
CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route);
CONFIG_PARSER_PROTOTYPE(config_parse_tcp_congestion);
diff --git a/test/test-network/conf/25-route-congctl.network b/test/test-network/conf/25-route-congctl.network
index f924d73cd97..2af783ad14e 100644
--- a/test/test-network/conf/25-route-congctl.network
+++ b/test/test-network/conf/25-route-congctl.network
@@ -10,7 +10,9 @@ Address=149.10.124.58/28
[Route]
Destination=2001:1234:5:8fff:ff:ff:ff:ff/128
TCPCongestionControlAlgorithm=dctcp
+TCPRetransmissionTimeOutSec=300s
[Route]
Destination=149.10.124.66
TCPCongestionControlAlgorithm=dctcp
+TCPRetransmissionTimeOutSec=300s
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 799d3bf784d..2257003c0b4 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -3175,6 +3175,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities):
print(output)
self.assertIn('149.10.124.66 proto static', output)
self.assertIn('congctl dctcp', output)
+ self.assertIn('rto_min 300s', output)
@expectedFailureIfModuleIsNotAvailable('vrf')
def test_route_vrf(self):