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  }