github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/tcpip/link/sharedmem/queue/queue_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package queue
    16  
    17  import (
    18  	"encoding/binary"
    19  	"reflect"
    20  	"testing"
    21  
    22  	"github.com/SagerNet/gvisor/pkg/tcpip/link/sharedmem/pipe"
    23  )
    24  
    25  func TestBasicTxQueue(t *testing.T) {
    26  	// Tests that a basic transmit on a queue works, and that completion
    27  	// gets properly reported as well.
    28  	pb1 := make([]byte, 100)
    29  	pb2 := make([]byte, 100)
    30  
    31  	var rxp pipe.Rx
    32  	rxp.Init(pb1)
    33  
    34  	var txp pipe.Tx
    35  	txp.Init(pb2)
    36  
    37  	var q Tx
    38  	q.Init(pb1, pb2)
    39  
    40  	// Enqueue two buffers.
    41  	b := []TxBuffer{
    42  		{nil, 100, 60},
    43  		{nil, 200, 40},
    44  	}
    45  
    46  	b[0].Next = &b[1]
    47  
    48  	const usedID = 1002
    49  	const usedTotalSize = 100
    50  	if !q.Enqueue(usedID, usedTotalSize, 2, &b[0]) {
    51  		t.Fatalf("Enqueue failed on empty queue")
    52  	}
    53  
    54  	// Check the contents of the pipe.
    55  	d := rxp.Pull()
    56  	if d == nil {
    57  		t.Fatalf("Tx pipe is empty after Enqueue")
    58  	}
    59  
    60  	want := []byte{
    61  		234, 3, 0, 0, 0, 0, 0, 0, // id
    62  		100, 0, 0, 0, // total size
    63  		0, 0, 0, 0, // reserved
    64  		100, 0, 0, 0, 0, 0, 0, 0, // offset 1
    65  		60, 0, 0, 0, // size 1
    66  		200, 0, 0, 0, 0, 0, 0, 0, // offset 2
    67  		40, 0, 0, 0, // size 2
    68  	}
    69  
    70  	if !reflect.DeepEqual(want, d) {
    71  		t.Fatalf("Bad posted packet: got %v, want %v", d, want)
    72  	}
    73  
    74  	rxp.Flush()
    75  
    76  	// Check that there are no completions yet.
    77  	if _, ok := q.CompletedPacket(); ok {
    78  		t.Fatalf("Packet reported as completed too soon")
    79  	}
    80  
    81  	// Post a completion.
    82  	d = txp.Push(8)
    83  	if d == nil {
    84  		t.Fatalf("Unable to push to rx pipe")
    85  	}
    86  	binary.LittleEndian.PutUint64(d, usedID)
    87  	txp.Flush()
    88  
    89  	// Check that completion is properly reported.
    90  	id, ok := q.CompletedPacket()
    91  	if !ok {
    92  		t.Fatalf("Completion not reported")
    93  	}
    94  
    95  	if id != usedID {
    96  		t.Fatalf("Bad completion id: got %v, want %v", id, usedID)
    97  	}
    98  }
    99  
   100  func TestBasicRxQueue(t *testing.T) {
   101  	// Tests that a basic receive on a queue works.
   102  	pb1 := make([]byte, 100)
   103  	pb2 := make([]byte, 100)
   104  
   105  	var rxp pipe.Rx
   106  	rxp.Init(pb1)
   107  
   108  	var txp pipe.Tx
   109  	txp.Init(pb2)
   110  
   111  	var q Rx
   112  	q.Init(pb1, pb2, nil)
   113  
   114  	// Post two buffers.
   115  	b := []RxBuffer{
   116  		{100, 60, 1077, 0},
   117  		{200, 40, 2123, 0},
   118  	}
   119  
   120  	if !q.PostBuffers(b) {
   121  		t.Fatalf("PostBuffers failed on empty queue")
   122  	}
   123  
   124  	// Check the contents of the pipe.
   125  	want := [][]byte{
   126  		{
   127  			100, 0, 0, 0, 0, 0, 0, 0, // Offset1
   128  			60, 0, 0, 0, // Size1
   129  			0, 0, 0, 0, // Remaining in group 1
   130  			0, 0, 0, 0, 0, 0, 0, 0, // User data 1
   131  			53, 4, 0, 0, 0, 0, 0, 0, // ID 1
   132  		},
   133  		{
   134  			200, 0, 0, 0, 0, 0, 0, 0, // Offset2
   135  			40, 0, 0, 0, // Size2
   136  			0, 0, 0, 0, // Remaining in group 2
   137  			0, 0, 0, 0, 0, 0, 0, 0, // User data 2
   138  			75, 8, 0, 0, 0, 0, 0, 0, // ID 2
   139  		},
   140  	}
   141  
   142  	for i := range b {
   143  		d := rxp.Pull()
   144  		if d == nil {
   145  			t.Fatalf("Tx pipe is empty after PostBuffers")
   146  		}
   147  
   148  		if !reflect.DeepEqual(want[i], d) {
   149  			t.Fatalf("Bad posted packet: got %v, want %v", d, want[i])
   150  		}
   151  
   152  		rxp.Flush()
   153  	}
   154  
   155  	// Check that there are no completions.
   156  	if _, n := q.Dequeue(nil); n != 0 {
   157  		t.Fatalf("Packet reported as received too soon")
   158  	}
   159  
   160  	// Post a completion.
   161  	d := txp.Push(sizeOfConsumedPacketHeader + 2*sizeOfConsumedBuffer)
   162  	if d == nil {
   163  		t.Fatalf("Unable to push to rx pipe")
   164  	}
   165  
   166  	copy(d, []byte{
   167  		100, 0, 0, 0, // packet size
   168  		0, 0, 0, 0, // reserved
   169  
   170  		100, 0, 0, 0, 0, 0, 0, 0, // offset 1
   171  		60, 0, 0, 0, // size 1
   172  		0, 0, 0, 0, 0, 0, 0, 0, // user data 1
   173  		53, 4, 0, 0, 0, 0, 0, 0, // ID 1
   174  
   175  		200, 0, 0, 0, 0, 0, 0, 0, // offset 2
   176  		40, 0, 0, 0, // size 2
   177  		0, 0, 0, 0, 0, 0, 0, 0, // user data 2
   178  		75, 8, 0, 0, 0, 0, 0, 0, // ID 2
   179  	})
   180  
   181  	txp.Flush()
   182  
   183  	// Check that completion is properly reported.
   184  	bufs, n := q.Dequeue(nil)
   185  	if n != 100 {
   186  		t.Fatalf("Bad packet size: got %v, want %v", n, 100)
   187  	}
   188  
   189  	if !reflect.DeepEqual(bufs, b) {
   190  		t.Fatalf("Bad returned buffers: got %v, want %v", bufs, b)
   191  	}
   192  }
   193  
   194  func TestBadTxCompletion(t *testing.T) {
   195  	// Check that tx completions with bad sizes are properly ignored.
   196  	pb1 := make([]byte, 100)
   197  	pb2 := make([]byte, 100)
   198  
   199  	var rxp pipe.Rx
   200  	rxp.Init(pb1)
   201  
   202  	var txp pipe.Tx
   203  	txp.Init(pb2)
   204  
   205  	var q Tx
   206  	q.Init(pb1, pb2)
   207  
   208  	// Post a completion that is too short, and check that it is ignored.
   209  	if d := txp.Push(7); d == nil {
   210  		t.Fatalf("Unable to push to rx pipe")
   211  	}
   212  	txp.Flush()
   213  
   214  	if _, ok := q.CompletedPacket(); ok {
   215  		t.Fatalf("Bad completion not ignored")
   216  	}
   217  
   218  	// Post a completion that is too long, and check that it is ignored.
   219  	if d := txp.Push(10); d == nil {
   220  		t.Fatalf("Unable to push to rx pipe")
   221  	}
   222  	txp.Flush()
   223  
   224  	if _, ok := q.CompletedPacket(); ok {
   225  		t.Fatalf("Bad completion not ignored")
   226  	}
   227  }
   228  
   229  func TestBadRxCompletion(t *testing.T) {
   230  	// Check that bad rx completions are properly ignored.
   231  	pb1 := make([]byte, 100)
   232  	pb2 := make([]byte, 100)
   233  
   234  	var rxp pipe.Rx
   235  	rxp.Init(pb1)
   236  
   237  	var txp pipe.Tx
   238  	txp.Init(pb2)
   239  
   240  	var q Rx
   241  	q.Init(pb1, pb2, nil)
   242  
   243  	// Post a completion that is too short, and check that it is ignored.
   244  	if d := txp.Push(7); d == nil {
   245  		t.Fatalf("Unable to push to rx pipe")
   246  	}
   247  	txp.Flush()
   248  
   249  	if b, _ := q.Dequeue(nil); b != nil {
   250  		t.Fatalf("Bad completion not ignored")
   251  	}
   252  
   253  	// Post a completion whose buffer sizes add up to less than the total
   254  	// size.
   255  	d := txp.Push(sizeOfConsumedPacketHeader + 2*sizeOfConsumedBuffer)
   256  	if d == nil {
   257  		t.Fatalf("Unable to push to rx pipe")
   258  	}
   259  
   260  	copy(d, []byte{
   261  		100, 0, 0, 0, // packet size
   262  		0, 0, 0, 0, // reserved
   263  
   264  		100, 0, 0, 0, 0, 0, 0, 0, // offset 1
   265  		10, 0, 0, 0, // size 1
   266  		0, 0, 0, 0, 0, 0, 0, 0, // user data 1
   267  		53, 4, 0, 0, 0, 0, 0, 0, // ID 1
   268  
   269  		200, 0, 0, 0, 0, 0, 0, 0, // offset 2
   270  		10, 0, 0, 0, // size 2
   271  		0, 0, 0, 0, 0, 0, 0, 0, // user data 2
   272  		75, 8, 0, 0, 0, 0, 0, 0, // ID 2
   273  	})
   274  
   275  	txp.Flush()
   276  	if b, _ := q.Dequeue(nil); b != nil {
   277  		t.Fatalf("Bad completion not ignored")
   278  	}
   279  
   280  	// Post a completion whose buffer sizes will cause a 32-bit overflow,
   281  	// but adds up to the right number.
   282  	d = txp.Push(sizeOfConsumedPacketHeader + 2*sizeOfConsumedBuffer)
   283  	if d == nil {
   284  		t.Fatalf("Unable to push to rx pipe")
   285  	}
   286  
   287  	copy(d, []byte{
   288  		100, 0, 0, 0, // packet size
   289  		0, 0, 0, 0, // reserved
   290  
   291  		100, 0, 0, 0, 0, 0, 0, 0, // offset 1
   292  		255, 255, 255, 255, // size 1
   293  		0, 0, 0, 0, 0, 0, 0, 0, // user data 1
   294  		53, 4, 0, 0, 0, 0, 0, 0, // ID 1
   295  
   296  		200, 0, 0, 0, 0, 0, 0, 0, // offset 2
   297  		101, 0, 0, 0, // size 2
   298  		0, 0, 0, 0, 0, 0, 0, 0, // user data 2
   299  		75, 8, 0, 0, 0, 0, 0, 0, // ID 2
   300  	})
   301  
   302  	txp.Flush()
   303  	if b, _ := q.Dequeue(nil); b != nil {
   304  		t.Fatalf("Bad completion not ignored")
   305  	}
   306  }
   307  
   308  func TestFillTxPipe(t *testing.T) {
   309  	// Check that transmitting a new buffer when the buffer pipe is full
   310  	// fails gracefully.
   311  	pb1 := make([]byte, 104)
   312  	pb2 := make([]byte, 104)
   313  
   314  	var rxp pipe.Rx
   315  	rxp.Init(pb1)
   316  
   317  	var txp pipe.Tx
   318  	txp.Init(pb2)
   319  
   320  	var q Tx
   321  	q.Init(pb1, pb2)
   322  
   323  	// Transmit twice, which should fill the tx pipe.
   324  	b := []TxBuffer{
   325  		{nil, 100, 60},
   326  		{nil, 200, 40},
   327  	}
   328  
   329  	b[0].Next = &b[1]
   330  
   331  	const usedID = 1002
   332  	const usedTotalSize = 100
   333  	for i := uint64(0); i < 2; i++ {
   334  		if !q.Enqueue(usedID+i, usedTotalSize, 2, &b[0]) {
   335  			t.Fatalf("Failed to transmit buffer")
   336  		}
   337  	}
   338  
   339  	// Transmit another packet now that the tx pipe is full.
   340  	if q.Enqueue(usedID+2, usedTotalSize, 2, &b[0]) {
   341  		t.Fatalf("Enqueue succeeded when tx pipe is full")
   342  	}
   343  }
   344  
   345  func TestFillRxPipe(t *testing.T) {
   346  	// Check that posting a new buffer when the buffer pipe is full fails
   347  	// gracefully.
   348  	pb1 := make([]byte, 100)
   349  	pb2 := make([]byte, 100)
   350  
   351  	var rxp pipe.Rx
   352  	rxp.Init(pb1)
   353  
   354  	var txp pipe.Tx
   355  	txp.Init(pb2)
   356  
   357  	var q Rx
   358  	q.Init(pb1, pb2, nil)
   359  
   360  	// Post a buffer twice, it should fill the tx pipe.
   361  	b := []RxBuffer{
   362  		{100, 60, 1077, 0},
   363  	}
   364  
   365  	for i := 0; i < 2; i++ {
   366  		if !q.PostBuffers(b) {
   367  			t.Fatalf("PostBuffers failed on non-full queue")
   368  		}
   369  	}
   370  
   371  	// Post another buffer now that the tx pipe is full.
   372  	if q.PostBuffers(b) {
   373  		t.Fatalf("PostBuffers succeeded on full queue")
   374  	}
   375  }
   376  
   377  func TestLotsOfTransmissions(t *testing.T) {
   378  	// Make sure pipes are being properly flushed when transmitting packets.
   379  	pb1 := make([]byte, 100)
   380  	pb2 := make([]byte, 100)
   381  
   382  	var rxp pipe.Rx
   383  	rxp.Init(pb1)
   384  
   385  	var txp pipe.Tx
   386  	txp.Init(pb2)
   387  
   388  	var q Tx
   389  	q.Init(pb1, pb2)
   390  
   391  	// Prepare packet with two buffers.
   392  	b := []TxBuffer{
   393  		{nil, 100, 60},
   394  		{nil, 200, 40},
   395  	}
   396  
   397  	b[0].Next = &b[1]
   398  
   399  	const usedID = 1002
   400  	const usedTotalSize = 100
   401  
   402  	// Post 100000 packets and completions.
   403  	for i := 100000; i > 0; i-- {
   404  		if !q.Enqueue(usedID, usedTotalSize, 2, &b[0]) {
   405  			t.Fatalf("Enqueue failed on non-full queue")
   406  		}
   407  
   408  		if d := rxp.Pull(); d == nil {
   409  			t.Fatalf("Tx pipe is empty after Enqueue")
   410  		}
   411  		rxp.Flush()
   412  
   413  		d := txp.Push(8)
   414  		if d == nil {
   415  			t.Fatalf("Unable to write to rx pipe")
   416  		}
   417  		binary.LittleEndian.PutUint64(d, usedID)
   418  		txp.Flush()
   419  		if _, ok := q.CompletedPacket(); !ok {
   420  			t.Fatalf("Completion not returned")
   421  		}
   422  	}
   423  }
   424  
   425  func TestLotsOfReceptions(t *testing.T) {
   426  	// Make sure pipes are being properly flushed when receiving packets.
   427  	pb1 := make([]byte, 100)
   428  	pb2 := make([]byte, 100)
   429  
   430  	var rxp pipe.Rx
   431  	rxp.Init(pb1)
   432  
   433  	var txp pipe.Tx
   434  	txp.Init(pb2)
   435  
   436  	var q Rx
   437  	q.Init(pb1, pb2, nil)
   438  
   439  	// Prepare for posting two buffers.
   440  	b := []RxBuffer{
   441  		{100, 60, 1077, 0},
   442  		{200, 40, 2123, 0},
   443  	}
   444  
   445  	// Post 100000 buffers and completions.
   446  	for i := 100000; i > 0; i-- {
   447  		if !q.PostBuffers(b) {
   448  			t.Fatalf("PostBuffers failed on non-full queue")
   449  		}
   450  
   451  		if d := rxp.Pull(); d == nil {
   452  			t.Fatalf("Tx pipe is empty after PostBuffers")
   453  		}
   454  		rxp.Flush()
   455  
   456  		if d := rxp.Pull(); d == nil {
   457  			t.Fatalf("Tx pipe is empty after PostBuffers")
   458  		}
   459  		rxp.Flush()
   460  
   461  		d := txp.Push(sizeOfConsumedPacketHeader + 2*sizeOfConsumedBuffer)
   462  		if d == nil {
   463  			t.Fatalf("Unable to push to rx pipe")
   464  		}
   465  
   466  		copy(d, []byte{
   467  			100, 0, 0, 0, // packet size
   468  			0, 0, 0, 0, // reserved
   469  
   470  			100, 0, 0, 0, 0, 0, 0, 0, // offset 1
   471  			60, 0, 0, 0, // size 1
   472  			0, 0, 0, 0, 0, 0, 0, 0, // user data 1
   473  			53, 4, 0, 0, 0, 0, 0, 0, // ID 1
   474  
   475  			200, 0, 0, 0, 0, 0, 0, 0, // offset 2
   476  			40, 0, 0, 0, // size 2
   477  			0, 0, 0, 0, 0, 0, 0, 0, // user data 2
   478  			75, 8, 0, 0, 0, 0, 0, 0, // ID 2
   479  		})
   480  
   481  		txp.Flush()
   482  
   483  		if _, n := q.Dequeue(nil); n == 0 {
   484  			t.Fatalf("Dequeue failed when there is a completion")
   485  		}
   486  	}
   487  }
   488  
   489  func TestRxEnableNotification(t *testing.T) {
   490  	// Check that enabling nofifications results in properly updated state.
   491  	pb1 := make([]byte, 100)
   492  	pb2 := make([]byte, 100)
   493  
   494  	var state uint32
   495  	var q Rx
   496  	q.Init(pb1, pb2, &state)
   497  
   498  	q.EnableNotification()
   499  	if state != eventFDEnabled {
   500  		t.Fatalf("Bad value in shared state: got %v, want %v", state, eventFDEnabled)
   501  	}
   502  }
   503  
   504  func TestRxDisableNotification(t *testing.T) {
   505  	// Check that disabling nofifications results in properly updated state.
   506  	pb1 := make([]byte, 100)
   507  	pb2 := make([]byte, 100)
   508  
   509  	var state uint32
   510  	var q Rx
   511  	q.Init(pb1, pb2, &state)
   512  
   513  	q.DisableNotification()
   514  	if state != eventFDDisabled {
   515  		t.Fatalf("Bad value in shared state: got %v, want %v", state, eventFDDisabled)
   516  	}
   517  }