gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/network/arp/arp_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package arp_test
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"testing"
    21  
    22  	"github.com/google/go-cmp/cmp"
    23  	"github.com/google/go-cmp/cmp/cmpopts"
    24  	"gvisor.dev/gvisor/pkg/buffer"
    25  	"gvisor.dev/gvisor/pkg/refs"
    26  	"gvisor.dev/gvisor/pkg/tcpip"
    27  	"gvisor.dev/gvisor/pkg/tcpip/faketime"
    28  	"gvisor.dev/gvisor/pkg/tcpip/header"
    29  	"gvisor.dev/gvisor/pkg/tcpip/link/channel"
    30  	"gvisor.dev/gvisor/pkg/tcpip/link/sniffer"
    31  	"gvisor.dev/gvisor/pkg/tcpip/network/arp"
    32  	"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
    33  	"gvisor.dev/gvisor/pkg/tcpip/stack"
    34  	"gvisor.dev/gvisor/pkg/tcpip/testutil"
    35  )
    36  
    37  const (
    38  	nicID = 1
    39  
    40  	stackLinkAddr  = tcpip.LinkAddress("\x0a\x0a\x0b\x0b\x0c\x0c")
    41  	remoteLinkAddr = tcpip.LinkAddress("\x01\x02\x03\x04\x05\x06")
    42  )
    43  
    44  var (
    45  	stackAddr   = testutil.MustParse4("10.0.0.1")
    46  	remoteAddr  = testutil.MustParse4("10.0.0.2")
    47  	unknownAddr = testutil.MustParse4("10.0.0.3")
    48  )
    49  
    50  type eventType uint8
    51  
    52  const (
    53  	entryAdded eventType = iota
    54  	entryChanged
    55  	entryRemoved
    56  )
    57  
    58  func (t eventType) String() string {
    59  	switch t {
    60  	case entryAdded:
    61  		return "add"
    62  	case entryChanged:
    63  		return "change"
    64  	case entryRemoved:
    65  		return "remove"
    66  	default:
    67  		return fmt.Sprintf("unknown (%d)", t)
    68  	}
    69  }
    70  
    71  type eventInfo struct {
    72  	eventType eventType
    73  	nicID     tcpip.NICID
    74  	entry     stack.NeighborEntry
    75  }
    76  
    77  func (e eventInfo) String() string {
    78  	return fmt.Sprintf("%s event for NIC #%d, %#v", e.eventType, e.nicID, e.entry)
    79  }
    80  
    81  // arpDispatcher implements NUDDispatcher to validate the dispatching of
    82  // events upon certain NUD state machine events.
    83  type arpDispatcher struct {
    84  	// C is where events are queued
    85  	C chan eventInfo
    86  }
    87  
    88  var _ stack.NUDDispatcher = (*arpDispatcher)(nil)
    89  
    90  func (d *arpDispatcher) OnNeighborAdded(nicID tcpip.NICID, entry stack.NeighborEntry) {
    91  	e := eventInfo{
    92  		eventType: entryAdded,
    93  		nicID:     nicID,
    94  		entry:     entry,
    95  	}
    96  	d.C <- e
    97  }
    98  
    99  func (d *arpDispatcher) OnNeighborChanged(nicID tcpip.NICID, entry stack.NeighborEntry) {
   100  	e := eventInfo{
   101  		eventType: entryChanged,
   102  		nicID:     nicID,
   103  		entry:     entry,
   104  	}
   105  	d.C <- e
   106  }
   107  
   108  func (d *arpDispatcher) OnNeighborRemoved(nicID tcpip.NICID, entry stack.NeighborEntry) {
   109  	e := eventInfo{
   110  		eventType: entryRemoved,
   111  		nicID:     nicID,
   112  		entry:     entry,
   113  	}
   114  	d.C <- e
   115  }
   116  
   117  func (d *arpDispatcher) nextEvent() (eventInfo, bool) {
   118  	select {
   119  	case event := <-d.C:
   120  		return event, true
   121  	default:
   122  		return eventInfo{}, false
   123  	}
   124  }
   125  
   126  type testContext struct {
   127  	s       *stack.Stack
   128  	linkEP  *channel.Endpoint
   129  	nudDisp arpDispatcher
   130  }
   131  
   132  func makeTestContext(t *testing.T, eventDepth int, packetDepth int) testContext {
   133  	t.Helper()
   134  
   135  	tc := testContext{
   136  		nudDisp: arpDispatcher{
   137  			C: make(chan eventInfo, eventDepth),
   138  		},
   139  	}
   140  
   141  	tc.s = stack.New(stack.Options{
   142  		NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, arp.NewProtocol},
   143  		NUDDisp:          &tc.nudDisp,
   144  		Clock:            &faketime.NullClock{},
   145  	})
   146  
   147  	tc.linkEP = channel.New(packetDepth, header.IPv4MinimumMTU, stackLinkAddr)
   148  	tc.linkEP.LinkEPCapabilities |= stack.CapabilityResolutionRequired
   149  
   150  	wep := stack.LinkEndpoint(tc.linkEP)
   151  	if testing.Verbose() {
   152  		wep = sniffer.New(wep)
   153  	}
   154  	if err := tc.s.CreateNIC(nicID, wep); err != nil {
   155  		t.Fatalf("CreateNIC failed: %s", err)
   156  	}
   157  
   158  	protocolAddr := tcpip.ProtocolAddress{
   159  		Protocol:          ipv4.ProtocolNumber,
   160  		AddressWithPrefix: stackAddr.WithPrefix(),
   161  	}
   162  	if err := tc.s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   163  		t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   164  	}
   165  
   166  	tc.s.SetRouteTable([]tcpip.Route{{
   167  		Destination: header.IPv4EmptySubnet,
   168  		NIC:         nicID,
   169  	}})
   170  
   171  	return tc
   172  }
   173  
   174  func (c *testContext) cleanup() {
   175  	c.linkEP.Close()
   176  	c.s.Close()
   177  	c.s.Wait()
   178  }
   179  
   180  func TestMalformedPacket(t *testing.T) {
   181  	c := makeTestContext(t, 0, 0)
   182  	defer c.cleanup()
   183  
   184  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   185  		Payload: buffer.MakeWithData(make([]byte, header.ARPSize)),
   186  	})
   187  
   188  	c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   189  	pkt.DecRef()
   190  
   191  	if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
   192  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   193  	}
   194  	if got := c.s.Stats().ARP.MalformedPacketsReceived.Value(); got != 1 {
   195  		t.Errorf("got c.s.Stats().ARP.MalformedPacketsReceived.Value() = %d, want = 1", got)
   196  	}
   197  }
   198  
   199  func TestDisabledEndpoint(t *testing.T) {
   200  	c := makeTestContext(t, 0, 0)
   201  	defer c.cleanup()
   202  
   203  	ep, err := c.s.GetNetworkEndpoint(nicID, header.ARPProtocolNumber)
   204  	if err != nil {
   205  		t.Fatalf("GetNetworkEndpoint(%d, header.ARPProtocolNumber) failed: %s", nicID, err)
   206  	}
   207  	ep.Disable()
   208  
   209  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   210  		Payload: buffer.MakeWithData(make([]byte, header.ARPSize)),
   211  	})
   212  
   213  	c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   214  	pkt.DecRef()
   215  
   216  	if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
   217  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   218  	}
   219  	if got := c.s.Stats().ARP.DisabledPacketsReceived.Value(); got != 1 {
   220  		t.Errorf("got c.s.Stats().ARP.DisabledPacketsReceived.Value() = %d, want = 1", got)
   221  	}
   222  }
   223  
   224  func TestDirectReply(t *testing.T) {
   225  	c := makeTestContext(t, 0, 0)
   226  	defer c.cleanup()
   227  
   228  	const senderMAC = "\x01\x02\x03\x04\x05\x06"
   229  	const senderIPv4 = "\x0a\x00\x00\x02"
   230  
   231  	v := make([]byte, header.ARPSize)
   232  	h := header.ARP(v)
   233  	h.SetIPv4OverEthernet()
   234  	h.SetOp(header.ARPReply)
   235  
   236  	copy(h.HardwareAddressSender(), senderMAC)
   237  	copy(h.ProtocolAddressSender(), senderIPv4)
   238  	copy(h.HardwareAddressTarget(), stackLinkAddr)
   239  	copy(h.ProtocolAddressTarget(), stackAddr.AsSlice())
   240  
   241  	pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   242  		Payload: buffer.MakeWithData(v),
   243  	})
   244  
   245  	c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   246  	pkt.DecRef()
   247  
   248  	if got := c.s.Stats().ARP.PacketsReceived.Value(); got != 1 {
   249  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   250  	}
   251  	if got := c.s.Stats().ARP.RepliesReceived.Value(); got != 1 {
   252  		t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = 1", got)
   253  	}
   254  }
   255  
   256  func TestDirectRequest(t *testing.T) {
   257  	tests := []struct {
   258  		name           string
   259  		senderAddr     tcpip.Address
   260  		senderLinkAddr tcpip.LinkAddress
   261  		targetAddr     tcpip.Address
   262  		isValid        bool
   263  	}{
   264  		{
   265  			name:           "Loopback",
   266  			senderAddr:     stackAddr,
   267  			senderLinkAddr: stackLinkAddr,
   268  			targetAddr:     stackAddr,
   269  			isValid:        true,
   270  		},
   271  		{
   272  			name:           "Remote",
   273  			senderAddr:     remoteAddr,
   274  			senderLinkAddr: remoteLinkAddr,
   275  			targetAddr:     stackAddr,
   276  			isValid:        true,
   277  		},
   278  		{
   279  			name:           "RemoteInvalidTarget",
   280  			senderAddr:     remoteAddr,
   281  			senderLinkAddr: remoteLinkAddr,
   282  			targetAddr:     unknownAddr,
   283  			isValid:        false,
   284  		},
   285  	}
   286  
   287  	for _, test := range tests {
   288  		t.Run(test.name, func(t *testing.T) {
   289  			c := makeTestContext(t, 1, 1)
   290  			defer c.cleanup()
   291  
   292  			packetsRecv := c.s.Stats().ARP.PacketsReceived.Value()
   293  			requestsRecv := c.s.Stats().ARP.RequestsReceived.Value()
   294  			requestsRecvUnknownAddr := c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value()
   295  			outgoingReplies := c.s.Stats().ARP.OutgoingRepliesSent.Value()
   296  
   297  			// Inject an incoming ARP request.
   298  			v := make([]byte, header.ARPSize)
   299  			h := header.ARP(v)
   300  			h.SetIPv4OverEthernet()
   301  			h.SetOp(header.ARPRequest)
   302  			copy(h.HardwareAddressSender(), test.senderLinkAddr)
   303  			copy(h.ProtocolAddressSender(), test.senderAddr.AsSlice())
   304  			copy(h.ProtocolAddressTarget(), test.targetAddr.AsSlice())
   305  			pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   306  				Payload: buffer.MakeWithData(v),
   307  			})
   308  			c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   309  			pkt.DecRef()
   310  
   311  			if got, want := c.s.Stats().ARP.PacketsReceived.Value(), packetsRecv+1; got != want {
   312  				t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, want)
   313  			}
   314  			if got, want := c.s.Stats().ARP.RequestsReceived.Value(), requestsRecv+1; got != want {
   315  				t.Errorf("got c.s.Stats().ARP.PacketsReceived.Value() = %d, want = %d", got, want)
   316  			}
   317  
   318  			if !test.isValid {
   319  				// No packets should be sent after receiving an invalid ARP request.
   320  				// There is no need to perform a blocking read here, since packets are
   321  				// sent in the same function that handles ARP requests.
   322  				if pkt := c.linkEP.Read(); pkt != nil {
   323  					t.Errorf("unexpected packet sent: %+v", pkt)
   324  				}
   325  				if got, want := c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value(), requestsRecvUnknownAddr+1; got != want {
   326  					t.Errorf("got c.s.Stats().ARP.RequestsReceivedUnknownTargetAddress.Value() = %d, want = %d", got, want)
   327  				}
   328  				if got, want := c.s.Stats().ARP.OutgoingRepliesSent.Value(), outgoingReplies; got != want {
   329  					t.Errorf("got c.s.Stats().ARP.OutgoingRepliesSent.Value() = %d, want = %d", got, want)
   330  				}
   331  
   332  				return
   333  			}
   334  
   335  			if got, want := c.s.Stats().ARP.OutgoingRepliesSent.Value(), outgoingReplies+1; got != want {
   336  				t.Errorf("got c.s.Stats().ARP.OutgoingRepliesSent.Value() = %d, want = %d", got, want)
   337  			}
   338  
   339  			// Verify an ARP response was sent.
   340  			pi := c.linkEP.Read()
   341  			if pi == nil {
   342  				t.Fatal("expected ARP response to be sent, got none")
   343  			}
   344  
   345  			if got, want := pi.NetworkProtocolNumber, arp.ProtocolNumber; got != want {
   346  				t.Fatalf("expected %d, got network protocol number %d", want, got)
   347  			}
   348  			rep := header.ARP(pi.NetworkHeader().Slice())
   349  			pi.DecRef()
   350  			if !rep.IsValid() {
   351  				t.Fatalf("invalid ARP response: len = %d; response = %x", len(rep), rep)
   352  			}
   353  			if got, want := tcpip.LinkAddress(rep.HardwareAddressSender()), stackLinkAddr; got != want {
   354  				t.Errorf("got HardwareAddressSender() = %s, want = %s", got, want)
   355  			}
   356  			if got, want := tcpip.AddrFromSlice(rep.ProtocolAddressSender()), tcpip.AddrFromSlice(h.ProtocolAddressTarget()); got != want {
   357  				t.Errorf("got ProtocolAddressSender() = %s, want = %s", got, want)
   358  			}
   359  			if got, want := tcpip.LinkAddress(rep.HardwareAddressTarget()), tcpip.LinkAddress(h.HardwareAddressSender()); got != want {
   360  				t.Errorf("got HardwareAddressTarget() = %s, want = %s", got, want)
   361  			}
   362  			if got, want := tcpip.AddrFromSlice(rep.ProtocolAddressTarget()), tcpip.AddrFromSlice(h.ProtocolAddressSender()); got != want {
   363  				t.Errorf("got ProtocolAddressTarget() = %s, want = %s", got, want)
   364  			}
   365  
   366  			// Verify the sender was saved in the neighbor cache.
   367  			if got, ok := c.nudDisp.nextEvent(); ok {
   368  				want := eventInfo{
   369  					eventType: entryAdded,
   370  					nicID:     nicID,
   371  					entry: stack.NeighborEntry{
   372  						Addr:     test.senderAddr,
   373  						LinkAddr: test.senderLinkAddr,
   374  						State:    stack.Stale,
   375  					},
   376  				}
   377  				if diff := cmp.Diff(want, got, cmp.AllowUnexported(eventInfo{}), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAt")); diff != "" {
   378  					t.Errorf("got invalid event (-want +got):\n%s", diff)
   379  				}
   380  			} else {
   381  				t.Fatal("event didn't arrive")
   382  			}
   383  
   384  			neighbors, err := c.s.Neighbors(nicID, ipv4.ProtocolNumber)
   385  			if err != nil {
   386  				t.Fatalf("c.s.Neighbors(%d, %d): %s", nicID, ipv4.ProtocolNumber, err)
   387  			}
   388  
   389  			neighborByAddr := make(map[tcpip.Address]stack.NeighborEntry)
   390  			for _, n := range neighbors {
   391  				if existing, ok := neighborByAddr[n.Addr]; ok {
   392  					if diff := cmp.Diff(existing, n); diff != "" {
   393  						t.Fatalf("duplicate neighbor entry found (-existing +got):\n%s", diff)
   394  					}
   395  					t.Fatalf("exact neighbor entry duplicate found for addr=%s", n.Addr)
   396  				}
   397  				neighborByAddr[n.Addr] = n
   398  			}
   399  
   400  			neigh, ok := neighborByAddr[test.senderAddr]
   401  			if !ok {
   402  				t.Fatalf("expected neighbor entry with Addr = %s", test.senderAddr)
   403  			}
   404  			if got, want := neigh.LinkAddr, test.senderLinkAddr; got != want {
   405  				t.Errorf("got neighbor LinkAddr = %s, want = %s", got, want)
   406  			}
   407  			if got, want := neigh.State, stack.Stale; got != want {
   408  				t.Errorf("got neighbor State = %s, want = %s", got, want)
   409  			}
   410  
   411  			// No more events should be dispatched
   412  			for {
   413  				event, ok := c.nudDisp.nextEvent()
   414  				if !ok {
   415  					break
   416  				}
   417  				t.Errorf("unexpected %s", event)
   418  			}
   419  		})
   420  	}
   421  }
   422  
   423  func TestReplyPacketType(t *testing.T) {
   424  	for _, testCase := range []struct {
   425  		name             string
   426  		packetType       tcpip.PacketType
   427  		becomesReachable bool
   428  	}{
   429  		{
   430  			name:             "unicast",
   431  			packetType:       tcpip.PacketHost,
   432  			becomesReachable: true,
   433  		},
   434  		{
   435  			name:             "broadcast",
   436  			packetType:       tcpip.PacketBroadcast,
   437  			becomesReachable: false,
   438  		},
   439  	} {
   440  		t.Run(testCase.name, func(t *testing.T) {
   441  			c := makeTestContext(t, 1, 1)
   442  			defer c.cleanup()
   443  
   444  			// Inject an incoming ARP request first.
   445  			v := make([]byte, header.ARPSize)
   446  			h := header.ARP(v)
   447  			h.SetIPv4OverEthernet()
   448  			h.SetOp(header.ARPRequest)
   449  			if got, want := copy(h.HardwareAddressSender(), remoteLinkAddr), header.EthernetAddressSize; got != want {
   450  				t.Fatalf("got copy(_, _) = %d, want = %d", got, want)
   451  			}
   452  			if got, want := copy(h.ProtocolAddressSender(), remoteAddr.AsSlice()), header.IPv4AddressSize; got != want {
   453  				t.Fatalf("got copy(_, _) = %d, want = %d", got, want)
   454  			}
   455  			if got, want := copy(h.ProtocolAddressTarget(), stackAddr.AsSlice()), header.IPv4AddressSize; got != want {
   456  				t.Fatalf("got copy(_, _) = %d, want = %d", got, want)
   457  			}
   458  			pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{
   459  				Payload: buffer.MakeWithData(v),
   460  			})
   461  			pkt.PktType = tcpip.PacketBroadcast
   462  			c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   463  			pkt.DecRef()
   464  
   465  			if got, ok := c.nudDisp.nextEvent(); ok {
   466  				want := eventInfo{
   467  					eventType: entryAdded,
   468  					nicID:     nicID,
   469  					entry: stack.NeighborEntry{
   470  						Addr:     remoteAddr,
   471  						LinkAddr: remoteLinkAddr,
   472  						State:    stack.Stale,
   473  					},
   474  				}
   475  				if diff := cmp.Diff(want, got, cmp.AllowUnexported(eventInfo{}), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAt")); diff != "" {
   476  					t.Errorf("got invalid event (-want +got):\n%s", diff)
   477  				}
   478  			} else {
   479  				t.Fatal("event didn't arrive")
   480  			}
   481  
   482  			// Then inject replies with different packet types.
   483  			h.SetIPv4OverEthernet()
   484  			h.SetOp(header.ARPReply)
   485  			pkt = stack.NewPacketBuffer(stack.PacketBufferOptions{
   486  				Payload: buffer.MakeWithData(v),
   487  			})
   488  			pkt.PktType = testCase.packetType
   489  			c.linkEP.InjectInbound(arp.ProtocolNumber, pkt)
   490  			pkt.DecRef()
   491  
   492  			got, ok := c.nudDisp.nextEvent()
   493  			// If the entry doesn't become reachable we're not supposed to see a new
   494  			// event.
   495  			if got, want := ok, testCase.becomesReachable; got != want {
   496  				t.Errorf("got c.nudDisp.nextEvent() = %t, want %t", got, want)
   497  			}
   498  			if ok {
   499  				want := eventInfo{
   500  					eventType: entryChanged,
   501  					nicID:     nicID,
   502  					entry: stack.NeighborEntry{
   503  						Addr:     remoteAddr,
   504  						LinkAddr: remoteLinkAddr,
   505  						State:    stack.Reachable,
   506  					},
   507  				}
   508  				if diff := cmp.Diff(want, got, cmp.AllowUnexported(eventInfo{}), cmpopts.IgnoreFields(stack.NeighborEntry{}, "UpdatedAt")); diff != "" {
   509  					t.Errorf("got invalid event (-want +got):\n%s", diff)
   510  				}
   511  			}
   512  		})
   513  	}
   514  
   515  }
   516  
   517  var _ stack.LinkEndpoint = (*testLinkEndpoint)(nil)
   518  
   519  type testLinkEndpoint struct {
   520  	stack.LinkEndpoint
   521  
   522  	writeErr tcpip.Error
   523  }
   524  
   525  func (t *testLinkEndpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
   526  	if t.writeErr != nil {
   527  		return 0, t.writeErr
   528  	}
   529  
   530  	return t.LinkEndpoint.WritePackets(pkts)
   531  }
   532  
   533  func TestLinkAddressRequest(t *testing.T) {
   534  	const nicID = 1
   535  
   536  	testAddr := tcpip.AddrFrom4Slice([]byte{1, 2, 3, 4})
   537  
   538  	tests := []struct {
   539  		name                                            string
   540  		nicAddr                                         tcpip.Address
   541  		localAddr                                       tcpip.Address
   542  		remoteLinkAddr                                  tcpip.LinkAddress
   543  		linkErr                                         tcpip.Error
   544  		expectedErr                                     tcpip.Error
   545  		expectedLocalAddr                               tcpip.Address
   546  		expectedRemoteLinkAddr                          tcpip.LinkAddress
   547  		expectedRequestsSent                            uint64
   548  		expectedRequestBadLocalAddressErrors            uint64
   549  		expectedRequestInterfaceHasNoLocalAddressErrors uint64
   550  		expectedRequestDroppedErrors                    uint64
   551  	}{
   552  		{
   553  			name:                                 "Unicast",
   554  			nicAddr:                              stackAddr,
   555  			localAddr:                            stackAddr,
   556  			remoteLinkAddr:                       remoteLinkAddr,
   557  			expectedLocalAddr:                    stackAddr,
   558  			expectedRemoteLinkAddr:               remoteLinkAddr,
   559  			expectedRequestsSent:                 1,
   560  			expectedRequestBadLocalAddressErrors: 0,
   561  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   562  			expectedRequestDroppedErrors:                    0,
   563  		},
   564  		{
   565  			name:                                 "Multicast",
   566  			nicAddr:                              stackAddr,
   567  			localAddr:                            stackAddr,
   568  			remoteLinkAddr:                       "",
   569  			expectedLocalAddr:                    stackAddr,
   570  			expectedRemoteLinkAddr:               header.EthernetBroadcastAddress,
   571  			expectedRequestsSent:                 1,
   572  			expectedRequestBadLocalAddressErrors: 0,
   573  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   574  			expectedRequestDroppedErrors:                    0,
   575  		},
   576  		{
   577  			name:                                 "Unicast with unspecified source",
   578  			nicAddr:                              stackAddr,
   579  			localAddr:                            tcpip.Address{},
   580  			remoteLinkAddr:                       remoteLinkAddr,
   581  			expectedLocalAddr:                    stackAddr,
   582  			expectedRemoteLinkAddr:               remoteLinkAddr,
   583  			expectedRequestsSent:                 1,
   584  			expectedRequestBadLocalAddressErrors: 0,
   585  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   586  			expectedRequestDroppedErrors:                    0,
   587  		},
   588  		{
   589  			name:                                 "Multicast with unspecified source",
   590  			nicAddr:                              stackAddr,
   591  			localAddr:                            tcpip.Address{},
   592  			remoteLinkAddr:                       "",
   593  			expectedLocalAddr:                    stackAddr,
   594  			expectedRemoteLinkAddr:               header.EthernetBroadcastAddress,
   595  			expectedRequestsSent:                 1,
   596  			expectedRequestBadLocalAddressErrors: 0,
   597  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   598  			expectedRequestDroppedErrors:                    0,
   599  		},
   600  		{
   601  			name:                                 "Unicast with unassigned address",
   602  			nicAddr:                              stackAddr,
   603  			localAddr:                            testAddr,
   604  			remoteLinkAddr:                       remoteLinkAddr,
   605  			expectedErr:                          &tcpip.ErrBadLocalAddress{},
   606  			expectedRequestsSent:                 0,
   607  			expectedRequestBadLocalAddressErrors: 1,
   608  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   609  			expectedRequestDroppedErrors:                    0,
   610  		},
   611  		{
   612  			name:                                 "Multicast with unassigned address",
   613  			nicAddr:                              stackAddr,
   614  			localAddr:                            testAddr,
   615  			remoteLinkAddr:                       "",
   616  			expectedErr:                          &tcpip.ErrBadLocalAddress{},
   617  			expectedRequestsSent:                 0,
   618  			expectedRequestBadLocalAddressErrors: 1,
   619  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   620  			expectedRequestDroppedErrors:                    0,
   621  		},
   622  		{
   623  			name:                                 "Unicast with no local address available",
   624  			nicAddr:                              tcpip.Address{},
   625  			localAddr:                            tcpip.Address{},
   626  			remoteLinkAddr:                       remoteLinkAddr,
   627  			expectedErr:                          &tcpip.ErrNetworkUnreachable{},
   628  			expectedRequestsSent:                 0,
   629  			expectedRequestBadLocalAddressErrors: 0,
   630  			expectedRequestInterfaceHasNoLocalAddressErrors: 1,
   631  			expectedRequestDroppedErrors:                    0,
   632  		},
   633  		{
   634  			name:                                 "Multicast with no local address available",
   635  			nicAddr:                              tcpip.Address{},
   636  			localAddr:                            tcpip.Address{},
   637  			remoteLinkAddr:                       "",
   638  			expectedErr:                          &tcpip.ErrNetworkUnreachable{},
   639  			expectedRequestsSent:                 0,
   640  			expectedRequestBadLocalAddressErrors: 0,
   641  			expectedRequestInterfaceHasNoLocalAddressErrors: 1,
   642  			expectedRequestDroppedErrors:                    0,
   643  		},
   644  		{
   645  			name:                                 "Link error",
   646  			nicAddr:                              stackAddr,
   647  			localAddr:                            stackAddr,
   648  			remoteLinkAddr:                       remoteLinkAddr,
   649  			linkErr:                              &tcpip.ErrInvalidEndpointState{},
   650  			expectedErr:                          &tcpip.ErrInvalidEndpointState{},
   651  			expectedRequestsSent:                 0,
   652  			expectedRequestBadLocalAddressErrors: 0,
   653  			expectedRequestInterfaceHasNoLocalAddressErrors: 0,
   654  			expectedRequestDroppedErrors:                    1,
   655  		},
   656  	}
   657  
   658  	for _, test := range tests {
   659  		t.Run(test.name, func(t *testing.T) {
   660  			s := stack.New(stack.Options{
   661  				NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocol, ipv4.NewProtocol},
   662  			})
   663  			defer func() {
   664  				s.Close()
   665  				s.Wait()
   666  			}()
   667  			linkEP := channel.New(1, header.IPv4MinimumMTU, stackLinkAddr)
   668  			defer linkEP.Close()
   669  			if err := s.CreateNIC(nicID, &testLinkEndpoint{LinkEndpoint: linkEP, writeErr: test.linkErr}); err != nil {
   670  				t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   671  			}
   672  
   673  			ep, err := s.GetNetworkEndpoint(nicID, arp.ProtocolNumber)
   674  			if err != nil {
   675  				t.Fatalf("s.GetNetworkEndpoint(%d, %d): %s", nicID, arp.ProtocolNumber, err)
   676  			}
   677  			linkRes, ok := ep.(stack.LinkAddressResolver)
   678  			if !ok {
   679  				t.Fatalf("expected %T to implement stack.LinkAddressResolver", ep)
   680  			}
   681  
   682  			if test.nicAddr.Len() != 0 {
   683  				protocolAddr := tcpip.ProtocolAddress{
   684  					Protocol:          ipv4.ProtocolNumber,
   685  					AddressWithPrefix: test.nicAddr.WithPrefix(),
   686  				}
   687  				if err := s.AddProtocolAddress(nicID, protocolAddr, stack.AddressProperties{}); err != nil {
   688  					t.Fatalf("AddProtocolAddress(%d, %+v, {}): %s", nicID, protocolAddr, err)
   689  				}
   690  			}
   691  
   692  			{
   693  				err := linkRes.LinkAddressRequest(remoteAddr, test.localAddr, test.remoteLinkAddr)
   694  				if diff := cmp.Diff(test.expectedErr, err); diff != "" {
   695  					t.Fatalf("unexpected error from p.LinkAddressRequest(%s, %s, %s, _), (-want, +got):\n%s", remoteAddr, test.localAddr, test.remoteLinkAddr, diff)
   696  				}
   697  			}
   698  
   699  			if got := s.Stats().ARP.OutgoingRequestsSent.Value(); got != test.expectedRequestsSent {
   700  				t.Errorf("got s.Stats().ARP.OutgoingRequestsSent.Value() = %d, want = %d", got, test.expectedRequestsSent)
   701  			}
   702  			if got := s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value(); got != test.expectedRequestInterfaceHasNoLocalAddressErrors {
   703  				t.Errorf("got s.Stats().ARP.OutgoingRequestInterfaceHasNoLocalAddressErrors.Value() = %d, want = %d", got, test.expectedRequestInterfaceHasNoLocalAddressErrors)
   704  			}
   705  			if got := s.Stats().ARP.OutgoingRequestBadLocalAddressErrors.Value(); got != test.expectedRequestBadLocalAddressErrors {
   706  				t.Errorf("got s.Stats().ARP.OutgoingRequestBadLocalAddressErrors.Value() = %d, want = %d", got, test.expectedRequestBadLocalAddressErrors)
   707  			}
   708  			if got := s.Stats().ARP.OutgoingRequestsDropped.Value(); got != test.expectedRequestDroppedErrors {
   709  				t.Errorf("got s.Stats().ARP.OutgoingRequestsDropped.Value() = %d, want = %d", got, test.expectedRequestDroppedErrors)
   710  			}
   711  
   712  			if test.expectedErr != nil {
   713  				return
   714  			}
   715  
   716  			pkt := linkEP.Read()
   717  			if pkt == nil {
   718  				t.Fatal("expected to send a link address request")
   719  			}
   720  
   721  			if pkt.EgressRoute.RemoteLinkAddress != test.expectedRemoteLinkAddr {
   722  				t.Errorf("got pkt.EgressRoute.RemoteLinkAddress = %s, want = %s", pkt.EgressRoute.RemoteLinkAddress, test.expectedRemoteLinkAddr)
   723  			}
   724  
   725  			payload := stack.PayloadSince(pkt.NetworkHeader())
   726  			defer payload.Release()
   727  			rep := header.ARP(payload.AsSlice())
   728  			pkt.DecRef()
   729  			if got := rep.Op(); got != header.ARPRequest {
   730  				t.Errorf("got Op = %d, want = %d", got, header.ARPRequest)
   731  			}
   732  			if got := tcpip.LinkAddress(rep.HardwareAddressSender()); got != stackLinkAddr {
   733  				t.Errorf("got HardwareAddressSender = %s, want = %s", got, stackLinkAddr)
   734  			}
   735  			if got := tcpip.AddrFromSlice(rep.ProtocolAddressSender()); got != test.expectedLocalAddr {
   736  				t.Errorf("got ProtocolAddressSender = %s, want = %s", got, test.expectedLocalAddr)
   737  			}
   738  			if got, want := tcpip.LinkAddress(rep.HardwareAddressTarget()), tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00"); got != want {
   739  				t.Errorf("got HardwareAddressTarget = %s, want = %s", got, want)
   740  			}
   741  			if got := tcpip.AddrFromSlice(rep.ProtocolAddressTarget()); got != remoteAddr {
   742  				t.Errorf("got ProtocolAddressTarget = %s, want = %s", got, remoteAddr)
   743  			}
   744  		})
   745  	}
   746  }
   747  
   748  func TestDADARPRequestPacket(t *testing.T) {
   749  	clock := faketime.NewManualClock()
   750  	s := stack.New(stack.Options{
   751  		NetworkProtocols: []stack.NetworkProtocolFactory{arp.NewProtocolWithOptions(arp.Options{
   752  			DADConfigs: stack.DADConfigurations{
   753  				DupAddrDetectTransmits: 1,
   754  			},
   755  		}), ipv4.NewProtocol},
   756  		Clock: clock,
   757  	})
   758  	defer func() {
   759  		s.Close()
   760  		s.Wait()
   761  	}()
   762  	e := channel.New(1, header.IPv4MinimumMTU, stackLinkAddr)
   763  	defer e.Close()
   764  	if err := s.CreateNIC(nicID, e); err != nil {
   765  		t.Fatalf("s.CreateNIC(%d, _): %s", nicID, err)
   766  	}
   767  
   768  	if res, err := s.CheckDuplicateAddress(nicID, header.IPv4ProtocolNumber, remoteAddr, func(stack.DADResult) {}); err != nil {
   769  		t.Fatalf("s.CheckDuplicateAddress(%d, %d, %s, _): %s", nicID, header.IPv4ProtocolNumber, remoteAddr, err)
   770  	} else if res != stack.DADStarting {
   771  		t.Fatalf("got s.CheckDuplicateAddress(%d, %d, %s, _) = %d, want = %d", nicID, header.IPv4ProtocolNumber, remoteAddr, res, stack.DADStarting)
   772  	}
   773  
   774  	clock.RunImmediatelyScheduledJobs()
   775  	pkt := e.Read()
   776  	if pkt == nil {
   777  		t.Fatal("expected to send an ARP request")
   778  	}
   779  
   780  	if pkt.EgressRoute.RemoteLinkAddress != header.EthernetBroadcastAddress {
   781  		t.Errorf("got pkt.EgressRoute.RemoteLinkAddress = %s, want = %s", pkt.EgressRoute.RemoteLinkAddress, header.EthernetBroadcastAddress)
   782  	}
   783  	payload := stack.PayloadSince(pkt.NetworkHeader())
   784  	defer payload.Release()
   785  	req := header.ARP(payload.AsSlice())
   786  	pkt.DecRef()
   787  	if !req.IsValid() {
   788  		t.Errorf("got req.IsValid() = false, want = true")
   789  	}
   790  	if got := req.Op(); got != header.ARPRequest {
   791  		t.Errorf("got req.Op() = %d, want = %d", got, header.ARPRequest)
   792  	}
   793  	if got := tcpip.LinkAddress(req.HardwareAddressSender()); got != stackLinkAddr {
   794  		t.Errorf("got req.HardwareAddressSender() = %s, want = %s", got, stackLinkAddr)
   795  	}
   796  	if got := tcpip.AddrFromSlice(req.ProtocolAddressSender()); got != header.IPv4Any {
   797  		t.Errorf("got req.ProtocolAddressSender() = %s, want = %s", got, header.IPv4Any)
   798  	}
   799  	if got, want := tcpip.LinkAddress(req.HardwareAddressTarget()), tcpip.LinkAddress("\x00\x00\x00\x00\x00\x00"); got != want {
   800  		t.Errorf("got req.HardwareAddressTarget() = %s, want = %s", got, want)
   801  	}
   802  	if got := tcpip.AddrFromSlice(req.ProtocolAddressTarget()); got != remoteAddr {
   803  		t.Errorf("got req.ProtocolAddressTarget() = %s, want = %s", got, remoteAddr)
   804  	}
   805  }
   806  
   807  func TestMain(m *testing.M) {
   808  	refs.SetLeakMode(refs.LeaksPanic)
   809  	code := m.Run()
   810  	refs.DoLeakCheck()
   811  	os.Exit(code)
   812  }