misc: remove GNU Indent directives
[vpp.git] / src / plugins / unittest / test_buffer.c
1 /*
2  * Copyright (c) 2019 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 <vlib/vlib.h>
17 #include <vlib/buffer_funcs.h>
18
19 #define TEST_I(_cond, _comment, _args...)                                     \
20   ({                                                                          \
21     int _evald = (0 == (_cond));                                              \
22     if (_evald)                                                               \
23       {                                                                       \
24         fformat (stderr, "FAIL:%d: " _comment "\n", __LINE__, ##_args);       \
25       }                                                                       \
26     else                                                                      \
27       {                                                                       \
28         fformat (stderr, "PASS:%d: " _comment "\n", __LINE__, ##_args);       \
29       }                                                                       \
30     _evald;                                                                   \
31   })
32
33 #define TEST(_cond, _comment, _args...)                                       \
34   {                                                                           \
35     if (TEST_I (_cond, _comment, ##_args))                                    \
36       {                                                                       \
37         goto err;                                                             \
38       }                                                                       \
39   }
40
41 typedef struct
42 {
43   i16 current_data;
44   u16 current_length;
45   u8 ref_count;
46 } chained_buffer_template_t;
47
48 static int
49 build_chain (vlib_main_t *vm, const chained_buffer_template_t *tmpl, u32 n,
50              clib_random_buffer_t *randbuf, u8 **rand, vlib_buffer_t **b_,
51              u32 *bi_)
52 {
53   vlib_buffer_t *bufs[2 * VLIB_BUFFER_LINEARIZE_MAX], **b = bufs;
54   u32 bis[2 * VLIB_BUFFER_LINEARIZE_MAX + 1], *bi = bis;
55   u32 n_alloc;
56
57   if (rand)
58     vec_reset_length (*rand);
59
60   ASSERT (n <= ARRAY_LEN (bufs));
61   n_alloc = vlib_buffer_alloc (vm, bi, n);
62   if (n_alloc != n)
63     {
64       vlib_buffer_free (vm, bi, n_alloc);
65       return 0;
66     }
67
68   vlib_get_buffers (vm, bis, bufs, n);
69
70   while (n > 0)
71     {
72       b[0]->next_buffer = bi[1];
73       b[0]->flags |= VLIB_BUFFER_NEXT_PRESENT;
74       b[0]->current_data = tmpl->current_data;
75       b[0]->current_length = tmpl->current_length;
76       b[0]->ref_count = 0xff == tmpl->ref_count ? 1 : tmpl->ref_count;
77
78       if (rand)
79         {
80           const u16 len = b[0]->current_length;
81           if (len)
82             {
83               vec_add (*rand, clib_random_buffer_get_data (randbuf, len), len);
84               void *dst = vlib_buffer_get_current (b[0]);
85               const void *src =
86                 vec_elt_at_index (*rand, vec_len (*rand) - len);
87               clib_memcpy_fast (dst, src, len);
88             }
89         }
90
91       b++;
92       bi++;
93       tmpl++;
94       n--;
95     }
96
97   b[-1]->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
98
99   *b_ = bufs[0];
100   *bi_ = bis[0];
101   return 1;
102 }
103
104 static int
105 check_chain (vlib_main_t *vm, vlib_buffer_t *b, const u8 *rand)
106 {
107   int len_chain = vlib_buffer_length_in_chain (vm, b);
108   int len;
109
110   /* check for data corruption */
111   if (clib_memcmp (vlib_buffer_get_current (b), vec_elt_at_index (rand, 0),
112                    b->current_length))
113     return 0;
114   len = b->current_length;
115   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
116     {
117       b = vlib_get_buffer (vm, b->next_buffer);
118       if (clib_memcmp (vlib_buffer_get_current (b),
119                        vec_elt_at_index (rand, len), b->current_length))
120         return 0;
121       len += b->current_length;
122     }
123
124   /* check for data truncation */
125   if (len != vec_len (rand))
126     return 0;
127
128   /* check total length update is correct */
129   if (len != len_chain)
130     return 0;
131
132   return 1;
133 }
134
135 static int
136 test_chain (vlib_main_t *vm, const chained_buffer_template_t *tmpl,
137             const u32 n, const int clone_off, clib_random_buffer_t *randbuf,
138             u8 **rand)
139 {
140   vlib_buffer_t *b;
141   u32 bi[2];
142   int ret = 0;
143
144   if (!build_chain (vm, tmpl, n, randbuf, rand, &b, bi))
145     goto err0;
146
147   if (clone_off)
148     {
149       if (2 != vlib_buffer_clone (vm, bi[0], bi, 2, clone_off))
150         goto err1;
151       b = vlib_get_buffer (vm, bi[0]);
152     }
153
154   if (!(ret = vlib_buffer_chain_linearize (vm, b)))
155     goto err2;
156
157   if (!check_chain (vm, b, *rand))
158     {
159       ret = 0;
160       goto err2;
161     }
162
163 err2:
164   if (clone_off)
165     vlib_buffer_free_one (vm, bi[1]);
166 err1:
167   vlib_buffer_free_one (vm, bi[0]);
168 err0:
169   return ret;
170 }
171
172 static int
173 linearize_test (vlib_main_t *vm)
174 {
175   chained_buffer_template_t tmpl[VLIB_BUFFER_LINEARIZE_MAX];
176   clib_random_buffer_t randbuf;
177   u32 data_size = vlib_buffer_get_default_data_size (vm);
178   u8 *rand = 0;
179   int ret = 0;
180   int i;
181
182   clib_random_buffer_init (&randbuf, 0);
183
184   clib_memset (tmpl, 0xff, sizeof (tmpl));
185   for (i = 0; i < 2; i++)
186     {
187       tmpl[i].current_data = -14;
188       tmpl[i].current_length = 14 + data_size;
189     }
190   TEST (2 == test_chain (vm, tmpl, 2, 0, &randbuf, &rand),
191         "linearize chain with negative current data");
192
193   clib_memset (tmpl, 0xff, sizeof (tmpl));
194   tmpl[0].current_data = 12;
195   tmpl[0].current_length = data_size - 12;
196   tmpl[1].current_data = 0;
197   tmpl[1].current_length = 0;
198   TEST (1 == test_chain (vm, tmpl, 2, 0, &randbuf, &rand),
199         "linearize chain with empty next");
200
201   clib_memset (tmpl, 0xff, sizeof (tmpl));
202   tmpl[0].current_data = 0;
203   tmpl[0].current_length = data_size - 17;
204   tmpl[1].current_data = -5;
205   tmpl[1].current_length = 3;
206   tmpl[2].current_data = 17;
207   tmpl[2].current_length = 9;
208   tmpl[3].current_data = 3;
209   tmpl[3].current_length = 5;
210   TEST (1 == test_chain (vm, tmpl, 4, 0, &randbuf, &rand),
211         "linearize chain into a single buffer");
212
213   clib_memset (tmpl, 0xff, sizeof (tmpl));
214   tmpl[0].current_data = 0;
215   tmpl[0].current_length = data_size - 2;
216   tmpl[1].current_data = -VLIB_BUFFER_PRE_DATA_SIZE;
217   tmpl[1].current_length = 20;
218   tmpl[2].current_data = data_size - 10;
219   tmpl[2].current_length = 10;
220   tmpl[3].current_data = 0;
221   tmpl[3].current_length = data_size;
222   TEST (2 == test_chain (vm, tmpl, 4, data_size - 1, &randbuf, &rand),
223         "linearize cloned chain");
224
225   clib_memset (tmpl, 0xff, sizeof (tmpl));
226   for (i = 0; i < 100; i++)
227     {
228       u8 *r = clib_random_buffer_get_data (&randbuf, 1);
229       int n = clib_max (r[0] % ARRAY_LEN (tmpl), 1);
230       int j;
231       for (j = 0; j < n; j++)
232         {
233           r = clib_random_buffer_get_data (&randbuf, 3);
234           i16 current_data = (i16) r[0] - VLIB_BUFFER_PRE_DATA_SIZE;
235           u16 current_length = *(u16 *) (r + 1) % (data_size - current_data);
236           tmpl[j].current_data = current_data;
237           tmpl[j].current_length = current_length;
238         }
239       r = clib_random_buffer_get_data (&randbuf, 1);
240       TEST (
241         test_chain (vm, tmpl, n, r[0] > 250 ? r[0] % 128 : 0, &randbuf, &rand),
242         "linearize random chain %d", i);
243     }
244
245   ret = 1;
246 err:
247   clib_random_buffer_free (&randbuf);
248   vec_free (rand);
249   return ret;
250 }
251
252 static clib_error_t *
253 test_linearize_fn (vlib_main_t * vm, unformat_input_t * input,
254                    vlib_cli_command_t * cmd)
255 {
256
257   if (!linearize_test (vm))
258     {
259       return clib_error_return (0, "linearize test failed");
260     }
261
262   return 0;
263 }
264
265 VLIB_CLI_COMMAND (test_linearize_command, static) =
266 {
267   .path = "test chained-buffer-linearization",
268   .short_help = "test chained-buffer-linearization",
269   .function = test_linearize_fn,
270 };
271
272 static clib_error_t *
273 test_linearize_speed_fn (vlib_main_t *vm, unformat_input_t *input,
274                          vlib_cli_command_t *cmd)
275 {
276   /* typical 9000-bytes TCP jumbo frames */
277   const chained_buffer_template_t tmpl[5] = { { 14, 2034, 1 },
278                                               { 0, 2048, 1 },
279                                               { 0, 2048, 1 },
280                                               { 0, 2048, 1 },
281                                               { 0, 808, 1 } };
282   int i, j;
283
284   for (i = 0; i < 10; i++)
285     {
286       u64 tot = 0;
287       for (j = 0; j < 100000; j++)
288         {
289           vlib_buffer_t *b;
290           u32 bi;
291
292           if (!build_chain (vm, tmpl, 5, 0, 0, &b, &bi))
293             return clib_error_create ("build_chain() failed");
294
295           CLIB_COMPILER_BARRIER ();
296           u64 start = clib_cpu_time_now ();
297           CLIB_COMPILER_BARRIER ();
298
299           vlib_buffer_chain_linearize (vm, b);
300
301           CLIB_COMPILER_BARRIER ();
302           tot += clib_cpu_time_now () - start;
303           CLIB_COMPILER_BARRIER ();
304
305           vlib_buffer_free_one (vm, bi);
306         }
307       vlib_cli_output (vm, "%.03f ticks/call", (f64) tot / j);
308     }
309
310   return 0;
311 }
312
313 VLIB_CLI_COMMAND (test_linearize_speed_command, static) = {
314   .path = "test chained-buffer-linearization speed",
315   .short_help = "test chained-buffer-linearization speed",
316   .function = test_linearize_speed_fn,
317 };
318
319 /*
320  * fd.io coding-style-patch-verification: ON
321  *
322  * Local Variables:
323  * eval: (c-set-style "gnu")
324  * End:
325  */