mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 16:26:38 +00:00
Merge branch 'shutdown-block' into feature/detect-mac-wakeup
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,8 +200,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
|
||||||
|
|
||||||
// dns forwarder port
|
// dns forwarder port
|
||||||
dnsFwdPort uint16
|
dnsFwdPort uint16
|
||||||
@@ -326,10 +328,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
|
||||||
@@ -337,8 +335,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()
|
||||||
|
|
||||||
@@ -349,12 +345,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
|
||||||
@@ -484,14 +520,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)
|
||||||
}
|
}
|
||||||
@@ -892,7 +928,9 @@ func (e *Engine) updateSSH(sshConf *mgmProto.SSHConfig) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create ssh server: %w", err)
|
return fmt.Errorf("create ssh server: %w", err)
|
||||||
}
|
}
|
||||||
|
e.shutdownWg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
defer e.shutdownWg.Done()
|
||||||
// blocking
|
// blocking
|
||||||
err = e.sshServer.Start()
|
err = e.sshServer.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -950,7 +988,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)
|
||||||
@@ -1368,7 +1408,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()
|
||||||
@@ -1724,8 +1766,10 @@ func (e *Engine) probeICE(stuns, turns []*stun.URI) []relay.ProbeResult {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
||||||
|
|
||||||
@@ -1747,7 +1791,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")
|
||||||
@@ -1757,8 +1803,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,11 @@ 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
|
shutdownWg sync.WaitGroup
|
||||||
iceConfig ice.Config
|
iFaceDiscover stdnet.ExternalIFaceDiscover
|
||||||
|
iceConfig ice.Config
|
||||||
cancelIceMonitor context.CancelFunc
|
cancelIceMonitor context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,11 @@ func (w *SRWatcher) Start() {
|
|||||||
w.cancelIceMonitor = cancel
|
w.cancelIceMonitor = cancel
|
||||||
|
|
||||||
iceMonitor := NewICEMonitor(w.iFaceDiscover, w.iceConfig, GetICEMonitorPeriod())
|
iceMonitor := NewICEMonitor(w.iFaceDiscover, w.iceConfig, GetICEMonitorPeriod())
|
||||||
go iceMonitor.Start(ctx, w.onICEChanged)
|
w.shutdownWg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer w.shutdownWg.Done()
|
||||||
|
iceMonitor.Start(ctx, w.onICEChanged)
|
||||||
|
}()
|
||||||
w.signalClient.SetOnReconnectedListener(w.onReconnected)
|
w.signalClient.SetOnReconnectedListener(w.onReconnected)
|
||||||
w.relayManager.SetOnReconnectedListener(w.onReconnected)
|
w.relayManager.SetOnReconnectedListener(w.onReconnected)
|
||||||
|
|
||||||
@@ -60,14 +64,16 @@ func (w *SRWatcher) Start() {
|
|||||||
|
|
||||||
func (w *SRWatcher) Close() {
|
func (w *SRWatcher) Close() {
|
||||||
w.mu.Lock()
|
w.mu.Lock()
|
||||||
defer w.mu.Unlock()
|
|
||||||
|
|
||||||
if w.cancelIceMonitor == nil {
|
if w.cancelIceMonitor == nil {
|
||||||
|
w.mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.cancelIceMonitor()
|
w.cancelIceMonitor()
|
||||||
w.signalClient.SetOnReconnectedListener(nil)
|
w.signalClient.SetOnReconnectedListener(nil)
|
||||||
w.relayManager.SetOnReconnectedListener(nil)
|
w.relayManager.SetOnReconnectedListener(nil)
|
||||||
|
w.mu.Unlock()
|
||||||
|
|
||||||
|
w.shutdownWg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *SRWatcher) NewListener() chan struct{} {
|
func (w *SRWatcher) NewListener() chan struct{} {
|
||||||
|
|||||||
@@ -78,6 +78,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
|
||||||
@@ -273,6 +274,7 @@ func (m *DefaultManager) SetFirewall(firewall firewall.Manager) error {
|
|||||||
// 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()
|
||||||
}
|
}
|
||||||
@@ -474,7 +476,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})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +522,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,
|
||||||
|
|||||||
Reference in New Issue
Block a user