From 7bab15fa42e3c66fe4c03bbe346108e6aa2cf077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Fri, 14 Aug 2026 23:39:55 +0200 Subject: [PATCH] [client] Skip IPv6 route tests when the default nexthop is unusable ensureIPv6DefaultRoute treated a successful netlink RouteAdd as proof that a usable IPv6 nexthop exists. Installing ::/0 via loopback can succeed while the kernel still rejects that nexthop for a concrete prefix, which surfaced on ubuntu22/20260810.260 runners as: add route to table: netlink add route: invalid argument Probe the resolved nexthop by installing and removing a discard-prefix route through the same code path the tests use, and skip when it fails. EEXIST means the nexthop already carries a route, so it counts as usable. --- .../systemops/v6route_linux_test.go | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/client/internal/routemanager/systemops/v6route_linux_test.go b/client/internal/routemanager/systemops/v6route_linux_test.go index 449d4cbd2..9e53edc73 100644 --- a/client/internal/routemanager/systemops/v6route_linux_test.go +++ b/client/internal/routemanager/systemops/v6route_linux_test.go @@ -5,6 +5,7 @@ package systemops import ( "errors" "net" + "net/netip" "syscall" "testing" @@ -29,6 +30,7 @@ func ensureIPv6DefaultRoute(t *testing.T) { } if err := netlink.RouteAdd(route); err != nil { if errors.Is(err, syscall.EEXIST) { + requireUsableIPv6Nexthop(t) return } t.Skipf("install IPv6 fallback default route: %v", err) @@ -38,4 +40,29 @@ func ensureIPv6DefaultRoute(t *testing.T) { t.Logf("delete IPv6 fallback default route: %v", err) } }) + + requireUsableIPv6Nexthop(t) +} + +// requireUsableIPv6Nexthop skips the test unless the resolved IPv6 default +// nexthop can actually carry a route. Installing the default route succeeding +// does not imply the kernel accepts it as a nexthop for a concrete prefix. +func requireUsableIPv6Nexthop(t *testing.T) { + t.Helper() + + nexthop, err := GetNextHop(netip.IPv6Unspecified()) + if err != nil { + t.Skipf("resolve IPv6 default nexthop: %v", err) + } + + probe := netip.MustParsePrefix("100::64/128") + switch err := addRoute(probe, nexthop, syscall.RT_TABLE_MAIN); { + case err == nil: + if err := removeRoute(probe, nexthop, syscall.RT_TABLE_MAIN); err != nil { + t.Logf("remove IPv6 probe route: %v", err) + } + case errors.Is(err, syscall.EEXIST): + default: + t.Skipf("IPv6 nexthop %s unusable for route installation: %v", nexthop, err) + } }