svm: check if fifo free list index is valid on alloc
[vpp.git] / src / plugins / unittest / svm_fifo_test.c
index 8579cec..87b85da 100644 (file)
@@ -2009,6 +2009,67 @@ sfifo_test_fifo_replay (vlib_main_t * vm, unformat_input_t * input)
   return 0;
 }
 
+static int
+sfifo_test_fifo_make_rcv_wnd_zero (vlib_main_t * vm, unformat_input_t * input)
+{
+  int __clib_unused verbose = 0, fifo_size = 4096, deq_chunk;
+  fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm;
+  u8 *test_data = 0, *data_buf = 0;
+  fifo_segment_t *fs;
+  svm_fifo_t *f;
+  int rv;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "verbose"))
+       verbose = 1;
+      else
+       {
+         vlib_cli_output (vm, "parse error: '%U'", format_unformat_error,
+                          input);
+         return -1;
+       }
+    }
+
+  /*
+   * Init fifo and enqueue data such that multiple 4096 chunks are allocated
+   */
+  fs = fifo_segment_prepare (fsm, "fifo-rcv-wnd-zero", 0);
+  f = fifo_prepare (fs, fifo_size);
+
+  /* Enqueue 3000 into 4KB chunk, so there'll be 1096 free space */
+  svm_fifo_set_size (f, 4096);
+  validate_test_and_buf_vecs (&test_data, &data_buf, fifo_size);
+  rv = svm_fifo_enqueue (f, 3000, test_data);
+  SFIFO_TEST (rv == 3000, "enqueued %u", rv);
+  rv = svm_fifo_max_enqueue (f);
+  SFIFO_TEST (rv == 1096, "svm_fifo_max_enqueue %u", rv);
+  SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
+
+  /* Shrink fifo size to the in-use size */
+  svm_fifo_set_size (f, 3000);
+  SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
+
+  /* In TCP, this should result in rcv-wnd = 0 */
+  rv = svm_fifo_max_enqueue (f);
+  SFIFO_TEST (rv == 0, "svm_fifo_max_enqueue %u", rv);
+  rv = svm_fifo_max_enqueue_prod (f);
+  SFIFO_TEST (rv == 0, "svm_fifo_max_enqueue_prod %u", rv);
+
+  /* Dequeue and ... */
+  rv = svm_fifo_dequeue (f, 3000, data_buf);
+  SFIFO_TEST (rv == 3000, "dequeued %u", rv);
+
+  /* Clean up */
+  ft_fifo_free (fs, f);
+  ft_fifo_segment_free (fsm, fs);
+  vec_free (test_data);
+  vec_free (data_buf);
+
+  return 0;
+}
+
+
 static fifo_segment_main_t segment_main;
 
 static int
@@ -2066,9 +2127,9 @@ sfifo_test_fifo_segment_fifo_grow (int verbose)
   fifo_segment_main_t *sm = &segment_main;
   fifo_segment_create_args_t _a, *a = &_a;
   u8 *test_data = 0, *data_buf = 0;
-  u32 n_free_chunk_bytes;
+  u32 n_free_chunk_bytes, new_size;
   fifo_segment_t *fs;
-  svm_fifo_t *f;
+  svm_fifo_t *f, *tf;
 
   clib_memset (a, 0, sizeof (*a));
   a->segment_name = "fifo-test1";
@@ -2086,6 +2147,7 @@ sfifo_test_fifo_segment_fifo_grow (int verbose)
    * Alloc fifo
    */
   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
+  fs->h->pct_first_alloc = 100;
   f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
 
   SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo");
@@ -2236,12 +2298,20 @@ sfifo_test_fifo_segment_fifo_grow (int verbose)
              n_free_chunk_bytes, rv);
 
   /*
-   * Allocate fifo that has all chunks
+   * Allocate fifo that has all chunks. Because we have a chunk size limit of
+   * segment_size / 2, allocate 2 fifos.
    */
-  f = fifo_segment_alloc_fifo (fs, n_free_chunk_bytes, FIFO_SEGMENT_RX_FIFO);
+  tf = fifo_segment_alloc_fifo (fs, n_free_chunk_bytes / 2,
+                               FIFO_SEGMENT_RX_FIFO);
+  SFIFO_TEST (tf != 0, "allocation should work");
+  SFIFO_TEST (svm_fifo_is_sane (tf), "fifo should be sane");
+
+  f = fifo_segment_alloc_fifo (fs, n_free_chunk_bytes / 2,
+                              FIFO_SEGMENT_RX_FIFO);
   SFIFO_TEST (f != 0, "allocation should work");
   SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
 
+  fifo_segment_free_fifo (fs, tf);
   fifo_segment_free_fifo (fs, f);
 
   rv = fifo_segment_fl_chunk_bytes (fs);
@@ -2259,15 +2329,17 @@ sfifo_test_fifo_segment_fifo_grow (int verbose)
   /*
    * Allocate fifo and try to grow beyond available space
    */
-  f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO);
+  f = fifo_segment_alloc_fifo (fs, fifo_segment_free_bytes (fs),
+                              FIFO_SEGMENT_RX_FIFO);
 
   /* Try to force fifo growth */
