Session layer refactoring
[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 #include <vnet/tcp/tcp.h>
16
17 #define TCP_TEST_I(_cond, _comment, _args...)                   \
18 ({                                                              \
19   int _evald = (_cond);                                         \
20   if (!(_evald)) {                                              \
21     fformat(stderr, "FAIL:%d: " _comment "\n",                  \
22             __LINE__, ##_args);                                 \
23   } else {                                                      \
24     fformat(stderr, "PASS:%d: " _comment "\n",                  \
25             __LINE__, ##_args);                                 \
26   }                                                             \
27   _evald;                                                       \
28 })
29
30 #define TCP_TEST(_cond, _comment, _args...)                     \
31 {                                                               \
32     if (!TCP_TEST_I(_cond, _comment, ##_args)) {                \
33         return 1;                                               \
34     }                                                           \
35 }
36
37 static int
38 tcp_test_sack ()
39 {
40   tcp_connection_t _tc, *tc = &_tc;
41   sack_scoreboard_t *sb = &tc->sack_sb;
42   sack_block_t *sacks = 0, block;
43   sack_scoreboard_hole_t *hole;
44   int i;
45
46   memset (tc, 0, sizeof (*tc));
47
48   tc->snd_una = 0;
49   tc->snd_una_max = 1000;
50   tc->snd_nxt = 1000;
51   tc->opt.flags |= TCP_OPTS_FLAG_SACK;
52   scoreboard_init (&tc->sack_sb);
53
54   for (i = 0; i < 1000 / 100; i++)
55     {
56       block.start = i * 100;
57       block.end = (i + 1) * 100;
58       vec_add1 (sacks, block);
59     }
60
61   /*
62    * Inject even blocks
63    */
64
65   for (i = 0; i < 1000 / 200; i++)
66     {
67       vec_add1 (tc->opt.sacks, sacks[i * 2]);
68     }
69   tc->opt.n_sack_blocks = vec_len (tc->opt.sacks);
70   tcp_rcv_sacks (tc, 0);
71
72   TCP_TEST ((pool_elts (sb->holes) == 5),
73             "scoreboard has %d elements", pool_elts (sb->holes));
74
75   /* First SACK block should be rejected */
76   hole = scoreboard_first_hole (sb);
77   TCP_TEST ((hole->start == 0 && hole->end == 200),
78             "first hole start %u end %u", hole->start, hole->end);
79   hole = scoreboard_last_hole (sb);
80   TCP_TEST ((hole->start == 900 && hole->end == 1000),
81             "last hole start %u end %u", hole->start, hole->end);
82   TCP_TEST ((sb->sacked_bytes == 400), "sacked bytes %d", sb->sacked_bytes);
83   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
84   TCP_TEST ((sb->last_sacked_bytes == 400),
85             "last sacked bytes %d", sb->last_sacked_bytes);
86
87   /*
88    * Inject odd blocks
89    */
90
91   vec_reset_length (tc->opt.sacks);
92   for (i = 0; i < 1000 / 200; i++)
93     {
94       vec_add1 (tc->opt.sacks, sacks[i * 2 + 1]);
95     }
96   tc->opt.n_sack_blocks = vec_len (tc->opt.sacks);
97   tcp_rcv_sacks (tc, 0);
98
99   hole = scoreboard_first_hole (sb);
100   TCP_TEST ((pool_elts (sb->holes) == 1),
101             "scoreboard has %d holes", pool_elts (sb->holes));
102   TCP_TEST ((hole->start == 0 && hole->end == 100),
103             "first hole start %u end %u", hole->start, hole->end);
104   TCP_TEST ((sb->sacked_bytes == 900), "sacked bytes %d", sb->sacked_bytes);
105   TCP_TEST ((sb->snd_una_adv == 0), "snd_una_adv %u", sb->snd_una_adv);
106   TCP_TEST ((sb->max_byte_sacked == 1000),
107             "max sacked byte %u", sb->max_byte_sacked);
108   TCP_TEST ((sb->last_sacked_bytes == 500),
109             "last sacked bytes %d", sb->last_sacked_bytes);
110
111   /*
112    *  Ack until byte 100, all bytes are now acked + sacked
113    */
114   tcp_rcv_sacks (tc, 100);
115
116   TCP_TEST ((pool_elts (sb->holes) == 0),
117             "scoreboard has %d elements", pool_elts (sb->holes));
118   TCP_TEST ((sb->snd_una_adv == 900),
119             "snd_una_adv after ack %u", sb->snd_una_adv);
120   TCP_TEST ((sb->max_byte_sacked == 1000),
121             "max sacked byte %u", sb->max_byte_sacked);
122   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
123   TCP_TEST ((sb->last_sacked_bytes == 0),
124             "last sacked bytes %d", sb->last_sacked_bytes);
125
126   /*
127    * Add new block
128    */
129
130   vec_reset_length (tc->opt.sacks);
131
132   block.start = 1200;
133   block.end = 1300;
134   vec_add1 (tc->opt.sacks, block);
135
136   tc->snd_una_max = 1500;
137   tc->snd_una = 1000;
138   tc->snd_nxt = 1500;
139   tcp_rcv_sacks (tc, 1000);
140
141   TCP_TEST ((sb->snd_una_adv == 0),
142             "snd_una_adv after ack %u", sb->snd_una_adv);
143   TCP_TEST ((pool_elts (sb->holes) == 2),
144             "scoreboard has %d holes", pool_elts (sb->holes));
145   hole = scoreboard_first_hole (sb);
146   TCP_TEST ((hole->start == 1000 && hole->end == 1200),
147             "first hole start %u end %u", hole->start, hole->end);
148   hole = scoreboard_last_hole (sb);
149   TCP_TEST ((hole->start == 1300 && hole->end == 1500),
150             "last hole start %u end %u", hole->start, hole->end);
151   TCP_TEST ((sb->sacked_bytes == 100), "sacked bytes %d", sb->sacked_bytes);
152
153   /*
154    * Ack first hole
155    */
156
157   vec_reset_length (tc->opt.sacks);
158   tcp_rcv_sacks (tc, 1200);
159
160   TCP_TEST ((sb->snd_una_adv == 100),
161             "snd_una_adv after ack %u", sb->snd_una_adv);
162   TCP_TEST ((sb->sacked_bytes == 0), "sacked bytes %d", sb->sacked_bytes);
163   TCP_TEST ((pool_elts (sb->holes) == 1),
164             "scoreboard has %d elements", pool_elts (sb->holes));
165
166   /*
167    * Remove all
168    */
169
170   scoreboard_clear (sb);
171   TCP_TEST ((pool_elts (sb->holes) == 0),
172             "number of holes %d", pool_elts (sb->holes));
173   return 0;
174 }
175
176 static int
177 tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input)
178 {
179   svm_fifo_t *f;
180   u32 fifo_size = 1 << 20;
181   u32 *test_data = 0;
182   u32 offset;
183   int i, rv;
184   u32 data_word, test_data_len;
185
186   /* $$$ parse args */
187   test_data_len = fifo_size / sizeof (u32);
188   vec_validate (test_data, test_data_len - 1);
189
190   for (i = 0; i < vec_len (test_data); i++)
191     test_data[i] = i;
192
193   f = svm_fifo_create (fifo_size);
194
195   /* Paint fifo data vector with -1's */
196   memset (f->data, 0xFF, test_data_len);
197
198   /* Enqueue an initial (un-dequeued) chunk */
199   rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ ,
200                                 sizeof (u32), (u8 *) test_data);
201
202   if (rv != sizeof (u32))
203     {
204       clib_warning ("enqueue returned %d", rv);
205       goto out;
206     }
207
208   /*
209    * Create 3 chunks in the future. The offsets are relative
210    * to the current fifo tail
211    */
212   for (i = 0; i < 3; i++)
213     {
214       offset = (2 * i + 1) * sizeof (u32);
215       vlib_cli_output (vm, "add offset %d", offset);
216
217       rv = svm_fifo_enqueue_with_offset
218         (f, 0 /* pid */ , offset, sizeof (u32),
219          (u8 *) (test_data + ((offset + sizeof (u32)) / sizeof (u32))));
220
221       if (rv)
222         {
223           clib_warning ("enqueue returned %d", rv);
224           goto out;
225         }
226     }
227
228   /* Paint missing data backwards */
229   for (i = 3; i > 0; i--)
230     {
231       offset = (2 * i + 0) * sizeof (u32);
232
233       vlib_cli_output (vm, "add offset %d", offset);
234
235       rv = svm_fifo_enqueue_with_offset
236         (f, 0 /* pid */ , offset, sizeof (u32),
237          (u8 *) (test_data + ((offset + sizeof (u32)) / sizeof (u32))));
238
239       if (rv)
240         {
241           clib_warning ("enqueue returned %d", rv);
242           goto out;
243         }
244     }
245
246   vlib_cli_output (vm, "fifo before missing link: %U",
247                    format_svm_fifo, f, 1 /* verbose */ );
248
249   /* Enqueue the missing u32 */
250   rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ ,
251                                 sizeof (u32), (u8 *) (test_data + 1));
252   if (rv != 7 * sizeof (u32))
253     {
254       clib_warning ("enqueue returned %d", rv);
255       goto out;
256     }
257
258   vlib_cli_output (vm, "fifo after missing link: %U",
259                    format_svm_fifo, f, 1 /* verbose */ );
260
261   /* Collect results */
262   for (i = 0; i < 7; i++)
263     {
264       rv = svm_fifo_dequeue_nowait (f, 0 /* pid */ , sizeof (u32),
265                                     (u8 *) & data_word);
266       if (rv != sizeof (u32))
267         {
268           clib_warning ("dequeue returned %d", rv);
269           goto out;
270         }
271       if (data_word != test_data[i])
272         {
273           clib_warning ("recovered data %d not %d", data_word, test_data[i]);
274           goto out;
275         }
276     }
277
278   clib_warning ("test complete...");
279
280 out:
281   svm_fifo_free (f);
282   vec_free (test_data);
283   return 0;
284 }
285
286
287
288 static clib_error_t *
289 tcp_test (vlib_main_t * vm,
290           unformat_input_t * input, vlib_cli_command_t * cmd_arg)
291 {
292   int res = 0;
293
294   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
295     {
296       if (unformat (input, "sack"))
297         {
298           res = tcp_test_sack ();
299         }
300       else if (unformat (input, "fifo"))
301         {
302           res = tcp_test_fifo (vm, input);
303         }
304       else
305         {
306           return clib_error_return (0, "unknown input `%U'",
307                                     format_unformat_error, input);
308         }
309     }
310
311   if (res)
312     {
313       return clib_error_return (0, "TCP unit test failed");
314     }
315   else
316     {
317       return 0;
318     }
319 }
320
321 /* *INDENT-OFF* */
322 VLIB_CLI_COMMAND (tcp_test_command, static) =
323 {
324   .path = "test tcp",
325   .short_help = "internal tcp unit tests",
326   .function = tcp_test,
327 };
328 /* *INDENT-ON* */
329
330
331 /*
332  * fd.io coding-style-patch-verification: ON
333  *
334  * Local Variables:
335  * eval: (c-set-style "gnu")
336  * End:
337  */