0725bb043f304401660860c4166e1bb8ba3e810f
[vpp.git] / src / vnet / tcp / tcp_test.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
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
16 #include <vnet/tcp/tcp.h>
17
18 #define TCP_TEST_I(_cond, _comment, _args...)                   \
19 ({                                                              \
20   int _evald = (_cond);                                         \
21   if (!(_evald)) {                                              \
22     fformat(stderr, "FAIL:%d: " _comment "\n",                  \
23             __LINE__, ##_args);                                 \
24   } else {                                                      \
25     fformat(stderr, "PASS:%d: " _comment "\n",                  \
26             __LINE__, ##_args);                                 \
27   }                                                             \
28   _evald;                                                       \
29 })
30
31 #define TCP_TEST(_cond, _comment, _args...)                     \
32 {                                                               \
33     if (!TCP_TEST_I(_cond, _comment, ##_args)) {                \
34         return 1;                                               \
35     }                                                           \
36 }
37
38 static int
39 tcp_test_sack ()
40 {
41   tcp_connection_t _tc, *tc = &_tc;
42   sack_scoreboard_t *sb = &tc->sack_sb;
43   sack_block_t *sacks = 0, block;
44   sack_scoreboard_hole_t *hole;
45   int i;
46
47   memset (tc, 0, sizeof (*tc));
48
49   tc->snd_una = 0;
50   tc->snd_una_max = 1000;
51   tc->snd_nxt = 1000;
52   tc->opt.flags |= TCP_OPTS_FLAG_SACK;
53   scoreboard_init (&tc->sack_sb);
54
55   for (i = 0; i < 1000 / 100; i++)
56     {
57       block.start = i * 100;
58       block.end = (i + 1) * 100;
59       vec_add1 (sacks, block);
60     }
61
62   /*
63    * Inject even blocks
64    */
65
66   for (i = 0; i < 1000 / 200; i++)
67     {
68       vec_add1 (tc->opt.sacks, sacks[i * 2]);
69     }
70   tc->opt.n_sack_blocks = vec_len (tc->opt.sacks);
71   tcp_rcv_sacks (tc, 0);
72
73   TCP_TEST ((pool_elts (sb->holes) == 5),
74             "scoreboard has %d elements", pool_elts (sb->holes));
75
76   /* First SACK block should be rejected */
77   hole = scoreboard_first_hole (sb);
78   TCP_TEST ((hole->start == 0 && hole->end == 200),
79             "first hole start %u end %u", hole->start, hole->end);
80   hole = scoreboard_last_hole (sb);
81   TCP_TEST ((hole->start == 900 && hole->end == 1000),
82             "last hole start %u end %u", hole->start, hole->end);
83   TCP_TEST ((sb->sacked_bytes == 400), "sacked bytes %d", sb->sacked_bytes);
84   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
85   TCP_TEST ((sb->last_sacked_bytes == 400),
86             "last sacked bytes %d", sb->last_sacked_bytes);
87
88   /*
89    * Inject odd blocks
90    */
91
92   vec_reset_length (tc->opt.sacks);
93   for (i = 0; i < 1000 / 200; i++)
94     {
95       vec_add1 (tc->opt.sacks, sacks[i * 2 + 1]);
96     }
97   tc->opt.n_sack_blocks = vec_len (tc->opt.sacks);
98   tcp_rcv_sacks (tc, 0);
99
100   hole = scoreboard_first_hole (sb);
101   TCP_TEST ((pool_elts (sb->holes) == 1),
102             "scoreboard has %d holes", pool_elts (sb->holes));
103   TCP_TEST ((hole->start == 0 && hole->end == 100),
104             "first hole start %u end %u", hole->start, hole->end);
105   TCP_TEST ((sb->sacked_bytes == 900), "sacked bytes %d", sb->sacked_bytes);
106   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
107   TCP_TEST ((sb->max_byte_sacked == 1000),
108             "max sacked byte %u", sb->max_byte_sacked);
109   TCP_TEST ((sb->last_sacked_bytes == 500),
110             "last sacked bytes %d", sb->last_sacked_bytes);
111
112   /*
113    *  Ack until byte 100, all bytes are now acked + sacked
114    */
115   tcp_rcv_sacks (tc, 100);
116
117   TCP_TEST ((pool_elts (sb->holes) == 0),
118             "scoreboard has %d elements", pool_elts (sb->holes));
119   TCP_TEST ((sb->snd_una_adv == 900),
120             "snd_una_adv after ack %u", sb->snd_una_adv);
121   TCP_TEST ((sb->max_byte_sacked == 1000),
122             "max sacked byte %u", sb->max_byte_sacked);
123   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
124   TCP_TEST ((sb->last_sacked_bytes == 0),
125             "last sacked bytes %d", sb->last_sacked_bytes);
126
127   /*
128    * Add new block
129    */
130
131   vec_reset_length (tc->opt.sacks);
132
133   block.start = 1200;
134   block.end = 1300;
135   vec_add1 (tc->opt.sacks, block);
136
137   tc->snd_una_max = 1500;
138   tc->snd_una = 1000;
139   tc->snd_nxt = 1500;
140   tcp_rcv_sacks (tc, 1000);
141
142   TCP_TEST ((sb->snd_una_adv == 0),
143             "snd_una_adv after ack %u", sb->snd_una_adv);
144   TCP_TEST ((pool_elts (sb->holes) == 2),
145             "scoreboard has %d holes", pool_elts (sb->holes));
146   hole = scoreboard_first_hole (sb);
147   TCP_TEST ((hole->start == 1000 && hole->end == 1200),
148             "first hole start %u end %u", hole->start, hole->end);
149   hole = scoreboard_last_hole (sb);
150   TCP_TEST ((hole->start == 1300 && hole->end == 1500),
151             "last hole start %u end %u", hole->start, hole->end);
152   TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
153
154   /*
155    * Ack first hole
156    */
157
158   vec_reset_length (tc->opt.sacks);
159   tcp_rcv_sacks (tc, 1200);
160
161   TCP_TEST ((sb->snd_una_adv == 100),
162             "snd_una_adv after ack %u", sb->snd_una_adv);
163   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
164   TCP_TEST ((pool_elts (sb->holes) == 1),
165             "scoreboard has %d elements", pool_elts (sb->holes));
166
167   /*
168    * Remove all
169    */
170
171   scoreboard_clear (sb);
172   TCP_TEST ((pool_elts (sb->holes) == 0),
173             "number of holes %d", pool_elts (sb->holes));
174   return 0;
175 }
176
177 static clib_error_t *
178 tcp_test (vlib_main_t * vm,
179           unformat_input_t * input, vlib_cli_command_t * cmd_arg)
180 {
181   int res = 0;
182
183   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
184     {
185       if (unformat (input, "sack"))
186         {
187           res = tcp_test_sack ();
188         }
189       else
190         {
191           return clib_error_return (0, "unknown input `%U'",
192                                     format_unformat_error, input);
193         }
194     }
195
196   if (res)
197     {
198       return clib_error_return (0, "TCP unit test failed");
199     }
200   else
201     {
202       return 0;
203     }
204 }
205
206 VLIB_CLI_COMMAND (tcp_test_command, static) =
207 {
208 .path = "test tcp",.short_help = "internal tcp unit tests",.function =
209     tcp_test,};
210 /*
211  * fd.io coding-style-patch-verification: ON
212  *
213  * Local Variables:
214  * eval: (c-set-style "gnu")
215  * End:
216  */