github.com/google/netstack@v0.0.0-20191123085552-55fcc16cd0eb/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/google/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, err := f.Process(in.id, in.first, in.last, in.more, in.vv)
    87  				if err != nil {
    88  					t.Fatalf("f.Process(%+v, %+d, %+d, %t, %+v) failed: %v", in.id, in.first, in.last, in.more, in.vv, err)
    89  				}
    90  				if !reflect.DeepEqual(vv, c.out[i].vv) {
    91  					t.Errorf("got Process(%d) = %+v, want = %+v", i, vv, c.out[i].vv)
    92  				}
    93  				if done != c.out[i].done {
    94  					t.Errorf("got Process(%d) = %+v, want = %+v", i, done, c.out[i].done)
    95  				}
    96  				if c.out[i].done {
    97  					if _, ok := f.reassemblers[in.id]; ok {
    98  						t.Errorf("Process(%d) did not remove buffer from reassemblers", i)
    99  					}
   100  					for n := f.rList.Front(); n != nil; n = n.Next() {
   101  						if n.id == in.id {
   102  							t.Errorf("Process(%d) did not remove buffer from rList", i)
   103  						}
   104  					}
   105  				}
   106  			}
   107  		})
   108  	}
   109  }
   110  
   111  func TestReassemblingTimeout(t *testing.T) {
   112  	timeout := time.Millisecond
   113  	f := NewFragmentation(1024, 512, timeout)
   114  	// Send first fragment with id = 0, first = 0, last = 0, and more = true.
   115  	f.Process(0, 0, 0, true, vv(1, "0"))
   116  	// Sleep more than the timeout.
   117  	time.Sleep(2 * timeout)
   118  	// Send another fragment that completes a packet.
   119  	// However, no packet should be reassembled because the fragment arrived after the timeout.
   120  	_, done, err := f.Process(0, 1, 1, false, vv(1, "1"))
   121  	if err != nil {
   122  		t.Fatalf("f.Process(0, 1, 1, false, vv(1, \"1\")) failed: %v", err)
   123  	}
   124  	if done {
   125  		t.Errorf("Fragmentation does not respect the reassembling timeout.")
   126  	}
   127  }
   128  
   129  func TestMemoryLimits(t *testing.T) {
   130  	f := NewFragmentation(3, 1, DefaultReassembleTimeout)
   131  	// Send first fragment with id = 0.
   132  	f.Process(0, 0, 0, true, vv(1, "0"))
   133  	// Send first fragment with id = 1.
   134  	f.Process(1, 0, 0, true, vv(1, "1"))
   135  	// Send first fragment with id = 2.
   136  	f.Process(2, 0, 0, true, vv(1, "2"))
   137  
   138  	// Send first fragment with id = 3. This should caused id = 0 and id = 1 to be
   139  	// evicted.
   140  	f.Process(3, 0, 0, true, vv(1, "3"))
   141  
   142  	if _, ok := f.reassemblers[0]; ok {
   143  		t.Errorf("Memory limits are not respected: id=0 has not been evicted.")
   144  	}
   145  	if _, ok := f.reassemblers[1]; ok {
   146  		t.Errorf("Memory limits are not respected: id=1 has not been evicted.")
   147  	}
   148  	if _, ok := f.reassemblers[3]; !ok {
   149  		t.Errorf("Implementation of memory limits is wrong: id=3 is not present.")
   150  	}
   151  }
   152  
   153  func TestMemoryLimitsIgnoresDuplicates(t *testing.T) {
   154  	f := NewFragmentation(1, 0, DefaultReassembleTimeout)
   155  	// Send first fragment with id = 0.
   156  	f.Process(0, 0, 0, true, vv(1, "0"))
   157  	// Send the same packet again.
   158  	f.Process(0, 0, 0, true, vv(1, "0"))
   159  
   160  	got := f.size
   161  	want := 1
   162  	if got != want {
   163  		t.Errorf("Wrong size, duplicates are not handled correctly: got=%d, want=%d.", got, want)
   164  	}
   165  }