github.com/vpnishe/netstack@v1.10.6/tcpip/stack/ndp_test.go (about)

     1  // Copyright 2019 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 stack_test
    16  
    17  import (
    18  	"encoding/binary"
    19  	"fmt"
    20  	"testing"
    21  	"time"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/vpnishe/netstack/tcpip"
    25  	"github.com/vpnishe/netstack/tcpip/buffer"
    26  	"github.com/vpnishe/netstack/tcpip/checker"
    27  	"github.com/vpnishe/netstack/tcpip/header"
    28  	"github.com/vpnishe/netstack/tcpip/link/channel"
    29  	"github.com/vpnishe/netstack/tcpip/network/ipv6"
    30  	"github.com/vpnishe/netstack/tcpip/stack"
    31  	"github.com/vpnishe/netstack/tcpip/transport/icmp"
    32  )
    33  
    34  const (
    35  	addr1          = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
    36  	addr2          = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"
    37  	addr3          = "\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"
    38  	linkAddr1      = "\x02\x02\x03\x04\x05\x06"
    39  	linkAddr2      = "\x02\x02\x03\x04\x05\x07"
    40  	linkAddr3      = "\x02\x02\x03\x04\x05\x08"
    41  	defaultTimeout = 250 * time.Millisecond
    42  )
    43  
    44  var (
    45  	llAddr1 = header.LinkLocalAddr(linkAddr1)
    46  	llAddr2 = header.LinkLocalAddr(linkAddr2)
    47  	llAddr3 = header.LinkLocalAddr(linkAddr3)
    48  )
    49  
    50  // TestDADDisabled tests that an address successfully resolves immediately
    51  // when DAD is not enabled (the default for an empty stack.Options).
    52  func TestDADDisabled(t *testing.T) {
    53  	opts := stack.Options{
    54  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
    55  	}
    56  
    57  	e := channel.New(10, 1280, linkAddr1)
    58  	s := stack.New(opts)
    59  	if err := s.CreateNIC(1, e); err != nil {
    60  		t.Fatalf("CreateNIC(_) = %s", err)
    61  	}
    62  
    63  	if err := s.AddAddress(1, header.IPv6ProtocolNumber, addr1); err != nil {
    64  		t.Fatalf("AddAddress(_, %d, %s) = %s", header.IPv6ProtocolNumber, addr1, err)
    65  	}
    66  
    67  	// Should get the address immediately since we should not have performed
    68  	// DAD on it.
    69  	addr, err := s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
    70  	if err != nil {
    71  		t.Fatalf("stack.GetMainNICAddress(_, _) err = %s", err)
    72  	}
    73  	if addr.Address != addr1 {
    74  		t.Fatalf("got stack.GetMainNICAddress(_, _) = %s, want = %s", addr, addr1)
    75  	}
    76  
    77  	// We should not have sent any NDP NS messages.
    78  	if got := s.Stats().ICMP.V6PacketsSent.NeighborSolicit.Value(); got != 0 {
    79  		t.Fatalf("got NeighborSolicit = %d, want = 0", got)
    80  	}
    81  }
    82  
    83  // ndpDADEvent is a set of parameters that was passed to
    84  // ndpDispatcher.OnDuplicateAddressDetectionStatus.
    85  type ndpDADEvent struct {
    86  	nicID    tcpip.NICID
    87  	addr     tcpip.Address
    88  	resolved bool
    89  	err      *tcpip.Error
    90  }
    91  
    92  type ndpRouterEvent struct {
    93  	nicID tcpip.NICID
    94  	addr  tcpip.Address
    95  	// true if router was discovered, false if invalidated.
    96  	discovered bool
    97  }
    98  
    99  type ndpPrefixEvent struct {
   100  	nicID  tcpip.NICID
   101  	prefix tcpip.Subnet
   102  	// true if prefix was discovered, false if invalidated.
   103  	discovered bool
   104  }
   105  
   106  var _ stack.NDPDispatcher = (*ndpDispatcher)(nil)
   107  
   108  // ndpDispatcher implements NDPDispatcher so tests can know when various NDP
   109  // related events happen for test purposes.
   110  type ndpDispatcher struct {
   111  	dadC           chan ndpDADEvent
   112  	routerC        chan ndpRouterEvent
   113  	rememberRouter bool
   114  	prefixC        chan ndpPrefixEvent
   115  	rememberPrefix bool
   116  	routeTable     []tcpip.Route
   117  }
   118  
   119  // Implements stack.NDPDispatcher.OnDuplicateAddressDetectionStatus.
   120  func (n *ndpDispatcher) OnDuplicateAddressDetectionStatus(nicID tcpip.NICID, addr tcpip.Address, resolved bool, err *tcpip.Error) {
   121  	if n.dadC != nil {
   122  		n.dadC <- ndpDADEvent{
   123  			nicID,
   124  			addr,
   125  			resolved,
   126  			err,
   127  		}
   128  	}
   129  }
   130  
   131  // Implements stack.NDPDispatcher.OnDefaultRouterDiscovered.
   132  func (n *ndpDispatcher) OnDefaultRouterDiscovered(nicID tcpip.NICID, addr tcpip.Address) (bool, []tcpip.Route) {
   133  	if n.routerC != nil {
   134  		n.routerC <- ndpRouterEvent{
   135  			nicID,
   136  			addr,
   137  			true,
   138  		}
   139  	}
   140  
   141  	if !n.rememberRouter {
   142  		return false, nil
   143  	}
   144  
   145  	rt := append([]tcpip.Route(nil), n.routeTable...)
   146  	rt = append(rt, tcpip.Route{
   147  		Destination: header.IPv6EmptySubnet,
   148  		Gateway:     addr,
   149  		NIC:         nicID,
   150  	})
   151  	n.routeTable = rt
   152  	return true, rt
   153  }
   154  
   155  // Implements stack.NDPDispatcher.OnDefaultRouterInvalidated.
   156  func (n *ndpDispatcher) OnDefaultRouterInvalidated(nicID tcpip.NICID, addr tcpip.Address) []tcpip.Route {
   157  	if n.routerC != nil {
   158  		n.routerC <- ndpRouterEvent{
   159  			nicID,
   160  			addr,
   161  			false,
   162  		}
   163  	}
   164  
   165  	var rt []tcpip.Route
   166  	exclude := tcpip.Route{
   167  		Destination: header.IPv6EmptySubnet,
   168  		Gateway:     addr,
   169  		NIC:         nicID,
   170  	}
   171  
   172  	for _, r := range n.routeTable {
   173  		if r != exclude {
   174  			rt = append(rt, r)
   175  		}
   176  	}
   177  	n.routeTable = rt
   178  	return rt
   179  }
   180  
   181  // Implements stack.NDPDispatcher.OnOnLinkPrefixDiscovered.
   182  func (n *ndpDispatcher) OnOnLinkPrefixDiscovered(nicID tcpip.NICID, prefix tcpip.Subnet) (bool, []tcpip.Route) {
   183  	if n.prefixC != nil {
   184  		n.prefixC <- ndpPrefixEvent{
   185  			nicID,
   186  			prefix,
   187  			true,
   188  		}
   189  	}
   190  
   191  	if !n.rememberPrefix {
   192  		return false, nil
   193  	}
   194  
   195  	rt := append([]tcpip.Route(nil), n.routeTable...)
   196  	rt = append(rt, tcpip.Route{
   197  		Destination: prefix,
   198  		NIC:         nicID,
   199  	})
   200  	n.routeTable = rt
   201  	return true, rt
   202  }
   203  
   204  // Implements stack.NDPDispatcher.OnOnLinkPrefixInvalidated.
   205  func (n *ndpDispatcher) OnOnLinkPrefixInvalidated(nicID tcpip.NICID, prefix tcpip.Subnet) []tcpip.Route {
   206  	if n.prefixC != nil {
   207  		n.prefixC <- ndpPrefixEvent{
   208  			nicID,
   209  			prefix,
   210  			false,
   211  		}
   212  	}
   213  
   214  	rt := make([]tcpip.Route, 0)
   215  	exclude := tcpip.Route{
   216  		Destination: prefix,
   217  		NIC:         nicID,
   218  	}
   219  
   220  	for _, r := range n.routeTable {
   221  		if r != exclude {
   222  			rt = append(rt, r)
   223  		}
   224  	}
   225  	n.routeTable = rt
   226  	return rt
   227  }
   228  
   229  // TestDADResolve tests that an address successfully resolves after performing
   230  // DAD for various values of DupAddrDetectTransmits and RetransmitTimer.
   231  // Included in the subtests is a test to make sure that an invalid
   232  // RetransmitTimer (<1ms) values get fixed to the default RetransmitTimer of 1s.
   233  func TestDADResolve(t *testing.T) {
   234  	tests := []struct {
   235  		name                    string
   236  		dupAddrDetectTransmits  uint8
   237  		retransTimer            time.Duration
   238  		expectedRetransmitTimer time.Duration
   239  	}{
   240  		{"1:1s:1s", 1, time.Second, time.Second},
   241  		{"2:1s:1s", 2, time.Second, time.Second},
   242  		{"1:2s:2s", 1, 2 * time.Second, 2 * time.Second},
   243  		// 0s is an invalid RetransmitTimer timer and will be fixed to
   244  		// the default RetransmitTimer value of 1s.
   245  		{"1:0s:1s", 1, 0, time.Second},
   246  	}
   247  
   248  	for _, test := range tests {
   249  		t.Run(test.name, func(t *testing.T) {
   250  			ndpDisp := ndpDispatcher{
   251  				dadC: make(chan ndpDADEvent),
   252  			}
   253  			opts := stack.Options{
   254  				NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   255  				NDPDisp:          &ndpDisp,
   256  			}
   257  			opts.NDPConfigs.RetransmitTimer = test.retransTimer
   258  			opts.NDPConfigs.DupAddrDetectTransmits = test.dupAddrDetectTransmits
   259  
   260  			e := channel.New(10, 1280, linkAddr1)
   261  			s := stack.New(opts)
   262  			if err := s.CreateNIC(1, e); err != nil {
   263  				t.Fatalf("CreateNIC(_) = %s", err)
   264  			}
   265  
   266  			if err := s.AddAddress(1, header.IPv6ProtocolNumber, addr1); err != nil {
   267  				t.Fatalf("AddAddress(_, %d, %s) = %s", header.IPv6ProtocolNumber, addr1, err)
   268  			}
   269  
   270  			stat := s.Stats().ICMP.V6PacketsSent.NeighborSolicit
   271  
   272  			// Should have sent an NDP NS immediately.
   273  			if got := stat.Value(); got != 1 {
   274  				t.Fatalf("got NeighborSolicit = %d, want = 1", got)
   275  
   276  			}
   277  
   278  			// Address should not be considered bound to the NIC yet
   279  			// (DAD ongoing).
   280  			addr, err := s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   281  			if err != nil {
   282  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   283  			}
   284  			if want := (tcpip.AddressWithPrefix{}); addr != want {
   285  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   286  			}
   287  
   288  			// Wait for the remaining time - some delta (500ms), to
   289  			// make sure the address is still not resolved.
   290  			const delta = 500 * time.Millisecond
   291  			time.Sleep(test.expectedRetransmitTimer*time.Duration(test.dupAddrDetectTransmits) - delta)
   292  			addr, err = s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   293  			if err != nil {
   294  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   295  			}
   296  			if want := (tcpip.AddressWithPrefix{}); addr != want {
   297  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   298  			}
   299  
   300  			// Wait for DAD to resolve.
   301  			select {
   302  			case <-time.After(2 * delta):
   303  				// We should get a resolution event after 500ms
   304  				// (delta) since we wait for 500ms less than the
   305  				// expected resolution time above to make sure
   306  				// that the address did not yet resolve. Waiting
   307  				// for 1s (2x delta) without a resolution event
   308  				// means something is wrong.
   309  				t.Fatal("timed out waiting for DAD resolution")
   310  			case e := <-ndpDisp.dadC:
   311  				if e.err != nil {
   312  					t.Fatal("got DAD error: ", e.err)
   313  				}
   314  				if e.nicID != 1 {
   315  					t.Fatalf("got DAD event w/ nicID = %d, want = 1", e.nicID)
   316  				}
   317  				if e.addr != addr1 {
   318  					t.Fatalf("got DAD event w/ addr = %s, want = %s", addr, addr1)
   319  				}
   320  				if !e.resolved {
   321  					t.Fatal("got DAD event w/ resolved = false, want = true")
   322  				}
   323  			}
   324  			addr, err = s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   325  			if err != nil {
   326  				t.Fatalf("stack.GetMainNICAddress(_, _) err = %s", err)
   327  			}
   328  			if addr.Address != addr1 {
   329  				t.Fatalf("got stack.GetMainNICAddress(_, _) = %s, want = %s", addr, addr1)
   330  			}
   331  
   332  			// Should not have sent any more NS messages.
   333  			if got := stat.Value(); got != uint64(test.dupAddrDetectTransmits) {
   334  				t.Fatalf("got NeighborSolicit = %d, want = %d", got, test.dupAddrDetectTransmits)
   335  			}
   336  
   337  			// Validate the sent Neighbor Solicitation messages.
   338  			for i := uint8(0); i < test.dupAddrDetectTransmits; i++ {
   339  				p := <-e.C
   340  
   341  				// Make sure its an IPv6 packet.
   342  				if p.Proto != header.IPv6ProtocolNumber {
   343  					t.Fatalf("got Proto = %d, want = %d", p.Proto, header.IPv6ProtocolNumber)
   344  				}
   345  
   346  				// Check NDP packet.
   347  				checker.IPv6(t, p.Pkt.Header.View().ToVectorisedView().First(),
   348  					checker.TTL(header.NDPHopLimit),
   349  					checker.NDPNS(
   350  						checker.NDPNSTargetAddress(addr1)))
   351  			}
   352  		})
   353  	}
   354  
   355  }
   356  
   357  // TestDADFail tests to make sure that the DAD process fails if another node is
   358  // detected to be performing DAD on the same address (receive an NS message from
   359  // a node doing DAD for the same address), or if another node is detected to own
   360  // the address already (receive an NA message for the tentative address).
   361  func TestDADFail(t *testing.T) {
   362  	tests := []struct {
   363  		name    string
   364  		makeBuf func(tgt tcpip.Address) buffer.Prependable
   365  		getStat func(s tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter
   366  	}{
   367  		{
   368  			"RxSolicit",
   369  			func(tgt tcpip.Address) buffer.Prependable {
   370  				hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.ICMPv6NeighborSolicitMinimumSize)
   371  				pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborSolicitMinimumSize))
   372  				pkt.SetType(header.ICMPv6NeighborSolicit)
   373  				ns := header.NDPNeighborSolicit(pkt.NDPPayload())
   374  				ns.SetTargetAddress(tgt)
   375  				snmc := header.SolicitedNodeAddr(tgt)
   376  				pkt.SetChecksum(header.ICMPv6Checksum(pkt, header.IPv6Any, snmc, buffer.VectorisedView{}))
   377  				payloadLength := hdr.UsedLength()
   378  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   379  				ip.Encode(&header.IPv6Fields{
   380  					PayloadLength: uint16(payloadLength),
   381  					NextHeader:    uint8(icmp.ProtocolNumber6),
   382  					HopLimit:      255,
   383  					SrcAddr:       header.IPv6Any,
   384  					DstAddr:       snmc,
   385  				})
   386  
   387  				return hdr
   388  
   389  			},
   390  			func(s tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   391  				return s.NeighborSolicit
   392  			},
   393  		},
   394  		{
   395  			"RxAdvert",
   396  			func(tgt tcpip.Address) buffer.Prependable {
   397  				hdr := buffer.NewPrependable(header.IPv6MinimumSize + header.ICMPv6NeighborAdvertSize)
   398  				pkt := header.ICMPv6(hdr.Prepend(header.ICMPv6NeighborAdvertSize))
   399  				pkt.SetType(header.ICMPv6NeighborAdvert)
   400  				na := header.NDPNeighborAdvert(pkt.NDPPayload())
   401  				na.SetSolicitedFlag(true)
   402  				na.SetOverrideFlag(true)
   403  				na.SetTargetAddress(tgt)
   404  				pkt.SetChecksum(header.ICMPv6Checksum(pkt, tgt, header.IPv6AllNodesMulticastAddress, buffer.VectorisedView{}))
   405  				payloadLength := hdr.UsedLength()
   406  				ip := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   407  				ip.Encode(&header.IPv6Fields{
   408  					PayloadLength: uint16(payloadLength),
   409  					NextHeader:    uint8(icmp.ProtocolNumber6),
   410  					HopLimit:      255,
   411  					SrcAddr:       tgt,
   412  					DstAddr:       header.IPv6AllNodesMulticastAddress,
   413  				})
   414  
   415  				return hdr
   416  
   417  			},
   418  			func(s tcpip.ICMPv6ReceivedPacketStats) *tcpip.StatCounter {
   419  				return s.NeighborAdvert
   420  			},
   421  		},
   422  	}
   423  
   424  	for _, test := range tests {
   425  		t.Run(test.name, func(t *testing.T) {
   426  			ndpDisp := ndpDispatcher{
   427  				dadC: make(chan ndpDADEvent),
   428  			}
   429  			ndpConfigs := stack.DefaultNDPConfigurations()
   430  			opts := stack.Options{
   431  				NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   432  				NDPConfigs:       ndpConfigs,
   433  				NDPDisp:          &ndpDisp,
   434  			}
   435  			opts.NDPConfigs.RetransmitTimer = time.Second * 2
   436  
   437  			e := channel.New(10, 1280, linkAddr1)
   438  			s := stack.New(opts)
   439  			if err := s.CreateNIC(1, e); err != nil {
   440  				t.Fatalf("CreateNIC(_) = %s", err)
   441  			}
   442  
   443  			if err := s.AddAddress(1, header.IPv6ProtocolNumber, addr1); err != nil {
   444  				t.Fatalf("AddAddress(_, %d, %s) = %s", header.IPv6ProtocolNumber, addr1, err)
   445  			}
   446  
   447  			// Address should not be considered bound to the NIC yet
   448  			// (DAD ongoing).
   449  			addr, err := s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   450  			if err != nil {
   451  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   452  			}
   453  			if want := (tcpip.AddressWithPrefix{}); addr != want {
   454  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   455  			}
   456  
   457  			// Receive a packet to simulate multiple nodes owning or
   458  			// attempting to own the same address.
   459  			hdr := test.makeBuf(addr1)
   460  			e.InjectInbound(header.IPv6ProtocolNumber, tcpip.PacketBuffer{
   461  				Data: hdr.View().ToVectorisedView(),
   462  			})
   463  
   464  			stat := test.getStat(s.Stats().ICMP.V6PacketsReceived)
   465  			if got := stat.Value(); got != 1 {
   466  				t.Fatalf("got stat = %d, want = 1", got)
   467  			}
   468  
   469  			// Wait for DAD to fail and make sure the address did
   470  			// not get resolved.
   471  			select {
   472  			case <-time.After(time.Duration(ndpConfigs.DupAddrDetectTransmits)*ndpConfigs.RetransmitTimer + time.Second):
   473  				// If we don't get a failure event after the
   474  				// expected resolution time + extra 1s buffer,
   475  				// something is wrong.
   476  				t.Fatal("timed out waiting for DAD failure")
   477  			case e := <-ndpDisp.dadC:
   478  				if e.err != nil {
   479  					t.Fatal("got DAD error: ", e.err)
   480  				}
   481  				if e.nicID != 1 {
   482  					t.Fatalf("got DAD event w/ nicID = %d, want = 1", e.nicID)
   483  				}
   484  				if e.addr != addr1 {
   485  					t.Fatalf("got DAD event w/ addr = %s, want = %s", addr, addr1)
   486  				}
   487  				if e.resolved {
   488  					t.Fatal("got DAD event w/ resolved = true, want = false")
   489  				}
   490  			}
   491  			addr, err = s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   492  			if err != nil {
   493  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   494  			}
   495  			if want := (tcpip.AddressWithPrefix{}); addr != want {
   496  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   497  			}
   498  		})
   499  	}
   500  }
   501  
   502  // TestDADStop tests to make sure that the DAD process stops when an address is
   503  // removed.
   504  func TestDADStop(t *testing.T) {
   505  	ndpDisp := ndpDispatcher{
   506  		dadC: make(chan ndpDADEvent),
   507  	}
   508  	ndpConfigs := stack.NDPConfigurations{
   509  		RetransmitTimer:        time.Second,
   510  		DupAddrDetectTransmits: 2,
   511  	}
   512  	opts := stack.Options{
   513  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   514  		NDPDisp:          &ndpDisp,
   515  		NDPConfigs:       ndpConfigs,
   516  	}
   517  
   518  	e := channel.New(10, 1280, linkAddr1)
   519  	s := stack.New(opts)
   520  	if err := s.CreateNIC(1, e); err != nil {
   521  		t.Fatalf("CreateNIC(_) = %s", err)
   522  	}
   523  
   524  	if err := s.AddAddress(1, header.IPv6ProtocolNumber, addr1); err != nil {
   525  		t.Fatalf("AddAddress(_, %d, %s) = %s", header.IPv6ProtocolNumber, addr1, err)
   526  	}
   527  
   528  	// Address should not be considered bound to the NIC yet (DAD ongoing).
   529  	addr, err := s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   530  	if err != nil {
   531  		t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   532  	}
   533  	if want := (tcpip.AddressWithPrefix{}); addr != want {
   534  		t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   535  	}
   536  
   537  	// Remove the address. This should stop DAD.
   538  	if err := s.RemoveAddress(1, addr1); err != nil {
   539  		t.Fatalf("RemoveAddress(_, %s) = %s", addr1, err)
   540  	}
   541  
   542  	// Wait for DAD to fail (since the address was removed during DAD).
   543  	select {
   544  	case <-time.After(time.Duration(ndpConfigs.DupAddrDetectTransmits)*ndpConfigs.RetransmitTimer + time.Second):
   545  		// If we don't get a failure event after the expected resolution
   546  		// time + extra 1s buffer, something is wrong.
   547  		t.Fatal("timed out waiting for DAD failure")
   548  	case e := <-ndpDisp.dadC:
   549  		if e.err != nil {
   550  			t.Fatal("got DAD error: ", e.err)
   551  		}
   552  		if e.nicID != 1 {
   553  			t.Fatalf("got DAD event w/ nicID = %d, want = 1", e.nicID)
   554  		}
   555  		if e.addr != addr1 {
   556  			t.Fatalf("got DAD event w/ addr = %s, want = %s", addr, addr1)
   557  		}
   558  		if e.resolved {
   559  			t.Fatal("got DAD event w/ resolved = true, want = false")
   560  		}
   561  
   562  	}
   563  	addr, err = s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   564  	if err != nil {
   565  		t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   566  	}
   567  	if want := (tcpip.AddressWithPrefix{}); addr != want {
   568  		t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   569  	}
   570  
   571  	// Should not have sent more than 1 NS message.
   572  	if got := s.Stats().ICMP.V6PacketsSent.NeighborSolicit.Value(); got > 1 {
   573  		t.Fatalf("got NeighborSolicit = %d, want <= 1", got)
   574  	}
   575  }
   576  
   577  // TestSetNDPConfigurationFailsForBadNICID tests to make sure we get an error if
   578  // we attempt to update NDP configurations using an invalid NICID.
   579  func TestSetNDPConfigurationFailsForBadNICID(t *testing.T) {
   580  	s := stack.New(stack.Options{
   581  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   582  	})
   583  
   584  	// No NIC with ID 1 yet.
   585  	if got := s.SetNDPConfigurations(1, stack.NDPConfigurations{}); got != tcpip.ErrUnknownNICID {
   586  		t.Fatalf("got s.SetNDPConfigurations = %v, want = %s", got, tcpip.ErrUnknownNICID)
   587  	}
   588  }
   589  
   590  // TestSetNDPConfigurations tests that we can update and use per-interface NDP
   591  // configurations without affecting the default NDP configurations or other
   592  // interfaces' configurations.
   593  func TestSetNDPConfigurations(t *testing.T) {
   594  	tests := []struct {
   595  		name                    string
   596  		dupAddrDetectTransmits  uint8
   597  		retransmitTimer         time.Duration
   598  		expectedRetransmitTimer time.Duration
   599  	}{
   600  		{
   601  			"OK",
   602  			1,
   603  			time.Second,
   604  			time.Second,
   605  		},
   606  		{
   607  			"Invalid Retransmit Timer",
   608  			1,
   609  			0,
   610  			time.Second,
   611  		},
   612  	}
   613  
   614  	for _, test := range tests {
   615  		t.Run(test.name, func(t *testing.T) {
   616  			ndpDisp := ndpDispatcher{
   617  				dadC: make(chan ndpDADEvent),
   618  			}
   619  			e := channel.New(10, 1280, linkAddr1)
   620  			s := stack.New(stack.Options{
   621  				NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   622  				NDPDisp:          &ndpDisp,
   623  			})
   624  
   625  			// This NIC(1)'s NDP configurations will be updated to
   626  			// be different from the default.
   627  			if err := s.CreateNIC(1, e); err != nil {
   628  				t.Fatalf("CreateNIC(1) = %s", err)
   629  			}
   630  
   631  			// Created before updating NIC(1)'s NDP configurations
   632  			// but updating NIC(1)'s NDP configurations should not
   633  			// affect other existing NICs.
   634  			if err := s.CreateNIC(2, e); err != nil {
   635  				t.Fatalf("CreateNIC(2) = %s", err)
   636  			}
   637  
   638  			// Update the NDP configurations on NIC(1) to use DAD.
   639  			configs := stack.NDPConfigurations{
   640  				DupAddrDetectTransmits: test.dupAddrDetectTransmits,
   641  				RetransmitTimer:        test.retransmitTimer,
   642  			}
   643  			if err := s.SetNDPConfigurations(1, configs); err != nil {
   644  				t.Fatalf("got SetNDPConfigurations(1, _) = %s", err)
   645  			}
   646  
   647  			// Created after updating NIC(1)'s NDP configurations
   648  			// but the stack's default NDP configurations should not
   649  			// have been updated.
   650  			if err := s.CreateNIC(3, e); err != nil {
   651  				t.Fatalf("CreateNIC(3) = %s", err)
   652  			}
   653  
   654  			// Add addresses for each NIC.
   655  			if err := s.AddAddress(1, header.IPv6ProtocolNumber, addr1); err != nil {
   656  				t.Fatalf("AddAddress(1, %d, %s) = %s", header.IPv6ProtocolNumber, addr1, err)
   657  			}
   658  			if err := s.AddAddress(2, header.IPv6ProtocolNumber, addr2); err != nil {
   659  				t.Fatalf("AddAddress(2, %d, %s) = %s", header.IPv6ProtocolNumber, addr2, err)
   660  			}
   661  			if err := s.AddAddress(3, header.IPv6ProtocolNumber, addr3); err != nil {
   662  				t.Fatalf("AddAddress(3, %d, %s) = %s", header.IPv6ProtocolNumber, addr3, err)
   663  			}
   664  
   665  			// Address should not be considered bound to NIC(1) yet
   666  			// (DAD ongoing).
   667  			addr, err := s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   668  			if err != nil {
   669  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   670  			}
   671  			if want := (tcpip.AddressWithPrefix{}); addr != want {
   672  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   673  			}
   674  
   675  			// Should get the address on NIC(2) and NIC(3)
   676  			// immediately since we should not have performed DAD on
   677  			// it as the stack was configured to not do DAD by
   678  			// default and we only updated the NDP configurations on
   679  			// NIC(1).
   680  			addr, err = s.GetMainNICAddress(2, header.IPv6ProtocolNumber)
   681  			if err != nil {
   682  				t.Fatalf("stack.GetMainNICAddress(2, _) err = %s", err)
   683  			}
   684  			if addr.Address != addr2 {
   685  				t.Fatalf("got stack.GetMainNICAddress(2, _) = %s, want = %s", addr, addr2)
   686  			}
   687  			addr, err = s.GetMainNICAddress(3, header.IPv6ProtocolNumber)
   688  			if err != nil {
   689  				t.Fatalf("stack.GetMainNICAddress(3, _) err = %s", err)
   690  			}
   691  			if addr.Address != addr3 {
   692  				t.Fatalf("got stack.GetMainNICAddress(3, _) = %s, want = %s", addr, addr3)
   693  			}
   694  
   695  			// Sleep until right (500ms before) before resolution to
   696  			// make sure the address didn't resolve on NIC(1) yet.
   697  			const delta = 500 * time.Millisecond
   698  			time.Sleep(time.Duration(test.dupAddrDetectTransmits)*test.expectedRetransmitTimer - delta)
   699  			addr, err = s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   700  			if err != nil {
   701  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (_, %v), want = (_, nil)", err)
   702  			}
   703  			if want := (tcpip.AddressWithPrefix{}); addr != want {
   704  				t.Fatalf("got stack.GetMainNICAddress(_, _) = (%s, nil), want = (%s, nil)", addr, want)
   705  			}
   706  
   707  			// Wait for DAD to resolve.
   708  			select {
   709  			case <-time.After(2 * delta):
   710  				// We should get a resolution event after 500ms
   711  				// (delta) since we wait for 500ms less than the
   712  				// expected resolution time above to make sure
   713  				// that the address did not yet resolve. Waiting
   714  				// for 1s (2x delta) without a resolution event
   715  				// means something is wrong.
   716  				t.Fatal("timed out waiting for DAD resolution")
   717  			case e := <-ndpDisp.dadC:
   718  				if e.err != nil {
   719  					t.Fatal("got DAD error: ", e.err)
   720  				}
   721  				if e.nicID != 1 {
   722  					t.Fatalf("got DAD event w/ nicID = %d, want = 1", e.nicID)
   723  				}
   724  				if e.addr != addr1 {
   725  					t.Fatalf("got DAD event w/ addr = %s, want = %s", addr, addr1)
   726  				}
   727  				if !e.resolved {
   728  					t.Fatal("got DAD event w/ resolved = false, want = true")
   729  				}
   730  			}
   731  			addr, err = s.GetMainNICAddress(1, header.IPv6ProtocolNumber)
   732  			if err != nil {
   733  				t.Fatalf("stack.GetMainNICAddress(1, _) err = %s", err)
   734  			}
   735  			if addr.Address != addr1 {
   736  				t.Fatalf("got stack.GetMainNICAddress(1, _) = %s, want = %s", addr, addr1)
   737  			}
   738  		})
   739  	}
   740  }
   741  
   742  // raBufWithOpts returns a valid NDP Router Advertisement with options.
   743  //
   744  // Note, raBufWithOpts does not populate any of the RA fields other than the
   745  // Router Lifetime.
   746  func raBufWithOpts(ip tcpip.Address, rl uint16, optSer header.NDPOptionsSerializer) tcpip.PacketBuffer {
   747  	icmpSize := header.ICMPv6HeaderSize + header.NDPRAMinimumSize + int(optSer.Length())
   748  	hdr := buffer.NewPrependable(header.IPv6MinimumSize + icmpSize)
   749  	pkt := header.ICMPv6(hdr.Prepend(icmpSize))
   750  	pkt.SetType(header.ICMPv6RouterAdvert)
   751  	pkt.SetCode(0)
   752  	ra := header.NDPRouterAdvert(pkt.NDPPayload())
   753  	opts := ra.Options()
   754  	opts.Serialize(optSer)
   755  	// Populate the Router Lifetime.
   756  	binary.BigEndian.PutUint16(pkt.NDPPayload()[2:], rl)
   757  	pkt.SetChecksum(header.ICMPv6Checksum(pkt, ip, header.IPv6AllNodesMulticastAddress, buffer.VectorisedView{}))
   758  	payloadLength := hdr.UsedLength()
   759  	iph := header.IPv6(hdr.Prepend(header.IPv6MinimumSize))
   760  	iph.Encode(&header.IPv6Fields{
   761  		PayloadLength: uint16(payloadLength),
   762  		NextHeader:    uint8(icmp.ProtocolNumber6),
   763  		HopLimit:      header.NDPHopLimit,
   764  		SrcAddr:       ip,
   765  		DstAddr:       header.IPv6AllNodesMulticastAddress,
   766  	})
   767  
   768  	return tcpip.PacketBuffer{Data: hdr.View().ToVectorisedView()}
   769  }
   770  
   771  // raBuf returns a valid NDP Router Advertisement.
   772  //
   773  // Note, raBuf does not populate any of the RA fields other than the
   774  // Router Lifetime.
   775  func raBuf(ip tcpip.Address, rl uint16) tcpip.PacketBuffer {
   776  	return raBufWithOpts(ip, rl, header.NDPOptionsSerializer{})
   777  }
   778  
   779  // raBufWithPI returns a valid NDP Router Advertisement with a single Prefix
   780  // Information option.
   781  //
   782  // Note, raBufWithPI does not populate any of the RA fields other than the
   783  // Router Lifetime.
   784  func raBufWithPI(ip tcpip.Address, rl uint16, prefix tcpip.AddressWithPrefix, onLink bool, vl uint32) tcpip.PacketBuffer {
   785  	flags := uint8(0)
   786  	if onLink {
   787  		flags |= 128
   788  	}
   789  
   790  	buf := [30]byte{}
   791  	buf[0] = uint8(prefix.PrefixLen)
   792  	buf[1] = flags
   793  	binary.BigEndian.PutUint32(buf[2:], vl)
   794  	copy(buf[14:], prefix.Address)
   795  	return raBufWithOpts(ip, rl, header.NDPOptionsSerializer{
   796  		header.NDPPrefixInformation(buf[:]),
   797  	})
   798  }
   799  
   800  // TestNoRouterDiscovery tests that router discovery will not be performed if
   801  // configured not to.
   802  func TestNoRouterDiscovery(t *testing.T) {
   803  	// Being configured to discover routers means handle and
   804  	// discover are set to true and forwarding is set to false.
   805  	// This tests all possible combinations of the configurations,
   806  	// except for the configuration where handle = true, discover =
   807  	// true and forwarding = false (the required configuration to do
   808  	// router discovery) - that will done in other tests.
   809  	for i := 0; i < 7; i++ {
   810  		handle := i&1 != 0
   811  		discover := i&2 != 0
   812  		forwarding := i&4 == 0
   813  
   814  		t.Run(fmt.Sprintf("HandleRAs(%t), DiscoverDefaultRouters(%t), Forwarding(%t)", handle, discover, forwarding), func(t *testing.T) {
   815  			ndpDisp := ndpDispatcher{
   816  				routerC: make(chan ndpRouterEvent, 10),
   817  			}
   818  			e := channel.New(10, 1280, linkAddr1)
   819  			s := stack.New(stack.Options{
   820  				NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   821  				NDPConfigs: stack.NDPConfigurations{
   822  					HandleRAs:              handle,
   823  					DiscoverDefaultRouters: discover,
   824  				},
   825  				NDPDisp: &ndpDisp,
   826  			})
   827  			s.SetForwarding(forwarding)
   828  
   829  			if err := s.CreateNIC(1, e); err != nil {
   830  				t.Fatalf("CreateNIC(1) = %s", err)
   831  			}
   832  
   833  			// Rx an RA with non-zero lifetime.
   834  			e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr2, 1000))
   835  			select {
   836  			case <-ndpDisp.routerC:
   837  				t.Fatal("unexpectedly discovered a router when configured not to")
   838  			case <-time.After(defaultTimeout):
   839  			}
   840  		})
   841  	}
   842  }
   843  
   844  // TestRouterDiscoveryDispatcherNoRemember tests that the stack does not
   845  // remember a discovered router when the dispatcher asks it not to.
   846  func TestRouterDiscoveryDispatcherNoRemember(t *testing.T) {
   847  	ndpDisp := ndpDispatcher{
   848  		routerC: make(chan ndpRouterEvent, 10),
   849  	}
   850  	e := channel.New(10, 1280, linkAddr1)
   851  	s := stack.New(stack.Options{
   852  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   853  		NDPConfigs: stack.NDPConfigurations{
   854  			HandleRAs:              true,
   855  			DiscoverDefaultRouters: true,
   856  		},
   857  		NDPDisp: &ndpDisp,
   858  	})
   859  
   860  	if err := s.CreateNIC(1, e); err != nil {
   861  		t.Fatalf("CreateNIC(1) = %s", err)
   862  	}
   863  
   864  	routeTable := []tcpip.Route{
   865  		{
   866  			header.IPv6EmptySubnet,
   867  			llAddr3,
   868  			1,
   869  		},
   870  	}
   871  	s.SetRouteTable(routeTable)
   872  
   873  	// Rx an RA with short lifetime.
   874  	lifetime := time.Duration(1)
   875  	e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr2, uint16(lifetime)))
   876  	select {
   877  	case r := <-ndpDisp.routerC:
   878  		if r.nicID != 1 {
   879  			t.Fatalf("got r.nicID = %d, want = 1", r.nicID)
   880  		}
   881  		if r.addr != llAddr2 {
   882  			t.Fatalf("got r.addr = %s, want = %s", r.addr, llAddr2)
   883  		}
   884  		if !r.discovered {
   885  			t.Fatal("got r.discovered = false, want = true")
   886  		}
   887  	case <-time.After(defaultTimeout):
   888  		t.Fatal("timeout waiting for router discovery event")
   889  	}
   890  
   891  	// Original route table should not have been modified.
   892  	if got := s.GetRouteTable(); !cmp.Equal(got, routeTable) {
   893  		t.Fatalf("got GetRouteTable = %v, want = %v", got, routeTable)
   894  	}
   895  
   896  	// Wait for the normal invalidation time plus an extra second to
   897  	// make sure we do not actually receive any invalidation events as
   898  	// we should not have remembered the router in the first place.
   899  	select {
   900  	case <-ndpDisp.routerC:
   901  		t.Fatal("should not have received any router events")
   902  	case <-time.After(lifetime*time.Second + defaultTimeout):
   903  	}
   904  
   905  	// Original route table should not have been modified.
   906  	if got := s.GetRouteTable(); !cmp.Equal(got, routeTable) {
   907  		t.Fatalf("got GetRouteTable = %v, want = %v", got, routeTable)
   908  	}
   909  }
   910  
   911  func TestRouterDiscovery(t *testing.T) {
   912  	ndpDisp := ndpDispatcher{
   913  		routerC:        make(chan ndpRouterEvent, 10),
   914  		rememberRouter: true,
   915  	}
   916  	e := channel.New(10, 1280, linkAddr1)
   917  	s := stack.New(stack.Options{
   918  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
   919  		NDPConfigs: stack.NDPConfigurations{
   920  			HandleRAs:              true,
   921  			DiscoverDefaultRouters: true,
   922  		},
   923  		NDPDisp: &ndpDisp,
   924  	})
   925  
   926  	waitForEvent := func(addr tcpip.Address, discovered bool, timeout time.Duration) {
   927  		t.Helper()
   928  
   929  		select {
   930  		case r := <-ndpDisp.routerC:
   931  			if r.nicID != 1 {
   932  				t.Fatalf("got r.nicID = %d, want = 1", r.nicID)
   933  			}
   934  			if r.addr != addr {
   935  				t.Fatalf("got r.addr = %s, want = %s", r.addr, addr)
   936  			}
   937  			if r.discovered != discovered {
   938  				t.Fatalf("got r.discovered = %t, want = %t", r.discovered, discovered)
   939  			}
   940  		case <-time.After(timeout):
   941  			t.Fatal("timeout waiting for router discovery event")
   942  		}
   943  	}
   944  
   945  	if err := s.CreateNIC(1, e); err != nil {
   946  		t.Fatalf("CreateNIC(1) = %s", err)
   947  	}
   948  
   949  	// Rx an RA from lladdr2 with zero lifetime. It should not be
   950  	// remembered.
   951  	e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr2, 0))
   952  	select {
   953  	case <-ndpDisp.routerC:
   954  		t.Fatal("unexpectedly discovered a router with 0 lifetime")
   955  	case <-time.After(defaultTimeout):
   956  	}
   957  
   958  	// Rx an RA from lladdr2 with a huge lifetime.
   959  	e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr2, 1000))
   960  	waitForEvent(llAddr2, true, defaultTimeout)
   961  
   962  	// Should have a default route through the discovered router.
   963  	if got, want := s.GetRouteTable(), []tcpip.Route{{header.IPv6EmptySubnet, llAddr2, 1}}; !cmp.Equal(got, want) {
   964  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
   965  	}
   966  
   967  	// Rx an RA from another router (lladdr3) with non-zero lifetime.
   968  	l3Lifetime := time.Duration(6)
   969  	e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr3, uint16(l3Lifetime)))
   970  	waitForEvent(llAddr3, true, defaultTimeout)
   971  
   972  	// Should have default routes through the discovered routers.
   973  	if got, want := s.GetRouteTable(), []tcpip.Route{{header.IPv6EmptySubnet, llAddr2, 1}, {header.IPv6EmptySubnet, llAddr3, 1}}; !cmp.Equal(got, want) {
   974  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
   975  	}
   976  
   977  	// Rx an RA from lladdr2 with lesser lifetime.
   978  	l2Lifetime := time.Duration(2)
   979  	e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr2, uint16(l2Lifetime)))
   980  	select {
   981  	case <-ndpDisp.routerC:
   982  		t.Fatal("Should not receive a router event when updating lifetimes for known routers")
   983  	case <-time.After(defaultTimeout):
   984  	}
   985  
   986  	// Should still have a default route through the discovered routers.
   987  	if got, want := s.GetRouteTable(), []tcpip.Route{{header.IPv6EmptySubnet, llAddr2, 1}, {header.IPv6EmptySubnet, llAddr3, 1}}; !cmp.Equal(got, want) {
   988  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
   989  	}
   990  
   991  	// Wait for lladdr2's router invalidation timer to fire. The lifetime
   992  	// of the router should have been updated to the most recent (smaller)
   993  	// lifetime.
   994  	//
   995  	// Wait for the normal lifetime plus an extra bit for the
   996  	// router to get invalidated. If we don't get an invalidation
   997  	// event after this time, then something is wrong.
   998  	waitForEvent(llAddr2, false, l2Lifetime*time.Second+defaultTimeout)
   999  
  1000  	// Should no longer have the default route through lladdr2.
  1001  	if got, want := s.GetRouteTable(), []tcpip.Route{{header.IPv6EmptySubnet, llAddr3, 1}}; !cmp.Equal(got, want) {
  1002  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1003  	}
  1004  
  1005  	// Rx an RA from lladdr2 with huge lifetime.
  1006  	e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr2, 1000))
  1007  	waitForEvent(llAddr2, true, defaultTimeout)
  1008  
  1009  	// Should have a default route through the discovered routers.
  1010  	if got, want := s.GetRouteTable(), []tcpip.Route{{header.IPv6EmptySubnet, llAddr3, 1}, {header.IPv6EmptySubnet, llAddr2, 1}}; !cmp.Equal(got, want) {
  1011  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1012  	}
  1013  
  1014  	// Rx an RA from lladdr2 with zero lifetime. It should be invalidated.
  1015  	e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr2, 0))
  1016  	waitForEvent(llAddr2, false, defaultTimeout)
  1017  
  1018  	// Should have deleted the default route through the router that just
  1019  	// got invalidated.
  1020  	if got, want := s.GetRouteTable(), []tcpip.Route{{header.IPv6EmptySubnet, llAddr3, 1}}; !cmp.Equal(got, want) {
  1021  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1022  	}
  1023  
  1024  	// Wait for lladdr3's router invalidation timer to fire. The lifetime
  1025  	// of the router should have been updated to the most recent (smaller)
  1026  	// lifetime.
  1027  	//
  1028  	// Wait for the normal lifetime plus an extra bit for the
  1029  	// router to get invalidated. If we don't get an invalidation
  1030  	// event after this time, then something is wrong.
  1031  	waitForEvent(llAddr3, false, l3Lifetime*time.Second+defaultTimeout)
  1032  
  1033  	// Should not have any routes now that all discovered routers have been
  1034  	// invalidated.
  1035  	if got := len(s.GetRouteTable()); got != 0 {
  1036  		t.Fatalf("got len(s.GetRouteTable()) = %d, want = 0", got)
  1037  	}
  1038  }
  1039  
  1040  // TestRouterDiscoveryMaxRouters tests that only
  1041  // stack.MaxDiscoveredDefaultRouters discovered routers are remembered.
  1042  func TestRouterDiscoveryMaxRouters(t *testing.T) {
  1043  	ndpDisp := ndpDispatcher{
  1044  		routerC:        make(chan ndpRouterEvent, 10),
  1045  		rememberRouter: true,
  1046  	}
  1047  	e := channel.New(10, 1280, linkAddr1)
  1048  	s := stack.New(stack.Options{
  1049  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
  1050  		NDPConfigs: stack.NDPConfigurations{
  1051  			HandleRAs:              true,
  1052  			DiscoverDefaultRouters: true,
  1053  		},
  1054  		NDPDisp: &ndpDisp,
  1055  	})
  1056  
  1057  	if err := s.CreateNIC(1, e); err != nil {
  1058  		t.Fatalf("CreateNIC(1) = %s", err)
  1059  	}
  1060  
  1061  	expectedRt := [stack.MaxDiscoveredDefaultRouters]tcpip.Route{}
  1062  
  1063  	// Receive an RA from 2 more than the max number of discovered routers.
  1064  	for i := 1; i <= stack.MaxDiscoveredDefaultRouters+2; i++ {
  1065  		linkAddr := []byte{2, 2, 3, 4, 5, 0}
  1066  		linkAddr[5] = byte(i)
  1067  		llAddr := header.LinkLocalAddr(tcpip.LinkAddress(linkAddr))
  1068  
  1069  		e.InjectInbound(header.IPv6ProtocolNumber, raBuf(llAddr, 5))
  1070  
  1071  		if i <= stack.MaxDiscoveredDefaultRouters {
  1072  			expectedRt[i-1] = tcpip.Route{header.IPv6EmptySubnet, llAddr, 1}
  1073  			select {
  1074  			case r := <-ndpDisp.routerC:
  1075  				if r.nicID != 1 {
  1076  					t.Fatalf("got r.nicID = %d, want = 1", r.nicID)
  1077  				}
  1078  				if r.addr != llAddr {
  1079  					t.Fatalf("got r.addr = %s, want = %s", r.addr, llAddr)
  1080  				}
  1081  				if !r.discovered {
  1082  					t.Fatal("got r.discovered = false, want = true")
  1083  				}
  1084  			case <-time.After(defaultTimeout):
  1085  				t.Fatal("timeout waiting for router discovery event")
  1086  			}
  1087  
  1088  		} else {
  1089  			select {
  1090  			case <-ndpDisp.routerC:
  1091  				t.Fatal("should not have discovered a new router after we already discovered the max number of routers")
  1092  			case <-time.After(defaultTimeout):
  1093  			}
  1094  		}
  1095  	}
  1096  
  1097  	// Should only have default routes for the first
  1098  	// stack.MaxDiscoveredDefaultRouters discovered routers.
  1099  	if got := s.GetRouteTable(); !cmp.Equal(got, expectedRt[:]) {
  1100  		t.Fatalf("got GetRouteTable = %v, want = %v", got, expectedRt)
  1101  	}
  1102  }
  1103  
  1104  // TestNoPrefixDiscovery tests that prefix discovery will not be performed if
  1105  // configured not to.
  1106  func TestNoPrefixDiscovery(t *testing.T) {
  1107  	prefix := tcpip.AddressWithPrefix{
  1108  		Address:   tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00"),
  1109  		PrefixLen: 64,
  1110  	}
  1111  
  1112  	// Being configured to discover prefixes means handle and
  1113  	// discover are set to true and forwarding is set to false.
  1114  	// This tests all possible combinations of the configurations,
  1115  	// except for the configuration where handle = true, discover =
  1116  	// true and forwarding = false (the required configuration to do
  1117  	// prefix discovery) - that will done in other tests.
  1118  	for i := 0; i < 7; i++ {
  1119  		handle := i&1 != 0
  1120  		discover := i&2 != 0
  1121  		forwarding := i&4 == 0
  1122  
  1123  		t.Run(fmt.Sprintf("HandleRAs(%t), DiscoverOnLinkPrefixes(%t), Forwarding(%t)", handle, discover, forwarding), func(t *testing.T) {
  1124  			ndpDisp := ndpDispatcher{
  1125  				prefixC: make(chan ndpPrefixEvent, 10),
  1126  			}
  1127  			e := channel.New(10, 1280, linkAddr1)
  1128  			s := stack.New(stack.Options{
  1129  				NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
  1130  				NDPConfigs: stack.NDPConfigurations{
  1131  					HandleRAs:              handle,
  1132  					DiscoverOnLinkPrefixes: discover,
  1133  				},
  1134  				NDPDisp: &ndpDisp,
  1135  			})
  1136  			s.SetForwarding(forwarding)
  1137  
  1138  			if err := s.CreateNIC(1, e); err != nil {
  1139  				t.Fatalf("CreateNIC(1) = %s", err)
  1140  			}
  1141  
  1142  			// Rx an RA with prefix with non-zero lifetime.
  1143  			e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, 10))
  1144  
  1145  			select {
  1146  			case <-ndpDisp.prefixC:
  1147  				t.Fatal("unexpectedly discovered a prefix when configured not to")
  1148  			case <-time.After(defaultTimeout):
  1149  			}
  1150  		})
  1151  	}
  1152  }
  1153  
  1154  // TestPrefixDiscoveryDispatcherNoRemember tests that the stack does not
  1155  // remember a discovered on-link prefix when the dispatcher asks it not to.
  1156  func TestPrefixDiscoveryDispatcherNoRemember(t *testing.T) {
  1157  	prefix := tcpip.AddressWithPrefix{
  1158  		Address:   tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00"),
  1159  		PrefixLen: 64,
  1160  	}
  1161  	subnet := prefix.Subnet()
  1162  
  1163  	ndpDisp := ndpDispatcher{
  1164  		prefixC: make(chan ndpPrefixEvent, 10),
  1165  	}
  1166  	e := channel.New(10, 1280, linkAddr1)
  1167  	s := stack.New(stack.Options{
  1168  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
  1169  		NDPConfigs: stack.NDPConfigurations{
  1170  			HandleRAs:              true,
  1171  			DiscoverDefaultRouters: false,
  1172  			DiscoverOnLinkPrefixes: true,
  1173  		},
  1174  		NDPDisp: &ndpDisp,
  1175  	})
  1176  
  1177  	if err := s.CreateNIC(1, e); err != nil {
  1178  		t.Fatalf("CreateNIC(1) = %s", err)
  1179  	}
  1180  
  1181  	routeTable := []tcpip.Route{
  1182  		{
  1183  			header.IPv6EmptySubnet,
  1184  			llAddr3,
  1185  			1,
  1186  		},
  1187  	}
  1188  	s.SetRouteTable(routeTable)
  1189  
  1190  	// Rx an RA with prefix with a short lifetime.
  1191  	const lifetime = 1
  1192  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, lifetime))
  1193  	select {
  1194  	case r := <-ndpDisp.prefixC:
  1195  		if r.nicID != 1 {
  1196  			t.Fatalf("got r.nicID = %d, want = 1", r.nicID)
  1197  		}
  1198  		if r.prefix != subnet {
  1199  			t.Fatalf("got r.prefix = %s, want = %s", r.prefix, subnet)
  1200  		}
  1201  		if !r.discovered {
  1202  			t.Fatal("got r.discovered = false, want = true")
  1203  		}
  1204  	case <-time.After(defaultTimeout):
  1205  		t.Fatal("timeout waiting for prefix discovery event")
  1206  	}
  1207  
  1208  	// Original route table should not have been modified.
  1209  	if got := s.GetRouteTable(); !cmp.Equal(got, routeTable) {
  1210  		t.Fatalf("got GetRouteTable = %v, want = %v", got, routeTable)
  1211  	}
  1212  
  1213  	// Wait for the normal invalidation time plus some buffer to
  1214  	// make sure we do not actually receive any invalidation events as
  1215  	// we should not have remembered the prefix in the first place.
  1216  	select {
  1217  	case <-ndpDisp.prefixC:
  1218  		t.Fatal("should not have received any prefix events")
  1219  	case <-time.After(lifetime*time.Second + defaultTimeout):
  1220  	}
  1221  
  1222  	// Original route table should not have been modified.
  1223  	if got := s.GetRouteTable(); !cmp.Equal(got, routeTable) {
  1224  		t.Fatalf("got GetRouteTable = %v, want = %v", got, routeTable)
  1225  	}
  1226  }
  1227  
  1228  func TestPrefixDiscovery(t *testing.T) {
  1229  	prefix1 := tcpip.AddressWithPrefix{
  1230  		Address:   tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00"),
  1231  		PrefixLen: 64,
  1232  	}
  1233  	prefix2 := tcpip.AddressWithPrefix{
  1234  		Address:   tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x09\x00\x00\x00\x00\x00\x00\x00\x00"),
  1235  		PrefixLen: 64,
  1236  	}
  1237  	prefix3 := tcpip.AddressWithPrefix{
  1238  		Address:   tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x09\x0a\x00\x00\x00\x00\x00\x00\x00"),
  1239  		PrefixLen: 72,
  1240  	}
  1241  	subnet1 := prefix1.Subnet()
  1242  	subnet2 := prefix2.Subnet()
  1243  	subnet3 := prefix3.Subnet()
  1244  
  1245  	ndpDisp := ndpDispatcher{
  1246  		prefixC:        make(chan ndpPrefixEvent, 10),
  1247  		rememberPrefix: true,
  1248  	}
  1249  	e := channel.New(10, 1280, linkAddr1)
  1250  	s := stack.New(stack.Options{
  1251  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
  1252  		NDPConfigs: stack.NDPConfigurations{
  1253  			HandleRAs:              true,
  1254  			DiscoverOnLinkPrefixes: true,
  1255  		},
  1256  		NDPDisp: &ndpDisp,
  1257  	})
  1258  
  1259  	waitForEvent := func(subnet tcpip.Subnet, discovered bool, timeout time.Duration) {
  1260  		t.Helper()
  1261  
  1262  		select {
  1263  		case r := <-ndpDisp.prefixC:
  1264  			if r.nicID != 1 {
  1265  				t.Fatalf("got r.nicID = %d, want = 1", r.nicID)
  1266  			}
  1267  			if r.prefix != subnet {
  1268  				t.Fatalf("got r.prefix = %s, want = %s", r.prefix, subnet)
  1269  			}
  1270  			if r.discovered != discovered {
  1271  				t.Fatalf("got r.discovered = %t, want = %t", r.discovered, discovered)
  1272  			}
  1273  		case <-time.After(timeout):
  1274  			t.Fatal("timeout waiting for prefix discovery event")
  1275  		}
  1276  	}
  1277  
  1278  	if err := s.CreateNIC(1, e); err != nil {
  1279  		t.Fatalf("CreateNIC(1) = %s", err)
  1280  	}
  1281  
  1282  	// Receive an RA with prefix1 in an NDP Prefix Information option (PI)
  1283  	// with zero valid lifetime.
  1284  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, 0))
  1285  	select {
  1286  	case <-ndpDisp.prefixC:
  1287  		t.Fatal("unexpectedly discovered a prefix with 0 lifetime")
  1288  	case <-time.After(defaultTimeout):
  1289  	}
  1290  
  1291  	// Receive an RA with prefix1 in an NDP Prefix Information option (PI)
  1292  	// with non-zero lifetime.
  1293  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, 100))
  1294  	waitForEvent(subnet1, true, defaultTimeout)
  1295  
  1296  	// Should have added a device route for subnet1 through the nic.
  1297  	if got, want := s.GetRouteTable(), []tcpip.Route{{subnet1, tcpip.Address([]byte(nil)), 1}}; !cmp.Equal(got, want) {
  1298  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1299  	}
  1300  
  1301  	// Receive an RA with prefix2 in a PI.
  1302  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix2, true, 100))
  1303  	waitForEvent(subnet2, true, defaultTimeout)
  1304  
  1305  	// Should have added a device route for subnet2 through the nic.
  1306  	if got, want := s.GetRouteTable(), []tcpip.Route{{subnet1, tcpip.Address([]byte(nil)), 1}, {subnet2, tcpip.Address([]byte(nil)), 1}}; !cmp.Equal(got, want) {
  1307  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1308  	}
  1309  
  1310  	// Receive an RA with prefix3 in a PI.
  1311  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix3, true, 100))
  1312  	waitForEvent(subnet3, true, defaultTimeout)
  1313  
  1314  	// Should have added a device route for subnet3 through the nic.
  1315  	if got, want := s.GetRouteTable(), []tcpip.Route{{subnet1, tcpip.Address([]byte(nil)), 1}, {subnet2, tcpip.Address([]byte(nil)), 1}, {subnet3, tcpip.Address([]byte(nil)), 1}}; !cmp.Equal(got, want) {
  1316  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1317  	}
  1318  
  1319  	// Receive an RA with prefix1 in a PI with lifetime = 0.
  1320  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix1, true, 0))
  1321  	waitForEvent(subnet1, false, defaultTimeout)
  1322  
  1323  	// Should have removed the device route for subnet1 through the nic.
  1324  	if got, want := s.GetRouteTable(), []tcpip.Route{{subnet2, tcpip.Address([]byte(nil)), 1}, {subnet3, tcpip.Address([]byte(nil)), 1}}; !cmp.Equal(got, want) {
  1325  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1326  	}
  1327  
  1328  	// Receive an RA with prefix2 in a PI with lesser lifetime.
  1329  	lifetime := uint32(2)
  1330  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix2, true, lifetime))
  1331  	select {
  1332  	case <-ndpDisp.prefixC:
  1333  		t.Fatal("unexpectedly received prefix event when updating lifetime")
  1334  	case <-time.After(defaultTimeout):
  1335  	}
  1336  
  1337  	// Should not have updated route table.
  1338  	if got, want := s.GetRouteTable(), []tcpip.Route{{subnet2, tcpip.Address([]byte(nil)), 1}, {subnet3, tcpip.Address([]byte(nil)), 1}}; !cmp.Equal(got, want) {
  1339  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1340  	}
  1341  
  1342  	// Wait for prefix2's most recent invalidation timer plus some buffer to
  1343  	// expire.
  1344  	waitForEvent(subnet2, false, time.Duration(lifetime)*time.Second+defaultTimeout)
  1345  
  1346  	// Should have removed the device route for subnet2 through the nic.
  1347  	if got, want := s.GetRouteTable(), []tcpip.Route{{subnet3, tcpip.Address([]byte(nil)), 1}}; !cmp.Equal(got, want) {
  1348  		t.Fatalf("got GetRouteTable = %v, want = %v", got, want)
  1349  	}
  1350  
  1351  	// Receive RA to invalidate prefix3.
  1352  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix3, true, 0))
  1353  	waitForEvent(subnet3, false, defaultTimeout)
  1354  
  1355  	// Should not have any routes.
  1356  	if got := len(s.GetRouteTable()); got != 0 {
  1357  		t.Fatalf("got len(s.GetRouteTable()) = %d, want = 0", got)
  1358  	}
  1359  }
  1360  
  1361  func TestPrefixDiscoveryWithInfiniteLifetime(t *testing.T) {
  1362  	// Update the infinite lifetime value to a smaller value so we can test
  1363  	// that when we receive a PI with such a lifetime value, we do not
  1364  	// invalidate the prefix.
  1365  	const testInfiniteLifetimeSeconds = 2
  1366  	const testInfiniteLifetime = testInfiniteLifetimeSeconds * time.Second
  1367  	saved := header.NDPPrefixInformationInfiniteLifetime
  1368  	header.NDPPrefixInformationInfiniteLifetime = testInfiniteLifetime
  1369  	defer func() {
  1370  		header.NDPPrefixInformationInfiniteLifetime = saved
  1371  	}()
  1372  
  1373  	prefix := tcpip.AddressWithPrefix{
  1374  		Address:   tcpip.Address("\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00"),
  1375  		PrefixLen: 64,
  1376  	}
  1377  	subnet := prefix.Subnet()
  1378  
  1379  	ndpDisp := ndpDispatcher{
  1380  		prefixC:        make(chan ndpPrefixEvent, 10),
  1381  		rememberPrefix: true,
  1382  	}
  1383  	e := channel.New(10, 1280, linkAddr1)
  1384  	s := stack.New(stack.Options{
  1385  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
  1386  		NDPConfigs: stack.NDPConfigurations{
  1387  			HandleRAs:              true,
  1388  			DiscoverOnLinkPrefixes: true,
  1389  		},
  1390  		NDPDisp: &ndpDisp,
  1391  	})
  1392  
  1393  	waitForEvent := func(discovered bool, timeout time.Duration) {
  1394  		t.Helper()
  1395  
  1396  		select {
  1397  		case r := <-ndpDisp.prefixC:
  1398  			if r.nicID != 1 {
  1399  				t.Errorf("got r.nicID = %d, want = 1", r.nicID)
  1400  			}
  1401  			if r.prefix != subnet {
  1402  				t.Errorf("got r.prefix = %s, want = %s", r.prefix, subnet)
  1403  			}
  1404  			if r.discovered != discovered {
  1405  				t.Errorf("got r.discovered = %t, want = %t", r.discovered, discovered)
  1406  			}
  1407  		case <-time.After(timeout):
  1408  			t.Fatal("timeout waiting for prefix discovery event")
  1409  		}
  1410  	}
  1411  
  1412  	if err := s.CreateNIC(1, e); err != nil {
  1413  		t.Fatalf("CreateNIC(1) = %s", err)
  1414  	}
  1415  
  1416  	// Receive an RA with prefix in an NDP Prefix Information option (PI)
  1417  	// with infinite valid lifetime which should not get invalidated.
  1418  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, testInfiniteLifetimeSeconds))
  1419  	waitForEvent(true, defaultTimeout)
  1420  	select {
  1421  	case <-ndpDisp.prefixC:
  1422  		t.Fatal("unexpectedly invalidated a prefix with infinite lifetime")
  1423  	case <-time.After(testInfiniteLifetime + defaultTimeout):
  1424  	}
  1425  
  1426  	// Receive an RA with finite lifetime.
  1427  	// The prefix should get invalidated after 1s.
  1428  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, testInfiniteLifetimeSeconds-1))
  1429  	waitForEvent(false, testInfiniteLifetime)
  1430  
  1431  	// Receive an RA with finite lifetime.
  1432  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, testInfiniteLifetimeSeconds-1))
  1433  	waitForEvent(true, defaultTimeout)
  1434  
  1435  	// Receive an RA with prefix with an infinite lifetime.
  1436  	// The prefix should not be invalidated.
  1437  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, testInfiniteLifetimeSeconds))
  1438  	select {
  1439  	case <-ndpDisp.prefixC:
  1440  		t.Fatal("unexpectedly invalidated a prefix with infinite lifetime")
  1441  	case <-time.After(testInfiniteLifetime + defaultTimeout):
  1442  	}
  1443  
  1444  	// Receive an RA with a prefix with a lifetime value greater than the
  1445  	// set infinite lifetime value.
  1446  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, testInfiniteLifetimeSeconds+1))
  1447  	select {
  1448  	case <-ndpDisp.prefixC:
  1449  		t.Fatal("unexpectedly invalidated a prefix with infinite lifetime")
  1450  	case <-time.After((testInfiniteLifetimeSeconds+1)*time.Second + defaultTimeout):
  1451  	}
  1452  
  1453  	// Receive an RA with 0 lifetime.
  1454  	// The prefix should get invalidated.
  1455  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithPI(llAddr2, 0, prefix, true, 0))
  1456  	waitForEvent(false, defaultTimeout)
  1457  }
  1458  
  1459  // TestPrefixDiscoveryMaxRouters tests that only
  1460  // stack.MaxDiscoveredOnLinkPrefixes discovered on-link prefixes are remembered.
  1461  func TestPrefixDiscoveryMaxOnLinkPrefixes(t *testing.T) {
  1462  	ndpDisp := ndpDispatcher{
  1463  		prefixC:        make(chan ndpPrefixEvent, stack.MaxDiscoveredOnLinkPrefixes+3),
  1464  		rememberPrefix: true,
  1465  	}
  1466  	e := channel.New(10, 1280, linkAddr1)
  1467  	s := stack.New(stack.Options{
  1468  		NetworkProtocols: []stack.NetworkProtocol{ipv6.NewProtocol()},
  1469  		NDPConfigs: stack.NDPConfigurations{
  1470  			HandleRAs:              true,
  1471  			DiscoverDefaultRouters: false,
  1472  			DiscoverOnLinkPrefixes: true,
  1473  		},
  1474  		NDPDisp: &ndpDisp,
  1475  	})
  1476  
  1477  	if err := s.CreateNIC(1, e); err != nil {
  1478  		t.Fatalf("CreateNIC(1) = %s", err)
  1479  	}
  1480  
  1481  	optSer := make(header.NDPOptionsSerializer, stack.MaxDiscoveredOnLinkPrefixes+2)
  1482  	expectedRt := [stack.MaxDiscoveredOnLinkPrefixes]tcpip.Route{}
  1483  	prefixes := [stack.MaxDiscoveredOnLinkPrefixes + 2]tcpip.Subnet{}
  1484  
  1485  	// Receive an RA with 2 more than the max number of discovered on-link
  1486  	// prefixes.
  1487  	for i := 0; i < stack.MaxDiscoveredOnLinkPrefixes+2; i++ {
  1488  		prefixAddr := [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0}
  1489  		prefixAddr[7] = byte(i)
  1490  		prefix := tcpip.AddressWithPrefix{
  1491  			Address:   tcpip.Address(prefixAddr[:]),
  1492  			PrefixLen: 64,
  1493  		}
  1494  		prefixes[i] = prefix.Subnet()
  1495  		buf := [30]byte{}
  1496  		buf[0] = uint8(prefix.PrefixLen)
  1497  		buf[1] = 128
  1498  		binary.BigEndian.PutUint32(buf[2:], 10)
  1499  		copy(buf[14:], prefix.Address)
  1500  
  1501  		optSer[i] = header.NDPPrefixInformation(buf[:])
  1502  
  1503  		if i < stack.MaxDiscoveredOnLinkPrefixes {
  1504  			expectedRt[i] = tcpip.Route{prefixes[i], tcpip.Address([]byte(nil)), 1}
  1505  		}
  1506  	}
  1507  
  1508  	e.InjectInbound(header.IPv6ProtocolNumber, raBufWithOpts(llAddr1, 0, optSer))
  1509  	for i := 0; i < stack.MaxDiscoveredOnLinkPrefixes+2; i++ {
  1510  		if i < stack.MaxDiscoveredOnLinkPrefixes {
  1511  			select {
  1512  			case r := <-ndpDisp.prefixC:
  1513  				if r.nicID != 1 {
  1514  					t.Fatalf("got r.nicID = %d, want = 1", r.nicID)
  1515  				}
  1516  				if r.prefix != prefixes[i] {
  1517  					t.Fatalf("got r.prefix = %s, want = %s", r.prefix, prefixes[i])
  1518  				}
  1519  				if !r.discovered {
  1520  					t.Fatal("got r.discovered = false, want = true")
  1521  				}
  1522  			case <-time.After(defaultTimeout):
  1523  				t.Fatal("timeout waiting for prefix discovery event")
  1524  			}
  1525  		} else {
  1526  			select {
  1527  			case <-ndpDisp.prefixC:
  1528  				t.Fatal("should not have discovered a new prefix after we already discovered the max number of prefixes")
  1529  			case <-time.After(defaultTimeout):
  1530  			}
  1531  		}
  1532  	}
  1533  
  1534  	// Should only have device routes for the first
  1535  	// stack.MaxDiscoveredOnLinkPrefixes discovered on-link prefixes.
  1536  	if got := s.GetRouteTable(); !cmp.Equal(got, expectedRt[:]) {
  1537  		t.Fatalf("got GetRouteTable = %v, want = %v", got, expectedRt)
  1538  	}
  1539  }