mirror of
https://github.com/netbirdio/netbird.git
synced 2026-06-29 11:19:56 +00:00
Compare commits
3 Commits
netmap_pro
...
fix/skip-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4642233b83 | ||
|
|
65b3117603 | ||
|
|
0be397431e |
@@ -28,11 +28,16 @@ type NetworkMonitor struct {
|
||||
cancel context.CancelFunc
|
||||
wg sync.WaitGroup
|
||||
mu sync.Mutex
|
||||
|
||||
// nexthopChanged reports whether the default next hop changed; overridable in tests.
|
||||
nexthopChanged func(oldv4, oldv6 systemops.Nexthop) bool
|
||||
}
|
||||
|
||||
// New creates a new network monitor.
|
||||
func New() *NetworkMonitor {
|
||||
return &NetworkMonitor{}
|
||||
return &NetworkMonitor{
|
||||
nexthopChanged: nexthopChanged,
|
||||
}
|
||||
}
|
||||
|
||||
// Listen begins monitoring network changes. When a change is detected, this function will return without error.
|
||||
@@ -97,7 +102,12 @@ func (nw *NetworkMonitor) Listen(ctx context.Context) (err error) {
|
||||
case <-event:
|
||||
timer.Reset(debounceTime)
|
||||
case <-timer.C:
|
||||
return nil
|
||||
// A flapping NIC may return to the same default route after the
|
||||
// debounce window; only restart if the next hop actually changed.
|
||||
if nw.nexthopChanged(nexthop4, nexthop6) {
|
||||
return nil
|
||||
}
|
||||
log.Debug("Network monitor: default route unchanged after debounce, ignoring")
|
||||
case <-ctx.Done():
|
||||
timer.Stop()
|
||||
return ctx.Err()
|
||||
@@ -134,3 +144,26 @@ func (nw *NetworkMonitor) checkChanges(ctx context.Context, event chan struct{},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// nexthopChanged reports whether the current default next hop differs from the
|
||||
// given baseline, per protocol. A failed lookup is treated as an absent route
|
||||
// (zero Nexthop), so a protocol that had no default route to begin with (e.g.
|
||||
// IPv6 in a single-stack network) does not by itself count as a change.
|
||||
func nexthopChanged(oldv4, oldv6 systemops.Nexthop) bool {
|
||||
newv4, _ := systemops.GetNextHop(netip.IPv4Unspecified())
|
||||
newv6, _ := systemops.GetNextHop(netip.IPv6Unspecified())
|
||||
return !sameNexthop(oldv4, newv4) || !sameNexthop(oldv6, newv6)
|
||||
}
|
||||
|
||||
func sameNexthop(a, b systemops.Nexthop) bool {
|
||||
if a.IP != b.IP {
|
||||
return false
|
||||
}
|
||||
if (a.Intf == nil) != (b.Intf == nil) {
|
||||
return false
|
||||
}
|
||||
if a.Intf != nil && a.Intf.Index != b.Intf.Index {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package networkmonitor
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/netip"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -59,6 +61,7 @@ func TestNetworkMonitor_Event(t *testing.T) {
|
||||
}
|
||||
}
|
||||
nw := New()
|
||||
nw.nexthopChanged = func(_, _ systemops.Nexthop) bool { return true }
|
||||
defer nw.Stop()
|
||||
|
||||
var resErr error
|
||||
@@ -80,6 +83,7 @@ func TestNetworkMonitor_MultiEvent(t *testing.T) {
|
||||
checkChangeFn = me.checkChange
|
||||
|
||||
nw := New()
|
||||
nw.nexthopChanged = func(_, _ systemops.Nexthop) bool { return true }
|
||||
defer nw.Stop()
|
||||
|
||||
done := make(chan struct{})
|
||||
@@ -97,3 +101,31 @@ func TestNetworkMonitor_MultiEvent(t *testing.T) {
|
||||
t.Errorf("unexpected duration: %v", time.Since(started))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSameNexthop(t *testing.T) {
|
||||
eth0 := &net.Interface{Index: 1, Name: "eth0"}
|
||||
eth1 := &net.Interface{Index: 2, Name: "eth1"}
|
||||
ip1 := netip.MustParseAddr("192.168.1.1")
|
||||
ip2 := netip.MustParseAddr("192.168.2.1")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
a, b systemops.Nexthop
|
||||
want bool
|
||||
}{
|
||||
{"identical", systemops.Nexthop{IP: ip1, Intf: eth0}, systemops.Nexthop{IP: ip1, Intf: eth0}, true},
|
||||
{"same index different pointer", systemops.Nexthop{IP: ip1, Intf: eth0}, systemops.Nexthop{IP: ip1, Intf: &net.Interface{Index: 1, Name: "eth0"}}, true},
|
||||
{"different ip", systemops.Nexthop{IP: ip1, Intf: eth0}, systemops.Nexthop{IP: ip2, Intf: eth0}, false},
|
||||
{"different interface", systemops.Nexthop{IP: ip1, Intf: eth0}, systemops.Nexthop{IP: ip1, Intf: eth1}, false},
|
||||
{"both nil interface", systemops.Nexthop{IP: ip1}, systemops.Nexthop{IP: ip1}, true},
|
||||
{"one nil interface", systemops.Nexthop{IP: ip1, Intf: eth0}, systemops.Nexthop{IP: ip1}, false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := sameNexthop(tt.a, tt.b); got != tt.want {
|
||||
t.Errorf("sameNexthop() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user