github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/stack/neighbor_entry_test.go (about) 1 // Copyright 2020 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 16 17 import ( 18 "fmt" 19 "math" 20 "math/rand" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/google/go-cmp/cmp" 26 "github.com/SagerNet/gvisor/pkg/tcpip" 27 "github.com/SagerNet/gvisor/pkg/tcpip/faketime" 28 "github.com/SagerNet/gvisor/pkg/tcpip/header" 29 "github.com/SagerNet/gvisor/pkg/tcpip/testutil" 30 ) 31 32 const ( 33 entryTestNetNumber tcpip.NetworkProtocolNumber = math.MaxUint32 34 35 entryTestNICID tcpip.NICID = 1 36 37 entryTestLinkAddr1 = tcpip.LinkAddress("\x0a\x00\x00\x00\x00\x01") 38 entryTestLinkAddr2 = tcpip.LinkAddress("\x0a\x00\x00\x00\x00\x02") 39 ) 40 41 var ( 42 entryTestAddr1 = testutil.MustParse6("a::1") 43 entryTestAddr2 = testutil.MustParse6("a::2") 44 ) 45 46 // runImmediatelyScheduledJobs runs all jobs scheduled to run at the current 47 // time. 48 func runImmediatelyScheduledJobs(clock *faketime.ManualClock) { 49 clock.Advance(immediateDuration) 50 } 51 52 // The following unit tests exercise every state transition and verify its 53 // behavior with RFC 4681 and RFC 7048. 54 // 55 // | From | To | Cause | Update | Action | Event | 56 // | =========== | =========== | ========================================== | ======== | ===========| ======= | 57 // | Unknown | Unknown | Confirmation w/ unknown address | | | Added | 58 // | Unknown | Incomplete | Packet queued to unknown address | | Send probe | Added | 59 // | Unknown | Stale | Probe | | | Added | 60 // | Incomplete | Incomplete | Retransmit timer expired | | Send probe | Changed | 61 // | Incomplete | Reachable | Solicited confirmation | LinkAddr | Notify | Changed | 62 // | Incomplete | Stale | Unsolicited confirmation | LinkAddr | Notify | Changed | 63 // | Incomplete | Stale | Probe | LinkAddr | Notify | Changed | 64 // | Incomplete | Unreachable | Max probes sent without reply | | Notify | Changed | 65 // | Reachable | Reachable | Confirmation w/ different isRouter flag | IsRouter | | | 66 // | Reachable | Stale | Reachable timer expired | | | Changed | 67 // | Reachable | Stale | Probe or confirmation w/ different address | | | Changed | 68 // | Stale | Reachable | Solicited override confirmation | LinkAddr | | Changed | 69 // | Stale | Reachable | Solicited confirmation w/o address | | Notify | Changed | 70 // | Stale | Stale | Override confirmation | LinkAddr | | Changed | 71 // | Stale | Stale | Probe w/ different address | LinkAddr | | Changed | 72 // | Stale | Delay | Packet sent | | | Changed | 73 // | Delay | Reachable | Upper-layer confirmation | | | Changed | 74 // | Delay | Reachable | Solicited override confirmation | LinkAddr | | Changed | 75 // | Delay | Reachable | Solicited confirmation w/o address | | Notify | Changed | 76 // | Delay | Stale | Probe or confirmation w/ different address | | | Changed | 77 // | Delay | Probe | Delay timer expired | | Send probe | Changed | 78 // | Probe | Reachable | Solicited override confirmation | LinkAddr | | Changed | 79 // | Probe | Reachable | Solicited confirmation w/ same address | | Notify | Changed | 80 // | Probe | Reachable | Solicited confirmation w/o address | | Notify | Changed | 81 // | Probe | Stale | Probe or confirmation w/ different address | | | Changed | 82 // | Probe | Probe | Retransmit timer expired | | | Changed | 83 // | Probe | Unreachable | Max probes sent without reply | | Notify | Changed | 84 // | Unreachable | Incomplete | Packet queued | | Send probe | Changed | 85 // | Unreachable | Stale | Probe w/ different address | LinkAddr | | Changed | 86 87 type testEntryEventType uint8 88 89 const ( 90 entryTestAdded testEntryEventType = iota 91 entryTestChanged 92 entryTestRemoved 93 ) 94 95 func (t testEntryEventType) String() string { 96 switch t { 97 case entryTestAdded: 98 return "add" 99 case entryTestChanged: 100 return "change" 101 case entryTestRemoved: 102 return "remove" 103 default: 104 return fmt.Sprintf("unknown (%d)", t) 105 } 106 } 107 108 // Fields are exported for use with cmp.Diff. 109 type testEntryEventInfo struct { 110 EventType testEntryEventType 111 NICID tcpip.NICID 112 Entry NeighborEntry 113 } 114 115 func (e testEntryEventInfo) String() string { 116 return fmt.Sprintf("%s event for NIC #%d, %#v", e.EventType, e.NICID, e.Entry) 117 } 118 119 // testNUDDispatcher implements NUDDispatcher to validate the dispatching of 120 // events upon certain NUD state machine events. 121 type testNUDDispatcher struct { 122 mu struct { 123 sync.Mutex 124 events []testEntryEventInfo 125 } 126 } 127 128 var _ NUDDispatcher = (*testNUDDispatcher)(nil) 129 130 func (d *testNUDDispatcher) queueEvent(e testEntryEventInfo) { 131 d.mu.Lock() 132 defer d.mu.Unlock() 133 d.mu.events = append(d.mu.events, e) 134 } 135 136 func (d *testNUDDispatcher) OnNeighborAdded(nicID tcpip.NICID, entry NeighborEntry) { 137 d.queueEvent(testEntryEventInfo{ 138 EventType: entryTestAdded, 139 NICID: nicID, 140 Entry: entry, 141 }) 142 } 143 144 func (d *testNUDDispatcher) OnNeighborChanged(nicID tcpip.NICID, entry NeighborEntry) { 145 d.queueEvent(testEntryEventInfo{ 146 EventType: entryTestChanged, 147 NICID: nicID, 148 Entry: entry, 149 }) 150 } 151 152 func (d *testNUDDispatcher) OnNeighborRemoved(nicID tcpip.NICID, entry NeighborEntry) { 153 d.queueEvent(testEntryEventInfo{ 154 EventType: entryTestRemoved, 155 NICID: nicID, 156 Entry: entry, 157 }) 158 } 159 160 type entryTestLinkResolver struct { 161 mu struct { 162 sync.Mutex 163 probes []entryTestProbeInfo 164 } 165 } 166 167 var _ LinkAddressResolver = (*entryTestLinkResolver)(nil) 168 169 type entryTestProbeInfo struct { 170 RemoteAddress tcpip.Address 171 RemoteLinkAddress tcpip.LinkAddress 172 LocalAddress tcpip.Address 173 } 174 175 func (p entryTestProbeInfo) String() string { 176 return fmt.Sprintf("probe with RemoteAddress=%q, RemoteLinkAddress=%q, LocalAddress=%q", p.RemoteAddress, p.RemoteLinkAddress, p.LocalAddress) 177 } 178 179 // LinkAddressRequest sends a request for the LinkAddress of addr. Broadcasts 180 // to the local network if linkAddr is the zero value. 181 func (r *entryTestLinkResolver) LinkAddressRequest(targetAddr, localAddr tcpip.Address, linkAddr tcpip.LinkAddress) tcpip.Error { 182 r.mu.Lock() 183 defer r.mu.Unlock() 184 r.mu.probes = append(r.mu.probes, entryTestProbeInfo{ 185 RemoteAddress: targetAddr, 186 RemoteLinkAddress: linkAddr, 187 LocalAddress: localAddr, 188 }) 189 return nil 190 } 191 192 // ResolveStaticAddress attempts to resolve address without sending requests. 193 // It either resolves the name immediately or returns the empty LinkAddress. 194 func (*entryTestLinkResolver) ResolveStaticAddress(tcpip.Address) (tcpip.LinkAddress, bool) { 195 return "", false 196 } 197 198 // LinkAddressProtocol returns the network protocol of the addresses this 199 // resolver can resolve. 200 func (*entryTestLinkResolver) LinkAddressProtocol() tcpip.NetworkProtocolNumber { 201 return entryTestNetNumber 202 } 203 204 func entryTestSetup(c NUDConfigurations) (*neighborEntry, *testNUDDispatcher, *entryTestLinkResolver, *faketime.ManualClock) { 205 clock := faketime.NewManualClock() 206 disp := testNUDDispatcher{} 207 nic := nic{ 208 LinkEndpoint: nil, // entryTestLinkResolver doesn't use a LinkEndpoint 209 210 id: entryTestNICID, 211 stack: &Stack{ 212 clock: clock, 213 nudDisp: &disp, 214 nudConfigs: c, 215 randomGenerator: rand.New(rand.NewSource(time.Now().UnixNano())), 216 }, 217 stats: makeNICStats(tcpip.NICStats{}.FillIn()), 218 } 219 netEP := (&testIPv6Protocol{}).NewEndpoint(&nic, nil) 220 nic.networkEndpoints = map[tcpip.NetworkProtocolNumber]NetworkEndpoint{ 221 header.IPv6ProtocolNumber: netEP, 222 } 223 224 var linkRes entryTestLinkResolver 225 // Stub out the neighbor cache to verify deletion from the cache. 226 l := &linkResolver{ 227 resolver: &linkRes, 228 } 229 l.neigh.init(&nic, &linkRes) 230 231 entry := newNeighborEntry(&l.neigh, entryTestAddr1 /* remoteAddr */, l.neigh.state) 232 l.neigh.mu.Lock() 233 l.neigh.mu.cache[entryTestAddr1] = entry 234 l.neigh.mu.Unlock() 235 nic.linkAddrResolvers = map[tcpip.NetworkProtocolNumber]*linkResolver{ 236 header.IPv6ProtocolNumber: l, 237 } 238 239 return entry, &disp, &linkRes, clock 240 } 241 242 // TestEntryInitiallyUnknown verifies that the state of a newly created 243 // neighborEntry is Unknown. 244 func TestEntryInitiallyUnknown(t *testing.T) { 245 c := DefaultNUDConfigurations() 246 e, nudDisp, linkRes, clock := entryTestSetup(c) 247 248 e.mu.Lock() 249 if e.mu.neigh.State != Unknown { 250 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Unknown) 251 } 252 e.mu.Unlock() 253 254 clock.Advance(c.RetransmitTimer) 255 256 // No probes should have been sent. 257 linkRes.mu.Lock() 258 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 259 linkRes.mu.Unlock() 260 if diff != "" { 261 t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff) 262 } 263 264 // No events should have been dispatched. 265 nudDisp.mu.Lock() 266 if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.mu.events); diff != "" { 267 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 268 } 269 nudDisp.mu.Unlock() 270 } 271 272 func TestEntryUnknownToUnknownWhenConfirmationWithUnknownAddress(t *testing.T) { 273 c := DefaultNUDConfigurations() 274 e, nudDisp, linkRes, clock := entryTestSetup(c) 275 276 e.mu.Lock() 277 e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{ 278 Solicited: false, 279 Override: false, 280 IsRouter: false, 281 }) 282 if e.mu.neigh.State != Unknown { 283 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Unknown) 284 } 285 e.mu.Unlock() 286 287 clock.Advance(time.Hour) 288 289 // No probes should have been sent. 290 linkRes.mu.Lock() 291 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 292 linkRes.mu.Unlock() 293 if diff != "" { 294 t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff) 295 } 296 297 // No events should have been dispatched. 298 nudDisp.mu.Lock() 299 if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.mu.events); diff != "" { 300 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 301 } 302 nudDisp.mu.Unlock() 303 } 304 305 func TestEntryUnknownToIncomplete(t *testing.T) { 306 c := DefaultNUDConfigurations() 307 e, nudDisp, linkRes, clock := entryTestSetup(c) 308 309 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 310 t.Fatalf("unknownToIncomplete(...) = %s", err) 311 } 312 } 313 314 func unknownToIncomplete(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 315 if err := func() error { 316 e.mu.Lock() 317 defer e.mu.Unlock() 318 319 if e.mu.neigh.State != Unknown { 320 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Unknown) 321 } 322 e.handlePacketQueuedLocked(entryTestAddr2) 323 if e.mu.neigh.State != Incomplete { 324 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Incomplete) 325 } 326 return nil 327 }(); err != nil { 328 return err 329 } 330 331 runImmediatelyScheduledJobs(clock) 332 wantProbes := []entryTestProbeInfo{ 333 { 334 RemoteAddress: entryTestAddr1, 335 RemoteLinkAddress: tcpip.LinkAddress(""), 336 LocalAddress: entryTestAddr2, 337 }, 338 } 339 linkRes.mu.Lock() 340 diff := cmp.Diff(wantProbes, linkRes.mu.probes) 341 linkRes.mu.probes = nil 342 linkRes.mu.Unlock() 343 if diff != "" { 344 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 345 } 346 347 wantEvents := []testEntryEventInfo{ 348 { 349 EventType: entryTestAdded, 350 NICID: entryTestNICID, 351 Entry: NeighborEntry{ 352 Addr: entryTestAddr1, 353 LinkAddr: tcpip.LinkAddress(""), 354 State: Incomplete, 355 UpdatedAt: clock.Now(), 356 }, 357 }, 358 } 359 { 360 nudDisp.mu.Lock() 361 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 362 nudDisp.mu.events = nil 363 nudDisp.mu.Unlock() 364 if diff != "" { 365 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 366 } 367 } 368 return nil 369 } 370 371 func TestEntryUnknownToStale(t *testing.T) { 372 c := DefaultNUDConfigurations() 373 e, nudDisp, linkRes, clock := entryTestSetup(c) 374 375 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 376 t.Fatalf("unknownToStale(...) = %s", err) 377 } 378 } 379 380 func unknownToStale(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 381 if err := func() error { 382 e.mu.Lock() 383 defer e.mu.Unlock() 384 385 if e.mu.neigh.State != Unknown { 386 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Unknown) 387 } 388 e.handleProbeLocked(entryTestLinkAddr1) 389 if e.mu.neigh.State != Stale { 390 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 391 } 392 return nil 393 }(); err != nil { 394 return err 395 } 396 397 // No probes should have been sent. 398 runImmediatelyScheduledJobs(clock) 399 { 400 linkRes.mu.Lock() 401 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 402 linkRes.mu.Unlock() 403 if diff != "" { 404 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 405 } 406 } 407 408 wantEvents := []testEntryEventInfo{ 409 { 410 EventType: entryTestAdded, 411 NICID: entryTestNICID, 412 Entry: NeighborEntry{ 413 Addr: entryTestAddr1, 414 LinkAddr: entryTestLinkAddr1, 415 State: Stale, 416 UpdatedAt: clock.Now(), 417 }, 418 }, 419 } 420 { 421 nudDisp.mu.Lock() 422 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 423 nudDisp.mu.events = nil 424 nudDisp.mu.Unlock() 425 if diff != "" { 426 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 427 } 428 } 429 430 return nil 431 } 432 433 func TestEntryIncompleteToIncompleteDoesNotChangeUpdatedAt(t *testing.T) { 434 c := DefaultNUDConfigurations() 435 c.MaxMulticastProbes = 3 436 e, nudDisp, linkRes, clock := entryTestSetup(c) 437 438 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 439 t.Fatalf("unknownToIncomplete(...) = %s", err) 440 } 441 442 // UpdatedAt should remain the same during address resolution. 443 e.mu.Lock() 444 startedAt := e.mu.neigh.UpdatedAt 445 e.mu.Unlock() 446 447 // Wait for the rest of the reachability probe transmissions, signifying 448 // Incomplete to Incomplete transitions. 449 for i := uint32(1); i < c.MaxMulticastProbes; i++ { 450 clock.Advance(c.RetransmitTimer) 451 452 wantProbes := []entryTestProbeInfo{ 453 { 454 RemoteAddress: entryTestAddr1, 455 RemoteLinkAddress: tcpip.LinkAddress(""), 456 LocalAddress: entryTestAddr2, 457 }, 458 } 459 linkRes.mu.Lock() 460 diff := cmp.Diff(wantProbes, linkRes.mu.probes) 461 linkRes.mu.probes = nil 462 linkRes.mu.Unlock() 463 if diff != "" { 464 t.Fatalf("link address resolver probes mismatch (-want, +got):\n%s", diff) 465 } 466 467 e.mu.Lock() 468 if got, want := e.mu.neigh.UpdatedAt, startedAt; got != want { 469 t.Errorf("got e.mu.neigh.UpdatedAt = %q, want = %q", got, want) 470 } 471 e.mu.Unlock() 472 } 473 474 // UpdatedAt should change after failing address resolution. Timing out after 475 // sending the last probe transitions the entry to Unreachable. 476 clock.Advance(c.RetransmitTimer) 477 478 wantEvents := []testEntryEventInfo{ 479 { 480 EventType: entryTestChanged, 481 NICID: entryTestNICID, 482 Entry: NeighborEntry{ 483 Addr: entryTestAddr1, 484 LinkAddr: tcpip.LinkAddress(""), 485 State: Unreachable, 486 UpdatedAt: clock.Now(), 487 }, 488 }, 489 } 490 nudDisp.mu.Lock() 491 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 492 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 493 } 494 nudDisp.mu.Unlock() 495 } 496 497 func TestEntryIncompleteToReachable(t *testing.T) { 498 c := DefaultNUDConfigurations() 499 e, nudDisp, linkRes, clock := entryTestSetup(c) 500 501 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 502 t.Fatalf("unknownToIncomplete(...) = %s", err) 503 } 504 if err := incompleteToReachable(e, nudDisp, linkRes, clock); err != nil { 505 t.Fatalf("incompleteToReachable(...) = %s", err) 506 } 507 } 508 509 func incompleteToReachableWithFlags(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock, flags ReachabilityConfirmationFlags) error { 510 if err := func() error { 511 e.mu.Lock() 512 defer e.mu.Unlock() 513 514 if e.mu.neigh.State != Incomplete { 515 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Incomplete) 516 } 517 e.handleConfirmationLocked(entryTestLinkAddr1, flags) 518 if e.mu.neigh.State != Reachable { 519 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 520 } 521 if e.mu.neigh.LinkAddr != entryTestLinkAddr1 { 522 return fmt.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr1) 523 } 524 return nil 525 }(); err != nil { 526 return err 527 } 528 529 // No probes should have been sent. 530 runImmediatelyScheduledJobs(clock) 531 { 532 linkRes.mu.Lock() 533 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 534 linkRes.mu.Unlock() 535 if diff != "" { 536 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 537 } 538 } 539 540 wantEvents := []testEntryEventInfo{ 541 { 542 EventType: entryTestChanged, 543 NICID: entryTestNICID, 544 Entry: NeighborEntry{ 545 Addr: entryTestAddr1, 546 LinkAddr: entryTestLinkAddr1, 547 State: Reachable, 548 UpdatedAt: clock.Now(), 549 }, 550 }, 551 } 552 { 553 nudDisp.mu.Lock() 554 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 555 nudDisp.mu.events = nil 556 nudDisp.mu.Unlock() 557 if diff != "" { 558 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 559 } 560 } 561 562 return nil 563 } 564 565 func incompleteToReachable(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 566 if err := incompleteToReachableWithFlags(e, nudDisp, linkRes, clock, ReachabilityConfirmationFlags{ 567 Solicited: true, 568 Override: false, 569 IsRouter: false, 570 }); err != nil { 571 return err 572 } 573 574 e.mu.Lock() 575 isRouter := e.mu.isRouter 576 e.mu.Unlock() 577 if isRouter { 578 return fmt.Errorf("got e.mu.isRouter = %t, want = false", isRouter) 579 } 580 581 return nil 582 } 583 584 func TestEntryIncompleteToReachableWithRouterFlag(t *testing.T) { 585 c := DefaultNUDConfigurations() 586 e, nudDisp, linkRes, clock := entryTestSetup(c) 587 588 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 589 t.Fatalf("unknownToIncomplete(...) = %s", err) 590 } 591 if err := incompleteToReachableWithRouterFlag(e, nudDisp, linkRes, clock); err != nil { 592 t.Fatalf("incompleteToReachableWithRouterFlag(...) = %s", err) 593 } 594 } 595 596 func incompleteToReachableWithRouterFlag(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 597 if err := incompleteToReachableWithFlags(e, nudDisp, linkRes, clock, ReachabilityConfirmationFlags{ 598 Solicited: true, 599 Override: false, 600 IsRouter: true, 601 }); err != nil { 602 return err 603 } 604 605 e.mu.Lock() 606 isRouter := e.mu.isRouter 607 e.mu.Unlock() 608 if !isRouter { 609 return fmt.Errorf("got e.mu.isRouter = %t, want = true", isRouter) 610 } 611 612 return nil 613 } 614 615 func TestEntryIncompleteToStaleWhenUnsolicitedConfirmation(t *testing.T) { 616 c := DefaultNUDConfigurations() 617 e, nudDisp, linkRes, clock := entryTestSetup(c) 618 619 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 620 t.Fatalf("unknownToIncomplete(...) = %s", err) 621 } 622 623 e.mu.Lock() 624 e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{ 625 Solicited: false, 626 Override: false, 627 IsRouter: false, 628 }) 629 if e.mu.neigh.State != Stale { 630 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 631 } 632 if e.mu.isRouter { 633 t.Errorf("got e.mu.isRouter = %t, want = false", e.mu.isRouter) 634 } 635 e.mu.Unlock() 636 637 wantEvents := []testEntryEventInfo{ 638 { 639 EventType: entryTestChanged, 640 NICID: entryTestNICID, 641 Entry: NeighborEntry{ 642 Addr: entryTestAddr1, 643 LinkAddr: entryTestLinkAddr1, 644 State: Stale, 645 UpdatedAt: clock.Now(), 646 }, 647 }, 648 } 649 nudDisp.mu.Lock() 650 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 651 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 652 } 653 nudDisp.mu.Unlock() 654 } 655 656 func TestEntryIncompleteToStaleWhenProbe(t *testing.T) { 657 c := DefaultNUDConfigurations() 658 e, nudDisp, linkRes, clock := entryTestSetup(c) 659 660 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 661 t.Fatalf("unknownToIncomplete(...) = %s", err) 662 } 663 664 e.mu.Lock() 665 e.handleProbeLocked(entryTestLinkAddr1) 666 if e.mu.neigh.State != Stale { 667 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 668 } 669 e.mu.Unlock() 670 671 wantEvents := []testEntryEventInfo{ 672 { 673 EventType: entryTestChanged, 674 NICID: entryTestNICID, 675 Entry: NeighborEntry{ 676 Addr: entryTestAddr1, 677 LinkAddr: entryTestLinkAddr1, 678 State: Stale, 679 UpdatedAt: clock.Now(), 680 }, 681 }, 682 } 683 nudDisp.mu.Lock() 684 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 685 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 686 } 687 nudDisp.mu.Unlock() 688 } 689 690 func TestEntryIncompleteToUnreachable(t *testing.T) { 691 c := DefaultNUDConfigurations() 692 c.MaxMulticastProbes = 3 693 e, nudDisp, linkRes, clock := entryTestSetup(c) 694 695 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 696 t.Fatalf("unknownToIncomplete(...) = %s", err) 697 } 698 if err := incompleteToUnreachable(c, e, nudDisp, linkRes, clock); err != nil { 699 t.Fatalf("incompleteToUnreachable(...) = %s", err) 700 } 701 } 702 703 func incompleteToUnreachable(c NUDConfigurations, e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 704 { 705 e.mu.Lock() 706 state := e.mu.neigh.State 707 e.mu.Unlock() 708 if state != Incomplete { 709 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Incomplete) 710 } 711 } 712 713 // The first probe was sent in the transition from Unknown to Incomplete. 714 clock.Advance(c.RetransmitTimer) 715 716 // Observe each subsequent multicast probe transmitted. 717 for i := uint32(1); i < c.MaxMulticastProbes; i++ { 718 wantProbes := []entryTestProbeInfo{{ 719 RemoteAddress: entryTestAddr1, 720 RemoteLinkAddress: "", 721 LocalAddress: entryTestAddr2, 722 }} 723 linkRes.mu.Lock() 724 diff := cmp.Diff(wantProbes, linkRes.mu.probes) 725 linkRes.mu.probes = nil 726 linkRes.mu.Unlock() 727 if diff != "" { 728 return fmt.Errorf("link address resolver probe #%d mismatch (-want, +got):\n%s", i+1, diff) 729 } 730 731 e.mu.Lock() 732 state := e.mu.neigh.State 733 e.mu.Unlock() 734 if state != Incomplete { 735 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Incomplete) 736 } 737 738 clock.Advance(c.RetransmitTimer) 739 } 740 741 { 742 e.mu.Lock() 743 state := e.mu.neigh.State 744 e.mu.Unlock() 745 if state != Unreachable { 746 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Unreachable) 747 } 748 } 749 750 wantEvents := []testEntryEventInfo{ 751 { 752 EventType: entryTestChanged, 753 NICID: entryTestNICID, 754 Entry: NeighborEntry{ 755 Addr: entryTestAddr1, 756 LinkAddr: tcpip.LinkAddress(""), 757 State: Unreachable, 758 UpdatedAt: clock.Now(), 759 }, 760 }, 761 } 762 nudDisp.mu.Lock() 763 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 764 nudDisp.mu.events = nil 765 nudDisp.mu.Unlock() 766 if diff != "" { 767 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 768 } 769 770 return nil 771 } 772 773 type testLocker struct{} 774 775 var _ sync.Locker = (*testLocker)(nil) 776 777 func (*testLocker) Lock() {} 778 func (*testLocker) Unlock() {} 779 780 func TestEntryReachableToReachableClearsRouterWhenConfirmationWithoutRouter(t *testing.T) { 781 c := DefaultNUDConfigurations() 782 e, nudDisp, linkRes, clock := entryTestSetup(c) 783 784 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 785 t.Fatalf("unknownToIncomplete(...) = %s", err) 786 } 787 if err := incompleteToReachableWithRouterFlag(e, nudDisp, linkRes, clock); err != nil { 788 t.Fatalf("incompleteToReachableWithRouterFlag(...) = %s", err) 789 } 790 791 e.mu.Lock() 792 e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{ 793 Solicited: false, 794 Override: false, 795 IsRouter: false, 796 }) 797 if e.mu.neigh.State != Reachable { 798 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 799 } 800 if got, want := e.mu.isRouter, false; got != want { 801 t.Errorf("got e.mu.isRouter = %t, want = %t", got, want) 802 } 803 ipv6EP := e.cache.nic.networkEndpoints[header.IPv6ProtocolNumber].(*testIPv6Endpoint) 804 if ipv6EP.invalidatedRtr != e.mu.neigh.Addr { 805 t.Errorf("got ipv6EP.invalidatedRtr = %s, want = %s", ipv6EP.invalidatedRtr, e.mu.neigh.Addr) 806 } 807 e.mu.Unlock() 808 809 // No probes should have been sent. 810 runImmediatelyScheduledJobs(clock) 811 { 812 linkRes.mu.Lock() 813 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 814 linkRes.mu.Unlock() 815 if diff != "" { 816 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 817 } 818 } 819 820 // No events should have been dispatched. 821 nudDisp.mu.Lock() 822 diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.mu.events) 823 nudDisp.mu.Unlock() 824 if diff != "" { 825 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 826 } 827 } 828 829 func TestEntryReachableToReachableWhenProbeWithSameAddress(t *testing.T) { 830 c := DefaultNUDConfigurations() 831 e, nudDisp, linkRes, clock := entryTestSetup(c) 832 833 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 834 t.Fatalf("unknownToIncomplete(...) = %s", err) 835 } 836 if err := incompleteToReachable(e, nudDisp, linkRes, clock); err != nil { 837 t.Fatalf("incompleteToReachable(...) = %s", err) 838 } 839 840 e.mu.Lock() 841 e.handleProbeLocked(entryTestLinkAddr1) 842 if e.mu.neigh.State != Reachable { 843 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 844 } 845 if e.mu.neigh.LinkAddr != entryTestLinkAddr1 { 846 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr1) 847 } 848 e.mu.Unlock() 849 850 // No probes should have been sent. 851 runImmediatelyScheduledJobs(clock) 852 { 853 linkRes.mu.Lock() 854 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 855 linkRes.mu.Unlock() 856 if diff != "" { 857 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 858 } 859 } 860 861 // No events should have been dispatched. 862 nudDisp.mu.Lock() 863 diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.mu.events) 864 nudDisp.mu.Unlock() 865 if diff != "" { 866 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 867 } 868 } 869 870 func TestEntryReachableToStaleWhenTimeout(t *testing.T) { 871 c := DefaultNUDConfigurations() 872 // Eliminate random factors from ReachableTime computation so the transition 873 // from Stale to Reachable will only take BaseReachableTime duration. 874 c.MinRandomFactor = 1 875 c.MaxRandomFactor = 1 876 877 e, nudDisp, linkRes, clock := entryTestSetup(c) 878 879 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 880 t.Fatalf("unknownToIncomplete(...) = %s", err) 881 } 882 if err := incompleteToReachable(e, nudDisp, linkRes, clock); err != nil { 883 t.Fatalf("incompleteToReachable(...) = %s", err) 884 } 885 if err := reachableToStale(c, e, nudDisp, linkRes, clock); err != nil { 886 t.Fatalf("reachableToStale(...) = %s", err) 887 } 888 } 889 890 // reachableToStale transitions a neighborEntry in Reachable state to Stale 891 // state. Depends on the elimination of random factors in the ReachableTime 892 // computation. 893 // 894 // c.MinRandomFactor = 1 895 // c.MaxRandomFactor = 1 896 func reachableToStale(c NUDConfigurations, e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 897 // Ensure there are no random factors in the ReachableTime computation. 898 if c.MinRandomFactor != 1 { 899 return fmt.Errorf("got c.MinRandomFactor = %f, want = 1", c.MinRandomFactor) 900 } 901 if c.MaxRandomFactor != 1 { 902 return fmt.Errorf("got c.MaxRandomFactor = %f, want = 1", c.MaxRandomFactor) 903 } 904 905 { 906 e.mu.Lock() 907 state := e.mu.neigh.State 908 e.mu.Unlock() 909 if state != Reachable { 910 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Reachable) 911 } 912 } 913 914 clock.Advance(c.BaseReachableTime) 915 916 { 917 e.mu.Lock() 918 state := e.mu.neigh.State 919 e.mu.Unlock() 920 if state != Stale { 921 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Stale) 922 } 923 } 924 925 // No probes should have been sent. 926 runImmediatelyScheduledJobs(clock) 927 { 928 linkRes.mu.Lock() 929 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 930 linkRes.mu.Unlock() 931 if diff != "" { 932 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 933 } 934 } 935 936 wantEvents := []testEntryEventInfo{ 937 { 938 EventType: entryTestChanged, 939 NICID: entryTestNICID, 940 Entry: NeighborEntry{ 941 Addr: entryTestAddr1, 942 LinkAddr: entryTestLinkAddr1, 943 State: Stale, 944 UpdatedAt: clock.Now(), 945 }, 946 }, 947 } 948 { 949 950 nudDisp.mu.Lock() 951 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 952 nudDisp.mu.events = nil 953 nudDisp.mu.Unlock() 954 if diff != "" { 955 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 956 } 957 } 958 959 return nil 960 } 961 962 func TestEntryReachableToStaleWhenProbeWithDifferentAddress(t *testing.T) { 963 c := DefaultNUDConfigurations() 964 e, nudDisp, linkRes, clock := entryTestSetup(c) 965 966 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 967 t.Fatalf("unknownToIncomplete(...) = %s", err) 968 } 969 if err := incompleteToReachable(e, nudDisp, linkRes, clock); err != nil { 970 t.Fatalf("incompleteToReachable(...) = %s", err) 971 } 972 973 e.mu.Lock() 974 e.handleProbeLocked(entryTestLinkAddr2) 975 if e.mu.neigh.State != Stale { 976 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 977 } 978 e.mu.Unlock() 979 980 // No probes should have been sent. 981 runImmediatelyScheduledJobs(clock) 982 { 983 linkRes.mu.Lock() 984 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 985 linkRes.mu.Unlock() 986 if diff != "" { 987 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 988 } 989 } 990 991 wantEvents := []testEntryEventInfo{ 992 { 993 EventType: entryTestChanged, 994 NICID: entryTestNICID, 995 Entry: NeighborEntry{ 996 Addr: entryTestAddr1, 997 LinkAddr: entryTestLinkAddr2, 998 State: Stale, 999 UpdatedAt: clock.Now(), 1000 }, 1001 }, 1002 } 1003 nudDisp.mu.Lock() 1004 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1005 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1006 } 1007 nudDisp.mu.Unlock() 1008 } 1009 1010 func TestEntryReachableToStaleWhenConfirmationWithDifferentAddress(t *testing.T) { 1011 c := DefaultNUDConfigurations() 1012 e, nudDisp, linkRes, clock := entryTestSetup(c) 1013 1014 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 1015 t.Fatalf("unknownToIncomplete(...) = %s", err) 1016 } 1017 if err := incompleteToReachable(e, nudDisp, linkRes, clock); err != nil { 1018 t.Fatalf("incompleteToReachable(...) = %s", err) 1019 } 1020 1021 e.mu.Lock() 1022 e.handleConfirmationLocked(entryTestLinkAddr2, ReachabilityConfirmationFlags{ 1023 Solicited: false, 1024 Override: false, 1025 IsRouter: false, 1026 }) 1027 if e.mu.neigh.State != Stale { 1028 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1029 } 1030 e.mu.Unlock() 1031 1032 // No probes should have been sent. 1033 runImmediatelyScheduledJobs(clock) 1034 { 1035 linkRes.mu.Lock() 1036 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1037 linkRes.mu.Unlock() 1038 if diff != "" { 1039 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1040 } 1041 } 1042 1043 wantEvents := []testEntryEventInfo{ 1044 { 1045 EventType: entryTestChanged, 1046 NICID: entryTestNICID, 1047 Entry: NeighborEntry{ 1048 Addr: entryTestAddr1, 1049 LinkAddr: entryTestLinkAddr1, 1050 State: Stale, 1051 UpdatedAt: clock.Now(), 1052 }, 1053 }, 1054 } 1055 nudDisp.mu.Lock() 1056 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1057 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1058 } 1059 nudDisp.mu.Unlock() 1060 } 1061 1062 func TestEntryReachableToStaleWhenConfirmationWithDifferentAddressAndOverride(t *testing.T) { 1063 c := DefaultNUDConfigurations() 1064 e, nudDisp, linkRes, clock := entryTestSetup(c) 1065 1066 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 1067 t.Fatalf("unknownToIncomplete(...) = %s", err) 1068 } 1069 if err := incompleteToReachable(e, nudDisp, linkRes, clock); err != nil { 1070 t.Fatalf("incompleteToReachable(...) = %s", err) 1071 } 1072 1073 e.mu.Lock() 1074 e.handleConfirmationLocked(entryTestLinkAddr2, ReachabilityConfirmationFlags{ 1075 Solicited: false, 1076 Override: true, 1077 IsRouter: false, 1078 }) 1079 if e.mu.neigh.State != Stale { 1080 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1081 } 1082 e.mu.Unlock() 1083 1084 // No probes should have been sent. 1085 runImmediatelyScheduledJobs(clock) 1086 { 1087 linkRes.mu.Lock() 1088 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1089 linkRes.mu.Unlock() 1090 if diff != "" { 1091 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1092 } 1093 } 1094 1095 wantEvents := []testEntryEventInfo{ 1096 { 1097 EventType: entryTestChanged, 1098 NICID: entryTestNICID, 1099 Entry: NeighborEntry{ 1100 Addr: entryTestAddr1, 1101 LinkAddr: entryTestLinkAddr2, 1102 State: Stale, 1103 UpdatedAt: clock.Now(), 1104 }, 1105 }, 1106 } 1107 nudDisp.mu.Lock() 1108 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1109 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1110 } 1111 nudDisp.mu.Unlock() 1112 } 1113 1114 func TestEntryStaleToStaleWhenProbeWithSameAddress(t *testing.T) { 1115 c := DefaultNUDConfigurations() 1116 e, nudDisp, linkRes, clock := entryTestSetup(c) 1117 1118 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1119 t.Fatalf("unknownToStale(...) = %s", err) 1120 } 1121 1122 e.mu.Lock() 1123 e.handleProbeLocked(entryTestLinkAddr1) 1124 if e.mu.neigh.State != Stale { 1125 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1126 } 1127 if e.mu.neigh.LinkAddr != entryTestLinkAddr1 { 1128 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr1) 1129 } 1130 e.mu.Unlock() 1131 1132 // No probes should have been sent. 1133 runImmediatelyScheduledJobs(clock) 1134 { 1135 linkRes.mu.Lock() 1136 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1137 linkRes.mu.Unlock() 1138 if diff != "" { 1139 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1140 } 1141 } 1142 1143 // No events should have been dispatched. 1144 nudDisp.mu.Lock() 1145 if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.mu.events); diff != "" { 1146 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1147 } 1148 nudDisp.mu.Unlock() 1149 } 1150 1151 func TestEntryStaleToReachableWhenSolicitedOverrideConfirmation(t *testing.T) { 1152 c := DefaultNUDConfigurations() 1153 e, nudDisp, linkRes, clock := entryTestSetup(c) 1154 1155 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1156 t.Fatalf("unknownToStale(...) = %s", err) 1157 } 1158 1159 e.mu.Lock() 1160 e.handleConfirmationLocked(entryTestLinkAddr2, ReachabilityConfirmationFlags{ 1161 Solicited: true, 1162 Override: true, 1163 IsRouter: false, 1164 }) 1165 if e.mu.neigh.State != Reachable { 1166 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 1167 } 1168 if e.mu.neigh.LinkAddr != entryTestLinkAddr2 { 1169 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr2) 1170 } 1171 e.mu.Unlock() 1172 1173 // No probes should have been sent. 1174 runImmediatelyScheduledJobs(clock) 1175 { 1176 linkRes.mu.Lock() 1177 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1178 linkRes.mu.Unlock() 1179 if diff != "" { 1180 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1181 } 1182 } 1183 1184 wantEvents := []testEntryEventInfo{ 1185 { 1186 EventType: entryTestChanged, 1187 NICID: entryTestNICID, 1188 Entry: NeighborEntry{ 1189 Addr: entryTestAddr1, 1190 LinkAddr: entryTestLinkAddr2, 1191 State: Reachable, 1192 UpdatedAt: clock.Now(), 1193 }, 1194 }, 1195 } 1196 nudDisp.mu.Lock() 1197 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1198 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1199 } 1200 nudDisp.mu.Unlock() 1201 } 1202 1203 func TestEntryStaleToReachableWhenSolicitedConfirmationWithoutAddress(t *testing.T) { 1204 c := DefaultNUDConfigurations() 1205 e, nudDisp, linkRes, clock := entryTestSetup(c) 1206 1207 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1208 t.Fatalf("unknownToStale(...) = %s", err) 1209 } 1210 1211 e.mu.Lock() 1212 e.handleConfirmationLocked("" /* linkAddr */, ReachabilityConfirmationFlags{ 1213 Solicited: true, 1214 Override: false, 1215 IsRouter: false, 1216 }) 1217 if e.mu.neigh.State != Reachable { 1218 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 1219 } 1220 if e.mu.neigh.LinkAddr != entryTestLinkAddr1 { 1221 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr1) 1222 } 1223 e.mu.Unlock() 1224 1225 // No probes should have been sent. 1226 runImmediatelyScheduledJobs(clock) 1227 { 1228 linkRes.mu.Lock() 1229 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1230 linkRes.mu.Unlock() 1231 if diff != "" { 1232 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1233 } 1234 } 1235 1236 wantEvents := []testEntryEventInfo{ 1237 { 1238 EventType: entryTestChanged, 1239 NICID: entryTestNICID, 1240 Entry: NeighborEntry{ 1241 Addr: entryTestAddr1, 1242 LinkAddr: entryTestLinkAddr1, 1243 State: Reachable, 1244 UpdatedAt: clock.Now(), 1245 }, 1246 }, 1247 } 1248 nudDisp.mu.Lock() 1249 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1250 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1251 } 1252 nudDisp.mu.Unlock() 1253 } 1254 1255 func TestEntryStaleToStaleWhenOverrideConfirmation(t *testing.T) { 1256 c := DefaultNUDConfigurations() 1257 e, nudDisp, linkRes, clock := entryTestSetup(c) 1258 1259 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1260 t.Fatalf("unknownToStale(...) = %s", err) 1261 } 1262 1263 e.mu.Lock() 1264 e.handleConfirmationLocked(entryTestLinkAddr2, ReachabilityConfirmationFlags{ 1265 Solicited: false, 1266 Override: true, 1267 IsRouter: false, 1268 }) 1269 if e.mu.neigh.State != Stale { 1270 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1271 } 1272 if e.mu.neigh.LinkAddr != entryTestLinkAddr2 { 1273 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr2) 1274 } 1275 e.mu.Unlock() 1276 1277 wantEvents := []testEntryEventInfo{ 1278 { 1279 EventType: entryTestChanged, 1280 NICID: entryTestNICID, 1281 Entry: NeighborEntry{ 1282 Addr: entryTestAddr1, 1283 LinkAddr: entryTestLinkAddr2, 1284 State: Stale, 1285 UpdatedAt: clock.Now(), 1286 }, 1287 }, 1288 } 1289 nudDisp.mu.Lock() 1290 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1291 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1292 } 1293 nudDisp.mu.Unlock() 1294 } 1295 1296 func TestEntryStaleToStaleWhenProbeUpdateAddress(t *testing.T) { 1297 c := DefaultNUDConfigurations() 1298 e, nudDisp, linkRes, clock := entryTestSetup(c) 1299 1300 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1301 t.Fatalf("unknownToStale(...) = %s", err) 1302 } 1303 1304 e.mu.Lock() 1305 e.handleProbeLocked(entryTestLinkAddr2) 1306 if e.mu.neigh.State != Stale { 1307 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1308 } 1309 if e.mu.neigh.LinkAddr != entryTestLinkAddr2 { 1310 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr2) 1311 } 1312 e.mu.Unlock() 1313 1314 // No probes should have been sent. 1315 runImmediatelyScheduledJobs(clock) 1316 { 1317 linkRes.mu.Lock() 1318 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1319 linkRes.mu.Unlock() 1320 if diff != "" { 1321 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1322 } 1323 } 1324 1325 wantEvents := []testEntryEventInfo{ 1326 { 1327 EventType: entryTestChanged, 1328 NICID: entryTestNICID, 1329 Entry: NeighborEntry{ 1330 Addr: entryTestAddr1, 1331 LinkAddr: entryTestLinkAddr2, 1332 State: Stale, 1333 UpdatedAt: clock.Now(), 1334 }, 1335 }, 1336 } 1337 nudDisp.mu.Lock() 1338 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1339 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1340 } 1341 nudDisp.mu.Unlock() 1342 } 1343 1344 func TestEntryStaleToDelay(t *testing.T) { 1345 c := DefaultNUDConfigurations() 1346 e, nudDisp, linkRes, clock := entryTestSetup(c) 1347 1348 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1349 t.Fatalf("unknownToStale(...) = %s", err) 1350 } 1351 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1352 t.Fatalf("staleToDelay(...) = %s", err) 1353 } 1354 } 1355 1356 func staleToDelay(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 1357 if err := func() error { 1358 e.mu.Lock() 1359 defer e.mu.Unlock() 1360 1361 if e.mu.neigh.State != Stale { 1362 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1363 } 1364 e.handlePacketQueuedLocked(entryTestAddr2) 1365 if e.mu.neigh.State != Delay { 1366 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Delay) 1367 } 1368 return nil 1369 }(); err != nil { 1370 return err 1371 } 1372 1373 // No probes should have been sent. 1374 runImmediatelyScheduledJobs(clock) 1375 { 1376 linkRes.mu.Lock() 1377 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1378 linkRes.mu.Unlock() 1379 if diff != "" { 1380 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1381 } 1382 } 1383 1384 wantEvents := []testEntryEventInfo{ 1385 { 1386 EventType: entryTestChanged, 1387 NICID: entryTestNICID, 1388 Entry: NeighborEntry{ 1389 Addr: entryTestAddr1, 1390 LinkAddr: entryTestLinkAddr1, 1391 State: Delay, 1392 UpdatedAt: clock.Now(), 1393 }, 1394 }, 1395 } 1396 nudDisp.mu.Lock() 1397 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 1398 nudDisp.mu.events = nil 1399 nudDisp.mu.Unlock() 1400 if diff != "" { 1401 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1402 } 1403 1404 return nil 1405 } 1406 1407 func TestEntryDelayToReachableWhenUpperLevelConfirmation(t *testing.T) { 1408 c := DefaultNUDConfigurations() 1409 e, nudDisp, linkRes, clock := entryTestSetup(c) 1410 1411 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1412 t.Fatalf("unknownToStale(...) = %s", err) 1413 } 1414 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1415 t.Fatalf("staleToDelay(...) = %s", err) 1416 } 1417 1418 e.mu.Lock() 1419 e.handleUpperLevelConfirmationLocked() 1420 if e.mu.neigh.State != Reachable { 1421 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 1422 } 1423 e.mu.Unlock() 1424 1425 // No probes should have been sent. 1426 runImmediatelyScheduledJobs(clock) 1427 { 1428 linkRes.mu.Lock() 1429 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1430 linkRes.mu.Unlock() 1431 if diff != "" { 1432 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1433 } 1434 } 1435 1436 wantEvents := []testEntryEventInfo{ 1437 { 1438 EventType: entryTestChanged, 1439 NICID: entryTestNICID, 1440 Entry: NeighborEntry{ 1441 Addr: entryTestAddr1, 1442 LinkAddr: entryTestLinkAddr1, 1443 State: Reachable, 1444 UpdatedAt: clock.Now(), 1445 }, 1446 }, 1447 } 1448 nudDisp.mu.Lock() 1449 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1450 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1451 } 1452 nudDisp.mu.Unlock() 1453 } 1454 1455 func TestEntryDelayToReachableWhenSolicitedOverrideConfirmation(t *testing.T) { 1456 c := DefaultNUDConfigurations() 1457 e, nudDisp, linkRes, clock := entryTestSetup(c) 1458 1459 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1460 t.Fatalf("unknownToStale(...) = %s", err) 1461 } 1462 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1463 t.Fatalf("staleToDelay(...) = %s", err) 1464 } 1465 1466 e.mu.Lock() 1467 e.handleConfirmationLocked(entryTestLinkAddr2, ReachabilityConfirmationFlags{ 1468 Solicited: true, 1469 Override: true, 1470 IsRouter: false, 1471 }) 1472 if e.mu.neigh.State != Reachable { 1473 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 1474 } 1475 if e.mu.neigh.LinkAddr != entryTestLinkAddr2 { 1476 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr2) 1477 } 1478 e.mu.Unlock() 1479 1480 // No probes should have been sent. 1481 runImmediatelyScheduledJobs(clock) 1482 { 1483 linkRes.mu.Lock() 1484 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1485 linkRes.mu.Unlock() 1486 if diff != "" { 1487 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1488 } 1489 } 1490 1491 wantEvents := []testEntryEventInfo{ 1492 { 1493 EventType: entryTestChanged, 1494 NICID: entryTestNICID, 1495 Entry: NeighborEntry{ 1496 Addr: entryTestAddr1, 1497 LinkAddr: entryTestLinkAddr2, 1498 State: Reachable, 1499 UpdatedAt: clock.Now(), 1500 }, 1501 }, 1502 } 1503 nudDisp.mu.Lock() 1504 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1505 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1506 } 1507 nudDisp.mu.Unlock() 1508 } 1509 1510 func TestEntryDelayToReachableWhenSolicitedConfirmationWithoutAddress(t *testing.T) { 1511 c := DefaultNUDConfigurations() 1512 e, nudDisp, linkRes, clock := entryTestSetup(c) 1513 1514 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1515 t.Fatalf("unknownToStale(...) = %s", err) 1516 } 1517 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1518 t.Fatalf("staleToDelay(...) = %s", err) 1519 } 1520 1521 e.mu.Lock() 1522 e.handleConfirmationLocked("" /* linkAddr */, ReachabilityConfirmationFlags{ 1523 Solicited: true, 1524 Override: false, 1525 IsRouter: false, 1526 }) 1527 if e.mu.neigh.State != Reachable { 1528 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 1529 } 1530 if e.mu.neigh.LinkAddr != entryTestLinkAddr1 { 1531 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr1) 1532 } 1533 e.mu.Unlock() 1534 1535 // No probes should have been sent. 1536 runImmediatelyScheduledJobs(clock) 1537 { 1538 linkRes.mu.Lock() 1539 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1540 linkRes.mu.Unlock() 1541 if diff != "" { 1542 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1543 } 1544 } 1545 1546 wantEvents := []testEntryEventInfo{ 1547 { 1548 EventType: entryTestChanged, 1549 NICID: entryTestNICID, 1550 Entry: NeighborEntry{ 1551 Addr: entryTestAddr1, 1552 LinkAddr: entryTestLinkAddr1, 1553 State: Reachable, 1554 UpdatedAt: clock.Now(), 1555 }, 1556 }, 1557 } 1558 nudDisp.mu.Lock() 1559 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1560 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1561 } 1562 nudDisp.mu.Unlock() 1563 } 1564 1565 func TestEntryDelayToDelayWhenOverrideConfirmationWithSameAddress(t *testing.T) { 1566 c := DefaultNUDConfigurations() 1567 e, nudDisp, linkRes, clock := entryTestSetup(c) 1568 1569 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1570 t.Fatalf("unknownToStale(...) = %s", err) 1571 } 1572 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1573 t.Fatalf("staleToDelay(...) = %s", err) 1574 } 1575 1576 e.mu.Lock() 1577 e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{ 1578 Solicited: false, 1579 Override: true, 1580 IsRouter: false, 1581 }) 1582 if e.mu.neigh.State != Delay { 1583 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Delay) 1584 } 1585 if e.mu.neigh.LinkAddr != entryTestLinkAddr1 { 1586 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, entryTestLinkAddr1) 1587 } 1588 e.mu.Unlock() 1589 1590 // No probes should have been sent. 1591 runImmediatelyScheduledJobs(clock) 1592 { 1593 linkRes.mu.Lock() 1594 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1595 linkRes.mu.Unlock() 1596 if diff != "" { 1597 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1598 } 1599 } 1600 1601 // No events should have been dispatched. 1602 nudDisp.mu.Lock() 1603 if diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.mu.events); diff != "" { 1604 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1605 } 1606 nudDisp.mu.Unlock() 1607 } 1608 1609 func TestEntryDelayToStaleWhenProbeWithDifferentAddress(t *testing.T) { 1610 c := DefaultNUDConfigurations() 1611 e, nudDisp, linkRes, clock := entryTestSetup(c) 1612 1613 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1614 t.Fatalf("unknownToStale(...) = %s", err) 1615 } 1616 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1617 t.Fatalf("staleToDelay(...) = %s", err) 1618 } 1619 1620 e.mu.Lock() 1621 e.handleProbeLocked(entryTestLinkAddr2) 1622 if e.mu.neigh.State != Stale { 1623 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1624 } 1625 e.mu.Unlock() 1626 1627 // No probes should have been sent. 1628 runImmediatelyScheduledJobs(clock) 1629 { 1630 linkRes.mu.Lock() 1631 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1632 linkRes.mu.Unlock() 1633 if diff != "" { 1634 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1635 } 1636 } 1637 1638 wantEvents := []testEntryEventInfo{ 1639 { 1640 EventType: entryTestChanged, 1641 NICID: entryTestNICID, 1642 Entry: NeighborEntry{ 1643 Addr: entryTestAddr1, 1644 LinkAddr: entryTestLinkAddr2, 1645 State: Stale, 1646 UpdatedAt: clock.Now(), 1647 }, 1648 }, 1649 } 1650 nudDisp.mu.Lock() 1651 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1652 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1653 } 1654 nudDisp.mu.Unlock() 1655 } 1656 1657 func TestEntryDelayToStaleWhenConfirmationWithDifferentAddress(t *testing.T) { 1658 c := DefaultNUDConfigurations() 1659 e, nudDisp, linkRes, clock := entryTestSetup(c) 1660 1661 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1662 t.Fatalf("unknownToStale(...) = %s", err) 1663 } 1664 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1665 t.Fatalf("staleToDelay(...) = %s", err) 1666 } 1667 1668 e.mu.Lock() 1669 e.handleConfirmationLocked(entryTestLinkAddr2, ReachabilityConfirmationFlags{ 1670 Solicited: false, 1671 Override: true, 1672 IsRouter: false, 1673 }) 1674 if e.mu.neigh.State != Stale { 1675 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1676 } 1677 e.mu.Unlock() 1678 1679 // No probes should have been sent. 1680 runImmediatelyScheduledJobs(clock) 1681 { 1682 linkRes.mu.Lock() 1683 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1684 linkRes.mu.Unlock() 1685 if diff != "" { 1686 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1687 } 1688 } 1689 1690 wantEvents := []testEntryEventInfo{ 1691 { 1692 EventType: entryTestChanged, 1693 NICID: entryTestNICID, 1694 Entry: NeighborEntry{ 1695 Addr: entryTestAddr1, 1696 LinkAddr: entryTestLinkAddr2, 1697 State: Stale, 1698 UpdatedAt: clock.Now(), 1699 }, 1700 }, 1701 } 1702 nudDisp.mu.Lock() 1703 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1704 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1705 } 1706 nudDisp.mu.Unlock() 1707 } 1708 1709 func TestEntryDelayToProbe(t *testing.T) { 1710 c := DefaultNUDConfigurations() 1711 e, nudDisp, linkRes, clock := entryTestSetup(c) 1712 1713 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1714 t.Fatalf("unknownToStale(...) = %s", err) 1715 } 1716 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1717 t.Fatalf("staleToDelay(...) = %s", err) 1718 } 1719 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 1720 t.Fatalf("delayToProbe(...) = %s", err) 1721 } 1722 } 1723 1724 func delayToProbe(c NUDConfigurations, e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 1725 { 1726 e.mu.Lock() 1727 state := e.mu.neigh.State 1728 e.mu.Unlock() 1729 if state != Delay { 1730 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Delay) 1731 } 1732 } 1733 1734 // Wait for the first unicast probe to be transmitted, marking the 1735 // transition from Delay to Probe. 1736 clock.Advance(c.DelayFirstProbeTime) 1737 1738 { 1739 e.mu.Lock() 1740 state := e.mu.neigh.State 1741 e.mu.Unlock() 1742 if state != Probe { 1743 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Probe) 1744 } 1745 } 1746 1747 wantProbes := []entryTestProbeInfo{ 1748 { 1749 RemoteAddress: entryTestAddr1, 1750 RemoteLinkAddress: entryTestLinkAddr1, 1751 }, 1752 } 1753 { 1754 linkRes.mu.Lock() 1755 diff := cmp.Diff(wantProbes, linkRes.mu.probes) 1756 linkRes.mu.probes = nil 1757 linkRes.mu.Unlock() 1758 if diff != "" { 1759 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1760 } 1761 } 1762 1763 wantEvents := []testEntryEventInfo{ 1764 { 1765 EventType: entryTestChanged, 1766 NICID: entryTestNICID, 1767 Entry: NeighborEntry{ 1768 Addr: entryTestAddr1, 1769 LinkAddr: entryTestLinkAddr1, 1770 State: Probe, 1771 UpdatedAt: clock.Now(), 1772 }, 1773 }, 1774 } 1775 { 1776 nudDisp.mu.Lock() 1777 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 1778 nudDisp.mu.events = nil 1779 nudDisp.mu.Unlock() 1780 if diff != "" { 1781 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1782 } 1783 } 1784 1785 return nil 1786 } 1787 1788 func TestEntryProbeToStaleWhenProbeWithDifferentAddress(t *testing.T) { 1789 c := DefaultNUDConfigurations() 1790 e, nudDisp, linkRes, clock := entryTestSetup(c) 1791 1792 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1793 t.Fatalf("unknownToStale(...) = %s", err) 1794 } 1795 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1796 t.Fatalf("staleToDelay(...) = %s", err) 1797 } 1798 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 1799 t.Fatalf("delayToProbe(...) = %s", err) 1800 } 1801 1802 e.mu.Lock() 1803 e.handleProbeLocked(entryTestLinkAddr2) 1804 if e.mu.neigh.State != Stale { 1805 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1806 } 1807 e.mu.Unlock() 1808 1809 // No probes should have been sent. 1810 runImmediatelyScheduledJobs(clock) 1811 { 1812 linkRes.mu.Lock() 1813 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1814 linkRes.mu.Unlock() 1815 if diff != "" { 1816 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1817 } 1818 } 1819 1820 wantEvents := []testEntryEventInfo{ 1821 { 1822 EventType: entryTestChanged, 1823 NICID: entryTestNICID, 1824 Entry: NeighborEntry{ 1825 Addr: entryTestAddr1, 1826 LinkAddr: entryTestLinkAddr2, 1827 State: Stale, 1828 UpdatedAt: clock.Now(), 1829 }, 1830 }, 1831 } 1832 nudDisp.mu.Lock() 1833 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1834 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1835 } 1836 nudDisp.mu.Unlock() 1837 } 1838 1839 func TestEntryProbeToStaleWhenConfirmationWithDifferentAddress(t *testing.T) { 1840 c := DefaultNUDConfigurations() 1841 e, nudDisp, linkRes, clock := entryTestSetup(c) 1842 1843 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1844 t.Fatalf("unknownToStale(...) = %s", err) 1845 } 1846 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1847 t.Fatalf("staleToDelay(...) = %s", err) 1848 } 1849 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 1850 t.Fatalf("delayToProbe(...) = %s", err) 1851 } 1852 1853 e.mu.Lock() 1854 e.handleConfirmationLocked(entryTestLinkAddr2, ReachabilityConfirmationFlags{ 1855 Solicited: false, 1856 Override: true, 1857 IsRouter: false, 1858 }) 1859 if e.mu.neigh.State != Stale { 1860 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Stale) 1861 } 1862 e.mu.Unlock() 1863 1864 // No probes should have been sent. 1865 runImmediatelyScheduledJobs(clock) 1866 { 1867 linkRes.mu.Lock() 1868 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1869 linkRes.mu.Unlock() 1870 if diff != "" { 1871 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1872 } 1873 } 1874 1875 wantEvents := []testEntryEventInfo{ 1876 { 1877 EventType: entryTestChanged, 1878 NICID: entryTestNICID, 1879 Entry: NeighborEntry{ 1880 Addr: entryTestAddr1, 1881 LinkAddr: entryTestLinkAddr2, 1882 State: Stale, 1883 UpdatedAt: clock.Now(), 1884 }, 1885 }, 1886 } 1887 nudDisp.mu.Lock() 1888 if diff := cmp.Diff(wantEvents, nudDisp.mu.events); diff != "" { 1889 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1890 } 1891 nudDisp.mu.Unlock() 1892 } 1893 1894 func TestEntryProbeToProbeWhenOverrideConfirmationWithSameAddress(t *testing.T) { 1895 c := DefaultNUDConfigurations() 1896 e, nudDisp, linkRes, clock := entryTestSetup(c) 1897 1898 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1899 t.Fatalf("unknownToStale(...) = %s", err) 1900 } 1901 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1902 t.Fatalf("staleToDelay(...) = %s", err) 1903 } 1904 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 1905 t.Fatalf("delayToProbe(...) = %s", err) 1906 } 1907 1908 e.mu.Lock() 1909 e.handleConfirmationLocked(entryTestLinkAddr1, ReachabilityConfirmationFlags{ 1910 Solicited: false, 1911 Override: true, 1912 IsRouter: false, 1913 }) 1914 if e.mu.neigh.State != Probe { 1915 t.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Probe) 1916 } 1917 if got, want := e.mu.neigh.LinkAddr, entryTestLinkAddr1; got != want { 1918 t.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", got, want) 1919 } 1920 e.mu.Unlock() 1921 1922 // No probes should have been sent. 1923 runImmediatelyScheduledJobs(clock) 1924 { 1925 linkRes.mu.Lock() 1926 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1927 linkRes.mu.Unlock() 1928 if diff != "" { 1929 t.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1930 } 1931 } 1932 1933 // No events should have been dispatched. 1934 nudDisp.mu.Lock() 1935 diff := cmp.Diff([]testEntryEventInfo(nil), nudDisp.mu.events) 1936 nudDisp.mu.Unlock() 1937 if diff != "" { 1938 t.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 1939 } 1940 } 1941 1942 func TestEntryProbeToReachableWhenSolicitedOverrideConfirmation(t *testing.T) { 1943 c := DefaultNUDConfigurations() 1944 e, nudDisp, linkRes, clock := entryTestSetup(c) 1945 1946 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 1947 t.Fatalf("unknownToStale(...) = %s", err) 1948 } 1949 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 1950 t.Fatalf("staleToDelay(...) = %s", err) 1951 } 1952 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 1953 t.Fatalf("delayToProbe(...) = %s", err) 1954 } 1955 if err := probeToReachableWithOverride(e, nudDisp, linkRes, clock, entryTestLinkAddr2); err != nil { 1956 t.Fatalf("probeToReachableWithOverride(...) = %s", err) 1957 } 1958 } 1959 1960 func probeToReachableWithFlags(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock, linkAddr tcpip.LinkAddress, flags ReachabilityConfirmationFlags) error { 1961 if err := func() error { 1962 e.mu.Lock() 1963 defer e.mu.Unlock() 1964 1965 prevLinkAddr := e.mu.neigh.LinkAddr 1966 if e.mu.neigh.State != Probe { 1967 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Probe) 1968 } 1969 e.handleConfirmationLocked(linkAddr, flags) 1970 1971 if e.mu.neigh.State != Reachable { 1972 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Reachable) 1973 } 1974 if linkAddr == "" { 1975 linkAddr = prevLinkAddr 1976 } 1977 if e.mu.neigh.LinkAddr != linkAddr { 1978 return fmt.Errorf("got e.mu.neigh.LinkAddr = %q, want = %q", e.mu.neigh.LinkAddr, linkAddr) 1979 } 1980 return nil 1981 }(); err != nil { 1982 return err 1983 } 1984 1985 // No probes should have been sent. 1986 runImmediatelyScheduledJobs(clock) 1987 { 1988 linkRes.mu.Lock() 1989 diff := cmp.Diff([]entryTestProbeInfo(nil), linkRes.mu.probes) 1990 linkRes.mu.Unlock() 1991 if diff != "" { 1992 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 1993 } 1994 } 1995 1996 wantEvents := []testEntryEventInfo{ 1997 { 1998 EventType: entryTestChanged, 1999 NICID: entryTestNICID, 2000 Entry: NeighborEntry{ 2001 Addr: entryTestAddr1, 2002 LinkAddr: linkAddr, 2003 State: Reachable, 2004 UpdatedAt: clock.Now(), 2005 }, 2006 }, 2007 } 2008 { 2009 nudDisp.mu.Lock() 2010 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 2011 nudDisp.mu.events = nil 2012 nudDisp.mu.Unlock() 2013 if diff != "" { 2014 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 2015 } 2016 } 2017 2018 return nil 2019 } 2020 2021 func probeToReachableWithOverride(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock, linkAddr tcpip.LinkAddress) error { 2022 return probeToReachableWithFlags(e, nudDisp, linkRes, clock, linkAddr, ReachabilityConfirmationFlags{ 2023 Solicited: true, 2024 Override: true, 2025 IsRouter: false, 2026 }) 2027 } 2028 2029 func TestEntryProbeToReachableWhenSolicitedConfirmationWithSameAddress(t *testing.T) { 2030 c := DefaultNUDConfigurations() 2031 e, nudDisp, linkRes, clock := entryTestSetup(c) 2032 2033 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 2034 t.Fatalf("unknownToStale(...) = %s", err) 2035 } 2036 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 2037 t.Fatalf("staleToDelay(...) = %s", err) 2038 } 2039 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 2040 t.Fatalf("delayToProbe(...) = %s", err) 2041 } 2042 if err := probeToReachable(e, nudDisp, linkRes, clock); err != nil { 2043 t.Fatalf("probeToReachable(...) = %s", err) 2044 } 2045 } 2046 2047 func probeToReachable(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 2048 return probeToReachableWithFlags(e, nudDisp, linkRes, clock, entryTestLinkAddr1, ReachabilityConfirmationFlags{ 2049 Solicited: true, 2050 Override: false, 2051 IsRouter: false, 2052 }) 2053 } 2054 2055 func TestEntryProbeToReachableWhenSolicitedConfirmationWithoutAddress(t *testing.T) { 2056 c := DefaultNUDConfigurations() 2057 e, nudDisp, linkRes, clock := entryTestSetup(c) 2058 2059 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 2060 t.Fatalf("unknownToStale(...) = %s", err) 2061 } 2062 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 2063 t.Fatalf("staleToDelay(...) = %s", err) 2064 } 2065 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 2066 t.Fatalf("delayToProbe(...) = %s", err) 2067 } 2068 if err := probeToReachableWithoutAddress(e, nudDisp, linkRes, clock); err != nil { 2069 t.Fatalf("probeToReachableWithoutAddress(...) = %s", err) 2070 } 2071 } 2072 2073 func probeToReachableWithoutAddress(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 2074 return probeToReachableWithFlags(e, nudDisp, linkRes, clock, "" /* linkAddr */, ReachabilityConfirmationFlags{ 2075 Solicited: true, 2076 Override: false, 2077 IsRouter: false, 2078 }) 2079 } 2080 2081 func TestEntryProbeToUnreachable(t *testing.T) { 2082 c := DefaultNUDConfigurations() 2083 c.MaxMulticastProbes = 3 2084 c.MaxUnicastProbes = 3 2085 c.DelayFirstProbeTime = c.RetransmitTimer 2086 e, nudDisp, linkRes, clock := entryTestSetup(c) 2087 2088 if err := unknownToStale(e, nudDisp, linkRes, clock); err != nil { 2089 t.Fatalf("unknownToStale(...) = %s", err) 2090 } 2091 if err := staleToDelay(e, nudDisp, linkRes, clock); err != nil { 2092 t.Fatalf("staleToDelay(...) = %s", err) 2093 } 2094 if err := delayToProbe(c, e, nudDisp, linkRes, clock); err != nil { 2095 t.Fatalf("delayToProbe(...) = %s", err) 2096 } 2097 if err := probeToUnreachable(c, e, nudDisp, linkRes, clock); err != nil { 2098 t.Fatalf("probeToUnreachable(...) = %s", err) 2099 } 2100 } 2101 2102 func probeToUnreachable(c NUDConfigurations, e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 2103 { 2104 e.mu.Lock() 2105 state := e.mu.neigh.State 2106 e.mu.Unlock() 2107 if state != Probe { 2108 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Probe) 2109 } 2110 } 2111 2112 // The first probe was sent in the transition from Delay to Probe. 2113 clock.Advance(c.RetransmitTimer) 2114 2115 // Observe each subsequent unicast probe transmitted. 2116 for i := uint32(1); i < c.MaxUnicastProbes; i++ { 2117 wantProbes := []entryTestProbeInfo{{ 2118 RemoteAddress: entryTestAddr1, 2119 RemoteLinkAddress: entryTestLinkAddr1, 2120 }} 2121 linkRes.mu.Lock() 2122 diff := cmp.Diff(wantProbes, linkRes.mu.probes) 2123 linkRes.mu.probes = nil 2124 linkRes.mu.Unlock() 2125 if diff != "" { 2126 return fmt.Errorf("link address resolver probe #%d mismatch (-want, +got):\n%s", i+1, diff) 2127 } 2128 2129 e.mu.Lock() 2130 state := e.mu.neigh.State 2131 e.mu.Unlock() 2132 if state != Probe { 2133 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Probe) 2134 } 2135 2136 clock.Advance(c.RetransmitTimer) 2137 } 2138 2139 { 2140 e.mu.Lock() 2141 state := e.mu.neigh.State 2142 e.mu.Unlock() 2143 if state != Unreachable { 2144 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", state, Unreachable) 2145 } 2146 } 2147 2148 wantEvents := []testEntryEventInfo{ 2149 { 2150 EventType: entryTestChanged, 2151 NICID: entryTestNICID, 2152 Entry: NeighborEntry{ 2153 Addr: entryTestAddr1, 2154 LinkAddr: entryTestLinkAddr1, 2155 State: Unreachable, 2156 UpdatedAt: clock.Now(), 2157 }, 2158 }, 2159 } 2160 nudDisp.mu.Lock() 2161 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 2162 nudDisp.mu.events = nil 2163 nudDisp.mu.Unlock() 2164 if diff != "" { 2165 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 2166 } 2167 2168 return nil 2169 } 2170 2171 func TestEntryUnreachableToIncomplete(t *testing.T) { 2172 c := DefaultNUDConfigurations() 2173 c.MaxMulticastProbes = 3 2174 e, nudDisp, linkRes, clock := entryTestSetup(c) 2175 2176 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 2177 t.Fatalf("unknownToIncomplete(...) = %s", err) 2178 } 2179 if err := incompleteToUnreachable(c, e, nudDisp, linkRes, clock); err != nil { 2180 t.Fatalf("incompleteToUnreachable(...) = %s", err) 2181 } 2182 if err := unreachableToIncomplete(e, nudDisp, linkRes, clock); err != nil { 2183 t.Fatalf("unreachableToIncomplete(...) = %s", err) 2184 } 2185 } 2186 2187 func unreachableToIncomplete(e *neighborEntry, nudDisp *testNUDDispatcher, linkRes *entryTestLinkResolver, clock *faketime.ManualClock) error { 2188 if err := func() error { 2189 e.mu.Lock() 2190 defer e.mu.Unlock() 2191 2192 if e.mu.neigh.State != Unreachable { 2193 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Unreachable) 2194 } 2195 e.handlePacketQueuedLocked(entryTestAddr2) 2196 if e.mu.neigh.State != Incomplete { 2197 return fmt.Errorf("got e.mu.neigh.State = %q, want = %q", e.mu.neigh.State, Incomplete) 2198 } 2199 return nil 2200 }(); err != nil { 2201 return err 2202 } 2203 2204 runImmediatelyScheduledJobs(clock) 2205 wantProbes := []entryTestProbeInfo{ 2206 { 2207 RemoteAddress: entryTestAddr1, 2208 RemoteLinkAddress: tcpip.LinkAddress(""), 2209 LocalAddress: entryTestAddr2, 2210 }, 2211 } 2212 linkRes.mu.Lock() 2213 diff := cmp.Diff(wantProbes, linkRes.mu.probes) 2214 linkRes.mu.probes = nil 2215 linkRes.mu.Unlock() 2216 if diff != "" { 2217 return fmt.Errorf("link address resolver probes mismatch (-want, +got):\n%s", diff) 2218 } 2219 2220 wantEvents := []testEntryEventInfo{ 2221 { 2222 EventType: entryTestChanged, 2223 NICID: entryTestNICID, 2224 Entry: NeighborEntry{ 2225 Addr: entryTestAddr1, 2226 LinkAddr: tcpip.LinkAddress(""), 2227 State: Incomplete, 2228 UpdatedAt: clock.Now(), 2229 }, 2230 }, 2231 } 2232 { 2233 nudDisp.mu.Lock() 2234 diff := cmp.Diff(wantEvents, nudDisp.mu.events) 2235 nudDisp.mu.events = nil 2236 nudDisp.mu.Unlock() 2237 if diff != "" { 2238 return fmt.Errorf("nud dispatcher events mismatch (-want, +got):\n%s", diff) 2239 } 2240 } 2241 return nil 2242 } 2243 2244 func TestEntryUnreachableToStale(t *testing.T) { 2245 c := DefaultNUDConfigurations() 2246 c.MaxMulticastProbes = 3 2247 // Eliminate random factors from ReachableTime computation so the transition 2248 // from Stale to Reachable will only take BaseReachableTime duration. 2249 c.MinRandomFactor = 1 2250 c.MaxRandomFactor = 1 2251 2252 e, nudDisp, linkRes, clock := entryTestSetup(c) 2253 2254 if err := unknownToIncomplete(e, nudDisp, linkRes, clock); err != nil { 2255 t.Fatalf("unknownToIncomplete(...) = %s", err) 2256 } 2257 if err := incompleteToUnreachable(c, e, nudDisp, linkRes, clock); err != nil { 2258 t.Fatalf("incompleteToUnreachable(...) = %s", err) 2259 } 2260 if err := unreachableToIncomplete(e, nudDisp, linkRes, clock); err != nil { 2261 t.Fatalf("unreachableToIncomplete(...) = %s", err) 2262 } 2263 if err := incompleteToReachable(e, nudDisp, linkRes, clock); err != nil { 2264 t.Fatalf("incompleteToReachable(...) = %s", err) 2265 } 2266 if err := reachableToStale(c, e, nudDisp, linkRes, clock); err != nil { 2267 t.Fatalf("reachableToStale(...) = %s", err) 2268 } 2269 }