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