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  }