From 51b87530177f529f8906d155730e6e4395e4761f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 26 Aug 2022 14:33:54 +0900 Subject: [PATCH 1/3] sd-netlink: fix attribute type for RTAX_CC_ALGO --- src/libsystemd/sd-netlink/netlink-types-rtnl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd/sd-netlink/netlink-types-rtnl.c b/src/libsystemd/sd-netlink/netlink-types-rtnl.c index be6f7cf791..919512d110 100644 --- a/src/libsystemd/sd-netlink/netlink-types-rtnl.c +++ b/src/libsystemd/sd-netlink/netlink-types-rtnl.c @@ -929,7 +929,7 @@ static const NLAPolicy rtnl_route_metrics_policies[] = { [RTAX_RTO_MIN] = BUILD_POLICY(U32), [RTAX_INITRWND] = BUILD_POLICY(U32), [RTAX_QUICKACK] = BUILD_POLICY(U32), - [RTAX_CC_ALGO] = BUILD_POLICY(U32), + [RTAX_CC_ALGO] = BUILD_POLICY(STRING), [RTAX_FASTOPEN_NO_COOKIE] = BUILD_POLICY(U32), }; From dc7c21f00109886c52f04a4162ad6e36a43ca8c5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 26 Aug 2022 14:43:07 +0900 Subject: [PATCH 2/3] network: introduce TCPCongestionControlAlgorithm= Closes #24432. --- man/systemd.network.xml | 9 ++++ src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-route.c | 54 ++++++++++++++++++++++++ src/network/networkd-route.h | 2 + test/fuzz/fuzz-network-parser/directives | 1 + 5 files changed, 67 insertions(+) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 818df99e5a..b9d74d6097 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1622,6 +1622,15 @@ Table=1234 + + TCPCongestionControlAlgorithm= + + Specifies the TCP congestion control algorithm for the route. Takes a name of the algorithm, + e.g. bbr, dctcp, or vegas. 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 a4f038681a..dce7339d2f 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -196,6 +196,7 @@ Route.Type, config_parse_route_type, Route.InitialCongestionWindow, config_parse_tcp_window, 0, 0 Route.InitialAdvertisedReceiveWindow, config_parse_tcp_window, 0, 0 Route.TCPAdvertisedMaximumSegmentSize, config_parse_tcp_advmss, 0, 0 +Route.TCPCongestionControlAlgorithm, config_parse_tcp_congestion, 0, 0 Route.QuickAck, config_parse_route_boolean, 0, 0 Route.FastOpenNoCookie, config_parse_route_boolean, 0, 0 Route.TTLPropagate, config_parse_route_boolean, 0, 0 diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 71e578d898..4f097364a1 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -107,6 +107,8 @@ Route *route_free(Route *route) { sd_event_source_disable_unref(route->expire); + free(route->tcp_congestion_control_algo); + return mfree(route); } @@ -319,6 +321,7 @@ int route_get(Manager *manager, Link *link, const Route *in, Route **ret) { int route_dup(const Route *src, Route **ret) { _cleanup_(route_freep) Route *dest = NULL; + int r; /* This does not copy mulipath routes. */ @@ -336,6 +339,11 @@ int route_dup(const Route *src, Route **ret) { dest->manager = NULL; dest->multipath_routes = NULL; dest->expire = NULL; + dest->tcp_congestion_control_algo = NULL; + + r = free_and_strdup(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo); + if (r < 0) + return r; *ret = TAKE_PTR(dest); return 0; @@ -1231,6 +1239,12 @@ static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link return r; } + if (!isempty(route->tcp_congestion_control_algo)) { + r = sd_netlink_message_append_string(m, RTAX_CC_ALGO, route->tcp_congestion_control_algo); + if (r < 0) + return r; + } + r = sd_netlink_message_close_container(m); if (r < 0) return r; @@ -2498,6 +2512,46 @@ int config_parse_route_type( return 0; } +int config_parse_tcp_congestion( + 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; + 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 = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, + rvalue, &n->tcp_congestion_control_algo, userdata); + if (r < 0) + return r; + + TAKE_PTR(n); + return 0; +} + int config_parse_tcp_advmss( const char *unit, const char *filename, diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index b431e1a30f..fd4433eae4 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -50,6 +50,7 @@ struct Route { uint32_t initcwnd; uint32_t initrwnd; uint32_t advmss; + char *tcp_congestion_control_algo; unsigned char pref; unsigned flags; int gateway_onlink; /* Only used in conf parser and route_section_verify(). */ @@ -123,5 +124,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_route_type); CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window); CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu); CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route); +CONFIG_PARSER_PROTOTYPE(config_parse_tcp_congestion); CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss); CONFIG_PARSER_PROTOTYPE(config_parse_route_nexthop); diff --git a/test/fuzz/fuzz-network-parser/directives b/test/fuzz/fuzz-network-parser/directives index b7e8f16834..6f76f7ee18 100644 --- a/test/fuzz/fuzz-network-parser/directives +++ b/test/fuzz/fuzz-network-parser/directives @@ -189,6 +189,7 @@ Metric= TTLPropagate= MultiPathRoute= TCPAdvertisedMaximumSegmentSize= +TCPCongestionControlAlgorithm= NextHop= [Network] KeepMaster= From 93e898d6247d888cf97d171f49e3d7ed019085da Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 26 Aug 2022 15:01:30 +0900 Subject: [PATCH 3/3] test-network: add test for TCPCongestionControlAlgorithm= --- .../test-network/conf/25-route-congctl.network | 16 ++++++++++++++++ test/test-network/systemd-networkd-tests.py | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/test-network/conf/25-route-congctl.network diff --git a/test/test-network/conf/25-route-congctl.network b/test/test-network/conf/25-route-congctl.network new file mode 100644 index 0000000000..f924d73cd9 --- /dev/null +++ b/test/test-network/conf/25-route-congctl.network @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=dummy98 + +[Network] +IPv6AcceptRA=no +Address=2001:1234:5:8f63::1/128 +Address=149.10.124.58/28 + +[Route] +Destination=2001:1234:5:8fff:ff:ff:ff:ff/128 +TCPCongestionControlAlgorithm=dctcp + +[Route] +Destination=149.10.124.66 +TCPCongestionControlAlgorithm=dctcp diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 284bc3146f..1dddd86331 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -2800,6 +2800,24 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58') self.assertRegex(output, '149.10.124.66 via inet6 2001:1234:5:8fff:ff:ff:ff:ff proto static') + @expectedFailureIfModuleIsNotAvailable('tcp_dctcp') + def test_route_congctl(self): + copy_network_unit('25-route-congctl.network', '12-dummy.netdev') + start_networkd() + self.wait_online(['dummy98:routable']) + + print('### ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff') + output = check_output('ip -6 route show dev dummy98 2001:1234:5:8fff:ff:ff:ff:ff') + print(output) + self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output) + self.assertIn('congctl dctcp', output) + + print('### ip -4 route show dev dummy98 149.10.124.66') + output = check_output('ip -4 route show dev dummy98 149.10.124.66') + print(output) + self.assertIn('149.10.124.66 proto static', output) + self.assertIn('congctl dctcp', output) + @expectedFailureIfModuleIsNotAvailable('vrf') def test_route_vrf(self): copy_network_unit('25-route-vrf.network', '12-dummy.netdev',