github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/network/fragmentation/fragmentation_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 fragmentation
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/FlowerWrong/netstack/tcpip/buffer"
    23  )
    24  
    25  // vv is a helper to build VectorisedView from different strings.
    26  func vv(size int, pieces ...string) buffer.VectorisedView {
    27  	views := make([]buffer.View, len(pieces))
    28  	for i, p := range pieces {
    29  		views[i] = []byte(p)
    30  	}
    31  
    32  	return buffer.NewVectorisedView(size, views)
    33  }
    34  
    35  type processInput struct {
    36  	id    uint32
    37  	first uint16
    38  	last  uint16
    39  	more  bool
    40  	vv    buffer.VectorisedView
    41  }
    42  
    43  type processOutput struct {
    44  	vv   buffer.VectorisedView
    45  	done bool
    46  }
    47  
    48  var processTestCases = []struct {
    49  	comment string
    50  	in      []processInput
    51  	out     []processOutput
    52  }{
    53  	{
    54  		comment: "One ID",
    55  		in: []processInput{
    56  			{id: 0, first: 0, last: 1, more: true, vv: vv(2, "01")},
    57  			{id: 0, first: 2, last: 3, more: false, vv: vv(2, "23")},
    58  		},
    59  		out: []processOutput{
    60  			{vv: buffer.VectorisedView{}, done: false},
    61  			{vv: vv(4, "01", "23"), done: true},
    62  		},
    63  	},
    64  	{
    65  		comment: "Two IDs",
    66  		in: []processInput{
    67  			{id: 0, first: 0, last: 1, more: true, vv: vv(2, "01")},
    68  			{id: 1, first: 0, last: 1, more: true, vv: vv(2, "ab")},
    69  			{id: 1, first: 2, last: 3, more: false, vv: vv(2, "cd")},
    70  			{id: 0, first: 2, last: 3, more: false, vv: vv(2, "23")},
    71  		},
    72  		out: []processOutput{
    73  			{vv: buffer.VectorisedView{}, done: false},
    74  			{vv: buffer.VectorisedView{}, done: false},
    75  			{vv: vv(4, "ab", "cd"), done: true},
    76  			{vv: vv(4, "01", "23"), done: true},
    77  		},
    78  	},
    79  }
    80  
    81  func TestFragmentationProcess(t *testing.T) {
    82  	for _, c := range processTestCases {
    83  		t.Run(c.comment, func(t *testing.T) {
    84  			f := NewFragmentation(1024, 512, DefaultReassembleTimeout)
    85  			for i, in := range c.in {
    86  				vv, done := f.Process(in.id, in.first, in.last, in.more, in.vv)
    87  				if !reflect.DeepEqual(vv, c.out[i].vv) {
    88  					t.Errorf("got Process(%d) = %+v, want = %+v", i, vv, c.out[i].vv)
    89  				}
    90  				if done != c.out[i].done {
    91  					t.Errorf("got Process(%d) = %+v, want = %+v", i, done, c.out[i].done)
    92  				}
    93  				if c.out[i].done {
    94  					if _, ok := f.reassemblers[in.id]; ok {
    95  						t.Errorf("Process(%d) did not remove buffer from reassemblers", i)
    96  					}
    97  					for n := f.rList.Front(); n != nil; n = n.Next() {
    98  						if n.id == in.id {
    99  							t.Errorf("Process(%d) did not remove buffer from rList", i)
   100  						}
   101  					}
   102  				}
   103  			}
   104  		})
   105  	}
   106  }
   107  
   108  func TestReassemblingTimeout(t *testing.T) {
   109  	timeout := time.Millisecond
   110  	f := NewFragmentation(1024, 512, timeout)
   111  	// Send first fragment with id = 0, first = 0, last = 0, and more = true.
   112  	f.Process(0, 0, 0, true, vv(1, "0"))
   113  	// Sleep more than the timeout.
   114  	time.Sleep(2 * timeout)
   115  	// Send another fragment that completes a packet.
   116  	// However, no packet should be reassembled because the fragment arrived after the timeout.
   117  	_, done := f.Process(0, 1, 1, false, vv(1, "1"))
   118  	if done {
   119  		t.Errorf("Fragmentation does not respect the reassembling timeout.")
   120  	}
   121  }
   122  
   123  func TestMemoryLimits(t *testing.T) {
   124  	f := NewFragmentation(3, 1, DefaultReassembleTimeout)
   125  	// Send first fragment with id = 0.
   126  	f.Process(0, 0, 0, true, vv(1, "0"))
   127  	// Send first fragment with id = 1.
   128  	f.Process(1, 0, 0, true, vv(1, "1"))
   129  	// Send first fragment with id = 2.
   130  	f.Process(2, 0, 0, true, vv(1, "2"))
   131  
   132  	// Send first fragment with id = 3. This should caused id = 0 and id = 1 to be
   133  	// evicted.
   134  	f.Process(3, 0, 0, true, vv(1, "3"))
   135  
   136  	if _, ok := f.reassemblers[0]; ok {
   137  		t.Errorf("Memory limits are not respected: id=0 has not been evicted.")
   138  	}
   139  	if _, ok := f.reassemblers[1]; ok {
   140  		t.Errorf("Memory limits are not respected: id=1 has not been evicted.")
   141  	}
   142  	if _, ok := f.reassemblers[3]; !ok {
   143  		t.Errorf("Implementation of memory limits is wrong: id=3 is not present.")
   144  	}
   145  }
   146  
   147  func TestMemoryLimitsIgnoresDuplicates(t *testing.T) {
   148  	f := NewFragmentation(1, 0, DefaultReassembleTimeout)
   149  	// Send first fragment with id = 0.
   150  	f.Process(0, 0, 0, true, vv(1, "0"))
   151  	// Send the same packet again.
   152  	f.Process(0, 0, 0, true, vv(1, "0"))
   153  
   154  	got := f.size
   155  	want := 1
   156  	if got != want {
   157  		t.Errorf("Wrong size, duplicates are not handled correctly: got=%d, want=%d.", got, want)
   158  	}
   159  }