blob: 3dbbdf6ff77526bec07fbb6de3b3b98bfbead402 [file] [log] [blame]
Florin Coras6792ec02017-03-13 03:49:51 -07001/*
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 */
Florin Coras6792ec02017-03-13 03:49:51 -070015#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
37static int
38tcp_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
Florin Coras6cf30ad2017-04-04 23:08:23 -0700176static int
177tcp_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
280out:
281 svm_fifo_free (f);
282 vec_free (test_data);
283 return 0;
284}
285
286
287
Florin Coras6792ec02017-03-13 03:49:51 -0700288static clib_error_t *
289tcp_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 }
Florin Coras6cf30ad2017-04-04 23:08:23 -0700300 else if (unformat (input, "fifo"))
301 {
302 res = tcp_test_fifo (vm, input);
303 }
Florin Coras6792ec02017-03-13 03:49:51 -0700304 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
Florin Coras6cf30ad2017-04-04 23:08:23 -0700321/* *INDENT-OFF* */
Florin Coras6792ec02017-03-13 03:49:51 -0700322VLIB_CLI_COMMAND (tcp_test_command, static) =
323{
Florin Coras6cf30ad2017-04-04 23:08:23 -0700324 .path = "test tcp",
325 .short_help = "internal tcp unit tests",
326 .function = tcp_test,
327};
328/* *INDENT-ON* */
329
330
Florin Coras6792ec02017-03-13 03:49:51 -0700331/*
332 * fd.io coding-style-patch-verification: ON
333 *
334 * Local Variables:
335 * eval: (c-set-style "gnu")
336 * End:
337 */