Do not hold NIC local address in neighbor entries

Previously, the NIC local address used when completing link resolution
was held in the neighbor entry. A neighbor is not identified by any
NIC local address so remove it.

PiperOrigin-RevId: 338699695
This commit is contained in:
Ghanan Gowripalan
2020-10-23 10:31:44 -07:00
committed by gVisor bot
parent 5d909dd49c
commit dad08229b8
9 changed files with 446 additions and 311 deletions
+21 -4
View File
@@ -151,7 +151,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
remoteAddr := tcpip.Address(h.ProtocolAddressSender())
remoteLinkAddr := tcpip.LinkAddress(h.HardwareAddressSender())
e.nud.HandleProbe(remoteAddr, localAddr, ProtocolNumber, remoteLinkAddr, e.protocol)
e.nud.HandleProbe(remoteAddr, ProtocolNumber, remoteLinkAddr, e.protocol)
}
respPkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
@@ -208,6 +208,7 @@ func (e *endpoint) HandlePacket(r *stack.Route, pkt *stack.PacketBuffer) {
// protocol implements stack.NetworkProtocol and stack.LinkAddressResolver.
type protocol struct {
stack *stack.Stack
}
func (p *protocol) Number() tcpip.NetworkProtocolNumber { return ProtocolNumber }
@@ -236,11 +237,27 @@ func (*protocol) LinkAddressProtocol() tcpip.NetworkProtocolNumber {
}
// LinkAddressRequest implements stack.LinkAddressResolver.LinkAddressRequest.
func (*protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, nic stack.NetworkInterface) *tcpip.Error {
func (p *protocol) LinkAddressRequest(targetAddr, localAddr tcpip.Address, remoteLinkAddr tcpip.LinkAddress, nic stack.NetworkInterface) *tcpip.Error {
if len(remoteLinkAddr) == 0 {
remoteLinkAddr = header.EthernetBroadcastAddress
}
nicID := nic.ID()
if len(localAddr) == 0 {
addr, err := p.stack.GetMainNICAddress(nicID, header.IPv4ProtocolNumber)
if err != nil {
return err
}
if len(addr.Address) == 0 {
return tcpip.ErrNetworkUnreachable
}
localAddr = addr.Address
} else if p.stack.CheckLocalAddress(nicID, header.IPv4ProtocolNumber, localAddr) == 0 {
return tcpip.ErrBadLocalAddress
}
pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
ReserveHeaderBytes: int(nic.MaxHeaderLength()) + header.ARPSize,
})
@@ -297,6 +314,6 @@ func (*protocol) Parse(pkt *stack.PacketBuffer) (proto tcpip.TransportProtocolNu
// Note, to make sure that the ARP endpoint receives ARP packets, the "arp"
// address must be added to every NIC that should respond to ARP requests. See
// ProtocolAddress for more details.
func NewProtocol(*stack.Stack) stack.NetworkProtocol {
return &protocol{}
func NewProtocol(s *stack.Stack) stack.NetworkProtocol {
return &protocol{stack: s}
}
+115 -27
View File
@@ -404,9 +404,6 @@ func TestDirectRequestWithNeighborCache(t *testing.T) {
if got, want := neigh.LinkAddr, test.senderLinkAddr; got != want {
t.Errorf("got neighbor LinkAddr = %s, want = %s", got, want)
}
if got, want := neigh.LocalAddr, stackAddr; got != want {
t.Errorf("got neighbor LocalAddr = %s, want = %s", got, want)
}
if got, want := neigh.State, stack.Stale; got != want {
t.Errorf("got neighbor State = %s, want = %s", got, want)
}
@@ -427,10 +424,12 @@ var _ stack.NetworkInterface = (*testInterface)(nil)
type testInterface struct {
stack.LinkEndpoint
nicID tcpip.NICID
}
func (*testInterface) ID() tcpip.NICID {
return 1
func (t *testInterface) ID() tcpip.NICID {
return t.nicID
}
func (*testInterface) IsLoopback() bool {
@@ -454,42 +453,131 @@ func (t *testInterface) WritePacketToRemote(remoteLinkAddr tcpip.LinkAddress, gs
}
func TestLinkAddressRequest(t *testing.T) {
const nicID = 1
testAddr := tcpip.Address([]byte{1, 2, 3, 4})
tests := []struct {
name string
nicAddr tcpip.Address
localAddr tcpip.Address
remoteLinkAddr tcpip.LinkAddress
expectLinkAddr tcpip.LinkAddress
expectedErr *tcpip.Error
expectedLocalAddr tcpip.Address
expectedRemoteLinkAddr tcpip.LinkAddress
}{
{
name: "Unicast",
remoteLinkAddr: remoteLinkAddr,
expectLinkAddr: remoteLinkAddr,
name: "Unicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
},
{
name: "Multicast",
name: "Multicast",
nicAddr: stackAddr,
localAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
},
{
name: "Unicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: remoteLinkAddr,
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: remoteLinkAddr,
},
{
name: "Multicast with unspecified source",
nicAddr: stackAddr,
remoteLinkAddr: "",
expectedLocalAddr: stackAddr,
expectedRemoteLinkAddr: header.EthernetBroadcastAddress,
},
{
name: "Unicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrBadLocalAddress,
},
{
name: "Multicast with unassigned address",
localAddr: testAddr,
remoteLinkAddr: "",
expectLinkAddr: header.EthernetBroadcastAddress,
expectedErr: tcpip.ErrBadLocalAddress,
},
{
name: "Unicast with no local address available",
remoteLinkAddr: remoteLinkAddr,
expectedErr: tcpip.ErrNetworkUnreachable,
},
{
name: "Multicast with no local address available",
remoteLinkAddr: "",
expectedErr: tcpip.ErrNetworkUnreachable,
},
}
for _, test := range tests {
p := arp.NewProtocol(nil)
linkRes, ok := p.(stack.LinkAddressResolver)
if !ok {
t.Fatal("expected ARP protocol to implement stack.LinkAddressResolver")
}
t.Run(test.name, func(t *testing.T) {
s := stack.New(stack.Options{
NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
})
p := s.NetworkProtocolInstance(arp.ProtocolNumber)
linkRes, ok := p.(stack.LinkAddressResolver)
if !ok {
t.Fatal("expected ARP protocol to implement stack.LinkAddressResolver")
}
linkEP := channel.New(defaultChannelSize, defaultMTU, stackLinkAddr)
if err := linkRes.LinkAddressRequest(stackAddr, remoteAddr, test.remoteLinkAddr, &testInterface{LinkEndpoint: linkEP}); err != nil {
t.Errorf("got p.LinkAddressRequest(%s, %s, %s, _) = %s", stackAddr, remoteAddr, test.remoteLinkAddr, err)
}
linkEP := channel.New(defaultChannelSize, defaultMTU, stackLinkAddr)
if err := s.CreateNIC(nicID, linkEP); err != nil {
t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
}
pkt, ok := linkEP.Read()
if !ok {
t.Fatal("expected to send a link address request")
}
if len(test.nicAddr) != 0 {
if err := s.AddAddress(nicID, ipv4.ProtocolNumber, test.nicAddr); err != nil {
t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, ipv4.ProtocolNumber, test.nicAddr, err)
}
}
if got, want := pkt.Route.RemoteLinkAddress, test.expectLinkAddr; got != want {
t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", got, want)
}
// We pass a test network interface to LinkAddressRequest with the same
// NIC ID and link endpoint used by the NIC we created earlier so that we
// can mock a link address request and observe the packets sent to the
// link endpoint even though the stack uses the real NIC to validate the
// local address.
if err := linkRes.LinkAddressRequest(remoteAddr, test.localAddr, test.remoteLinkAddr, &testInterface{LinkEndpoint: linkEP, nicID: nicID}); err != test.expectedErr {
t.Fatalf("got p.LinkAddressRequest(%s, %s, %s, _) = %s, want = %s", remoteAddr, test.localAddr, test.remoteLinkAddr, err, test.expectedErr)
}
if test.expectedErr != nil {
return
}
pkt, ok := linkEP.Read()
if !ok {
t.Fatal("expected to send a link address request")
}
if pkt.Route.RemoteLinkAddress != test.expectedRemoteLinkAddr {
t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", pkt.Route.RemoteLinkAddress, test.expectedRemoteLinkAddr)
}
rep := header.ARP(stack.PayloadSince(pkt.Pkt.NetworkHeader()))
if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
t.Errorf("got HardwareAddressSender = %s, want = %s", got, stackLinkAddr)
}
if got := tcpip.Address(rep.ProtocolAddressSender()); got != test.expectedLocalAddr {
t.Errorf("got ProtocolAddressSender = %s, want = %s", got, test.expectedLocalAddr)
}
if got, want := tcpip.LinkAddress(rep.HardwareAddressTarget()), tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00"); got != want {
t.Errorf("got HardwareAddressTarget = %s, want = %s", got, want)
}
if got := tcpip.Address(rep.ProtocolAddressTarget()); got != remoteAddr {
t.Errorf("got ProtocolAddressTarget = %s, want = %s", got, remoteAddr)
}
})
}
}
+3 -3
View File
@@ -287,7 +287,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
received.Invalid.Increment()
return
} else if e.nud != nil {
e.nud.HandleProbe(r.RemoteAddress, r.LocalAddress, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
e.nud.HandleProbe(r.RemoteAddress, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
} else {
e.linkAddrCache.AddLinkAddress(e.nic.ID(), r.RemoteAddress, sourceLinkAddr)
}
@@ -558,7 +558,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
if e.nud != nil {
// A RS with a specified source IP address modifies the NUD state
// machine in the same way a reachability probe would.
e.nud.HandleProbe(r.RemoteAddress, r.LocalAddress, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
e.nud.HandleProbe(r.RemoteAddress, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
}
}
@@ -608,7 +608,7 @@ func (e *endpoint) handleICMP(r *stack.Route, pkt *stack.PacketBuffer, hasFragme
// If the RA has the source link layer option, update the link address
// cache with the link address for the advertised router.
if len(sourceLinkAddr) != 0 && e.nud != nil {
e.nud.HandleProbe(routerAddr, r.LocalAddress, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
e.nud.HandleProbe(routerAddr, header.IPv6ProtocolNumber, sourceLinkAddr, e.protocol)
}
e.mu.Lock()
+75 -24
View File
@@ -51,6 +51,7 @@ const (
var (
lladdr0 = header.LinkLocalAddr(linkAddr0)
lladdr1 = header.LinkLocalAddr(linkAddr1)
lladdr2 = header.LinkLocalAddr(linkAddr2)
)
type stubLinkEndpoint struct {
@@ -108,15 +109,15 @@ type stubNUDHandler struct {
var _ stack.NUDHandler = (*stubNUDHandler)(nil)
func (s *stubNUDHandler) HandleProbe(remoteAddr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, linkRes stack.LinkAddressResolver) {
func (s *stubNUDHandler) HandleProbe(tcpip.Address, tcpip.NetworkProtocolNumber, tcpip.LinkAddress, stack.LinkAddressResolver) {
s.probeCount++
}
func (s *stubNUDHandler) HandleConfirmation(addr tcpip.Address, linkAddr tcpip.LinkAddress, flags stack.ReachabilityConfirmationFlags) {
func (s *stubNUDHandler) HandleConfirmation(tcpip.Address, tcpip.LinkAddress, stack.ReachabilityConfirmationFlags) {
s.confirmationCount++
}
func (*stubNUDHandler) HandleUpperLevelConfirmation(addr tcpip.Address) {
func (*stubNUDHandler) HandleUpperLevelConfirmation(tcpip.Address) {
}
var _ stack.NetworkInterface = (*testInterface)(nil)
@@ -1245,22 +1246,66 @@ func TestLinkAddressRequest(t *testing.T) {
mcaddr := header.EthernetAddressFromMulticastIPv6Address(snaddr)
tests := []struct {
name string
remoteLinkAddr tcpip.LinkAddress
expectedLinkAddr tcpip.LinkAddress
expectedAddr tcpip.Address
name string
nicAddr tcpip.Address
localAddr tcpip.Address
remoteLinkAddr tcpip.LinkAddress
expectedErr *tcpip.Error
expectedRemoteAddr tcpip.Address
expectedRemoteLinkAddr tcpip.LinkAddress
}{
{
name: "Unicast",
remoteLinkAddr: linkAddr1,
expectedLinkAddr: linkAddr1,
expectedAddr: lladdr0,
name: "Unicast",
nicAddr: lladdr1,
localAddr: lladdr1,
remoteLinkAddr: linkAddr1,
expectedRemoteAddr: lladdr0,
expectedRemoteLinkAddr: linkAddr1,
},
{
name: "Multicast",
remoteLinkAddr: "",
expectedLinkAddr: mcaddr,
expectedAddr: snaddr,
name: "Multicast",
nicAddr: lladdr1,
localAddr: lladdr1,
remoteLinkAddr: "",
expectedRemoteAddr: snaddr,
expectedRemoteLinkAddr: mcaddr,
},
{
name: "Unicast with unspecified source",
nicAddr: lladdr1,
remoteLinkAddr: linkAddr1,
expectedRemoteAddr: lladdr0,
expectedRemoteLinkAddr: linkAddr1,
},
{
name: "Multicast with unspecified source",
nicAddr: lladdr1,
remoteLinkAddr: "",
expectedRemoteAddr: snaddr,
expectedRemoteLinkAddr: mcaddr,
},
{
name: "Unicast with unassigned address",
localAddr: lladdr1,
remoteLinkAddr: linkAddr1,
expectedErr: tcpip.ErrNetworkUnreachable,
},
{
name: "Multicast with unassigned address",
localAddr: lladdr1,
remoteLinkAddr: "",
expectedErr: tcpip.ErrNetworkUnreachable,
},
{
name: "Unicast with no local address available",
remoteLinkAddr: linkAddr1,
expectedErr: tcpip.ErrNetworkUnreachable,
},
{
name: "Multicast with no local address available",
remoteLinkAddr: "",
expectedErr: tcpip.ErrNetworkUnreachable,
},
}
@@ -1278,34 +1323,40 @@ func TestLinkAddressRequest(t *testing.T) {
if err := s.CreateNIC(nicID, linkEP); err != nil {
t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
}
if err := s.AddAddress(nicID, ProtocolNumber, lladdr1); err != nil {
t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, ProtocolNumber, lladdr1, err)
if len(test.nicAddr) != 0 {
if err := s.AddAddress(nicID, ProtocolNumber, test.nicAddr); err != nil {
t.Fatalf("s.AddAddress(%d, %d, %s): %s", nicID, ProtocolNumber, test.nicAddr, err)
}
}
// We pass a test network interface to LinkAddressRequest with the same NIC
// ID and link endpoint used by the NIC we created earlier so that we can
// mock a link address request and observe the packets sent to the link
// endpoint even though the stack uses the real NIC.
if err := linkRes.LinkAddressRequest(lladdr0, lladdr1, test.remoteLinkAddr, &testInterface{LinkEndpoint: linkEP, nicID: nicID}); err != nil {
t.Errorf("got p.LinkAddressRequest(%s, %s, %s, _) = %s", lladdr0, lladdr1, test.remoteLinkAddr, err)
if err := linkRes.LinkAddressRequest(lladdr0, test.localAddr, test.remoteLinkAddr, &testInterface{LinkEndpoint: linkEP, nicID: nicID}); err != test.expectedErr {
t.Errorf("got p.LinkAddressRequest(%s, %s, %s, _) = %s, want = %s", lladdr0, test.localAddr, test.remoteLinkAddr, err, test.expectedErr)
}
if test.expectedErr != nil {
return
}
pkt, ok := linkEP.Read()
if !ok {
t.Fatal("expected to send a link address request")
}
if pkt.Route.RemoteLinkAddress != test.expectedLinkAddr {
t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", pkt.Route.RemoteLinkAddress, test.expectedLinkAddr)
if pkt.Route.RemoteLinkAddress != test.expectedRemoteLinkAddr {
t.Errorf("got pkt.Route.RemoteLinkAddress = %s, want = %s", pkt.Route.RemoteLinkAddress, test.expectedRemoteLinkAddr)
}
if pkt.Route.RemoteAddress != test.expectedAddr {
t.Errorf("got pkt.Route.RemoteAddress = %s, want = %s", pkt.Route.RemoteAddress, test.expectedAddr)
if pkt.Route.RemoteAddress != test.expectedRemoteAddr {
t.Errorf("got pkt.Route.RemoteAddress = %s, want = %s", pkt.Route.RemoteAddress, test.expectedRemoteAddr)
}
if pkt.Route.LocalAddress != lladdr1 {
t.Errorf("got pkt.Route.LocalAddress = %s, want = %s", pkt.Route.LocalAddress, lladdr1)
}
checker.IPv6(t, stack.PayloadSince(pkt.Pkt.NetworkHeader()),
checker.SrcAddr(lladdr1),
checker.DstAddr(test.expectedAddr),
checker.DstAddr(test.expectedRemoteAddr),
checker.TTL(header.NDPHopLimit),
checker.NDPNS(
checker.NDPNSTargetAddress(lladdr0),
+11 -8
View File
@@ -68,7 +68,7 @@ var _ NUDHandler = (*neighborCache)(nil)
// reset to state incomplete, and returned. If no matching entry exists and the
// cache is not full, a new entry with state incomplete is allocated and
// returned.
func (n *neighborCache) getOrCreateEntry(remoteAddr, localAddr tcpip.Address, linkRes LinkAddressResolver) *neighborEntry {
func (n *neighborCache) getOrCreateEntry(remoteAddr tcpip.Address, linkRes LinkAddressResolver) *neighborEntry {
n.mu.Lock()
defer n.mu.Unlock()
@@ -84,7 +84,7 @@ func (n *neighborCache) getOrCreateEntry(remoteAddr, localAddr tcpip.Address, li
// The entry that needs to be created must be dynamic since all static
// entries are directly added to the cache via addStaticEntry.
entry := newNeighborEntry(n.nic, remoteAddr, localAddr, n.state, linkRes)
entry := newNeighborEntry(n.nic, remoteAddr, n.state, linkRes)
if n.dynamic.count == neighborCacheSize {
e := n.dynamic.lru.Back()
e.mu.Lock()
@@ -111,6 +111,10 @@ func (n *neighborCache) getOrCreateEntry(remoteAddr, localAddr tcpip.Address, li
// provided, it will be notified when address resolution is complete (success
// or not).
//
// If specified, the local address must be an address local to the interface the
// neighbor cache belongs to. The local address is the source address of a
// packet prompting NUD/link address resolution.
//
// If address resolution is required, ErrNoLinkAddress and a notification
// channel is returned for the top level caller to block. Channel is closed
// once address resolution is complete (success or not).
@@ -118,7 +122,6 @@ func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, linkRes LinkA
if linkAddr, ok := linkRes.ResolveStaticAddress(remoteAddr); ok {
e := NeighborEntry{
Addr: remoteAddr,
LocalAddr: localAddr,
LinkAddr: linkAddr,
State: Static,
UpdatedAt: time.Now(),
@@ -126,13 +129,13 @@ func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, linkRes LinkA
return e, nil, nil
}
entry := n.getOrCreateEntry(remoteAddr, localAddr, linkRes)
entry := n.getOrCreateEntry(remoteAddr, linkRes)
entry.mu.Lock()
defer entry.mu.Unlock()
switch s := entry.neigh.State; s {
case Stale:
entry.handlePacketQueuedLocked()
entry.handlePacketQueuedLocked(localAddr)
fallthrough
case Reachable, Static, Delay, Probe:
// As per RFC 4861 section 7.3.3:
@@ -152,7 +155,7 @@ func (n *neighborCache) entry(remoteAddr, localAddr tcpip.Address, linkRes LinkA
entry.done = make(chan struct{})
}
entry.handlePacketQueuedLocked()
entry.handlePacketQueuedLocked(localAddr)
return entry.neigh, entry.done, tcpip.ErrWouldBlock
case Failed:
return entry.neigh, nil, tcpip.ErrNoLinkAddress
@@ -292,8 +295,8 @@ func (n *neighborCache) setConfig(config NUDConfigurations) {
// HandleProbe implements NUDHandler.HandleProbe by following the logic defined
// in RFC 4861 section 7.2.3. Validation of the probe is expected to be handled
// by the caller.
func (n *neighborCache) HandleProbe(remoteAddr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, linkRes LinkAddressResolver) {
entry := n.getOrCreateEntry(remoteAddr, localAddr, linkRes)
func (n *neighborCache) HandleProbe(remoteAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, linkRes LinkAddressResolver) {
entry := n.getOrCreateEntry(remoteAddr, linkRes)
entry.mu.Lock()
entry.handleProbeLocked(remoteLinkAddr)
entry.mu.Unlock()
+105 -125
View File
@@ -128,9 +128,8 @@ func newTestEntryStore() *testEntryStore {
linkAddr := toLinkAddress(i)
store.entriesMap[addr] = NeighborEntry{
Addr: addr,
LocalAddr: testEntryLocalAddr,
LinkAddr: linkAddr,
Addr: addr,
LinkAddr: linkAddr,
}
}
return store
@@ -294,9 +293,8 @@ func TestNeighborCacheEntry(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
_, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
clock.Advance(typicalLatency)
@@ -324,8 +322,8 @@ func TestNeighborCacheEntry(t *testing.T) {
t.Fatalf("nud dispatcher events mismatch (-got, +want):\n%s", diff)
}
if _, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil); err != nil {
t.Fatalf("unexpected error from neigh.entry(%s, %s, _, nil): %s", entry.Addr, entry.LocalAddr, err)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != nil {
t.Fatalf("unexpected error from neigh.entry(%s, '', _, nil): %s", entry.Addr, err)
}
// No more events should have been dispatched.
@@ -354,9 +352,9 @@ func TestNeighborCacheRemoveEntry(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
_, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
clock.Advance(typicalLatency)
@@ -404,8 +402,8 @@ func TestNeighborCacheRemoveEntry(t *testing.T) {
}
}
if _, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
}
@@ -452,8 +450,8 @@ func (c *testContext) overflowCache(opts overflowOptions) error {
if !ok {
return fmt.Errorf("c.store.entry(%d) not found", i)
}
if _, _, err := c.neigh.entry(entry.Addr, entry.LocalAddr, c.linkRes, nil); err != tcpip.ErrWouldBlock {
return fmt.Errorf("got c.neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
return fmt.Errorf("got c.neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
c.clock.Advance(c.neigh.config().RetransmitTimer)
@@ -508,10 +506,9 @@ func (c *testContext) overflowCache(opts overflowOptions) error {
return fmt.Errorf("c.store.entry(%d) not found", i)
}
wantEntry := NeighborEntry{
Addr: entry.Addr,
LocalAddr: entry.LocalAddr,
LinkAddr: entry.LinkAddr,
State: Reachable,
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Reachable,
}
wantUnsortedEntries = append(wantUnsortedEntries, wantEntry)
}
@@ -564,9 +561,8 @@ func TestNeighborCacheRemoveEntryThenOverflow(t *testing.T) {
if !ok {
t.Fatalf("c.store.entry(0) not found")
}
_, _, err := c.neigh.entry(entry.Addr, entry.LocalAddr, c.linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got c.neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got c.neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
c.clock.Advance(c.neigh.config().RetransmitTimer)
wantEvents := []testEntryEventInfo{
@@ -800,9 +796,8 @@ func TestNeighborCacheOverwriteWithStaticEntryThenOverflow(t *testing.T) {
if !ok {
t.Fatalf("c.store.entry(0) not found")
}
_, _, err := c.neigh.entry(entry.Addr, entry.LocalAddr, c.linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got c.neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got c.neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
c.clock.Advance(typicalLatency)
wantEvents := []testEntryEventInfo{
@@ -861,10 +856,9 @@ func TestNeighborCacheOverwriteWithStaticEntryThenOverflow(t *testing.T) {
startAtEntryIndex: 1,
wantStaticEntries: []NeighborEntry{
{
Addr: entry.Addr,
LocalAddr: "", // static entries don't need a local address
LinkAddr: staticLinkAddr,
State: Static,
Addr: entry.Addr,
LinkAddr: staticLinkAddr,
State: Static,
},
},
}
@@ -896,12 +890,12 @@ func TestNeighborCacheNotifiesWaker(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
_, doneCh, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, &w)
_, doneCh, err := neigh.entry(entry.Addr, "", linkRes, &w)
if err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, %s, _, _ = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
t.Fatalf("got neigh.entry(%s, '', _, _ = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
if doneCh == nil {
t.Fatalf("expected done channel from neigh.entry(%s, %s, _, _)", entry.Addr, entry.LocalAddr)
t.Fatalf("expected done channel from neigh.entry(%s, '', _, _)", entry.Addr)
}
clock.Advance(typicalLatency)
@@ -913,7 +907,7 @@ func TestNeighborCacheNotifiesWaker(t *testing.T) {
id, ok := s.Fetch(false /* block */)
if !ok {
t.Errorf("expected waker to be notified after neigh.entry(%s, %s, _, _)", entry.Addr, entry.LocalAddr)
t.Errorf("expected waker to be notified after neigh.entry(%s, '', _, _)", entry.Addr)
}
if id != wakerID {
t.Errorf("got s.Fetch(false) = %d, want = %d", id, wakerID)
@@ -964,12 +958,12 @@ func TestNeighborCacheRemoveWaker(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
_, doneCh, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, &w)
_, doneCh, err := neigh.entry(entry.Addr, "", linkRes, &w)
if err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, %s, _, _) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
t.Fatalf("got neigh.entry(%s, '', _, _) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
if doneCh == nil {
t.Fatalf("expected done channel from neigh.entry(%s, %s, _, _)", entry.Addr, entry.LocalAddr)
t.Fatalf("expected done channel from neigh.entry(%s, '', _, _)", entry.Addr)
}
// Remove the waker before the neighbor cache has the opportunity to send a
@@ -1028,10 +1022,9 @@ func TestNeighborCacheAddStaticEntryThenOverflow(t *testing.T) {
t.Errorf("unexpected error from c.neigh.entry(%s, \"\", _, nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LocalAddr: "", // static entries don't need a local address
LinkAddr: entry.LinkAddr,
State: Static,
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Static,
}
if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
t.Errorf("c.neigh.entry(%s, \"\", _, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
@@ -1058,10 +1051,9 @@ func TestNeighborCacheAddStaticEntryThenOverflow(t *testing.T) {
startAtEntryIndex: 1,
wantStaticEntries: []NeighborEntry{
{
Addr: entry.Addr,
LocalAddr: "", // static entries don't need a local address
LinkAddr: entry.LinkAddr,
State: Static,
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Static,
},
},
}
@@ -1089,9 +1081,8 @@ func TestNeighborCacheClear(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
_, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
clock.Advance(typicalLatency)
@@ -1185,9 +1176,8 @@ func TestNeighborCacheClearThenOverflow(t *testing.T) {
if !ok {
t.Fatalf("c.store.entry(0) not found")
}
_, _, err := c.neigh.entry(entry.Addr, entry.LocalAddr, c.linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got c.neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := c.neigh.entry(entry.Addr, "", c.linkRes, nil); err != tcpip.ErrWouldBlock {
t.Errorf("got c.neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
c.clock.Advance(typicalLatency)
wantEvents := []testEntryEventInfo{
@@ -1274,15 +1264,15 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
if !ok {
t.Fatalf("store.entry(%d) not found", i)
}
_, doneCh, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
_, doneCh, err := neigh.entry(entry.Addr, "", linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
t.Errorf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
clock.Advance(typicalLatency)
select {
case <-doneCh:
default:
t.Fatalf("expected notification from done channel returned by neigh.entry(%s, %s, _, nil)", entry.Addr, entry.LocalAddr)
t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, nil)", entry.Addr)
}
wantEvents := []testEntryEventInfo{
{
@@ -1312,9 +1302,8 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
for i := neighborCacheSize; i < store.size(); i++ {
// Periodically refresh the frequently used entry
if i%(neighborCacheSize/2) == 0 {
_, _, err := neigh.entry(frequentlyUsedEntry.Addr, frequentlyUsedEntry.LocalAddr, linkRes, nil)
if err != nil {
t.Errorf("unexpected error from neigh.entry(%s, %s, _, nil): %s", frequentlyUsedEntry.Addr, frequentlyUsedEntry.LocalAddr, err)
if _, _, err := neigh.entry(frequentlyUsedEntry.Addr, "", linkRes, nil); err != nil {
t.Errorf("unexpected error from neigh.entry(%s, '', _, nil): %s", frequentlyUsedEntry.Addr, err)
}
}
@@ -1322,15 +1311,15 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
if !ok {
t.Fatalf("store.entry(%d) not found", i)
}
_, doneCh, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
_, doneCh, err := neigh.entry(entry.Addr, "", linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
t.Errorf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
clock.Advance(typicalLatency)
select {
case <-doneCh:
default:
t.Fatalf("expected notification from done channel returned by neigh.entry(%s, %s, _, nil)", entry.Addr, entry.LocalAddr)
t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, nil)", entry.Addr)
}
// An entry should have been removed, as per the LRU eviction strategy
@@ -1374,10 +1363,9 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
// have to be sorted before comparison.
wantUnsortedEntries := []NeighborEntry{
{
Addr: frequentlyUsedEntry.Addr,
LocalAddr: frequentlyUsedEntry.LocalAddr,
LinkAddr: frequentlyUsedEntry.LinkAddr,
State: Reachable,
Addr: frequentlyUsedEntry.Addr,
LinkAddr: frequentlyUsedEntry.LinkAddr,
State: Reachable,
},
}
@@ -1387,10 +1375,9 @@ func TestNeighborCacheKeepFrequentlyUsed(t *testing.T) {
t.Fatalf("store.entry(%d) not found", i)
}
wantEntry := NeighborEntry{
Addr: entry.Addr,
LocalAddr: entry.LocalAddr,
LinkAddr: entry.LinkAddr,
State: Reachable,
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Reachable,
}
wantUnsortedEntries = append(wantUnsortedEntries, wantEntry)
}
@@ -1430,9 +1417,8 @@ func TestNeighborCacheConcurrent(t *testing.T) {
wg.Add(1)
go func(entry NeighborEntry) {
defer wg.Done()
e, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
if err != nil && err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, %s, _, nil) = (%+v, _, %s), want (_, _, nil) or (_, _, %s)", entry.Addr, entry.LocalAddr, e, err, tcpip.ErrWouldBlock)
if e, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != nil && err != tcpip.ErrWouldBlock {
t.Errorf("got neigh.entry(%s, '', _, nil) = (%+v, _, %s), want (_, _, nil) or (_, _, %s)", entry.Addr, e, err, tcpip.ErrWouldBlock)
}
}(entry)
}
@@ -1456,10 +1442,9 @@ func TestNeighborCacheConcurrent(t *testing.T) {
t.Errorf("store.entry(%d) not found", i)
}
wantEntry := NeighborEntry{
Addr: entry.Addr,
LocalAddr: entry.LocalAddr,
LinkAddr: entry.LinkAddr,
State: Reachable,
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Reachable,
}
wantUnsortedEntries = append(wantUnsortedEntries, wantEntry)
}
@@ -1488,37 +1473,36 @@ func TestNeighborCacheReplace(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
_, doneCh, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
_, doneCh, err := neigh.entry(entry.Addr, "", linkRes, nil)
if err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
t.Fatalf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
clock.Advance(typicalLatency)
select {
case <-doneCh:
default:
t.Fatalf("expected notification from done channel returned by neigh.entry(%s, %s, _, nil)", entry.Addr, entry.LocalAddr)
t.Fatalf("expected notification from done channel returned by neigh.entry(%s, '', _, nil)", entry.Addr)
}
// Verify the entry exists
{
e, doneCh, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
e, doneCh, err := neigh.entry(entry.Addr, "", linkRes, nil)
if err != nil {
t.Errorf("unexpected error from neigh.entry(%s, %s, _, nil): %s", entry.Addr, entry.LocalAddr, err)
t.Errorf("unexpected error from neigh.entry(%s, '', _, nil): %s", entry.Addr, err)
}
if doneCh != nil {
t.Errorf("unexpected done channel from neigh.entry(%s, %s, _, nil): %v", entry.Addr, entry.LocalAddr, doneCh)
t.Errorf("unexpected done channel from neigh.entry(%s, '', _, nil): %v", entry.Addr, doneCh)
}
if t.Failed() {
t.FailNow()
}
want := NeighborEntry{
Addr: entry.Addr,
LocalAddr: entry.LocalAddr,
LinkAddr: entry.LinkAddr,
State: Reachable,
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Reachable,
}
if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
t.Errorf("neigh.entry(%s, %s, _, nil) mismatch (-got, +want):\n%s", entry.Addr, entry.LinkAddr, diff)
t.Errorf("neigh.entry(%s, '', _, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
}
}
@@ -1542,37 +1526,35 @@ func TestNeighborCacheReplace(t *testing.T) {
//
// Verify the entry's new link address and the new state.
{
e, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
e, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
if err != nil {
t.Fatalf("neigh.entry(%s, %s, _, nil): %s", entry.Addr, entry.LocalAddr, err)
t.Fatalf("neigh.entry(%s, '', _, nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LocalAddr: entry.LocalAddr,
LinkAddr: updatedLinkAddr,
State: Delay,
Addr: entry.Addr,
LinkAddr: updatedLinkAddr,
State: Delay,
}
if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
t.Errorf("neigh.entry(%s, %s, _, nil) mismatch (-got, +want):\n%s", entry.Addr, entry.LocalAddr, diff)
t.Errorf("neigh.entry(%s, '', _, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
}
clock.Advance(config.DelayFirstProbeTime + typicalLatency)
}
// Verify that the neighbor is now reachable.
{
e, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
e, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
clock.Advance(typicalLatency)
if err != nil {
t.Errorf("unexpected error from neigh.entry(%s, %s, _, nil): %s", entry.Addr, entry.LocalAddr, err)
t.Errorf("unexpected error from neigh.entry(%s, '', _, nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LocalAddr: entry.LocalAddr,
LinkAddr: updatedLinkAddr,
State: Reachable,
Addr: entry.Addr,
LinkAddr: updatedLinkAddr,
State: Reachable,
}
if diff := cmp.Diff(e, want, entryDiffOpts()...); diff != "" {
t.Errorf("neigh.entry(%s, %s, _, nil) mismatch (-got, +want):\n%s", entry.Addr, entry.LocalAddr, diff)
t.Errorf("neigh.entry(%s, '', _, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
}
}
}
@@ -1601,35 +1583,34 @@ func TestNeighborCacheResolutionFailed(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
if _, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil); err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
clock.Advance(typicalLatency)
got, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
got, _, err := neigh.entry(entry.Addr, "", linkRes, nil)
if err != nil {
t.Fatalf("unexpected error from neigh.entry(%s, %s, _, nil): %s", entry.Addr, entry.LocalAddr, err)
t.Fatalf("unexpected error from neigh.entry(%s, '', _, nil): %s", entry.Addr, err)
}
want := NeighborEntry{
Addr: entry.Addr,
LocalAddr: entry.LocalAddr,
LinkAddr: entry.LinkAddr,
State: Reachable,
Addr: entry.Addr,
LinkAddr: entry.LinkAddr,
State: Reachable,
}
if diff := cmp.Diff(got, want, entryDiffOpts()...); diff != "" {
t.Errorf("neigh.entry(%s, %s, _, nil) mismatch (-got, +want):\n%s", entry.Addr, entry.LocalAddr, diff)
t.Errorf("neigh.entry(%s, '', _, nil) mismatch (-got, +want):\n%s", entry.Addr, diff)
}
// Verify that address resolution for an unknown address returns ErrNoLinkAddress
before := atomic.LoadUint32(&requestCount)
entry.Addr += "2"
if _, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil); err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
waitFor := config.DelayFirstProbeTime + typicalLatency*time.Duration(config.MaxMulticastProbes)
clock.Advance(waitFor)
if _, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil); err != tcpip.ErrNoLinkAddress {
t.Fatalf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrNoLinkAddress)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrNoLinkAddress {
t.Fatalf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrNoLinkAddress)
}
maxAttempts := neigh.config().MaxUnicastProbes
@@ -1659,13 +1640,13 @@ func TestNeighborCacheResolutionTimeout(t *testing.T) {
if !ok {
t.Fatalf("store.entry(0) not found")
}
if _, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil); err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrWouldBlock {
t.Fatalf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
waitFor := config.RetransmitTimer * time.Duration(config.MaxMulticastProbes)
clock.Advance(waitFor)
if _, _, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil); err != tcpip.ErrNoLinkAddress {
t.Fatalf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrNoLinkAddress)
if _, _, err := neigh.entry(entry.Addr, "", linkRes, nil); err != tcpip.ErrNoLinkAddress {
t.Fatalf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrNoLinkAddress)
}
}
@@ -1683,18 +1664,17 @@ func TestNeighborCacheStaticResolution(t *testing.T) {
delay: typicalLatency,
}
got, _, err := neigh.entry(testEntryBroadcastAddr, testEntryLocalAddr, linkRes, nil)
got, _, err := neigh.entry(testEntryBroadcastAddr, "", linkRes, nil)
if err != nil {
t.Fatalf("unexpected error from neigh.entry(%s, %s, _, nil): %s", testEntryBroadcastAddr, testEntryLocalAddr, err)
t.Fatalf("unexpected error from neigh.entry(%s, '', _, nil): %s", testEntryBroadcastAddr, err)
}
want := NeighborEntry{
Addr: testEntryBroadcastAddr,
LocalAddr: testEntryLocalAddr,
LinkAddr: testEntryBroadcastLinkAddr,
State: Static,
Addr: testEntryBroadcastAddr,
LinkAddr: testEntryBroadcastLinkAddr,
State: Static,
}
if diff := cmp.Diff(got, want, entryDiffOpts()...); diff != "" {
t.Errorf("neigh.entry(%s, %s, _, nil) mismatch (-got, +want):\n%s", testEntryBroadcastAddr, testEntryLocalAddr, diff)
t.Errorf("neigh.entry(%s, '', _, nil) mismatch (-got, +want):\n%s", testEntryBroadcastAddr, diff)
}
}
@@ -1719,9 +1699,9 @@ func BenchmarkCacheClear(b *testing.B) {
if !ok {
b.Fatalf("store.entry(%d) not found", i)
}
_, doneCh, err := neigh.entry(entry.Addr, entry.LocalAddr, linkRes, nil)
_, doneCh, err := neigh.entry(entry.Addr, "", linkRes, nil)
if err != tcpip.ErrWouldBlock {
b.Fatalf("got neigh.entry(%s, %s, _, nil) = %v, want = %s", entry.Addr, entry.LocalAddr, err, tcpip.ErrWouldBlock)
b.Fatalf("got neigh.entry(%s, '', _, nil) = %v, want = %s", entry.Addr, err, tcpip.ErrWouldBlock)
}
if doneCh != nil {
<-doneCh
+63 -53
View File
@@ -27,7 +27,6 @@ import (
// NeighborEntry describes a neighboring device in the local network.
type NeighborEntry struct {
Addr tcpip.Address
LocalAddr tcpip.Address
LinkAddr tcpip.LinkAddress
State NeighborState
UpdatedAt time.Time
@@ -106,15 +105,14 @@ type neighborEntry struct {
// state, Unknown. Transition out of Unknown by calling either
// `handlePacketQueuedLocked` or `handleProbeLocked` on the newly created
// neighborEntry.
func newNeighborEntry(nic *NIC, remoteAddr tcpip.Address, localAddr tcpip.Address, nudState *NUDState, linkRes LinkAddressResolver) *neighborEntry {
func newNeighborEntry(nic *NIC, remoteAddr tcpip.Address, nudState *NUDState, linkRes LinkAddressResolver) *neighborEntry {
return &neighborEntry{
nic: nic,
linkRes: linkRes,
nudState: nudState,
neigh: NeighborEntry{
Addr: remoteAddr,
LocalAddr: localAddr,
State: Unknown,
Addr: remoteAddr,
State: Unknown,
},
}
}
@@ -206,51 +204,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
switch next {
case Incomplete:
var retryCounter uint32
var sendMulticastProbe func()
sendMulticastProbe = func() {
if retryCounter == config.MaxMulticastProbes {
// "If no Neighbor Advertisement is received after
// MAX_MULTICAST_SOLICIT solicitations, address resolution has failed.
// The sender MUST return ICMP destination unreachable indications with
// code 3 (Address Unreachable) for each packet queued awaiting address
// resolution." - RFC 4861 section 7.2.2
//
// There is no need to send an ICMP destination unreachable indication
// since the failure to resolve the address is expected to only occur
// on this node. Thus, redirecting traffic is currently not supported.
//
// "If the error occurs on a node other than the node originating the
// packet, an ICMP error message is generated. If the error occurs on
// the originating node, an implementation is not required to actually
// create and send an ICMP error packet to the source, as long as the
// upper-layer sender is notified through an appropriate mechanism
// (e.g. return value from a procedure call). Note, however, that an
// implementation may find it convenient in some cases to return errors
// to the sender by taking the offending packet, generating an ICMP
// error message, and then delivering it (locally) through the generic
// error-handling routines.' - RFC 4861 section 2.1
e.dispatchRemoveEventLocked()
e.setStateLocked(Failed)
return
}
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, e.neigh.LocalAddr, "", e.nic); err != nil {
// There is no need to log the error here; the NUD implementation may
// assume a working link. A valid link should be the responsibility of
// the NIC/stack.LinkEndpoint.
e.dispatchRemoveEventLocked()
e.setStateLocked(Failed)
return
}
retryCounter++
e.job = e.nic.stack.newJob(&e.mu, sendMulticastProbe)
e.job.Schedule(config.RetransmitTimer)
}
sendMulticastProbe()
panic(fmt.Sprintf("should never transition to Incomplete with setStateLocked; neigh = %#v, prev state = %s", e.neigh, prev))
case Reachable:
e.job = e.nic.stack.newJob(&e.mu, func() {
@@ -277,7 +231,7 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
return
}
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, e.neigh.LocalAddr, e.neigh.LinkAddr, e.nic); err != nil {
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, "" /* localAddr */, e.neigh.LinkAddr, e.nic); err != nil {
e.dispatchRemoveEventLocked()
e.setStateLocked(Failed)
return
@@ -315,11 +269,67 @@ func (e *neighborEntry) setStateLocked(next NeighborState) {
// being queued for outgoing transmission.
//
// Follows the logic defined in RFC 4861 section 7.3.3.
func (e *neighborEntry) handlePacketQueuedLocked() {
func (e *neighborEntry) handlePacketQueuedLocked(localAddr tcpip.Address) {
switch e.neigh.State {
case Unknown:
e.dispatchAddEventLocked(Incomplete)
e.setStateLocked(Incomplete)
e.neigh.State = Incomplete
e.neigh.UpdatedAt = time.Now()
config := e.nudState.Config()
var retryCounter uint32
var sendMulticastProbe func()
sendMulticastProbe = func() {
if retryCounter == config.MaxMulticastProbes {
// "If no Neighbor Advertisement is received after
// MAX_MULTICAST_SOLICIT solicitations, address resolution has failed.
// The sender MUST return ICMP destination unreachable indications with
// code 3 (Address Unreachable) for each packet queued awaiting address
// resolution." - RFC 4861 section 7.2.2
//
// There is no need to send an ICMP destination unreachable indication
// since the failure to resolve the address is expected to only occur
// on this node. Thus, redirecting traffic is currently not supported.
//
// "If the error occurs on a node other than the node originating the
// packet, an ICMP error message is generated. If the error occurs on
// the originating node, an implementation is not required to actually
// create and send an ICMP error packet to the source, as long as the
// upper-layer sender is notified through an appropriate mechanism
// (e.g. return value from a procedure call). Note, however, that an
// implementation may find it convenient in some cases to return errors
// to the sender by taking the offending packet, generating an ICMP
// error message, and then delivering it (locally) through the generic
// error-handling routines.' - RFC 4861 section 2.1
e.dispatchRemoveEventLocked()
e.setStateLocked(Failed)
return
}
// As per RFC 4861 section 7.2.2:
//
// If the source address of the packet prompting the solicitation is the
// same as one of the addresses assigned to the outgoing interface, that
// address SHOULD be placed in the IP Source Address of the outgoing
// solicitation.
//
if err := e.linkRes.LinkAddressRequest(e.neigh.Addr, localAddr, "", e.nic); err != nil {
// There is no need to log the error here; the NUD implementation may
// assume a working link. A valid link should be the responsibility of
// the NIC/stack.LinkEndpoint.
e.dispatchRemoveEventLocked()
e.setStateLocked(Failed)
return
}
retryCounter++
e.job = e.nic.stack.newJob(&e.mu, sendMulticastProbe)
e.job.Schedule(config.RetransmitTimer)
}
sendMulticastProbe()
case Stale:
e.dispatchChangeEventLocked(Delay)
+52 -66
View File
@@ -245,7 +245,7 @@ func entryTestSetup(c NUDConfigurations) (*neighborEntry, *testNUDDispatcher, *e
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
nudState := NewNUDState(c, rng)
linkRes := entryTestLinkResolver{}
entry := newNeighborEntry(&nic, entryTestAddr1 /* remoteAddr */, entryTestAddr2 /* localAddr */, nudState, &linkRes)
entry := newNeighborEntry(&nic, entryTestAddr1 /* remoteAddr */, nudState, &linkRes)
// Stub out the neighbor cache to verify deletion from the cache.
nic.neigh = &neighborCache{
@@ -326,7 +326,7 @@ func TestEntryUnknownToIncomplete(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Incomplete; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -406,7 +406,7 @@ func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Incomplete; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -498,7 +498,7 @@ func TestEntryIncompleteToReachable(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Incomplete; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -563,7 +563,7 @@ func TestEntryAddsAndClearsWakers(t *testing.T) {
defer s.Done()
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got := e.wakers; got != nil {
t.Errorf("got e.wakers = %v, want = nil", got)
}
@@ -629,7 +629,7 @@ func TestEntryIncompleteToReachableWithRouterFlag(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Incomplete; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -687,7 +687,7 @@ func TestEntryIncompleteToStale(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Incomplete; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -744,7 +744,7 @@ func TestEntryIncompleteToFailed(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Incomplete; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -822,7 +822,7 @@ func TestEntryStaysReachableWhenConfirmationWithRouterFlag(t *testing.T) {
ipv6EP := e.nic.networkEndpoints[header.IPv6ProtocolNumber].(*testIPv6Endpoint)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
@@ -896,7 +896,7 @@ func TestEntryStaysReachableWhenProbeWithSameAddress(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
@@ -961,7 +961,7 @@ func TestEntryReachableToStaleWhenTimeout(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
@@ -1029,7 +1029,7 @@ func TestEntryReachableToStaleWhenProbeWithDifferentAddress(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
@@ -1099,7 +1099,7 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddress(t *testing.T)
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
@@ -1173,7 +1173,7 @@ func TestEntryReachableToStaleWhenConfirmationWithDifferentAddressAndOverride(t
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: true,
Override: false,
@@ -1247,7 +1247,7 @@ func TestEntryStaysStaleWhenProbeWithSameAddress(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
@@ -1307,7 +1307,7 @@ func TestEntryStaleToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
@@ -1378,7 +1378,7 @@ func TestEntryStaleToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
@@ -1449,7 +1449,7 @@ func TestEntryStaleToStaleWhenOverrideConfirmation(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
@@ -1520,7 +1520,7 @@ func TestEntryStaleToStaleWhenProbeUpdateAddress(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
@@ -1587,7 +1587,7 @@ func TestEntryStaleToDelay(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
@@ -1596,7 +1596,7 @@ func TestEntryStaleToDelay(t *testing.T) {
if got, want := e.neigh.State, Stale; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Delay; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -1656,13 +1656,13 @@ func TestEntryDelayToReachableWhenUpperLevelConfirmation(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Delay; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -1743,13 +1743,13 @@ func TestEntryDelayToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Delay; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -1837,13 +1837,13 @@ func TestEntryDelayToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if e.neigh.State != Delay {
t.Errorf("got e.neigh.State = %q, want = %q", e.neigh.State, Delay)
}
@@ -1925,13 +1925,13 @@ func TestEntryStaysDelayWhenOverrideConfirmationWithSameAddress(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Delay; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -1997,13 +1997,13 @@ func TestEntryDelayToStaleWhenProbeWithDifferentAddress(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Delay; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -2069,13 +2069,13 @@ func TestEntryDelayToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
e, nudDisp, linkRes, _ := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Delay; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -2145,13 +2145,13 @@ func TestEntryDelayToProbe(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
if got, want := e.neigh.State, Delay; got != want {
t.Errorf("got e.neigh.State = %q, want = %q", got, want)
}
@@ -2170,7 +2170,6 @@ func TestEntryDelayToProbe(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2228,13 +2227,13 @@ func TestEntryProbeToStaleWhenProbeWithDifferentAddress(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
clock.Advance(c.DelayFirstProbeTime)
@@ -2250,7 +2249,6 @@ func TestEntryProbeToStaleWhenProbeWithDifferentAddress(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2325,13 +2323,13 @@ func TestEntryProbeToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
clock.Advance(c.DelayFirstProbeTime)
@@ -2347,7 +2345,6 @@ func TestEntryProbeToStaleWhenConfirmationWithDifferentAddress(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2426,13 +2423,13 @@ func TestEntryStaysProbeWhenOverrideConfirmationWithSameAddress(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
clock.Advance(c.DelayFirstProbeTime)
@@ -2448,7 +2445,6 @@ func TestEntryStaysProbeWhenOverrideConfirmationWithSameAddress(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2529,7 +2525,7 @@ func TestEntryUnknownToStaleToProbeToReachable(t *testing.T) {
e.mu.Lock()
e.handleProbeLocked(entryTestLinkAddr1)
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
clock.Advance(c.DelayFirstProbeTime)
@@ -2539,7 +2535,6 @@ func TestEntryUnknownToStaleToProbeToReachable(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2622,13 +2617,13 @@ func TestEntryProbeToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
clock.Advance(c.DelayFirstProbeTime)
@@ -2644,7 +2639,6 @@ func TestEntryProbeToReachableWhenSolicitedOverrideConfirmation(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2734,13 +2728,13 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithSameAddress(t *testin
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
clock.Advance(c.DelayFirstProbeTime)
@@ -2756,7 +2750,6 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithSameAddress(t *testin
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2843,13 +2836,13 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
clock.Advance(c.DelayFirstProbeTime)
@@ -2865,7 +2858,6 @@ func TestEntryProbeToReachableWhenSolicitedConfirmationWithoutAddress(t *testing
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -2949,13 +2941,13 @@ func TestEntryProbeToFailed(t *testing.T) {
e, nudDisp, linkRes, clock := entryTestSetup(c)
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
waitFor := c.DelayFirstProbeTime + c.RetransmitTimer*time.Duration(c.MaxUnicastProbes)
@@ -2972,17 +2964,14 @@ func TestEntryProbeToFailed(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
@@ -3054,13 +3043,13 @@ func TestEntryFailedGetsDeleted(t *testing.T) {
}
e.mu.Lock()
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{
Solicited: false,
Override: false,
IsRouter: false,
})
e.handlePacketQueuedLocked()
e.handlePacketQueuedLocked(entryTestAddr2)
e.mu.Unlock()
waitFor := c.DelayFirstProbeTime + c.RetransmitTimer*time.Duration(c.MaxUnicastProbes) + c.UnreachableTime
@@ -3077,17 +3066,14 @@ func TestEntryFailedGetsDeleted(t *testing.T) {
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
{
RemoteAddress: entryTestAddr1,
RemoteLinkAddress: entryTestLinkAddr1,
LocalAddress: entryTestAddr2,
},
}
linkRes.mu.Lock()
+1 -1
View File
@@ -177,7 +177,7 @@ type NUDHandler interface {
// Neighbor Solicitation for ARP or NDP, respectively). Validation of the
// probe needs to be performed before calling this function since the
// Neighbor Cache doesn't have access to view the NIC's assigned addresses.
HandleProbe(remoteAddr, localAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, linkRes LinkAddressResolver)
HandleProbe(remoteAddr tcpip.Address, protocol tcpip.NetworkProtocolNumber, remoteLinkAddr tcpip.LinkAddress, linkRes LinkAddressResolver)
// HandleConfirmation processes an incoming neighbor confirmation (e.g. ARP
// reply or Neighbor Advertisement for ARP or NDP, respectively).