Fix VPN fabric-only routing guard
This commit is contained in:
@@ -524,6 +524,52 @@ func TestFabricClientPacketIngressTriesAlternateRouteBeforeBackendFallback(t *te
|
||||
}
|
||||
}
|
||||
|
||||
func TestFabricClientPacketIngressDoesNotFailOverPreferredRouteToDifferentDestination(t *testing.T) {
|
||||
transport := &failoverProductionTransport{failNextHop: "relay-home"}
|
||||
ingress := &FabricClientPacketIngress{
|
||||
ForwardTransport: transport,
|
||||
Inbox: NewFabricPacketInbox(4),
|
||||
ClusterID: "cluster-1",
|
||||
LocalNodeID: "entry-1",
|
||||
Routes: func() []mesh.SyntheticRoute {
|
||||
return []mesh.SyntheticRoute{
|
||||
{
|
||||
RouteID: "route-other",
|
||||
ClusterID: "cluster-1",
|
||||
SourceNodeID: "entry-1",
|
||||
DestinationNodeID: "ifcm-1",
|
||||
Hops: []string{"entry-1", "relay-ifcm", "ifcm-1"},
|
||||
AllowedChannels: []string{mesh.ProductionChannelVPNPacket},
|
||||
ExpiresAt: time.Now().UTC().Add(time.Minute),
|
||||
MaxTTL: 8,
|
||||
},
|
||||
{
|
||||
RouteID: "route-home",
|
||||
ClusterID: "cluster-1",
|
||||
SourceNodeID: "entry-1",
|
||||
DestinationNodeID: "home-1",
|
||||
Hops: []string{"entry-1", "relay-home", "home-1"},
|
||||
AllowedChannels: []string{mesh.ProductionChannelVPNPacket},
|
||||
ExpiresAt: time.Now().UTC().Add(time.Minute),
|
||||
MaxTTL: 8,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
ingress.PreferClientRoute("route-home")
|
||||
|
||||
err := ingress.SendClientPacketBatch(context.Background(), "cluster-1", "vpn-1", [][]byte{[]byte("packet")})
|
||||
if err == nil {
|
||||
t.Fatal("send client packet batch succeeded after preferred route failure; want failure without cross-destination fallback")
|
||||
}
|
||||
if len(transport.calls) != 1 || transport.calls[0] != "relay-home" {
|
||||
t.Fatalf("route attempts = %#v, want only relay-home", transport.calls)
|
||||
}
|
||||
if transport.envelope.RouteID == "route-other" {
|
||||
t.Fatalf("cross-destination route was used: %+v", transport.envelope)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFabricClientPacketIngressAvoidsChannelFailedRouteOnNextSend(t *testing.T) {
|
||||
transport := &captureManyProductionTransport{}
|
||||
scheduler := NewFabricFlowScheduler(8, 16)
|
||||
@@ -822,6 +868,44 @@ func TestFabricClientPacketIngressPendingDegradedFallbackWithdrawsRouteWithoutAl
|
||||
}
|
||||
}
|
||||
|
||||
func TestFabricClientPacketIngressKeepsLastRouteWhenWithdrawalPreventionEnabled(t *testing.T) {
|
||||
transport := &captureManyProductionTransport{}
|
||||
ingress := &FabricClientPacketIngress{
|
||||
ForwardTransport: transport,
|
||||
Inbox: NewFabricPacketInbox(4),
|
||||
ClusterID: "cluster-1",
|
||||
LocalNodeID: "entry-1",
|
||||
PreventLastRouteWithdrawal: true,
|
||||
Routes: func() []mesh.SyntheticRoute {
|
||||
return []mesh.SyntheticRoute{{
|
||||
RouteID: "route-only",
|
||||
ClusterID: "cluster-1",
|
||||
SourceNodeID: "entry-1",
|
||||
DestinationNodeID: "exit-1",
|
||||
Hops: []string{"entry-1", "exit-1"},
|
||||
AllowedChannels: []string{mesh.ProductionChannelVPNPacket},
|
||||
ExpiresAt: time.Now().UTC().Add(time.Minute),
|
||||
MaxTTL: 8,
|
||||
}}
|
||||
},
|
||||
}
|
||||
ingress.UpdateRouteManager([]FabricServiceChannelRouteManagerDecision{{
|
||||
RouteID: "route-only",
|
||||
RebuildStatus: "pending_degraded_fallback",
|
||||
DecisionSource: "service_channel_feedback_no_alternate",
|
||||
}}, "config-v2", time.Now().UTC())
|
||||
|
||||
if err := ingress.SendClientPacketBatch(context.Background(), "cluster-1", "vpn-1", [][]byte{[]byte("packet")}); err != nil {
|
||||
t.Fatalf("send client packet batch: %v", err)
|
||||
}
|
||||
if len(transport.envelopes) != 1 || transport.envelopes[0].RouteID != "route-only" {
|
||||
t.Fatalf("envelopes = %+v, want preserved last route", transport.envelopes)
|
||||
}
|
||||
if snapshot := ingress.Snapshot("cluster-1"); snapshot.RouteCandidateCount != 1 {
|
||||
t.Fatalf("route candidate count = %d, want last withdrawn route preserved", snapshot.RouteCandidateCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFabricClientPacketIngressMarksChannelForRebuildAfterRepeatedRouteFailures(t *testing.T) {
|
||||
transport := &failoverProductionTransport{failNextHop: "relay-bad"}
|
||||
scheduler := NewFabricFlowScheduler(8, 16)
|
||||
@@ -1930,9 +2014,10 @@ func TestFabricClientPacketIngressBoundedLoadReportsPerChannelDrops(t *testing.T
|
||||
func TestFabricClientPacketIngressUsesLocalGatewayShortcutWithoutRoute(t *testing.T) {
|
||||
inbox := NewFabricPacketInbox(4)
|
||||
ingress := &FabricClientPacketIngress{
|
||||
Inbox: inbox,
|
||||
ClusterID: "cluster-1",
|
||||
LocalNodeID: "entry-1",
|
||||
Inbox: inbox,
|
||||
ClusterID: "cluster-1",
|
||||
LocalNodeID: "entry-1",
|
||||
AllowLegacyLocalGatewayFallback: true,
|
||||
LocalGateway: func(vpnConnectionID string) bool {
|
||||
return vpnConnectionID == "vpn-1"
|
||||
},
|
||||
@@ -1954,9 +2039,10 @@ func TestFabricClientPacketIngressUsesLocalGatewayShortcutWithoutRoute(t *testin
|
||||
func TestFabricClientPacketIngressReceivesLocalGatewayReplyWithoutRoute(t *testing.T) {
|
||||
inbox := NewFabricPacketInbox(4)
|
||||
ingress := &FabricClientPacketIngress{
|
||||
Inbox: inbox,
|
||||
ClusterID: "cluster-1",
|
||||
LocalNodeID: "entry-1",
|
||||
Inbox: inbox,
|
||||
ClusterID: "cluster-1",
|
||||
LocalNodeID: "entry-1",
|
||||
AllowLegacyLocalGatewayFallback: true,
|
||||
LocalGateway: func(vpnConnectionID string) bool {
|
||||
return vpnConnectionID == "vpn-1"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user