blob: 0725bb043f304401660860c4166e1bb8ba3e810f [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 */
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
38static int
39tcp_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
177static clib_error_t *
178tcp_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
206VLIB_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 */