-  svm_fifo_set_size (f, svm_fifo_size (f) + n_free_chunk_bytes);
-  validate_test_and_buf_vecs (&test_data, &data_buf, svm_fifo_size (f));
-  rv = svm_fifo_enqueue (f, svm_fifo_size (f), test_data);
+  new_size = svm_fifo_size (f) + n_free_chunk_bytes + 1;
+  svm_fifo_set_size (f, new_size);
+  validate_test_and_buf_vecs (&test_data, &data_buf, new_size);
+  rv = svm_fifo_enqueue (f, new_size, test_data);
 
-  SFIFO_TEST (rv != svm_fifo_size (f), "grow should fail size %u wrote %d",
-             svm_fifo_size (f), rv);
+  SFIFO_TEST (rv != new_size, "grow should fail size %u wrote %d",
+             new_size, rv);
 
   fifo_segment_free_fifo (fs, f);
 
@@ -2451,7 +2523,7 @@ sfifo_test_fifo_segment_prealloc (int verbose)
   fifo_segment_create_args_t _a, *a = &_a;
   fifo_segment_main_t *sm = &segment_main;
   u32 max_pairs, pairs_req, free_space, pair_mem;
-  svm_fifo_t *f, *old;
+  svm_fifo_t *f, *tf, *old;
   fifo_segment_t *fs;
   int rv, alloc;
 
@@ -2464,6 +2536,7 @@ sfifo_test_fifo_segment_prealloc (int verbose)
   rv = fifo_segment_create (sm, a);
   SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv);
   fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]);
+  fs->h->pct_first_alloc = 100;
 
   /*
    * Prealloc chunks and headers
@@ -2497,13 +2570,20 @@ sfifo_test_fifo_segment_prealloc (int verbose)
   SFIFO_TEST (clib_abs (rv - (int) free_space) < 512,
              "free space expected %u is %u", free_space, rv);
 
-  f = fifo_segment_alloc_fifo (fs, 200 << 10, FIFO_SEGMENT_RX_FIFO);
+  /* Use all free chunk memory */
+  f = fifo_segment_alloc_fifo (fs, 100 << 10, FIFO_SEGMENT_RX_FIFO);
   SFIFO_TEST (f != 0, "fifo allocated");
+  SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
+
+  tf = fifo_segment_alloc_fifo (fs, 100 << 10, FIFO_SEGMENT_RX_FIFO);
+  SFIFO_TEST (tf != 0, "fifo allocated");
+  SFIFO_TEST (svm_fifo_is_sane (tf), "fifo should be sane");
+
   rv = fifo_segment_num_free_chunks (fs, 4096);
   SFIFO_TEST (rv == 0, "prealloc chunks expected %u is %u", 0, rv);
   rv = fifo_segment_fl_chunk_bytes (fs);
   SFIFO_TEST (rv == 0, "chunk free space expected %u is %u", 0, rv);
-  SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane");
+
 
   /*
    * Multiple preallocs that consume the remaining space
@@ -2558,6 +2638,7 @@ sfifo_test_fifo_segment_prealloc (int verbose)
    * Cleanup
    */
   fifo_segment_free_fifo (fs, old);
+  fifo_segment_free_fifo (fs, tf);
   close (fs->ssvm.fd);
   fifo_segment_delete (sm, fs);
   return 0;
@@ -2568,7 +2649,6 @@ sfifo_test_fifo_segment (vlib_main_t * vm, unformat_input_t * input)
 {
   int rv, verbose = 0;
 
-  fifo_segment_main_init (&segment_main, HIGH_SEGMENT_BASEVA, 5);
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (input, "verbose"))
@@ -2630,7 +2710,8 @@ svm_fifo_test (vlib_main_t * vm, unformat_input_t * input,
   int res = 0;
   char *str;
 
-
+  clib_warning ("high mem %lu", HIGH_SEGMENT_BASEVA << 4);
+  fifo_segment_main_init (&segment_main, HIGH_SEGMENT_BASEVA << 4, 5);
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
       if (unformat (input, "fifo1"))
@@ -2657,6 +2738,8 @@ svm_fifo_test (vlib_main_t * vm, unformat_input_t * input,
        res = sfifo_test_fifo_shrink (vm, input);
       else if (unformat (input, "indirect"))
        res = sfifo_test_fifo_indirect (vm, input);
+      else if (unformat (input, "zero"))
+       res = sfifo_test_fifo_make_rcv_wnd_zero (vm, input);
       else if (unformat (input, "segment"))
        res = sfifo_test_fifo_segment (vm, input);
       else if (unformat (input, "all"))
@@ -2721,6 +2804,9 @@ svm_fifo_test (vlib_main_t * vm, unformat_input_t * input,
          if ((res = sfifo_test_fifo_indirect (vm, input)))
            goto done;
 
+         if ((res = sfifo_test_fifo_make_rcv_wnd_zero (vm, input)))
+           goto done;
+
          str = "all";
          unformat_init_cstring (input, str);
          if ((res = sfifo_test_fifo_segment (vm, input)))