github.com/flowerwrong/netstack@v0.0.0-20191009141956-e5848263af28/tcpip/transport/tcp/sack_scoreboard_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 tcp_test 16 17 import ( 18 "testing" 19 20 "github.com/FlowerWrong/netstack/tcpip/header" 21 "github.com/FlowerWrong/netstack/tcpip/seqnum" 22 "github.com/FlowerWrong/netstack/tcpip/transport/tcp" 23 ) 24 25 const smss = 1500 26 27 func initScoreboard(blocks []header.SACKBlock, iss seqnum.Value) *tcp.SACKScoreboard { 28 s := tcp.NewSACKScoreboard(smss, iss) 29 for _, blk := range blocks { 30 s.Insert(blk) 31 } 32 return s 33 } 34 35 func TestSACKScoreboardIsSACKED(t *testing.T) { 36 type blockTest struct { 37 block header.SACKBlock 38 sacked bool 39 } 40 testCases := []struct { 41 comment string 42 scoreboardBlocks []header.SACKBlock 43 blockTests []blockTest 44 iss seqnum.Value 45 }{ 46 { 47 "Test holes and unsacked SACK blocks in SACKed ranges and insertion of overlapping SACK blocks", 48 []header.SACKBlock{{10, 20}, {10, 30}, {30, 40}, {41, 50}, {5, 10}, {1, 50}, {111, 120}, {101, 110}, {52, 120}}, 49 []blockTest{ 50 {header.SACKBlock{15, 21}, true}, 51 {header.SACKBlock{200, 201}, false}, 52 {header.SACKBlock{50, 51}, false}, 53 {header.SACKBlock{53, 120}, true}, 54 }, 55 0, 56 }, 57 { 58 "Test disjoint SACKBlocks", 59 []header.SACKBlock{{2288624809, 2288810057}, {2288811477, 2288838565}}, 60 []blockTest{ 61 {header.SACKBlock{2288624809, 2288810057}, true}, 62 {header.SACKBlock{2288811477, 2288838565}, true}, 63 {header.SACKBlock{2288810057, 2288811477}, false}, 64 }, 65 2288624809, 66 }, 67 { 68 "Test sequence number wrap around", 69 []header.SACKBlock{{4294254144, 225652}, {5340409, 5350509}}, 70 []blockTest{ 71 {header.SACKBlock{4294254144, 4294254145}, true}, 72 {header.SACKBlock{4294254143, 4294254144}, false}, 73 {header.SACKBlock{4294254144, 1}, true}, 74 {header.SACKBlock{225652, 5350509}, false}, 75 {header.SACKBlock{5340409, 5350509}, true}, 76 {header.SACKBlock{5350509, 5350609}, false}, 77 }, 78 4294254144, 79 }, 80 { 81 "Test disjoint SACKBlocks out of order", 82 []header.SACKBlock{{827450276, 827454536}, {827426028, 827428868}}, 83 []blockTest{ 84 {header.SACKBlock{827426028, 827428867}, true}, 85 {header.SACKBlock{827450168, 827450275}, false}, 86 }, 87 827426000, 88 }, 89 } 90 for _, tc := range testCases { 91 sb := initScoreboard(tc.scoreboardBlocks, tc.iss) 92 for _, blkTest := range tc.blockTests { 93 if want, got := blkTest.sacked, sb.IsSACKED(blkTest.block); got != want { 94 t.Errorf("%s: s.IsSACKED(%v) = %v, want %v", tc.comment, blkTest.block, got, want) 95 } 96 } 97 } 98 } 99 100 func TestSACKScoreboardIsRangeLost(t *testing.T) { 101 s := tcp.NewSACKScoreboard(10, 0) 102 s.Insert(header.SACKBlock{1, 25}) 103 s.Insert(header.SACKBlock{25, 50}) 104 s.Insert(header.SACKBlock{51, 100}) 105 s.Insert(header.SACKBlock{111, 120}) 106 s.Insert(header.SACKBlock{101, 110}) 107 s.Insert(header.SACKBlock{121, 141}) 108 s.Insert(header.SACKBlock{145, 146}) 109 s.Insert(header.SACKBlock{147, 148}) 110 s.Insert(header.SACKBlock{149, 150}) 111 s.Insert(header.SACKBlock{153, 154}) 112 s.Insert(header.SACKBlock{155, 156}) 113 testCases := []struct { 114 block header.SACKBlock 115 lost bool 116 }{ 117 // Block not covered by SACK block and has more than 118 // nDupAckThreshold discontiguous SACK blocks after it as well 119 // as (nDupAckThreshold -1) * 10 (smss) bytes that have been 120 // SACKED above the sequence number covered by this block. 121 {block: header.SACKBlock{0, 1}, lost: true}, 122 123 // These blocks have all been SACKed and should not be 124 // considered lost. 125 {block: header.SACKBlock{1, 2}, lost: false}, 126 {block: header.SACKBlock{25, 26}, lost: false}, 127 {block: header.SACKBlock{1, 45}, lost: false}, 128 129 // Same as the first case above. 130 {block: header.SACKBlock{50, 51}, lost: true}, 131 132 // This block has been SACKed and should not be considered lost. 133 {block: header.SACKBlock{119, 120}, lost: false}, 134 135 // This one should return true because there are > 136 // (nDupAckThreshold - 1) * 10 (smss) bytes that have been 137 // sacked above this sequence number. 138 {block: header.SACKBlock{120, 121}, lost: true}, 139 140 // This block has been SACKed and should not be considered lost. 141 {block: header.SACKBlock{125, 126}, lost: false}, 142 143 // This block has not been SACKed and there are nDupAckThreshold 144 // number of SACKed blocks after it. 145 {block: header.SACKBlock{141, 145}, lost: true}, 146 147 // This block has not been SACKed and there are less than 148 // nDupAckThreshold SACKed sequences after it. 149 {block: header.SACKBlock{151, 152}, lost: false}, 150 } 151 for _, tc := range testCases { 152 if want, got := tc.lost, s.IsRangeLost(tc.block); got != want { 153 t.Errorf("s.IsRangeLost(%v) = %v, want %v", tc.block, got, want) 154 } 155 } 156 } 157 158 func TestSACKScoreboardIsLost(t *testing.T) { 159 s := tcp.NewSACKScoreboard(10, 0) 160 s.Insert(header.SACKBlock{1, 25}) 161 s.Insert(header.SACKBlock{25, 50}) 162 s.Insert(header.SACKBlock{51, 100}) 163 s.Insert(header.SACKBlock{111, 120}) 164 s.Insert(header.SACKBlock{101, 110}) 165 s.Insert(header.SACKBlock{121, 141}) 166 s.Insert(header.SACKBlock{121, 141}) 167 s.Insert(header.SACKBlock{145, 146}) 168 s.Insert(header.SACKBlock{147, 148}) 169 s.Insert(header.SACKBlock{149, 150}) 170 s.Insert(header.SACKBlock{153, 154}) 171 s.Insert(header.SACKBlock{155, 156}) 172 testCases := []struct { 173 seq seqnum.Value 174 lost bool 175 }{ 176 // Sequence number not covered by SACK block and has more than 177 // nDupAckThreshold discontiguous SACK blocks after it as well 178 // as (nDupAckThreshold -1) * 10 (smss) bytes that have been 179 // SACKED above the sequence number. 180 {seq: 0, lost: true}, 181 182 // These sequence numbers have all been SACKed and should not be 183 // considered lost. 184 {seq: 1, lost: false}, 185 {seq: 25, lost: false}, 186 {seq: 45, lost: false}, 187 188 // Same as first case above. 189 {seq: 50, lost: true}, 190 191 // This block has been SACKed and should not be considered lost. 192 {seq: 119, lost: false}, 193 194 // This one should return true because there are > 195 // (nDupAckThreshold - 1) * 10 (smss) bytes that have been 196 // sacked above this sequence number. 197 {seq: 120, lost: true}, 198 199 // This sequence number has been SACKed and should not be 200 // considered lost. 201 {seq: 125, lost: false}, 202 203 // This sequence number has not been SACKed and there are 204 // nDupAckThreshold number of SACKed blocks after it. 205 {seq: 141, lost: true}, 206 207 // This sequence number has not been SACKed and there are less 208 // than nDupAckThreshold SACKed sequences after it. 209 {seq: 151, lost: false}, 210 } 211 for _, tc := range testCases { 212 if want, got := tc.lost, s.IsLost(tc.seq); got != want { 213 t.Errorf("s.IsLost(%v) = %v, want %v", tc.seq, got, want) 214 } 215 } 216 } 217 218 func TestSACKScoreboardDelete(t *testing.T) { 219 blocks := []header.SACKBlock{{4294254144, 225652}, {5340409, 5350509}} 220 s := initScoreboard(blocks, 4294254143) 221 s.Delete(5340408) 222 if s.Empty() { 223 t.Fatalf("s.Empty() = true, want false") 224 } 225 if got, want := s.Sacked(), blocks[1].Start.Size(blocks[1].End); got != want { 226 t.Fatalf("incorrect sacked bytes in scoreboard got: %v, want: %v", got, want) 227 } 228 s.Delete(5340410) 229 if s.Empty() { 230 t.Fatal("s.Empty() = true, want false") 231 } 232 newSB := header.SACKBlock{5340410, 5350509} 233 if !s.IsSACKED(newSB) { 234 t.Fatalf("s.IsSACKED(%v) = false, want true, scoreboard: %v", newSB, s) 235 } 236 s.Delete(5350509) 237 lastOctet := header.SACKBlock{5350508, 5350509} 238 if s.IsSACKED(lastOctet) { 239 t.Fatalf("s.IsSACKED(%v) = false, want true", lastOctet) 240 } 241 242 s.Delete(5350510) 243 if !s.Empty() { 244 t.Fatal("s.Empty() = false, want true") 245 } 246 if got, want := s.Sacked(), seqnum.Size(0); got != want { 247 t.Fatalf("incorrect sacked bytes in scoreboard got: %v, want: %v", got, want) 248 } 249 }