mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-06 09:24:07 -04:00
Compare commits
4 Commits
add-defaul
...
nm/tests
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a21cccfbb | ||
|
|
971e68d321 | ||
|
|
f9142962de | ||
|
|
354c8cf7d3 |
@@ -111,7 +111,6 @@ func (c *ConnectClient) RunOniOS(
|
||||
fileDescriptor int32,
|
||||
networkChangeListener listener.NetworkChangeListener,
|
||||
dnsManager dns.IosDnsManager,
|
||||
dnsAddresses []netip.AddrPort,
|
||||
stateFilePath string,
|
||||
) error {
|
||||
// Set GC percent to 5% to reduce memory usage as iOS only allows 50MB of memory for the extension.
|
||||
@@ -121,7 +120,6 @@ func (c *ConnectClient) RunOniOS(
|
||||
FileDescriptor: fileDescriptor,
|
||||
NetworkChangeListener: networkChangeListener,
|
||||
DnsManager: dnsManager,
|
||||
HostDNSAddresses: dnsAddresses,
|
||||
StateFilePath: stateFilePath,
|
||||
}
|
||||
return c.run(mobileDependency, nil, "")
|
||||
|
||||
@@ -26,8 +26,7 @@ func (a iosHostManager) applyDNSConfig(config HostDNSConfig, _ *statemanager.Man
|
||||
return fmt.Errorf("marshal: %w", err)
|
||||
}
|
||||
jsonString := string(jsonData)
|
||||
log.Infof("iOS applyDNSConfig: routeAll=%v serverIP=%s domains=%d", config.RouteAll, config.ServerIP, len(config.Domains))
|
||||
log.Debugf("iOS applyDNSConfig: %s", jsonString)
|
||||
log.Debugf("Applying DNS settings: %s", jsonString)
|
||||
a.dnsManager.ApplyDns(jsonString)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -186,17 +186,11 @@ func NewDefaultServerIos(
|
||||
ctx context.Context,
|
||||
wgInterface WGIface,
|
||||
iosDnsManager IosDnsManager,
|
||||
hostsDnsList []netip.AddrPort,
|
||||
statusRecorder *peer.Status,
|
||||
disableSys bool,
|
||||
) *DefaultServer {
|
||||
log.Infof("iOS host dns address list is: %v", hostsDnsList)
|
||||
ds := newDefaultServer(ctx, wgInterface, NewServiceViaMemory(wgInterface), statusRecorder, nil, disableSys)
|
||||
ds.iosDnsManager = iosDnsManager
|
||||
ds.hostsDNSHolder.set(hostsDnsList)
|
||||
ds.permanent = true
|
||||
ds.addHostRootZone()
|
||||
log.Infof("iOS DNS server initialized: permanent=%v, hostDNS=%v", ds.permanent, hostsDnsList)
|
||||
return ds
|
||||
}
|
||||
|
||||
@@ -1039,10 +1033,9 @@ func (s *DefaultServer) upstreamCallbacks(
|
||||
func (s *DefaultServer) addHostRootZone() {
|
||||
hostDNSServers := s.hostsDNSHolder.get()
|
||||
if len(hostDNSServers) == 0 {
|
||||
log.Info("no host DNS servers available, skipping root zone handler creation")
|
||||
log.Debug("no host DNS servers available, skipping root zone handler creation")
|
||||
return
|
||||
}
|
||||
log.Infof("creating root zone handler with host DNS servers: %v", maps.Keys(hostDNSServers))
|
||||
|
||||
handler, err := newUpstreamResolver(
|
||||
s.ctx,
|
||||
|
||||
@@ -500,7 +500,7 @@ func (e *Engine) Start(netbirdConfig *mgmProto.NetbirdConfig, mgmtURL *url.URL)
|
||||
e.routeManager.SetRouteChangeListener(e.mobileDep.NetworkChangeListener)
|
||||
|
||||
e.dnsServer.SetRouteChecker(func(ip netip.Addr) bool {
|
||||
for _, routes := range e.routeManager.GetSelectedClientRoutes() {
|
||||
for _, routes := range e.routeManager.GetClientRoutes() {
|
||||
for _, r := range routes {
|
||||
if r.Network.Contains(ip) {
|
||||
return true
|
||||
@@ -1800,7 +1800,7 @@ func (e *Engine) newDnsServer(dnsConfig *nbdns.Config) (dns.Server, error) {
|
||||
return dnsServer, nil
|
||||
|
||||
case "ios":
|
||||
dnsServer := dns.NewDefaultServerIos(e.ctx, e.wgInterface, e.mobileDep.DnsManager, e.mobileDep.HostDNSAddresses, e.statusRecorder, e.config.DisableDNS)
|
||||
dnsServer := dns.NewDefaultServerIos(e.ctx, e.wgInterface, e.mobileDep.DnsManager, e.statusRecorder, e.config.DisableDNS)
|
||||
return dnsServer, nil
|
||||
|
||||
default:
|
||||
|
||||
@@ -52,7 +52,6 @@ type Manager interface {
|
||||
TriggerSelection(route.HAMap)
|
||||
GetRouteSelector() *routeselector.RouteSelector
|
||||
GetClientRoutes() route.HAMap
|
||||
GetSelectedClientRoutes() route.HAMap
|
||||
GetClientRoutesWithNetID() map[route.NetID][]*route.Route
|
||||
SetRouteChangeListener(listener listener.NetworkChangeListener)
|
||||
InitialRouteRange() []string
|
||||
@@ -466,16 +465,6 @@ func (m *DefaultManager) GetClientRoutes() route.HAMap {
|
||||
return maps.Clone(m.clientRoutes)
|
||||
}
|
||||
|
||||
// GetSelectedClientRoutes returns only the currently selected/active client routes,
|
||||
// filtering out deselected exit nodes. Use this instead of GetClientRoutes when checking
|
||||
// if traffic should be routed through the tunnel.
|
||||
func (m *DefaultManager) GetSelectedClientRoutes() route.HAMap {
|
||||
m.mux.Lock()
|
||||
defer m.mux.Unlock()
|
||||
|
||||
return m.routeSelector.FilterSelectedExitNodes(maps.Clone(m.clientRoutes))
|
||||
}
|
||||
|
||||
// GetClientRoutesWithNetID returns the current routes from the route map, but the keys consist of the network ID only
|
||||
func (m *DefaultManager) GetClientRoutesWithNetID() map[route.NetID][]*route.Route {
|
||||
m.mux.Lock()
|
||||
|
||||
@@ -18,7 +18,6 @@ type MockManager struct {
|
||||
TriggerSelectionFunc func(haMap route.HAMap)
|
||||
GetRouteSelectorFunc func() *routeselector.RouteSelector
|
||||
GetClientRoutesFunc func() route.HAMap
|
||||
GetSelectedClientRoutesFunc func() route.HAMap
|
||||
GetClientRoutesWithNetIDFunc func() map[route.NetID][]*route.Route
|
||||
StopFunc func(manager *statemanager.Manager)
|
||||
}
|
||||
@@ -62,7 +61,7 @@ func (m *MockManager) GetRouteSelector() *routeselector.RouteSelector {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClientRoutes mock implementation of GetClientRoutes from the Manager interface
|
||||
// GetClientRoutes mock implementation of GetClientRoutes from Manager interface
|
||||
func (m *MockManager) GetClientRoutes() route.HAMap {
|
||||
if m.GetClientRoutesFunc != nil {
|
||||
return m.GetClientRoutesFunc()
|
||||
@@ -70,14 +69,6 @@ func (m *MockManager) GetClientRoutes() route.HAMap {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSelectedClientRoutes mock implementation of GetSelectedClientRoutes from the Manager interface
|
||||
func (m *MockManager) GetSelectedClientRoutes() route.HAMap {
|
||||
if m.GetSelectedClientRoutesFunc != nil {
|
||||
return m.GetSelectedClientRoutesFunc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetClientRoutesWithNetID mock implementation of GetClientRoutesWithNetID from Manager interface
|
||||
func (m *MockManager) GetClientRoutesWithNetID() map[route.NetID][]*route.Route {
|
||||
if m.GetClientRoutesWithNetIDFunc != nil {
|
||||
|
||||
@@ -161,11 +161,7 @@ func (c *Client) Run(fd int32, interfaceName string, envList *EnvList) error {
|
||||
cfg.WgIface = interfaceName
|
||||
|
||||
c.connectClient = internal.NewConnectClient(ctx, cfg, c.recorder)
|
||||
hostDNS := []netip.AddrPort{
|
||||
netip.MustParseAddrPort("1.1.1.1:53"),
|
||||
netip.MustParseAddrPort("1.0.0.1:53"),
|
||||
}
|
||||
return c.connectClient.RunOniOS(fd, c.networkChangeListener, c.dnsManager, hostDNS, c.stateFile)
|
||||
return c.connectClient.RunOniOS(fd, c.networkChangeListener, c.dnsManager, c.stateFile)
|
||||
}
|
||||
|
||||
// Stop the internal client and free the resources
|
||||
|
||||
217
management/server/types/networkmap_benchmark_test.go
Normal file
217
management/server/types/networkmap_benchmark_test.go
Normal file
@@ -0,0 +1,217 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
nbdns "github.com/netbirdio/netbird/dns"
|
||||
"github.com/netbirdio/netbird/management/server/types"
|
||||
)
|
||||
|
||||
type benchmarkScale struct {
|
||||
name string
|
||||
peers int
|
||||
groups int
|
||||
}
|
||||
|
||||
var defaultScales = []benchmarkScale{
|
||||
{"100peers_5groups", 100, 5},
|
||||
{"500peers_20groups", 500, 20},
|
||||
{"1000peers_50groups", 1000, 50},
|
||||
{"5000peers_100groups", 5000, 100},
|
||||
{"10000peers_200groups", 10000, 200},
|
||||
{"20000peers_200groups", 20000, 200},
|
||||
{"30000peers_300groups", 30000, 300},
|
||||
}
|
||||
|
||||
func skipCIBenchmark(b *testing.B) {
|
||||
if os.Getenv("CI") == "true" {
|
||||
b.Skip("Skipping benchmark in CI")
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
// Single Peer Network Map Generation
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// BenchmarkNetworkMapGeneration_Components benchmarks the components-based approach for a single peer.
|
||||
func BenchmarkNetworkMapGeneration_Components(b *testing.B) {
|
||||
skipCIBenchmark(b)
|
||||
for _, scale := range defaultScales {
|
||||
b.Run(scale.name, func(b *testing.B) {
|
||||
account, validatedPeers := scalableTestAccount(scale.peers, scale.groups)
|
||||
ctx := context.Background()
|
||||
resourcePolicies := account.GetResourcePoliciesMap()
|
||||
routers := account.GetResourceRoutersMap()
|
||||
groupIDToUserIDs := account.GetActiveGroupUsers()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = account.GetPeerNetworkMapFromComponents(ctx, "peer-0", nbdns.CustomZone{}, nil, validatedPeers, resourcePolicies, routers, nil, groupIDToUserIDs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
// All Peers (UpdateAccountPeers hot path)
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// BenchmarkNetworkMapGeneration_AllPeers benchmarks generating network maps for ALL peers.
|
||||
func BenchmarkNetworkMapGeneration_AllPeers(b *testing.B) {
|
||||
skipCIBenchmark(b)
|
||||
scales := []benchmarkScale{
|
||||
{"100peers_5groups", 100, 5},
|
||||
{"500peers_20groups", 500, 20},
|
||||
{"1000peers_50groups", 1000, 50},
|
||||
{"5000peers_100groups", 5000, 100},
|
||||
}
|
||||
|
||||
for _, scale := range scales {
|
||||
account, validatedPeers := scalableTestAccount(scale.peers, scale.groups)
|
||||
ctx := context.Background()
|
||||
|
||||
peerIDs := make([]string, 0, len(account.Peers))
|
||||
for peerID := range account.Peers {
|
||||
peerIDs = append(peerIDs, peerID)
|
||||
}
|
||||
|
||||
b.Run("components/"+scale.name, func(b *testing.B) {
|
||||
resourcePolicies := account.GetResourcePoliciesMap()
|
||||
routers := account.GetResourceRoutersMap()
|
||||
groupIDToUserIDs := account.GetActiveGroupUsers()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
for _, peerID := range peerIDs {
|
||||
_ = account.GetPeerNetworkMapFromComponents(ctx, peerID, nbdns.CustomZone{}, nil, validatedPeers, resourcePolicies, routers, nil, groupIDToUserIDs)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
// Sub-operations
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// BenchmarkNetworkMapGeneration_ComponentsCreation benchmarks components extraction.
|
||||
func BenchmarkNetworkMapGeneration_ComponentsCreation(b *testing.B) {
|
||||
skipCIBenchmark(b)
|
||||
for _, scale := range defaultScales {
|
||||
b.Run(scale.name, func(b *testing.B) {
|
||||
account, validatedPeers := scalableTestAccount(scale.peers, scale.groups)
|
||||
ctx := context.Background()
|
||||
resourcePolicies := account.GetResourcePoliciesMap()
|
||||
routers := account.GetResourceRoutersMap()
|
||||
groupIDToUserIDs := account.GetActiveGroupUsers()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = account.GetPeerNetworkMapComponents(ctx, "peer-0", nbdns.CustomZone{}, nil, validatedPeers, resourcePolicies, routers, groupIDToUserIDs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkNetworkMapGeneration_ComponentsCalculation benchmarks calculation from pre-built components.
|
||||
func BenchmarkNetworkMapGeneration_ComponentsCalculation(b *testing.B) {
|
||||
skipCIBenchmark(b)
|
||||
for _, scale := range defaultScales {
|
||||
b.Run(scale.name, func(b *testing.B) {
|
||||
account, validatedPeers := scalableTestAccount(scale.peers, scale.groups)
|
||||
ctx := context.Background()
|
||||
resourcePolicies := account.GetResourcePoliciesMap()
|
||||
routers := account.GetResourceRoutersMap()
|
||||
groupIDToUserIDs := account.GetActiveGroupUsers()
|
||||
components := account.GetPeerNetworkMapComponents(ctx, "peer-0", nbdns.CustomZone{}, nil, validatedPeers, resourcePolicies, routers, groupIDToUserIDs)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = types.CalculateNetworkMapFromComponents(ctx, components)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkNetworkMapGeneration_PrecomputeMaps benchmarks precomputed map costs.
|
||||
func BenchmarkNetworkMapGeneration_PrecomputeMaps(b *testing.B) {
|
||||
skipCIBenchmark(b)
|
||||
for _, scale := range defaultScales {
|
||||
b.Run("ResourcePoliciesMap/"+scale.name, func(b *testing.B) {
|
||||
account, _ := scalableTestAccount(scale.peers, scale.groups)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = account.GetResourcePoliciesMap()
|
||||
}
|
||||
})
|
||||
b.Run("ResourceRoutersMap/"+scale.name, func(b *testing.B) {
|
||||
account, _ := scalableTestAccount(scale.peers, scale.groups)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = account.GetResourceRoutersMap()
|
||||
}
|
||||
})
|
||||
b.Run("ActiveGroupUsers/"+scale.name, func(b *testing.B) {
|
||||
account, _ := scalableTestAccount(scale.peers, scale.groups)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = account.GetActiveGroupUsers()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
// Scaling Analysis
|
||||
// ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// BenchmarkNetworkMapGeneration_GroupScaling tests group count impact on performance.
|
||||
func BenchmarkNetworkMapGeneration_GroupScaling(b *testing.B) {
|
||||
skipCIBenchmark(b)
|
||||
groupCounts := []int{1, 5, 20, 50, 100, 200, 500}
|
||||
for _, numGroups := range groupCounts {
|
||||
b.Run(fmt.Sprintf("components_%dgroups", numGroups), func(b *testing.B) {
|
||||
account, validatedPeers := scalableTestAccount(1000, numGroups)
|
||||
ctx := context.Background()
|
||||
resourcePolicies := account.GetResourcePoliciesMap()
|
||||
routers := account.GetResourceRoutersMap()
|
||||
groupIDToUserIDs := account.GetActiveGroupUsers()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = account.GetPeerNetworkMapFromComponents(ctx, "peer-0", nbdns.CustomZone{}, nil, validatedPeers, resourcePolicies, routers, nil, groupIDToUserIDs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkNetworkMapGeneration_PeerScaling tests peer count impact on performance.
|
||||
func BenchmarkNetworkMapGeneration_PeerScaling(b *testing.B) {
|
||||
skipCIBenchmark(b)
|
||||
peerCounts := []int{50, 100, 500, 1000, 2000, 5000, 10000, 20000, 30000}
|
||||
for _, numPeers := range peerCounts {
|
||||
numGroups := numPeers / 20
|
||||
if numGroups < 1 {
|
||||
numGroups = 1
|
||||
}
|
||||
b.Run(fmt.Sprintf("components_%dpeers", numPeers), func(b *testing.B) {
|
||||
account, validatedPeers := scalableTestAccount(numPeers, numGroups)
|
||||
ctx := context.Background()
|
||||
resourcePolicies := account.GetResourcePoliciesMap()
|
||||
routers := account.GetResourceRoutersMap()
|
||||
groupIDToUserIDs := account.GetActiveGroupUsers()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for range b.N {
|
||||
_ = account.GetPeerNetworkMapFromComponents(ctx, "peer-0", nbdns.CustomZone{}, nil, validatedPeers, resourcePolicies, routers, nil, groupIDToUserIDs)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
1192
management/server/types/networkmap_components_correctness_test.go
Normal file
1192
management/server/types/networkmap_components_correctness_test.go
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user