github.com/vpnishe/netstack@v1.10.6/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/vpnishe/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 }