LCOV - code coverage report
Current view: top level - plugins/unittest - test_buffer.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 115 144 79.9 %
Date: 2023-10-26 01:39:38 Functions: 9 10 90.0 %

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

Generated by: LCOV version 1.14