From bf78af07a69fe3e031dc724fe16228aa41db5436 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Fri, 15 May 2026 23:19:15 +0300 Subject: [PATCH] Tune VPN fabric batching and flow windows --- .../rap-node-agent/internal/agent/payload.go | 2 +- .../internal/vpnruntime/fabric_transport.go | 24 ++++++++++++------- .../vpnruntime/fabric_transport_test.go | 6 ++--- clients/android/app/build.gradle | 4 ++-- .../java/su/cin/rapvpn/RapVpnService.java | 2 +- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/agents/rap-node-agent/internal/agent/payload.go b/agents/rap-node-agent/internal/agent/payload.go index 72a9f1f..b125632 100644 --- a/agents/rap-node-agent/internal/agent/payload.go +++ b/agents/rap-node-agent/internal/agent/payload.go @@ -7,7 +7,7 @@ import ( "github.com/example/remote-access-platform/agents/rap-node-agent/internal/state" ) -const Version = "0.2.278-vpnpreempt" +const Version = "0.2.279-vpnperf" func EnrollmentPayload(clusterID, joinToken string, identity state.Identity) client.EnrollRequest { return client.EnrollRequest{ diff --git a/agents/rap-node-agent/internal/vpnruntime/fabric_transport.go b/agents/rap-node-agent/internal/vpnruntime/fabric_transport.go index 2098362..993fb9c 100644 --- a/agents/rap-node-agent/internal/vpnruntime/fabric_transport.go +++ b/agents/rap-node-agent/internal/vpnruntime/fabric_transport.go @@ -19,9 +19,9 @@ const ( FabricDirectionClientToGateway = "client_to_gateway" FabricDirectionGatewayToClient = "gateway_to_client" - defaultFabricFlowShardCount = 32 + defaultFabricFlowShardCount = 8 defaultFabricFlowQueueCapacity = 1024 - defaultFabricFlowParallelSendWindow = 4 + defaultFabricFlowParallelSendWindow = 8 defaultFabricFlowQualityWindowCapacity = 32 defaultFabricFlowFailureThreshold = 2 defaultFabricFlowSlowSendThreshold = 2 * time.Second @@ -332,8 +332,8 @@ func defaultFabricServiceChannelAdaptivePolicy() FabricServiceChannelAdaptivePol ClassWindows: map[string]int{ FabricTrafficClassControl: defaultFabricFlowParallelSendWindow, FabricTrafficClassInteractive: defaultFabricFlowParallelSendWindow, - FabricTrafficClassReliable: 3, - FabricTrafficClassBulk: 1, + FabricTrafficClassReliable: 6, + FabricTrafficClassBulk: 4, FabricTrafficClassDroppable: 1, }, }) @@ -361,8 +361,8 @@ func normalizeFabricServiceChannelAdaptivePolicy(policy FabricServiceChannelAdap defaults := map[string]int{ FabricTrafficClassControl: policy.MaxParallelWindow, FabricTrafficClassInteractive: policy.MaxParallelWindow, - FabricTrafficClassReliable: minPositive(policy.MaxParallelWindow, 3), - FabricTrafficClassBulk: 1, + FabricTrafficClassReliable: minPositive(policy.MaxParallelWindow, 6), + FabricTrafficClassBulk: minPositive(policy.MaxParallelWindow, 4), FabricTrafficClassDroppable: 1, } next := map[string]int{} @@ -538,12 +538,15 @@ func (s *FabricFlowScheduler) RecommendedParallelSendWindowForTrafficClass(traff return maxWindow } if classPressure.hasDrops { - return classWindowLimit(s.adaptivePolicy, trafficClass, boundedParallelWindow(maxWindow/2)) + return classWindowLimit(s.adaptivePolicy, trafficClass, 1) } if global.hasDrops { - return classWindowLimit(s.adaptivePolicy, trafficClass, boundedParallelWindow(maxWindow/2)) + return classWindowLimit(s.adaptivePolicy, trafficClass, 1) } if global.highPressure && global.interactiveOrControlQueues > 0 { + if trafficClass == FabricTrafficClassBulk || trafficClass == FabricTrafficClassDroppable { + return classWindowLimit(s.adaptivePolicy, trafficClass, 1) + } return classWindowLimit(s.adaptivePolicy, trafficClass, boundedParallelWindow(maxWindow/2)) } if global.highPressure { @@ -821,9 +824,12 @@ func (s *FabricFlowScheduler) recommendedParallelSendWindowForTrafficClassLocked return maxWindow } if classPressure.hasDrops || globalPressure.hasDrops { - return classWindowLimit(s.adaptivePolicy, trafficClass, boundedParallelWindow(maxWindow/2)) + return classWindowLimit(s.adaptivePolicy, trafficClass, 1) } if globalPressure.highPressure && globalPressure.interactiveOrControlQueues > 0 { + if trafficClass == FabricTrafficClassBulk || trafficClass == FabricTrafficClassDroppable { + return classWindowLimit(s.adaptivePolicy, trafficClass, 1) + } return classWindowLimit(s.adaptivePolicy, trafficClass, boundedParallelWindow(maxWindow/2)) } if globalPressure.highPressure { diff --git a/agents/rap-node-agent/internal/vpnruntime/fabric_transport_test.go b/agents/rap-node-agent/internal/vpnruntime/fabric_transport_test.go index dbb3b78..448372f 100644 --- a/agents/rap-node-agent/internal/vpnruntime/fabric_transport_test.go +++ b/agents/rap-node-agent/internal/vpnruntime/fabric_transport_test.go @@ -1457,14 +1457,14 @@ func TestFabricFlowSchedulerProtectsInteractiveWindowDuringBulkPressure(t *testi if got := scheduler.RecommendedParallelSendWindowForTrafficClass(FabricTrafficClassBulk, 4); got != 1 { t.Fatalf("bulk adaptive window = %d, want 1", got) } - if got := scheduler.RecommendedParallelSendWindowForTrafficClass(FabricTrafficClassInteractive, 4); got != 4 { - t.Fatalf("interactive adaptive window = %d, want 4", got) + if got := scheduler.RecommendedParallelSendWindowForTrafficClass(FabricTrafficClassInteractive, 8); got != 8 { + t.Fatalf("interactive adaptive window = %d, want 8", got) } snapshot := scheduler.Snapshot() if !snapshot.AdaptiveBackpressureActive || snapshot.AdaptiveBackpressureReason != "bulk_window_reduced_to_protect_interactive" { t.Fatalf("adaptive snapshot = %+v", snapshot) } - if snapshot.RecommendedParallelWindows[FabricTrafficClassBulk] != 1 || snapshot.RecommendedParallelWindows[FabricTrafficClassInteractive] != 4 { + if snapshot.RecommendedParallelWindows[FabricTrafficClassBulk] != 1 || snapshot.RecommendedParallelWindows[FabricTrafficClassInteractive] != 8 { t.Fatalf("recommended class windows = %+v", snapshot.RecommendedParallelWindows) } if snapshot.TrafficClassCounts[FabricTrafficClassBulk] != 16 || snapshot.TrafficClassCounts[FabricTrafficClassInteractive] != 1 { diff --git a/clients/android/app/build.gradle b/clients/android/app/build.gradle index 7eefbf3..b8add65 100644 --- a/clients/android/app/build.gradle +++ b/clients/android/app/build.gradle @@ -30,8 +30,8 @@ android { applicationId "su.cin.rapvpn" minSdk 26 targetSdk 35 - versionCode 209 - versionName "0.2.209" + versionCode 210 + versionName "0.2.210" buildConfigField "String", "DEFAULT_BACKEND_URL", "\"${normalizeGradleString(defaultBackendUrl)}\"" buildConfigField "String", "DEFAULT_CLUSTER_ID", "\"${normalizeGradleString(defaultClusterId)}\"" buildConfigField "String", "DEFAULT_ORGANIZATION_ID", "\"${normalizeGradleString(defaultOrganizationId)}\"" diff --git a/clients/android/app/src/main/java/su/cin/rapvpn/RapVpnService.java b/clients/android/app/src/main/java/su/cin/rapvpn/RapVpnService.java index c5e54c5..b72ca72 100644 --- a/clients/android/app/src/main/java/su/cin/rapvpn/RapVpnService.java +++ b/clients/android/app/src/main/java/su/cin/rapvpn/RapVpnService.java @@ -72,7 +72,7 @@ public class RapVpnService extends VpnService { private static final int DOWNLINK_POLL_MS_MIN = 2; private static final int DOWNLINK_POLL_MS_MAX = 40; private static final int DOWNLINK_POLL_MS_STEP = 4; - private static final int UPLINK_BATCH_GATHER_MS = 2; + private static final int UPLINK_BATCH_GATHER_MS = 12; private static final int TUN_WRITE_MAX_RETRIES = 1000; private static final int TUN_EAGAIN_SLEEP_MS = 1; private static final int RUNTIME_DETAIL_INTERVAL_MS = 250;