github.com/polevpn/netstack@v1.10.9/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/polevpn/netstack/tcpip/header"
    21  	"github.com/polevpn/netstack/tcpip/seqnum"
    22  	"github.com/polevpn/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  }