gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/tcpip/link/sharedmem/sharedmem_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 //go:build linux 16 // +build linux 17 18 package sharedmem 19 20 import ( 21 "bytes" 22 "math/rand" 23 "os" 24 "strings" 25 "testing" 26 "time" 27 28 "golang.org/x/sys/unix" 29 "gvisor.dev/gvisor/pkg/buffer" 30 "gvisor.dev/gvisor/pkg/refs" 31 "gvisor.dev/gvisor/pkg/sync" 32 "gvisor.dev/gvisor/pkg/tcpip" 33 "gvisor.dev/gvisor/pkg/tcpip/header" 34 "gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/pipe" 35 "gvisor.dev/gvisor/pkg/tcpip/link/sharedmem/queue" 36 "gvisor.dev/gvisor/pkg/tcpip/stack" 37 ) 38 39 const ( 40 localLinkAddr = "\xde\xad\xbe\xef\x56\x78" 41 remoteLinkAddr = "\xde\xad\xbe\xef\x12\x34" 42 43 queueDataSize = 1024 * 1024 44 queuePipeSize = 4096 45 ) 46 47 type queueBuffers struct { 48 data []byte 49 rx pipe.Tx 50 tx pipe.Rx 51 } 52 53 func initQueue(t *testing.T, q *queueBuffers, c *QueueConfig) { 54 // Prepare tx pipe. 55 b, err := getBuffer(c.TxPipeFD) 56 if err != nil { 57 t.Fatalf("getBuffer failed: %v", err) 58 } 59 q.tx.Init(b) 60 61 // Prepare rx pipe. 62 b, err = getBuffer(c.RxPipeFD) 63 if err != nil { 64 t.Fatalf("getBuffer failed: %v", err) 65 } 66 q.rx.Init(b) 67 68 // Get data slice. 69 q.data, err = getBuffer(c.DataFD) 70 if err != nil { 71 t.Fatalf("getBuffer failed: %v", err) 72 } 73 } 74 75 func (q *queueBuffers) cleanup() { 76 unix.Munmap(q.tx.Bytes()) 77 unix.Munmap(q.rx.Bytes()) 78 unix.Munmap(q.data) 79 } 80 81 type packetInfo struct { 82 proto tcpip.NetworkProtocolNumber 83 data []byte 84 linkHeader []byte 85 } 86 87 type testContext struct { 88 t *testing.T 89 ep *endpoint 90 txCfg QueueConfig 91 rxCfg QueueConfig 92 txq queueBuffers 93 rxq queueBuffers 94 95 packetCh chan struct{} 96 mu sync.Mutex 97 packets []packetInfo 98 } 99 100 func newTestContext(t *testing.T, mtu, bufferSize uint32, addr tcpip.LinkAddress) *testContext { 101 var err error 102 c := &testContext{ 103 t: t, 104 packetCh: make(chan struct{}, 1000000), 105 } 106 c.txCfg, err = createQueueFDs("" /* sharedMemPath */, queueSizes{ 107 dataSize: queueDataSize, 108 txPipeSize: queuePipeSize, 109 rxPipeSize: queuePipeSize, 110 sharedDataSize: 4096, 111 }) 112 if err != nil { 113 t.Fatalf("createQueueFDs for tx failed: %s", err) 114 } 115 c.rxCfg, err = createQueueFDs("" /* sharedMemPath */, queueSizes{ 116 dataSize: queueDataSize, 117 txPipeSize: queuePipeSize, 118 rxPipeSize: queuePipeSize, 119 sharedDataSize: 4096, 120 }) 121 if err != nil { 122 t.Fatalf("createQueueFDs for rx failed: %s", err) 123 } 124 125 initQueue(t, &c.txq, &c.txCfg) 126 initQueue(t, &c.rxq, &c.rxCfg) 127 128 ep, err := New(Options{ 129 MTU: mtu, 130 BufferSize: bufferSize, 131 LinkAddress: addr, 132 TX: c.txCfg, 133 RX: c.rxCfg, 134 PeerFD: -1, 135 }) 136 if err != nil { 137 t.Fatalf("New failed: %v", err) 138 } 139 140 c.ep = ep.(*endpoint) 141 c.ep.Attach(c) 142 143 return c 144 } 145 146 func (c *testContext) DeliverNetworkPacket(proto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { 147 c.mu.Lock() 148 c.packets = append(c.packets, packetInfo{ 149 proto: proto, 150 data: pkt.Data().AsRange().ToSlice(), 151 }) 152 c.mu.Unlock() 153 154 c.packetCh <- struct{}{} 155 } 156 157 func (c *testContext) DeliverLinkPacket(tcpip.NetworkProtocolNumber, *stack.PacketBuffer) { 158 c.t.Fatal("DeliverLinkPacket not implemented") 159 } 160 161 func (c *testContext) cleanup() { 162 c.ep.Close() 163 closeFDs(c.txCfg) 164 closeFDs(c.rxCfg) 165 c.txq.cleanup() 166 c.rxq.cleanup() 167 } 168 169 func (c *testContext) waitForPackets(n int, to <-chan time.Time, errorStr string) { 170 for i := 0; i < n; i++ { 171 select { 172 case <-c.packetCh: 173 case <-to: 174 c.t.Fatalf(errorStr) 175 } 176 } 177 } 178 179 func (c *testContext) pushRxCompletion(size uint32, bs []queue.RxBuffer) { 180 b := c.rxq.rx.Push(queue.RxCompletionSize(len(bs))) 181 queue.EncodeRxCompletion(b, size, 0) 182 for i := range bs { 183 queue.EncodeRxCompletionBuffer(b, i, queue.RxBuffer{ 184 Offset: bs[i].Offset, 185 Size: bs[i].Size, 186 ID: bs[i].ID, 187 }) 188 } 189 } 190 191 func randomFill(b []byte) { 192 for i := range b { 193 b[i] = byte(rand.Intn(256)) 194 } 195 } 196 197 func shuffle(b []int) { 198 for i := len(b) - 1; i >= 0; i-- { 199 j := rand.Intn(i + 1) 200 b[i], b[j] = b[j], b[i] 201 } 202 } 203 204 // TestSimpleSend sends 1000 packets with random header and payload sizes, 205 // then checks that the right payload is received on the shared memory queues. 206 func TestSimpleSend(t *testing.T) { 207 c := newTestContext(t, 20000, 1500, localLinkAddr) 208 defer c.cleanup() 209 210 for iters := 1000; iters > 0; iters-- { 211 func() { 212 hdrLen, dataLen := rand.Intn(10000), rand.Intn(10000) 213 214 // Prepare and send packet. 215 hdrBuf := make([]byte, hdrLen) 216 randomFill(hdrBuf) 217 218 data := make([]byte, dataLen) 219 randomFill(data) 220 221 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 222 ReserveHeaderBytes: hdrLen + int(c.ep.MaxHeaderLength()), 223 Payload: buffer.MakeWithData(data), 224 }) 225 copy(pkt.NetworkHeader().Push(hdrLen), hdrBuf) 226 proto := tcpip.NetworkProtocolNumber(rand.Intn(0x10000)) 227 // Every PacketBuffer must have these set: 228 // See nic.writePacket. 229 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 230 pkt.EgressRoute.LocalLinkAddress = localLinkAddr 231 pkt.NetworkProtocolNumber = proto 232 c.ep.AddHeader(pkt) 233 var pkts stack.PacketBufferList 234 pkts.PushBack(pkt) 235 defer pkts.DecRef() 236 if _, err := c.ep.WritePackets(pkts); err != nil { 237 t.Fatalf("WritePackets failed: %s", err) 238 } 239 240 // Receive packet. 241 desc := c.txq.tx.Pull() 242 pi := queue.DecodeTxPacketHeader(desc) 243 if pi.Reserved != 0 { 244 t.Fatalf("Reserved value is non-zero: 0x%x", pi.Reserved) 245 } 246 contents := make([]byte, 0, pi.Size) 247 for i := 0; i < pi.BufferCount; i++ { 248 bi := queue.DecodeTxBufferHeader(desc, i) 249 contents = append(contents, c.txq.data[bi.Offset:][:bi.Size]...) 250 } 251 c.txq.tx.Flush() 252 253 defer func() { 254 // Tell the endpoint about the completion of the write. 255 b := c.txq.rx.Push(8) 256 queue.EncodeTxCompletion(b, pi.ID) 257 c.txq.rx.Flush() 258 }() 259 260 // Check the ethernet header. 261 ethTemplate := make(header.Ethernet, header.EthernetMinimumSize) 262 ethTemplate.Encode(&header.EthernetFields{ 263 SrcAddr: localLinkAddr, 264 DstAddr: remoteLinkAddr, 265 Type: proto, 266 }) 267 if got := contents[:header.EthernetMinimumSize]; !bytes.Equal(got, []byte(ethTemplate)) { 268 t.Fatalf("Bad ethernet header in packet: got %x, want %x", got, ethTemplate) 269 } 270 271 // Compare contents skipping the ethernet header added by the 272 // endpoint. 273 merged := append(hdrBuf, data...) 274 if uint32(len(contents)) < pi.Size { 275 t.Fatalf("Sum of buffers is less than packet size: %v < %v", len(contents), pi.Size) 276 } 277 contents = contents[:pi.Size][header.EthernetMinimumSize:] 278 279 if !bytes.Equal(contents, merged) { 280 t.Fatalf("Buffers are different: got %x (%v bytes), want %x (%v bytes)", contents, len(contents), merged, len(merged)) 281 } 282 }() 283 } 284 } 285 286 // TestPreserveSrcAddressInSend calls WritePacket once with LocalLinkAddress 287 // set in Route (using much of the same code as TestSimpleSend), then checks 288 // that the encoded ethernet header received includes the correct SrcAddr. 289 func TestPreserveSrcAddressInSend(t *testing.T) { 290 c := newTestContext(t, 20000, 1500, localLinkAddr) 291 defer c.cleanup() 292 293 newLocalLinkAddress := tcpip.LinkAddress(strings.Repeat("0xFE", 6)) 294 295 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 296 // WritePacket panics given a prependable with anything less than 297 // the minimum size of the ethernet header. 298 ReserveHeaderBytes: header.EthernetMinimumSize, 299 }) 300 proto := tcpip.NetworkProtocolNumber(rand.Intn(0x10000)) 301 // Every PacketBuffer must have these set: 302 // See nic.writePacket. 303 pkt.EgressRoute.LocalLinkAddress = newLocalLinkAddress 304 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 305 pkt.NetworkProtocolNumber = proto 306 c.ep.AddHeader(pkt) 307 308 var pkts stack.PacketBufferList 309 defer func() { pkts.DecRef() }() 310 pkts.PushBack(pkt) 311 if _, err := c.ep.WritePackets(pkts); err != nil { 312 t.Fatalf("WritePackets failed: %s", err) 313 } 314 315 // Receive packet. 316 desc := c.txq.tx.Pull() 317 pi := queue.DecodeTxPacketHeader(desc) 318 if pi.Reserved != 0 { 319 t.Fatalf("Reserved value is non-zero: 0x%x", pi.Reserved) 320 } 321 contents := make([]byte, 0, pi.Size) 322 for i := 0; i < pi.BufferCount; i++ { 323 bi := queue.DecodeTxBufferHeader(desc, i) 324 contents = append(contents, c.txq.data[bi.Offset:][:bi.Size]...) 325 } 326 c.txq.tx.Flush() 327 328 defer func() { 329 // Tell the endpoint about the completion of the write. 330 b := c.txq.rx.Push(8) 331 queue.EncodeTxCompletion(b, pi.ID) 332 c.txq.rx.Flush() 333 }() 334 335 // Check that the ethernet header contains the expected SrcAddr. 336 ethTemplate := make(header.Ethernet, header.EthernetMinimumSize) 337 ethTemplate.Encode(&header.EthernetFields{ 338 SrcAddr: newLocalLinkAddress, 339 DstAddr: remoteLinkAddr, 340 Type: proto, 341 }) 342 if got := contents[:header.EthernetMinimumSize]; !bytes.Equal(got, []byte(ethTemplate)) { 343 t.Fatalf("Bad ethernet header in packet: got %x, want %x", got, ethTemplate) 344 } 345 } 346 347 // TestFillTxQueue sends packets until the queue is full. 348 func TestFillTxQueue(t *testing.T) { 349 c := newTestContext(t, 20000, 1500, localLinkAddr) 350 defer c.cleanup() 351 352 buf := make([]byte, 100) 353 354 // Each packet is uses no more than 40 bytes, so write that many packets 355 // until the tx queue if full. 356 // Each packet uses no more than 40 bytes, so write that many packets 357 // until the tx queue if full. 358 ids := make(map[uint64]struct{}) 359 for i := queuePipeSize / 40; i > 0; i-- { 360 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 361 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 362 Payload: buffer.MakeWithData(buf), 363 }) 364 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 365 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 366 c.ep.AddHeader(pkt) 367 368 var pkts stack.PacketBufferList 369 pkts.PushBack(pkt) 370 if _, err := c.ep.WritePackets(pkts); err != nil { 371 pkts.DecRef() 372 t.Fatalf("WritePackets failed unexpectedly: %s", err) 373 } 374 pkts.DecRef() 375 376 // Check that they have different IDs. 377 desc := c.txq.tx.Pull() 378 pi := queue.DecodeTxPacketHeader(desc) 379 if _, ok := ids[pi.ID]; ok { 380 t.Fatalf("ID (%v) reused", pi.ID) 381 } 382 ids[pi.ID] = struct{}{} 383 } 384 385 // Next attempt to write must fail. 386 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 387 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 388 Payload: buffer.MakeWithData(buf), 389 }) 390 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 391 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 392 c.ep.AddHeader(pkt) 393 394 var pkts stack.PacketBufferList 395 pkts.PushBack(pkt) 396 _, err := c.ep.WritePackets(pkts) 397 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 398 t.Fatalf("got WritePackets(...) = %s, want %s", err, &tcpip.ErrWouldBlock{}) 399 } 400 pkts.DecRef() 401 } 402 403 // TestFillTxQueueAfterBadCompletion sends a bad completion, then sends packets 404 // until the queue is full. 405 func TestFillTxQueueAfterBadCompletion(t *testing.T) { 406 c := newTestContext(t, 20000, 1500, localLinkAddr) 407 defer c.cleanup() 408 409 // Send a bad completion. 410 queue.EncodeTxCompletion(c.txq.rx.Push(8), 1) 411 c.txq.rx.Flush() 412 413 buf := make([]byte, 100) 414 415 // Send two packets so that the id slice has at least two slots. 416 { 417 var pkts stack.PacketBufferList 418 for i := 2; i > 0; i-- { 419 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 420 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 421 Payload: buffer.MakeWithData(buf), 422 }) 423 pkts.PushBack(pkt) 424 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 425 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 426 c.ep.AddHeader(pkt) 427 } 428 if _, err := c.ep.WritePackets(pkts); err != nil { 429 t.Fatalf("WritePackets failed unexpectedly: %s", err) 430 } 431 pkts.DecRef() 432 } 433 434 // Complete the two writes twice. 435 for i := 2; i > 0; i-- { 436 pi := queue.DecodeTxPacketHeader(c.txq.tx.Pull()) 437 438 queue.EncodeTxCompletion(c.txq.rx.Push(8), pi.ID) 439 queue.EncodeTxCompletion(c.txq.rx.Push(8), pi.ID) 440 c.txq.rx.Flush() 441 } 442 c.txq.tx.Flush() 443 444 // Each packet is uses no more than 40 bytes, so write that many packets 445 // until the tx queue if full. 446 ids := make(map[uint64]struct{}) 447 for i := queuePipeSize / 40; i > 0; i-- { 448 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 449 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 450 Payload: buffer.MakeWithData(buf), 451 }) 452 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 453 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 454 c.ep.AddHeader(pkt) 455 456 var pkts stack.PacketBufferList 457 pkts.PushBack(pkt) 458 if _, err := c.ep.WritePackets(pkts); err != nil { 459 t.Fatalf("WritePackets failed unexpectedly: %s", err) 460 } 461 pkts.DecRef() 462 463 // Check that they have different IDs. 464 desc := c.txq.tx.Pull() 465 pi := queue.DecodeTxPacketHeader(desc) 466 if _, ok := ids[pi.ID]; ok { 467 t.Fatalf("ID (%v) reused", pi.ID) 468 } 469 ids[pi.ID] = struct{}{} 470 } 471 472 // Next attempt to write must fail. 473 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 474 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 475 Payload: buffer.MakeWithData(buf), 476 }) 477 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 478 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 479 c.ep.AddHeader(pkt) 480 481 var pkts stack.PacketBufferList 482 pkts.PushBack(pkt) 483 _, err := c.ep.WritePackets(pkts) 484 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 485 t.Fatalf("got WritePackets(...) = %s, want %s", err, &tcpip.ErrWouldBlock{}) 486 } 487 pkts.DecRef() 488 } 489 490 // TestFillTxMemory sends packets until the we run out of shared memory. 491 func TestFillTxMemory(t *testing.T) { 492 const bufferSize = 1500 493 c := newTestContext(t, 20000, bufferSize, localLinkAddr) 494 defer c.cleanup() 495 496 buf := make([]byte, 100) 497 498 // Each packet is uses up one buffer, so write as many as possible until 499 // we fill the memory. 500 ids := make(map[uint64]struct{}) 501 for i := queueDataSize / bufferSize; i > 0; i-- { 502 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 503 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 504 Payload: buffer.MakeWithData(buf), 505 }) 506 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 507 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 508 c.ep.AddHeader(pkt) 509 510 var pkts stack.PacketBufferList 511 pkts.PushBack(pkt) 512 if _, err := c.ep.WritePackets(pkts); err != nil { 513 t.Fatalf("WritePackets failed unexpectedly: %s", err) 514 } 515 pkts.DecRef() 516 517 // Check that they have different IDs. 518 desc := c.txq.tx.Pull() 519 pi := queue.DecodeTxPacketHeader(desc) 520 if _, ok := ids[pi.ID]; ok { 521 t.Fatalf("ID (%v) reused", pi.ID) 522 } 523 ids[pi.ID] = struct{}{} 524 c.txq.tx.Flush() 525 } 526 527 // Next attempt to write must fail. 528 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 529 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 530 Payload: buffer.MakeWithData(buf), 531 }) 532 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 533 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 534 var pkts stack.PacketBufferList 535 pkts.PushBack(pkt) 536 _, err := c.ep.WritePackets(pkts) 537 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 538 t.Fatalf("got WritePackets(...) = %s, want %s", err, &tcpip.ErrWouldBlock{}) 539 } 540 pkts.DecRef() 541 } 542 543 // TestFillTxMemoryWithMultiBuffer sends packets until the we run out of 544 // shared memory for a 2-buffer packet, but still with room for a 1-buffer 545 // packet. 546 func TestFillTxMemoryWithMultiBuffer(t *testing.T) { 547 const bufferSize = 1500 548 c := newTestContext(t, 20000, bufferSize, localLinkAddr) 549 defer c.cleanup() 550 551 buf := make([]byte, 100) 552 553 // Each packet is uses up one buffer, so write as many as possible 554 // until there is only one buffer left. 555 for i := queueDataSize/bufferSize - 1; i > 0; i-- { 556 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 557 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 558 Payload: buffer.MakeWithData(buf), 559 }) 560 var pkts stack.PacketBufferList 561 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 562 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 563 pkts.PushBack(pkt) 564 if _, err := c.ep.WritePackets(pkts); err != nil { 565 t.Fatalf("WritePackets failed unexpectedly: %s", err) 566 } 567 pkts.DecRef() 568 569 // Pull the posted buffer. 570 c.txq.tx.Pull() 571 c.txq.tx.Flush() 572 } 573 574 // Attempt to write a two-buffer packet. It must fail. 575 { 576 var pkts stack.PacketBufferList 577 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 578 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 579 Payload: buffer.MakeWithData(make([]byte, bufferSize)), 580 }) 581 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 582 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 583 c.ep.AddHeader(pkt) 584 585 pkts.PushBack(pkt) 586 _, err := c.ep.WritePackets(pkts) 587 if _, ok := err.(*tcpip.ErrWouldBlock); !ok { 588 t.Fatalf("got WritePackets(...) = %s, want %s", err, &tcpip.ErrWouldBlock{}) 589 } 590 pkts.DecRef() 591 } 592 593 // Attempt to write the one-buffer packet again. It must succeed. 594 { 595 var pkts stack.PacketBufferList 596 pkt := stack.NewPacketBuffer(stack.PacketBufferOptions{ 597 ReserveHeaderBytes: int(c.ep.MaxHeaderLength()), 598 Payload: buffer.MakeWithData(buf), 599 }) 600 pkt.EgressRoute.RemoteLinkAddress = remoteLinkAddr 601 pkt.NetworkProtocolNumber = header.IPv4ProtocolNumber 602 pkts.PushBack(pkt) 603 if _, err := c.ep.WritePackets(pkts); err != nil { 604 t.Fatalf("WritePackets failed unexpectedly: %s", err) 605 } 606 pkts.DecRef() 607 } 608 } 609 610 func pollPull(t *testing.T, p *pipe.Rx, to <-chan time.Time, errStr string) []byte { 611 t.Helper() 612 613 for { 614 b := p.Pull() 615 if b != nil { 616 return b 617 } 618 619 select { 620 case <-time.After(10 * time.Millisecond): 621 case <-to: 622 t.Fatal(errStr) 623 } 624 } 625 } 626 627 // TestSimpleReceive completes 1000 different receives with random payload and 628 // random number of buffers. It checks that the contents match the expected 629 // values. 630 func TestSimpleReceive(t *testing.T) { 631 const bufferSize = 1500 632 c := newTestContext(t, 20000, bufferSize, localLinkAddr) 633 defer c.cleanup() 634 635 // Check that buffers have been posted. 636 limit := c.ep.rx.q.PostedBuffersLimit() 637 for i := uint64(0); i < limit; i++ { 638 timeout := time.After(2 * time.Second) 639 bi := queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, timeout, "Timeout waiting for all buffers to be posted")) 640 641 if want := i * bufferSize; want != bi.Offset { 642 t.Fatalf("Bad posted offset: got %v, want %v", bi.Offset, want) 643 } 644 645 if want := i; want != bi.ID { 646 t.Fatalf("Bad posted ID: got %v, want %v", bi.ID, want) 647 } 648 649 if bufferSize != bi.Size { 650 t.Fatalf("Bad posted bufferSize: got %v, want %v", bi.Size, bufferSize) 651 } 652 } 653 c.rxq.tx.Flush() 654 655 // Create a slice with the indices 0..limit-1. 656 idx := make([]int, limit) 657 for i := range idx { 658 idx[i] = i 659 } 660 661 // Complete random packets 1000 times. 662 for iters := 1000; iters > 0; iters-- { 663 timeout := time.After(2 * time.Second) 664 // Prepare a random packet. 665 shuffle(idx) 666 n := 1 + rand.Intn(10) 667 bufs := make([]queue.RxBuffer, n) 668 contents := make([]byte, bufferSize*n-rand.Intn(500)) 669 randomFill(contents) 670 for i := range bufs { 671 j := idx[i] 672 bufs[i].Size = bufferSize 673 bufs[i].Offset = uint64(bufferSize * j) 674 bufs[i].ID = uint64(j) 675 676 copy(c.rxq.data[bufs[i].Offset:][:bufferSize], contents[i*bufferSize:]) 677 } 678 679 // Push completion. 680 c.pushRxCompletion(uint32(len(contents)), bufs) 681 c.rxq.rx.Flush() 682 c.rxCfg.EventFD.Notify() 683 684 // Wait for packet to be received, then check it. 685 c.waitForPackets(1, time.After(5*time.Second), "Timeout waiting for packet") 686 c.mu.Lock() 687 rcvd := []byte(c.packets[0].data) 688 c.packets = c.packets[:0] 689 c.mu.Unlock() 690 691 if contents := contents[header.EthernetMinimumSize:]; !bytes.Equal(contents, rcvd) { 692 t.Fatalf("Unexpected buffer contents: got %x, want %x", rcvd, contents) 693 } 694 695 // Check that buffers have been reposted. 696 for i := range bufs { 697 bi := queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, timeout, "Timeout waiting for buffers to be reposted")) 698 if bi != bufs[i] { 699 t.Fatalf("Unexpected buffer reposted: got %x, want %x", bi, bufs[i]) 700 } 701 } 702 c.rxq.tx.Flush() 703 } 704 } 705 706 // TestRxBuffersReposted tests that rx buffers get reposted after they have been 707 // completed. 708 func TestRxBuffersReposted(t *testing.T) { 709 const bufferSize = 1500 710 c := newTestContext(t, 20000, bufferSize, localLinkAddr) 711 defer c.cleanup() 712 713 // Receive all posted buffers. 714 limit := c.ep.rx.q.PostedBuffersLimit() 715 buffers := make([]queue.RxBuffer, 0, limit) 716 for i := limit; i > 0; i-- { 717 timeout := time.After(2 * time.Second) 718 buffers = append(buffers, queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, timeout, "Timeout waiting for all buffers"))) 719 } 720 c.rxq.tx.Flush() 721 722 // Check that all buffers are reposted when individually completed. 723 for i := range buffers { 724 timeout := time.After(2 * time.Second) 725 // Complete the buffer. 726 c.pushRxCompletion(buffers[i].Size, buffers[i:][:1]) 727 c.rxq.rx.Flush() 728 c.rxCfg.EventFD.Notify() 729 730 // Wait for it to be reposted. 731 bi := queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, timeout, "Timeout waiting for buffer to be reposted")) 732 if bi != buffers[i] { 733 t.Fatalf("Different buffer posted: got %v, want %v", bi, buffers[i]) 734 } 735 } 736 c.rxq.tx.Flush() 737 738 // Check that all buffers are reposted when completed in pairs. 739 for i := 0; i < len(buffers)/2; i++ { 740 timeout := time.After(2 * time.Second) 741 // Complete with two buffers. 742 c.pushRxCompletion(2*bufferSize, buffers[2*i:][:2]) 743 c.rxq.rx.Flush() 744 c.rxCfg.EventFD.Notify() 745 746 // Wait for them to be reposted. 747 for j := 0; j < 2; j++ { 748 bi := queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, timeout, "Timeout waiting for buffer to be reposted")) 749 if bi != buffers[2*i+j] { 750 t.Fatalf("Different buffer posted: got %v, want %v", bi, buffers[2*i+j]) 751 } 752 } 753 } 754 c.rxq.tx.Flush() 755 } 756 757 // TestReceivePostingIsFull checks that the endpoint will properly handle the 758 // case when a received buffer cannot be immediately reposted because it hasn't 759 // been pulled from the tx pipe yet. 760 func TestReceivePostingIsFull(t *testing.T) { 761 const bufferSize = 1500 762 c := newTestContext(t, 20000, bufferSize, localLinkAddr) 763 defer c.cleanup() 764 765 // Complete first posted buffer before flushing it from the tx pipe. 766 first := queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, time.After(time.Second), "Timeout waiting for first buffer to be posted")) 767 c.pushRxCompletion(first.Size, []queue.RxBuffer{first}) 768 c.rxq.rx.Flush() 769 c.rxCfg.EventFD.Notify() 770 771 // Check that packet is received. 772 c.waitForPackets(1, time.After(time.Second), "Timeout waiting for completed packet") 773 774 // Complete another buffer. 775 second := queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, time.After(time.Second), "Timeout waiting for second buffer to be posted")) 776 c.pushRxCompletion(second.Size, []queue.RxBuffer{second}) 777 c.rxq.rx.Flush() 778 c.rxCfg.EventFD.Notify() 779 780 // Check that no packet is received yet, as the worker is blocked trying 781 // to repost. 782 select { 783 case <-time.After(500 * time.Millisecond): 784 case <-c.packetCh: 785 t.Fatalf("Unexpected packet received") 786 } 787 788 // Flush tx queue, which will allow the first buffer to be reposted, 789 // and the second completion to be pulled. 790 c.rxq.tx.Flush() 791 c.rxCfg.EventFD.Notify() 792 793 // Check that second packet completes. 794 c.waitForPackets(1, time.After(time.Second), "Timeout waiting for second completed packet") 795 } 796 797 // TestCloseWhileWaitingToPost closes the endpoint while it is waiting to 798 // repost a buffer. Make sure it backs out. 799 func TestCloseWhileWaitingToPost(t *testing.T) { 800 const bufferSize = 1500 801 c := newTestContext(t, 20000, bufferSize, localLinkAddr) 802 cleaned := false 803 defer func() { 804 if !cleaned { 805 c.cleanup() 806 } 807 }() 808 809 // Complete first posted buffer before flushing it from the tx pipe. 810 bi := queue.DecodeRxBufferHeader(pollPull(t, &c.rxq.tx, time.After(time.Second), "Timeout waiting for initial buffer to be posted")) 811 c.pushRxCompletion(bi.Size, []queue.RxBuffer{bi}) 812 c.rxq.rx.Flush() 813 c.rxCfg.EventFD.Notify() 814 815 // Wait for packet to be indicated. 816 c.waitForPackets(1, time.After(time.Second), "Timeout waiting for completed packet") 817 818 // Cleanup and wait for worker to complete. 819 c.cleanup() 820 cleaned = true 821 c.ep.Wait() 822 } 823 824 func TestMain(m *testing.M) { 825 refs.SetLeakMode(refs.LeaksPanic) 826 code := m.Run() 827 refs.DoLeakCheck() 828 os.Exit(code) 829 }