From 7a0dc10cccf626ab125d474eb831adac26a45c65 Mon Sep 17 00:00:00 2001 From: bcmmbaga Date: Wed, 26 Jun 2024 16:29:10 +0300 Subject: [PATCH] Add network map hash to avoid unnecessary updates --- go.mod | 1 + go.sum | 2 ++ management/server/account.go | 2 ++ management/server/network.go | 4 ++-- management/server/peer.go | 39 ++++++++++++++++++++++++++++++---- management/server/peer/peer.go | 2 ++ 6 files changed, 44 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 3753fe651..bd1d01981 100644 --- a/go.mod +++ b/go.mod @@ -70,6 +70,7 @@ require ( github.com/rs/xid v1.3.0 github.com/shirou/gopsutil/v3 v3.24.4 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 + github.com/spaolacci/murmur3 v1.1.0 github.com/stretchr/testify v1.9.0 github.com/testcontainers/testcontainers-go v0.31.0 github.com/testcontainers/testcontainers-go/modules/postgres v0.31.0 diff --git a/go.sum b/go.sum index e46b0b744..5e02e0d05 100644 --- a/go.sum +++ b/go.sum @@ -439,6 +439,8 @@ github.com/smartystreets/assertions v1.13.0 h1:Dx1kYM01xsSqKPno3aqLnrwac2LetPvN2 github.com/smartystreets/assertions v1.13.0/go.mod h1:wDmR7qL282YbGsPy6H/yAsesrxfxaaSlJazyFLYVFx8= github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= diff --git a/management/server/account.go b/management/server/account.go index 56787a31c..91386201d 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -167,6 +167,8 @@ type DefaultAccountManager struct { userDeleteFromIDPEnabled bool integratedPeerValidator integrated_validator.IntegratedValidator + + networkMapHash map[string]uint64 } // Settings represents Account settings structure that can be modified via API and Dashboard diff --git a/management/server/network.go b/management/server/network.go index 0e7d753a7..201b99a2d 100644 --- a/management/server/network.go +++ b/management/server/network.go @@ -40,9 +40,9 @@ type Network struct { Dns string // Serial is an ID that increments by 1 when any change to the network happened (e.g. new peer has been added). // Used to synchronize state to the client apps. - Serial uint64 + Serial uint64 `hash:"ignore"` - mu sync.Mutex `json:"-" gorm:"-"` + mu sync.Mutex `json:"-" gorm:"-" hash:"ignore"` } // NewNetwork creates a new Network initializing it with a Serial=0 diff --git a/management/server/peer.go b/management/server/peer.go index fa482eec0..9c6513a3d 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -6,6 +6,7 @@ import ( "strings" "time" + "github.com/mitchellh/hashstructure/v2" "github.com/netbirdio/netbird/management/server/posture" "github.com/rs/xid" log "github.com/sirupsen/logrus" @@ -915,6 +916,18 @@ func updatePeerMeta(peer *nbpeer.Peer, meta nbpeer.PeerSystemMeta, account *Acco // updateAccountPeers updates all peers that belong to an account. // Should be called when changes have to be synced to peers. func (am *DefaultAccountManager) updateAccountPeers(account *Account) { + start := time.Now() + var skipUpdate int + defer func() { + duration := time.Since(start) + log.Printf("Finished execution of updateAccountPeers, took %v\n", duration) + log.Println("not updated peers: ", skipUpdate) + }() + + if am.networkMapHash == nil { + am.networkMapHash = map[string]uint64{} + } + peers := account.GetPeers() approvedPeersMap, err := am.GetValidatedPeers(account) @@ -922,14 +935,32 @@ func (am *DefaultAccountManager) updateAccountPeers(account *Account) { log.Errorf("failed send out updates to peers, failed to validate peer: %v", err) return } + for _, peer := range peers { - if !am.peersUpdateManager.HasChannel(peer.ID) { - log.Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID) - continue + //if !am.peersUpdateManager.HasChannel(peer.ID) { + // log.Tracef("peer %s doesn't have a channel, skipping network map update", peer.ID) + // continue + //} + + remotePeerNetworkMap := account.GetPeerNetworkMap(peer.ID, am.dnsDomain, approvedPeersMap) + hash, err := hashstructure.Hash(remotePeerNetworkMap, hashstructure.FormatV2, &hashstructure.HashOptions{ + ZeroNil: true, + IgnoreZeroValue: true, + SlicesAsSets: true, + UseStringer: true, + }) + if err != nil { + log.Errorf("failed to generate network map hash: %v", err) + } else { + if am.networkMapHash[peer.ID] == hash { + log.Debugf("not sending network map update to peer: %s as there is nothing new", peer.ID) + skipUpdate++ + continue + } + am.networkMapHash[peer.ID] = hash } postureChecks := am.getPeerPostureChecks(account, peer) - remotePeerNetworkMap := account.GetPeerNetworkMap(peer.ID, am.dnsDomain, approvedPeersMap) update := toSyncResponse(nil, peer, nil, remotePeerNetworkMap, am.GetDNSDomain(), postureChecks) am.peersUpdateManager.SendUpdate(peer.ID, &UpdateMessage{Update: update}) } diff --git a/management/server/peer/peer.go b/management/server/peer/peer.go index 4f808a79e..77c9397b3 100644 --- a/management/server/peer/peer.go +++ b/management/server/peer/peer.go @@ -47,6 +47,8 @@ type Peer struct { Ephemeral bool // Geo location based on connection IP Location Location `gorm:"embedded;embeddedPrefix:location_"` + + NetworkMapHash uint64 `hash:"ignore"` } type PeerStatus struct { //nolint:revive