mirror of https://github.com/tailscale/tailscale/
wgengine/monitor: ignore duplicate RTM_NEWADDRs
Ignoring the events at this layer is the simpler path for right now, a broader change should follow to suppress irrelevant change events in a higher layer so as to avoid related problems with other monitoring paths on other platforms. This approach may also carry a small risk that it applies an at-most-once invariant low in the chain that could be assumed otherwise higher in the code. I adjusted the newAddrMessage type to include interface index rather than a label, as labels are not always supplied, and in particular on my test hosts they were consistently missing for ipv6 address messages. I adjusted the newAddrMessage.Addr field to be populated from Attributes.Address rather than Attributes.Local, as again for ipv6 .Local was always empty, and with ipv4 the .Address and .Local contained the same contents in each of my test environments. Update #4282 Signed-off-by: James Tucker <james@tailscale.com>pull/4402/head
parent
2f69c383a5
commit
f4aad61e67
@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
"github.com/mdlayher/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
func newAddrMsg(iface uint32, addr string, typ netlink.HeaderType) netlink.Message {
|
||||
ip := net.ParseIP(addr)
|
||||
if ip == nil {
|
||||
panic("newAddrMsg: invalid addr: " + addr)
|
||||
}
|
||||
|
||||
addrMsg := rtnetlink.AddressMessage{
|
||||
Index: iface,
|
||||
Attributes: &rtnetlink.AddressAttributes{
|
||||
Address: ip,
|
||||
},
|
||||
}
|
||||
|
||||
b, err := addrMsg.MarshalBinary()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return netlink.Message{
|
||||
Header: netlink.Header{Type: typ},
|
||||
Data: b,
|
||||
}
|
||||
}
|
||||
|
||||
// See issue #4282 and nlConn.addrCache.
|
||||
func TestIgnoreDuplicateNEWADDR(t *testing.T) {
|
||||
mustReceive := func(c *nlConn) message {
|
||||
msg, err := c.Receive()
|
||||
if err != nil {
|
||||
t.Fatalf("mustReceive: unwanted error: %s", err)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
t.Run("suppress duplicate NEWADDRs", func(t *testing.T) {
|
||||
c := nlConn{
|
||||
buffered: []netlink.Message{
|
||||
newAddrMsg(1, "192.168.0.5", unix.RTM_NEWADDR),
|
||||
newAddrMsg(1, "192.168.0.5", unix.RTM_NEWADDR),
|
||||
},
|
||||
addrCache: make(map[uint32]map[netaddr.IP]bool),
|
||||
}
|
||||
|
||||
msg := mustReceive(&c)
|
||||
if _, ok := msg.(*newAddrMessage); !ok {
|
||||
t.Fatalf("want newAddrMessage, got %T %v", msg, msg)
|
||||
}
|
||||
|
||||
msg = mustReceive(&c)
|
||||
if _, ok := msg.(ignoreMessage); !ok {
|
||||
t.Fatalf("want ignoreMessage, got %T %v", msg, msg)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("do not suppress after DELADDR", func(t *testing.T) {
|
||||
c := nlConn{
|
||||
buffered: []netlink.Message{
|
||||
newAddrMsg(1, "192.168.0.5", unix.RTM_NEWADDR),
|
||||
newAddrMsg(1, "192.168.0.5", unix.RTM_DELADDR),
|
||||
newAddrMsg(1, "192.168.0.5", unix.RTM_NEWADDR),
|
||||
},
|
||||
addrCache: make(map[uint32]map[netaddr.IP]bool),
|
||||
}
|
||||
|
||||
msg := mustReceive(&c)
|
||||
if _, ok := msg.(*newAddrMessage); !ok {
|
||||
t.Fatalf("want newAddrMessage, got %T %v", msg, msg)
|
||||
}
|
||||
|
||||
msg = mustReceive(&c)
|
||||
if m, ok := msg.(*newAddrMessage); !ok {
|
||||
t.Fatalf("want newAddrMessage, got %T %v", msg, msg)
|
||||
} else {
|
||||
if !m.Delete {
|
||||
t.Fatalf("want delete, got %#v", m)
|
||||
}
|
||||
}
|
||||
|
||||
msg = mustReceive(&c)
|
||||
if _, ok := msg.(*newAddrMessage); !ok {
|
||||
t.Fatalf("want newAddrMessage, got %T %v", msg, msg)
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue