From 4a6e85eac069802c2e01c37e6dd7cdc273c75e99 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 18:27:45 +0800 Subject: [PATCH 1/2] compare the whole route to avoid collapsing them in a set --- .../service/exe/WslCoreTcpIpStateTracking.h | 43 +++++-------------- test/windows/CMakeLists.txt | 1 + test/windows/NetworkTests.cpp | 31 +++++++++++++ 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/windows/service/exe/WslCoreTcpIpStateTracking.h b/src/windows/service/exe/WslCoreTcpIpStateTracking.h index 06ad59e505..5b2d98090c 100644 --- a/src/windows/service/exe/WslCoreTcpIpStateTracking.h +++ b/src/windows/service/exe/WslCoreTcpIpStateTracking.h @@ -161,44 +161,23 @@ struct TrackedRoute bool operator<(const TrackedRoute& other) const noexcept { - // return true if 'this' is less than (i.e. is ordered before) the input argument - if (Route.IsAutoGeneratedPrefixRoute || other.Route.IsAutoGeneratedPrefixRoute) - { - if (Route.IsAutoGeneratedPrefixRoute && other.Route.IsAutoGeneratedPrefixRoute) + const auto routeClass = [](const EndpointRoute& route) noexcept { + if (route.IsAutoGeneratedPrefixRoute) { - // if both are effectively equivalent, sort by their addresses - if (Route.DestinationPrefixString == other.Route.DestinationPrefixString) - { - return Route.Metric < other.Route.Metric; - } - return Route.DestinationPrefixString < other.Route.DestinationPrefixString; + return 0; } - // else return true if it's the left that's IsAutoGeneratedPrefixRoute - return Route.IsAutoGeneratedPrefixRoute; - } - if (Route.IsNextHopOnlink() || other.Route.IsNextHopOnlink()) - { - if (Route.IsNextHopOnlink() && other.Route.IsNextHopOnlink()) - { - // if both are effectively equivalent, sort by their addresses - if (Route.DestinationPrefixString == other.Route.DestinationPrefixString) - { - return Route.Metric < other.Route.Metric; - } - return Route.DestinationPrefixString < other.Route.DestinationPrefixString; - } - // else return true if it's the left that's IsNextHopOnlink() - return Route.IsNextHopOnlink(); - } + return route.IsNextHopOnlink() ? 1 : 2; + }; - // else it's an Add or Update for a route that's not an auto-generated route - // and whose next-hop address is not on-link - if (Route.DestinationPrefixString == other.Route.DestinationPrefixString) + const auto thisRouteClass = routeClass(Route); + const auto otherRouteClass = routeClass(other.Route); + if (thisRouteClass != otherRouteClass) { - return Route.Metric < other.Route.Metric; + return thisRouteClass < otherRouteClass; } - return Route.DestinationPrefixString < other.Route.DestinationPrefixString; + + return Route < other.Route; } }; diff --git a/test/windows/CMakeLists.txt b/test/windows/CMakeLists.txt index b19e5f9d9d..6d9df23e9a 100644 --- a/test/windows/CMakeLists.txt +++ b/test/windows/CMakeLists.txt @@ -33,6 +33,7 @@ if (DEFINED WSL_UNITY_BATCH_SIZE AND WSL_UNITY_BATCH_SIZE GREATER 0) endif () target_include_directories(wsltests PRIVATE + ${CMAKE_SOURCE_DIR}/src/windows/service/exe ${CMAKE_SOURCE_DIR}/src/windows/WslcSDK ${CMAKE_BINARY_DIR}/src/windows/WslcSDK/winrt/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}) target_link_directories(wsltests PRIVATE ${BIN}) diff --git a/test/windows/NetworkTests.cpp b/test/windows/NetworkTests.cpp index b06aae02b9..dda5863f24 100644 --- a/test/windows/NetworkTests.cpp +++ b/test/windows/NetworkTests.cpp @@ -18,6 +18,7 @@ Module Name: #include "wslpolicies.h" #include "hns_schema.h" #include "WslCoreNetworkEndpointSettings.h" +#include "WslCoreTcpIpStateTracking.h" #include #include @@ -607,6 +608,36 @@ class NetworkTests VERIFY_IS_TRUE(state.Routes.empty()); } + TEST_METHOD(TrackedRouteOrderingPreservesRouteIdentity) + { + const auto makeRoute = [](const wchar_t* destination, uint8_t prefixLength, const wchar_t* nextHop, ULONG metric = 10) { + MIB_IPFORWARD_ROW2 routeRow{}; + routeRow.DestinationPrefix.Prefix = wsl::windows::common::string::StringToSockAddrInet(destination); + routeRow.DestinationPrefix.PrefixLength = prefixLength; + routeRow.NextHop = wsl::windows::common::string::StringToSockAddrInet(nextHop); + routeRow.Metric = metric; + return wsl::core::networking::EndpointRoute(routeRow); + }; + + std::set routes; + routes.emplace(makeRoute(L"10.0.0.0", 8, L"192.168.0.1")); + routes.emplace(makeRoute(L"10.0.0.0", 24, L"192.168.0.1")); + routes.emplace(makeRoute(L"10.0.0.0", 24, L"192.168.0.2")); + routes.emplace(makeRoute(L"10.0.0.0", 24, L"192.168.0.2", 20)); + routes.emplace(makeRoute(L"10.0.0.0", 24, L"192.168.0.2")); + + VERIFY_ARE_EQUAL(static_cast(4), routes.size()); + + auto autoGeneratedRoute = makeRoute(L"192.168.0.0", 24, L"0.0.0.0"); + autoGeneratedRoute.IsAutoGeneratedPrefixRoute = true; + const wsl::core::networking::TrackedRoute trackedAutoGeneratedRoute(autoGeneratedRoute); + const wsl::core::networking::TrackedRoute trackedOnlinkRoute(makeRoute(L"192.168.1.0", 24, L"0.0.0.0")); + const wsl::core::networking::TrackedRoute trackedOfflinkRoute(makeRoute(L"192.168.2.0", 24, L"192.168.0.1")); + + VERIFY_IS_TRUE(trackedAutoGeneratedRoute < trackedOnlinkRoute); + VERIFY_IS_TRUE(trackedOnlinkRoute < trackedOfflinkRoute); + } + WSL2_TEST_METHOD(UpdateIpAddress) { TestCase({{L"eth0", {{L"192.168.0.2", 24}}, L"192.168.0.1", {{L"fc00::2", 64}}, L"fc00::1"}}); From e3e3b3ea78d5abaf8bb024a9ebfc9150725acbd0 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 13:23:56 +0800 Subject: [PATCH 2/2] resolve comment --- test/windows/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/windows/CMakeLists.txt b/test/windows/CMakeLists.txt index 6d9df23e9a..c523cefde7 100644 --- a/test/windows/CMakeLists.txt +++ b/test/windows/CMakeLists.txt @@ -33,9 +33,10 @@ if (DEFINED WSL_UNITY_BATCH_SIZE AND WSL_UNITY_BATCH_SIZE GREATER 0) endif () target_include_directories(wsltests PRIVATE - ${CMAKE_SOURCE_DIR}/src/windows/service/exe ${CMAKE_SOURCE_DIR}/src/windows/WslcSDK ${CMAKE_BINARY_DIR}/src/windows/WslcSDK/winrt/${TARGET_PLATFORM}/${CMAKE_BUILD_TYPE}) +set_property(SOURCE NetworkTests.cpp APPEND PROPERTY INCLUDE_DIRECTORIES + ${CMAKE_SOURCE_DIR}/src/windows/service/exe) target_link_directories(wsltests PRIVATE ${BIN}) target_precompile_headers(wsltests REUSE_FROM common) target_link_libraries(wsltests