tailscale/wgengine/monitor/monitor_linux_test.go
James Tucker f4aad61e67 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>
2022-04-11 14:35:19 -07:00

101 lines
2.3 KiB
Go

// 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)
}
})
}