mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-20 17:26:40 +00:00
[client] Block on all subsystems on shutdown (#4709)
This commit is contained in:
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/netbirdio/netbird/client/internal/peer"
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
"github.com/netbirdio/netbird/client/internal/profilemanager"
|
"github.com/netbirdio/netbird/client/internal/profilemanager"
|
||||||
"github.com/netbirdio/netbird/client/internal/stdnet"
|
"github.com/netbirdio/netbird/client/internal/stdnet"
|
||||||
|
nbnet "github.com/netbirdio/netbird/client/net"
|
||||||
cProto "github.com/netbirdio/netbird/client/proto"
|
cProto "github.com/netbirdio/netbird/client/proto"
|
||||||
"github.com/netbirdio/netbird/client/ssh"
|
"github.com/netbirdio/netbird/client/ssh"
|
||||||
"github.com/netbirdio/netbird/client/system"
|
"github.com/netbirdio/netbird/client/system"
|
||||||
@@ -34,7 +35,6 @@ import (
|
|||||||
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
relayClient "github.com/netbirdio/netbird/shared/relay/client"
|
||||||
signal "github.com/netbirdio/netbird/shared/signal/client"
|
signal "github.com/netbirdio/netbird/shared/signal/client"
|
||||||
"github.com/netbirdio/netbird/util"
|
"github.com/netbirdio/netbird/util"
|
||||||
nbnet "github.com/netbirdio/netbird/client/net"
|
|
||||||
"github.com/netbirdio/netbird/version"
|
"github.com/netbirdio/netbird/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -289,15 +289,18 @@ func (c *ConnectClient) run(mobileDependency MobileDependency, runningChan chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
<-engineCtx.Done()
|
<-engineCtx.Done()
|
||||||
|
|
||||||
c.engineMutex.Lock()
|
c.engineMutex.Lock()
|
||||||
if c.engine != nil && c.engine.wgInterface != nil {
|
engine := c.engine
|
||||||
log.Infof("ensuring %s is removed, Netbird engine context cancelled", c.engine.wgInterface.Name())
|
c.engine = nil
|
||||||
if err := c.engine.Stop(); err != nil {
|
c.engineMutex.Unlock()
|
||||||
|
|
||||||
|
if engine != nil && engine.wgInterface != nil {
|
||||||
|
log.Infof("ensuring %s is removed, Netbird engine context cancelled", engine.wgInterface.Name())
|
||||||
|
if err := engine.Stop(); err != nil {
|
||||||
log.Errorf("Failed to stop engine: %v", err)
|
log.Errorf("Failed to stop engine: %v", err)
|
||||||
}
|
}
|
||||||
c.engine = nil
|
|
||||||
}
|
}
|
||||||
c.engineMutex.Unlock()
|
|
||||||
c.statusRecorder.ClientTeardown()
|
c.statusRecorder.ClientTeardown()
|
||||||
|
|
||||||
backOff.Reset()
|
backOff.Reset()
|
||||||
@@ -382,19 +385,12 @@ func (c *ConnectClient) Status() StatusType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConnectClient) Stop() error {
|
func (c *ConnectClient) Stop() error {
|
||||||
if c == nil {
|
engine := c.Engine()
|
||||||
return nil
|
if engine != nil {
|
||||||
|
if err := engine.Stop(); err != nil {
|
||||||
|
return fmt.Errorf("stop engine: %w", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.engineMutex.Lock()
|
|
||||||
defer c.engineMutex.Unlock()
|
|
||||||
|
|
||||||
if c.engine == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := c.engine.Stop(); err != nil {
|
|
||||||
return fmt.Errorf("stop engine: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,8 +65,9 @@ type hostManagerWithOriginalNS interface {
|
|||||||
|
|
||||||
// DefaultServer dns server object
|
// DefaultServer dns server object
|
||||||
type DefaultServer struct {
|
type DefaultServer struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
|
shutdownWg sync.WaitGroup
|
||||||
// disableSys disables system DNS management (e.g., /etc/resolv.conf updates) while keeping the DNS service running.
|
// disableSys disables system DNS management (e.g., /etc/resolv.conf updates) while keeping the DNS service running.
|
||||||
// This is different from ServiceEnable=false from management which completely disables the DNS service.
|
// This is different from ServiceEnable=false from management which completely disables the DNS service.
|
||||||
disableSys bool
|
disableSys bool
|
||||||
@@ -318,6 +319,7 @@ func (s *DefaultServer) DnsIP() netip.Addr {
|
|||||||
// Stop stops the server
|
// Stop stops the server
|
||||||
func (s *DefaultServer) Stop() {
|
func (s *DefaultServer) Stop() {
|
||||||
s.ctxCancel()
|
s.ctxCancel()
|
||||||
|
s.shutdownWg.Wait()
|
||||||
|
|
||||||
s.mux.Lock()
|
s.mux.Lock()
|
||||||
defer s.mux.Unlock()
|
defer s.mux.Unlock()
|
||||||
@@ -507,8 +509,9 @@ func (s *DefaultServer) applyConfiguration(update nbdns.Config) error {
|
|||||||
|
|
||||||
s.applyHostConfig()
|
s.applyHostConfig()
|
||||||
|
|
||||||
|
s.shutdownWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
// persist dns state right away
|
defer s.shutdownWg.Done()
|
||||||
if err := s.stateManager.PersistState(s.ctx); err != nil {
|
if err := s.stateManager.PersistState(s.ctx); err != nil {
|
||||||
log.Errorf("Failed to persist dns state: %v", err)
|
log.Errorf("Failed to persist dns state: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ type Engine struct {
|
|||||||
|
|
||||||
// syncMsgMux is used to guarantee sequential Management Service message processing
|
// syncMsgMux is used to guarantee sequential Management Service message processing
|
||||||
syncMsgMux *sync.Mutex
|
syncMsgMux *sync.Mutex
|
||||||
|
// sshMux protects sshServer field access
|
||||||
|
sshMux sync.Mutex
|
||||||
|
|
||||||
config *EngineConfig
|
config *EngineConfig
|
||||||
mobileDep MobileDependency
|
mobileDep MobileDependency
|
||||||
@@ -200,8 +202,10 @@ type Engine struct {
|
|||||||
flowManager nftypes.FlowManager
|
flowManager nftypes.FlowManager
|
||||||
|
|
||||||
// WireGuard interface monitor
|
// WireGuard interface monitor
|
||||||
wgIfaceMonitor *WGIfaceMonitor
|
wgIfaceMonitor *WGIfaceMonitor
|
||||||
wgIfaceMonitorWg sync.WaitGroup
|
|
||||||
|
// shutdownWg tracks all long-running goroutines to ensure clean shutdown
|
||||||
|
shutdownWg sync.WaitGroup
|
||||||
|
|
||||||
probeStunTurn *relay.StunTurnProbe
|
probeStunTurn *relay.StunTurnProbe
|
||||||
}
|
}
|
||||||
@@ -320,10 +324,6 @@ func (e *Engine) Stop() error {
|
|||||||
e.cancel()
|
e.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
// very ugly but we want to remove peers from the WireGuard interface first before removing interface.
|
|
||||||
// Removing peers happens in the conn.Close() asynchronously
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
|
|
||||||
e.close()
|
e.close()
|
||||||
|
|
||||||
// stop flow manager after wg interface is gone
|
// stop flow manager after wg interface is gone
|
||||||
@@ -331,8 +331,6 @@ func (e *Engine) Stop() error {
|
|||||||
e.flowManager.Close()
|
e.flowManager.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("stopped Netbird Engine")
|
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -343,12 +341,52 @@ func (e *Engine) Stop() error {
|
|||||||
log.Errorf("failed to persist state: %v", err)
|
log.Errorf("failed to persist state: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop WireGuard interface monitor and wait for it to exit
|
timeout := e.calculateShutdownTimeout()
|
||||||
e.wgIfaceMonitorWg.Wait()
|
log.Debugf("waiting for goroutines to finish with timeout: %v", timeout)
|
||||||
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if err := waitWithContext(shutdownCtx, &e.shutdownWg); err != nil {
|
||||||
|
log.Warnf("shutdown timeout exceeded after %v, some goroutines may still be running", timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("stopped Netbird Engine")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculateShutdownTimeout returns shutdown timeout: 10s base + 100ms per peer, capped at 30s.
|
||||||
|
func (e *Engine) calculateShutdownTimeout() time.Duration {
|
||||||
|
peerCount := len(e.peerStore.PeersPubKey())
|
||||||
|
|
||||||
|
baseTimeout := 10 * time.Second
|
||||||
|
perPeerTimeout := time.Duration(peerCount) * 100 * time.Millisecond
|
||||||
|
timeout := baseTimeout + perPeerTimeout
|
||||||
|
|
||||||
|
maxTimeout := 30 * time.Second
|
||||||
|
if timeout > maxTimeout {
|
||||||
|
timeout = maxTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// waitWithContext waits for WaitGroup with timeout, returns ctx.Err() on timeout.
|
||||||
|
func waitWithContext(ctx context.Context, wg *sync.WaitGroup) error {
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return nil
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start creates a new WireGuard tunnel interface and listens to events from Signal and Management services
|
// Start creates a new WireGuard tunnel interface and listens to events from Signal and Management services
|
||||||
// Connections to remote peers are not established here.
|
// Connections to remote peers are not established here.
|
||||||
// However, they will be established once an event with a list of peers to connect to will be received from Management Service
|
// However, they will be established once an event with a list of peers to connect to will be received from Management Service
|
||||||
@@ -478,14 +516,14 @@ func (e *Engine) Start(netbirdConfig *mgmProto.NetbirdConfig, mgmtURL *url.URL)
|
|||||||
|
|
||||||
// monitor WireGuard interface lifecycle and restart engine on changes
|
// monitor WireGuard interface lifecycle and restart engine on changes
|
||||||
e.wgIfaceMonitor = NewWGIfaceMonitor()
|
e.wgIfaceMonitor = NewWGIfaceMonitor()
|
||||||
e.wgIfaceMonitorWg.Add(1)
|
e.shutdownWg.Add(1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer e.wgIfaceMonitorWg.Done()
|
defer e.shutdownWg.Done()
|
||||||
|
|
||||||
if shouldRestart, err := e.wgIfaceMonitor.Start(e.ctx, e.wgInterface.Name()); shouldRestart {
|
if shouldRestart, err := e.wgIfaceMonitor.Start(e.ctx, e.wgInterface.Name()); shouldRestart {
|
||||||
log.Infof("WireGuard interface monitor: %s, restarting engine", err)
|
log.Infof("WireGuard interface monitor: %s, restarting engine", err)
|
||||||
e.restartEngine()
|
e.triggerClientRestart()
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
log.Warnf("WireGuard interface monitor: %s", err)
|
log.Warnf("WireGuard interface monitor: %s", err)
|
||||||
}
|
}
|
||||||
@@ -669,9 +707,11 @@ func (e *Engine) removeAllPeers() error {
|
|||||||
func (e *Engine) removePeer(peerKey string) error {
|
func (e *Engine) removePeer(peerKey string) error {
|
||||||
log.Debugf("removing peer from engine %s", peerKey)
|
log.Debugf("removing peer from engine %s", peerKey)
|
||||||
|
|
||||||
|
e.sshMux.Lock()
|
||||||
if !isNil(e.sshServer) {
|
if !isNil(e.sshServer) {
|
||||||
e.sshServer.RemoveAuthorizedKey(peerKey)
|
e.sshServer.RemoveAuthorizedKey(peerKey)
|
||||||
}
|
}
|
||||||
|
e.sshMux.Unlock()
|
||||||
|
|
||||||
e.connMgr.RemovePeerConn(peerKey)
|
e.connMgr.RemovePeerConn(peerKey)
|
||||||
|
|
||||||
@@ -873,6 +913,7 @@ func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error {
|
|||||||
log.Warnf("running SSH server on %s is not supported", runtime.GOOS)
|
log.Warnf("running SSH server on %s is not supported", runtime.GOOS)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
e.sshMux.Lock()
|
||||||
// start SSH server if it wasn't running
|
// start SSH server if it wasn't running
|
||||||
if isNil(e.sshServer) {
|
if isNil(e.sshServer) {
|
||||||
listenAddr := fmt.Sprintf("%s:%d", e.wgInterface.Address().IP.String(), nbssh.DefaultSSHPort)
|
listenAddr := fmt.Sprintf("%s:%d", e.wgInterface.Address().IP.String(), nbssh.DefaultSSHPort)
|
||||||
@@ -880,34 +921,42 @@ func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error {
|
|||||||
listenAddr = fmt.Sprintf("127.0.0.1:%d", nbssh.DefaultSSHPort)
|
listenAddr = fmt.Sprintf("127.0.0.1:%d", nbssh.DefaultSSHPort)
|
||||||
}
|
}
|
||||||
// nil sshServer means it has not yet been started
|
// nil sshServer means it has not yet been started
|
||||||
var err error
|
server, err := e.sshServerFunc(e.config.SSHKey, listenAddr)
|
||||||
e.sshServer, err = e.sshServerFunc(e.config.SSHKey, listenAddr)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
e.sshMux.Unlock()
|
||||||
return fmt.Errorf("create ssh server: %w", err)
|
return fmt.Errorf("create ssh server: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.sshServer = server
|
||||||
|
e.sshMux.Unlock()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// blocking
|
// blocking
|
||||||
err = e.sshServer.Start()
|
err = server.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// will throw error when we stop it even if it is a graceful stop
|
// will throw error when we stop it even if it is a graceful stop
|
||||||
log.Debugf("stopped SSH server with error %v", err)
|
log.Debugf("stopped SSH server with error %v", err)
|
||||||
}
|
}
|
||||||
e.syncMsgMux.Lock()
|
e.sshMux.Lock()
|
||||||
defer e.syncMsgMux.Unlock()
|
|
||||||
e.sshServer = nil
|
e.sshServer = nil
|
||||||
|
e.sshMux.Unlock()
|
||||||
log.Infof("stopped SSH server")
|
log.Infof("stopped SSH server")
|
||||||
}()
|
}()
|
||||||
} else {
|
} else {
|
||||||
|
e.sshMux.Unlock()
|
||||||
log.Debugf("SSH server is already running")
|
log.Debugf("SSH server is already running")
|
||||||
}
|
}
|
||||||
} else if !isNil(e.sshServer) {
|
} else {
|
||||||
// Disable SSH server request, so stop it if it was running
|
e.sshMux.Lock()
|
||||||
err := e.sshServer.Stop()
|
if !isNil(e.sshServer) {
|
||||||
if err != nil {
|
// Disable SSH server request, so stop it if it was running
|
||||||
log.Warnf("failed to stop SSH server %v", err)
|
err := e.sshServer.Stop()
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("failed to stop SSH server %v", err)
|
||||||
|
}
|
||||||
|
e.sshServer = nil
|
||||||
}
|
}
|
||||||
e.sshServer = nil
|
e.sshMux.Unlock()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -944,7 +993,9 @@ func (e *Engine) updateConfig(conf *mgmProto.PeerConfig) error {
|
|||||||
// receiveManagementEvents connects to the Management Service event stream to receive updates from the management service
|
// receiveManagementEvents connects to the Management Service event stream to receive updates from the management service
|
||||||
// E.g. when a new peer has been registered and we are allowed to connect to it.
|
// E.g. when a new peer has been registered and we are allowed to connect to it.
|
||||||
func (e *Engine) receiveManagementEvents() {
|
func (e *Engine) receiveManagementEvents() {
|
||||||
|
e.shutdownWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
defer e.shutdownWg.Done()
|
||||||
info, err := system.GetInfoWithChecks(e.ctx, e.checks)
|
info, err := system.GetInfoWithChecks(e.ctx, e.checks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed to get system info with checks: %v", err)
|
log.Warnf("failed to get system info with checks: %v", err)
|
||||||
@@ -1120,6 +1171,7 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error {
|
|||||||
e.statusRecorder.FinishPeerListModifications()
|
e.statusRecorder.FinishPeerListModifications()
|
||||||
|
|
||||||
// update SSHServer by adding remote peer SSH keys
|
// update SSHServer by adding remote peer SSH keys
|
||||||
|
e.sshMux.Lock()
|
||||||
if !isNil(e.sshServer) {
|
if !isNil(e.sshServer) {
|
||||||
for _, config := range networkMap.GetRemotePeers() {
|
for _, config := range networkMap.GetRemotePeers() {
|
||||||
if config.GetSshConfig() != nil && config.GetSshConfig().GetSshPubKey() != nil {
|
if config.GetSshConfig() != nil && config.GetSshConfig().GetSshPubKey() != nil {
|
||||||
@@ -1130,6 +1182,7 @@ func (e *Engine) updateNetworkMap(networkMap *mgmProto.NetworkMap) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
e.sshMux.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// must set the exclude list after the peers are added. Without it the manager can not figure out the peers parameters from the store
|
// must set the exclude list after the peers are added. Without it the manager can not figure out the peers parameters from the store
|
||||||
@@ -1372,7 +1425,9 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs []netip.Prefix, agentV
|
|||||||
|
|
||||||
// receiveSignalEvents connects to the Signal Service event stream to negotiate connection with remote peers
|
// receiveSignalEvents connects to the Signal Service event stream to negotiate connection with remote peers
|
||||||
func (e *Engine) receiveSignalEvents() {
|
func (e *Engine) receiveSignalEvents() {
|
||||||
|
e.shutdownWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
defer e.shutdownWg.Done()
|
||||||
// connect to a stream of messages coming from the signal server
|
// connect to a stream of messages coming from the signal server
|
||||||
err := e.signal.Receive(e.ctx, func(msg *sProto.Message) error {
|
err := e.signal.Receive(e.ctx, func(msg *sProto.Message) error {
|
||||||
e.syncMsgMux.Lock()
|
e.syncMsgMux.Lock()
|
||||||
@@ -1489,12 +1544,14 @@ func (e *Engine) close() {
|
|||||||
e.statusRecorder.SetWgIface(nil)
|
e.statusRecorder.SetWgIface(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.sshMux.Lock()
|
||||||
if !isNil(e.sshServer) {
|
if !isNil(e.sshServer) {
|
||||||
err := e.sshServer.Stop()
|
err := e.sshServer.Stop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("failed stopping the SSH server: %v", err)
|
log.Warnf("failed stopping the SSH server: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
e.sshMux.Unlock()
|
||||||
|
|
||||||
if e.firewall != nil {
|
if e.firewall != nil {
|
||||||
err := e.firewall.Close(e.stateManager)
|
err := e.firewall.Close(e.stateManager)
|
||||||
@@ -1725,8 +1782,10 @@ func (e *Engine) RunHealthProbes(waitForResult bool) bool {
|
|||||||
return allHealthy
|
return allHealthy
|
||||||
}
|
}
|
||||||
|
|
||||||
// restartEngine restarts the engine by cancelling the client context
|
// triggerClientRestart triggers a full client restart by cancelling the client context.
|
||||||
func (e *Engine) restartEngine() {
|
// Note: This does NOT just restart the engine - it cancels the entire client context,
|
||||||
|
// which causes the connect client's retry loop to create a completely new engine.
|
||||||
|
func (e *Engine) triggerClientRestart() {
|
||||||
e.syncMsgMux.Lock()
|
e.syncMsgMux.Lock()
|
||||||
defer e.syncMsgMux.Unlock()
|
defer e.syncMsgMux.Unlock()
|
||||||
|
|
||||||
@@ -1748,7 +1807,9 @@ func (e *Engine) startNetworkMonitor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.networkMonitor = networkmonitor.New()
|
e.networkMonitor = networkmonitor.New()
|
||||||
|
e.shutdownWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
defer e.shutdownWg.Done()
|
||||||
if err := e.networkMonitor.Listen(e.ctx); err != nil {
|
if err := e.networkMonitor.Listen(e.ctx); err != nil {
|
||||||
if errors.Is(err, context.Canceled) {
|
if errors.Is(err, context.Canceled) {
|
||||||
log.Infof("network monitor stopped")
|
log.Infof("network monitor stopped")
|
||||||
@@ -1758,8 +1819,8 @@ func (e *Engine) startNetworkMonitor() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Network monitor: detected network change, restarting engine")
|
log.Infof("Network monitor: detected network change, triggering client restart")
|
||||||
e.restartEngine()
|
e.triggerClientRestart()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
// Manager handles netflow tracking and logging
|
// Manager handles netflow tracking and logging
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
|
shutdownWg sync.WaitGroup
|
||||||
logger nftypes.FlowLogger
|
logger nftypes.FlowLogger
|
||||||
flowConfig *nftypes.FlowConfig
|
flowConfig *nftypes.FlowConfig
|
||||||
conntrack nftypes.ConnTracker
|
conntrack nftypes.ConnTracker
|
||||||
@@ -105,8 +106,15 @@ func (m *Manager) resetClient() error {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
m.cancel = cancel
|
m.cancel = cancel
|
||||||
|
|
||||||
go m.receiveACKs(ctx, flowClient)
|
m.shutdownWg.Add(2)
|
||||||
go m.startSender(ctx)
|
go func() {
|
||||||
|
defer m.shutdownWg.Done()
|
||||||
|
m.receiveACKs(ctx, flowClient)
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
defer m.shutdownWg.Done()
|
||||||
|
m.startSender(ctx)
|
||||||
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -176,11 +184,12 @@ func (m *Manager) Update(update *nftypes.FlowConfig) error {
|
|||||||
// Close cleans up all resources
|
// Close cleans up all resources
|
||||||
func (m *Manager) Close() {
|
func (m *Manager) Close() {
|
||||||
m.mux.Lock()
|
m.mux.Lock()
|
||||||
defer m.mux.Unlock()
|
|
||||||
|
|
||||||
if err := m.disableFlow(); err != nil {
|
if err := m.disableFlow(); err != nil {
|
||||||
log.Warnf("failed to disable flow manager: %v", err)
|
log.Warnf("failed to disable flow manager: %v", err)
|
||||||
}
|
}
|
||||||
|
m.mux.Unlock()
|
||||||
|
|
||||||
|
m.shutdownWg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLogger returns the flow logger
|
// GetLogger returns the flow logger
|
||||||
|
|||||||
@@ -19,11 +19,10 @@ type SRWatcher struct {
|
|||||||
signalClient chNotifier
|
signalClient chNotifier
|
||||||
relayManager chNotifier
|
relayManager chNotifier
|
||||||
|
|
||||||
listeners map[chan struct{}]struct{}
|
listeners map[chan struct{}]struct{}
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
iFaceDiscover stdnet.ExternalIFaceDiscover
|
iFaceDiscover stdnet.ExternalIFaceDiscover
|
||||||
iceConfig ice.Config
|
iceConfig ice.Config
|
||||||
|
|
||||||
cancelIceMonitor context.CancelFunc
|
cancelIceMonitor context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ type DefaultManager struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
stop context.CancelFunc
|
stop context.CancelFunc
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
|
shutdownWg sync.WaitGroup
|
||||||
clientNetworks map[route.HAUniqueID]*client.Watcher
|
clientNetworks map[route.HAUniqueID]*client.Watcher
|
||||||
routeSelector *routeselector.RouteSelector
|
routeSelector *routeselector.RouteSelector
|
||||||
serverRouter *server.Router
|
serverRouter *server.Router
|
||||||
@@ -283,6 +284,7 @@ func (m *DefaultManager) SetDNSForwarderPort(port uint16) {
|
|||||||
// Stop stops the manager watchers and clean firewall rules
|
// Stop stops the manager watchers and clean firewall rules
|
||||||
func (m *DefaultManager) Stop(stateManager *statemanager.Manager) {
|
func (m *DefaultManager) Stop(stateManager *statemanager.Manager) {
|
||||||
m.stop()
|
m.stop()
|
||||||
|
m.shutdownWg.Wait()
|
||||||
if m.serverRouter != nil {
|
if m.serverRouter != nil {
|
||||||
m.serverRouter.CleanUp()
|
m.serverRouter.CleanUp()
|
||||||
}
|
}
|
||||||
@@ -485,7 +487,11 @@ func (m *DefaultManager) TriggerSelection(networks route.HAMap) {
|
|||||||
}
|
}
|
||||||
clientNetworkWatcher := client.NewWatcher(config)
|
clientNetworkWatcher := client.NewWatcher(config)
|
||||||
m.clientNetworks[id] = clientNetworkWatcher
|
m.clientNetworks[id] = clientNetworkWatcher
|
||||||
go clientNetworkWatcher.Start()
|
m.shutdownWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer m.shutdownWg.Done()
|
||||||
|
clientNetworkWatcher.Start()
|
||||||
|
}()
|
||||||
clientNetworkWatcher.SendUpdate(client.RoutesUpdate{Routes: routes})
|
clientNetworkWatcher.SendUpdate(client.RoutesUpdate{Routes: routes})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,7 +533,11 @@ func (m *DefaultManager) updateClientNetworks(updateSerial uint64, networks rout
|
|||||||
}
|
}
|
||||||
clientNetworkWatcher = client.NewWatcher(config)
|
clientNetworkWatcher = client.NewWatcher(config)
|
||||||
m.clientNetworks[id] = clientNetworkWatcher
|
m.clientNetworks[id] = clientNetworkWatcher
|
||||||
go clientNetworkWatcher.Start()
|
m.shutdownWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer m.shutdownWg.Done()
|
||||||
|
clientNetworkWatcher.Start()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
update := client.RoutesUpdate{
|
update := client.RoutesUpdate{
|
||||||
UpdateSerial: updateSerial,
|
UpdateSerial: updateSerial,
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
"github.com/hashicorp/go-multierror"
|
"github.com/hashicorp/go-multierror"
|
||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/errors"
|
"github.com/netbirdio/netbird/client/errors"
|
||||||
"github.com/netbirdio/netbird/route"
|
"github.com/netbirdio/netbird/route"
|
||||||
)
|
)
|
||||||
@@ -128,13 +126,11 @@ func (rs *RouteSelector) IsSelected(routeID route.NetID) bool {
|
|||||||
defer rs.mu.RUnlock()
|
defer rs.mu.RUnlock()
|
||||||
|
|
||||||
if rs.deselectAll {
|
if rs.deselectAll {
|
||||||
log.Debugf("Route %s not selected (deselect all)", routeID)
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
_, deselected := rs.deselectedRoutes[routeID]
|
_, deselected := rs.deselectedRoutes[routeID]
|
||||||
isSelected := !deselected
|
isSelected := !deselected
|
||||||
log.Debugf("Route %s selection status: %v (deselected: %v)", routeID, isSelected, deselected)
|
|
||||||
return isSelected
|
return isSelected
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user