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