From b59a7055524bae29a328958c493d0b600776dc27 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Tue, 18 Apr 2017 22:07:29 -0700 Subject: Add more svm fifo unit tests Change-Id: Ifc07b3f90ac155c26c3a216e073b474b499ebd44 Signed-off-by: Florin Coras --- src/svm/svm_fifo.c | 100 ++++++++-------- src/vnet/tcp/tcp_test.c | 305 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 292 insertions(+), 113 deletions(-) (limited to 'src') diff --git a/src/svm/svm_fifo.c b/src/svm/svm_fifo.c index bd968aea..f428d3ec 100644 --- a/src/svm/svm_fifo.c +++ b/src/svm/svm_fifo.c @@ -38,13 +38,37 @@ format_ooo_list (u8 * s, va_list * args) while (ooo_segment_index != OOO_SEGMENT_INVALID_INDEX) { seg = pool_elt_at_index (f->ooo_segments, ooo_segment_index); - s = format (s, "\n %U", format_ooo_segment, seg); - + s = format (s, " %U\n", format_ooo_segment, seg); ooo_segment_index = seg->next; } return s; } +u8 * +format_svm_fifo (u8 * s, va_list * args) +{ + svm_fifo_t *f = va_arg (*args, svm_fifo_t *); + int verbose = va_arg (*args, int); + + s = format (s, "cursize %u nitems %u has_event %d\n", + f->cursize, f->nitems, f->has_event); + s = format (s, "head %d tail %d\n", f->head, f->tail); + + if (verbose > 1) + s = format + (s, "server session %d thread %d client session %d thread %d\n", + f->server_session_index, f->server_thread_index, + f->client_session_index, f->client_thread_index); + + if (verbose) + { + s = format (s, "ooo pool %d active elts\n", + pool_elts (f->ooo_segments)); + s = format (s, "%U", format_ooo_list, f); + } + return s; +} + /** create an svm fifo, in the current heap. Fails vs blow up the process */ svm_fifo_t * svm_fifo_create (u32 data_size_in_bytes) @@ -274,33 +298,41 @@ ooo_segment_try_collect (svm_fifo_t * f, u32 n_bytes_enqueued) u32 index, bytes = 0, diff; u32 cursize; - /* read cursize, which can only increase while we're working */ - cursize = svm_fifo_max_dequeue (f); + /* current size has not yet been updated */ + cursize = svm_fifo_max_dequeue (f) + n_bytes_enqueued; s = pool_elt_at_index (f->ooo_segments, f->ooos_list_head); + diff = (f->nitems + (i32) (f->tail - s->start)) % f->nitems; + if (diff > cursize) + return 0; + /* If last tail update overlaps one/multiple ooo segments, remove them */ - diff = (f->nitems + ((int) s->start - f->tail)) % f->nitems; - while (0 < diff && diff < n_bytes_enqueued) + while (0 < diff && diff < cursize) { - /* Segment end is beyond the tail. Advance tail and be done */ + index = s - f->ooo_segments; + + /* Segment end is beyond the tail. Advance tail and remove segment */ if (diff < s->length) { f->tail += s->length - diff; f->tail %= f->nitems; + bytes = s->length - diff; + ooo_segment_del (f, index); break; } + /* If we have next go on */ - else if (s->next != OOO_SEGMENT_INVALID_INDEX) + if (s->next != OOO_SEGMENT_INVALID_INDEX) { - index = s - f->ooo_segments; s = pool_elt_at_index (f->ooo_segments, s->next); - diff = (f->nitems + ((int) s->start - f->tail)) % f->nitems; + diff = (f->nitems + (i32) (f->tail - s->start)) % f->nitems; ooo_segment_del (f, index); } /* End of search */ else { + ooo_segment_del (f, index); break; } } @@ -404,10 +436,7 @@ svm_fifo_enqueue_with_offset_internal (svm_fifo_t * f, u32 normalized_offset; int rv; - /* Safety: don't wrap more than nitems/2 */ - ASSERT ((f->nitems + offset - f->tail) % f->nitems < f->nitems / 2); - - /* Users would do do well to avoid this */ + /* Users would do well to avoid this */ if (PREDICT_FALSE (f->tail == (offset % f->nitems))) { rv = svm_fifo_enqueue_internal (f, pid, required_bytes, copy_from_here); @@ -421,7 +450,7 @@ svm_fifo_enqueue_with_offset_internal (svm_fifo_t * f, nitems = f->nitems; /* Will this request fit? */ - if ((required_bytes + offset) > (nitems - cursize)) + if ((required_bytes + (offset - f->tail) % nitems) > (nitems - cursize)) return -1; ooo_segment_add (f, offset, required_bytes); @@ -523,7 +552,7 @@ svm_fifo_dequeue_nowait (svm_fifo_t * f, } int -svm_fifo_peek (svm_fifo_t * f, int pid, u32 offset, u32 max_bytes, +svm_fifo_peek (svm_fifo_t * f, int pid, u32 relative_offset, u32 max_bytes, u8 * copy_here) { u32 total_copy_bytes, first_copy_bytes, second_copy_bytes; @@ -535,7 +564,7 @@ svm_fifo_peek (svm_fifo_t * f, int pid, u32 offset, u32 max_bytes, return -2; /* nothing in the fifo */ nitems = f->nitems; - real_head = f->head + offset; + real_head = f->head + relative_offset; real_head = real_head >= nitems ? real_head - nitems : real_head; /* Number of bytes we're going to copy */ @@ -596,43 +625,6 @@ svm_fifo_dequeue_drop (svm_fifo_t * f, int pid, u32 max_bytes) return total_drop_bytes; } -u8 * -format_svm_fifo (u8 * s, va_list * args) -{ - svm_fifo_t *f = va_arg (*args, svm_fifo_t *); - int verbose = va_arg (*args, int); - - s = format (s, "cursize %u nitems %u has_event %d\n", - f->cursize, f->nitems, f->has_event); - s = format (s, "head %d tail %d\n", f->head, f->tail); - - if (verbose > 1) - s = format - (s, "server session %d thread %d client session %d thread %d\n", - f->server_session_index, f->server_thread_index, - f->client_session_index, f->client_thread_index); - - if (verbose) - { - ooo_segment_t *seg; - u32 seg_index; - - s = format (s, "ooo pool %d active elts\n", - pool_elts (f->ooo_segments)); - - seg_index = f->ooos_list_head; - - while (seg_index != OOO_SEGMENT_INVALID_INDEX) - { - seg = pool_elt_at_index (f->ooo_segments, seg_index); - s = format (s, " pos %u, len %u next %d\n", - seg->start, seg->length, seg->next); - seg_index = seg->next; - } - } - return s; -} - u32 svm_fifo_number_ooo_segments (svm_fifo_t * f) { diff --git a/src/vnet/tcp/tcp_test.c b/src/vnet/tcp/tcp_test.c index 12579632..890e50b9 100644 --- a/src/vnet/tcp/tcp_test.c +++ b/src/vnet/tcp/tcp_test.c @@ -294,6 +294,34 @@ fifo_get_validate_pattern (vlib_main_t * vm, test_pattern_t * test_data, return validate_pattern; } +static svm_fifo_t * +fifo_prepare (u32 fifo_size) +{ + svm_fifo_t *f; + f = svm_fifo_create (fifo_size); + + /* Paint fifo data vector with -1's */ + memset (f->data, 0xFF, fifo_size); + + return f; +} + +static int +compare_data (u8 * data1, u8 * data2, u32 start, u32 len, u32 * index) +{ + int i; + + for (i = start; i < len; i++) + { + if (data1[i] != data2[i]) + { + *index = i; + return 1; + } + } + return 0; +} + int tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) { @@ -302,9 +330,9 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) u32 *test_data = 0; u32 offset; int i, rv, verbose = 0; - u32 data_word, test_data_len; + u32 data_word, test_data_len, j; ooo_segment_t *ooo_seg; - u8 *data; + u8 *data, *s, *data_buf = 0; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -318,12 +346,11 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) for (i = 0; i < vec_len (test_data); i++) test_data[i] = i; - f = svm_fifo_create (fifo_size); - - /* Paint fifo data vector with -1's */ - memset (f->data, 0xFF, test_data_len); + f = fifo_prepare (fifo_size); - /* Enqueue an initial (un-dequeued) chunk */ + /* + * Enqueue an initial (un-dequeued) chunk + */ rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ , sizeof (u32), (u8 *) test_data); TCP_TEST ((rv == sizeof (u32)), "enqueued %d", rv); @@ -337,9 +364,7 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) { offset = (2 * i + 1) * sizeof (u32); data = (u8 *) (test_data + (2 * i + 1)); - rv = - svm_fifo_enqueue_with_offset (f, 0 /* pid */ , offset, sizeof (u32), - data); + rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data); if (verbose) vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset, offset + sizeof (u32)); @@ -352,16 +377,23 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) if (verbose) vlib_cli_output (vm, "fifo after odd segs: %U", format_svm_fifo, f, 1); + TCP_TEST ((f->tail == 8), "fifo tail %u", f->tail); - /* Paint some of missing data backwards */ + /* + * Make sure format functions are not buggy + */ + s = format (0, "%U", format_svm_fifo, f, 2); + vec_free (s); + + /* + * Paint some of missing data backwards + */ for (i = 3; i > 1; i--) { offset = (2 * i + 0) * sizeof (u32); data = (u8 *) (test_data + (2 * i + 0)); - rv = - svm_fifo_enqueue_with_offset (f, 0 /* pid */ , offset, sizeof (u32), - data); + rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data); if (verbose) vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i, offset, offset + sizeof (u32)); @@ -383,7 +415,9 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) TCP_TEST ((ooo_seg->length == 16), "first ooo seg length %u", ooo_seg->length); - /* Enqueue the missing u32 */ + /* + * Enqueue the missing u32 + */ rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ , sizeof (u32), (u8 *) (test_data + 2)); if (verbose) @@ -393,7 +427,9 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0), "number of ooo segments %u", svm_fifo_number_ooo_segments (f)); - /* Collect results */ + /* + * Collect results + */ for (i = 0; i < 7; i++) { rv = svm_fifo_dequeue_nowait (f, 0 /* pid */ , sizeof (u32), @@ -411,8 +447,77 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) } } + /* + * Test segment overlaps: last ooo segment overlaps all + */ + svm_fifo_free (f); + f = fifo_prepare (fifo_size); + + for (i = 0; i < 4; i++) + { + offset = (2 * i + 1) * sizeof (u32); + data = (u8 *) (test_data + (2 * i + 1)); + rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data); + if (verbose) + vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset, + offset + sizeof (u32)); + if (rv) + { + clib_warning ("enqueue returned %d", rv); + goto err; + } + } + + rv = svm_fifo_enqueue_with_offset (f, 0, 8, 21, data); + TCP_TEST ((rv == 0), "ooo enqueued %u", rv); + TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1), + "number of ooo segments %u", svm_fifo_number_ooo_segments (f)); + + vec_validate (data_buf, vec_len (data)); + svm_fifo_peek (f, 0, 0, vec_len (data), data_buf); + if (compare_data (data_buf, data, 8, vec_len (data), &j)) + { + TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]); + } + vec_reset_length (data_buf); + + /* + * Test segment overlaps: enqueue and overlap ooo segments + */ + svm_fifo_free (f); + f = fifo_prepare (fifo_size); + + for (i = 0; i < 4; i++) + { + offset = (2 * i + 1) * sizeof (u32); + data = (u8 *) (test_data + (2 * i + 1)); + rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data); + if (verbose) + vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset, + offset + sizeof (u32)); + if (rv) + { + clib_warning ("enqueue returned %d", rv); + goto err; + } + } + + rv = svm_fifo_enqueue_nowait (f, 0, 29, data); + TCP_TEST ((rv == 32), "ooo enqueued %u", rv); + TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0), + "number of ooo segments %u", svm_fifo_number_ooo_segments (f)); + + vec_validate (data_buf, vec_len (data)); + svm_fifo_peek (f, 0, 0, vec_len (data), data_buf); + if (compare_data (data_buf, data, 0, vec_len (data), &j)) + { + TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]); + } + + vec_free (data_buf); svm_fifo_free (f); vec_free (test_data); + return 0; err: @@ -437,10 +542,7 @@ tcp_test_fifo2 (vlib_main_t * vm) vp = fifo_get_validate_pattern (vm, test_data, test_data_len); /* Create a fifo */ - f = svm_fifo_create (fifo_size); - - /* Paint the fifo data vector with -1's */ - memset (f->data, 0xFF, 1 << 20); + f = fifo_prepare (fifo_size); /* * Try with sorted data @@ -473,10 +575,7 @@ tcp_test_fifo2 (vlib_main_t * vm) * Now try it again w/ unsorted data... */ - f = svm_fifo_create (fifo_size); - - /* Paint fifo data vector with -1's */ - memset (f->data, 0xFF, 1 << 20); + f = fifo_prepare (fifo_size); for (i = 0; i < test_data_len; i++) { @@ -516,16 +615,13 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) u32 fifo_size = 4 << 10; u32 fifo_initial_offset = 0; u32 total_size = 2 << 10; - int overlap = 0; - int i, rv; - u8 *data_pattern = 0; + int overlap = 0, verbose = 0, randomize = 1, drop = 0, in_seq_all = 0; + u8 *data_pattern = 0, *data_buf = 0; test_pattern_t *tp, *generate = 0; - u32 nsegs = 2; - u32 seg_size, length_so_far; + u32 nsegs = 2, seg_size, length_so_far; u32 current_offset, offset_increment, len_this_chunk; - u32 seed = 0xdeaddabe; - int verbose = 0; - int randomize = 1; + u32 seed = 0xdeaddabe, j; + int i, rv; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -545,6 +641,10 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) ; else if (unformat (input, "no-randomize")) randomize = 0; + else if (unformat (input, "in-seq-all")) + in_seq_all = 1; + else if (unformat (input, "drop")) + drop = 1; else { clib_error_t *e = clib_error_return @@ -554,6 +654,18 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) } } + if (total_size > fifo_size) + { + clib_warning ("total_size %d greater than fifo size %d", total_size, + fifo_size); + return -1; + } + if (overlap && randomize == 0) + { + clib_warning ("Can't enqueue in-order with overlap"); + return -1; + } + /* * Generate data */ @@ -561,9 +673,12 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) for (i = 0; i < vec_len (data_pattern); i++) data_pattern[i] = i & 0xff; + /* + * Generate segments + */ seg_size = total_size / nsegs; length_so_far = 0; - current_offset = 1; + current_offset = randomize; while (length_so_far < total_size) { vec_add2 (generate, tp, 1); @@ -616,51 +731,100 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) generate[dst_index] = generate[src_index]; generate[src_index] = tmp[0]; } - } - - if (verbose) - { - vlib_cli_output (vm, "randomized data pattern:"); - for (i = 0; i < vec_len (generate); i++) + if (verbose) { - vlib_cli_output (vm, "[%d] offset %u len %u", i, - generate[i].offset, generate[i].len); + vlib_cli_output (vm, "randomized data pattern:"); + for (i = 0; i < vec_len (generate); i++) + { + vlib_cli_output (vm, "[%d] offset %u len %u", i, + generate[i].offset, generate[i].len); + } } } - /* Create a fifo */ - f = svm_fifo_create (fifo_size); - - /* Paint the fifo data vector with -1's */ - memset (f->data, 0xFF, fifo_size); + /* + * Create a fifo and add segments + */ + f = fifo_prepare (fifo_size); /* manually set head and tail pointers to validate modular arithmetic */ - f->head = fifo_initial_offset % fifo_size; - f->tail = fifo_initial_offset % fifo_size; + fifo_initial_offset = fifo_initial_offset % fifo_size; + f->head = fifo_initial_offset; + f->tail = fifo_initial_offset; for (i = 0; i < vec_len (generate); i++) { tp = generate + i; - rv = svm_fifo_enqueue_with_offset (f, 0, tp->offset, tp->len, + rv = svm_fifo_enqueue_with_offset (f, 0, fifo_initial_offset + + tp->offset, tp->len, (u8 *) data_pattern + tp->offset); } - /* Expected result: one big fat chunk at offset 1 */ + /* + * Expected result: one big fat chunk at offset 1 if randomize == 1 + */ if (verbose) vlib_cli_output (vm, "fifo before missing link: %U", format_svm_fifo, f, 1 /* verbose */ ); - rv = svm_fifo_enqueue_nowait (f, 0, 1 /* count */ , data_pattern + 0); + /* + * Add the missing byte if segments were randomized + */ + if (randomize) + { + u32 bytes_to_enq = 1; + if (in_seq_all) + bytes_to_enq = total_size; + rv = svm_fifo_enqueue_nowait (f, 0, bytes_to_enq, data_pattern + 0); + + if (verbose) + vlib_cli_output (vm, "in-order enqueue returned %d", rv); - if (verbose) - vlib_cli_output (vm, "in-order enqueue returned %d", rv); + TCP_TEST ((rv == total_size), "enqueued %u expected %u", rv, + total_size); + + } + + TCP_TEST ((svm_fifo_has_ooo_data (f) == 0), "number of ooo segments %u", + svm_fifo_number_ooo_segments (f)); + + /* + * Test if peeked data is the same as original data + */ + vec_validate (data_buf, vec_len (data_pattern)); + svm_fifo_peek (f, 0, 0, vec_len (data_pattern), data_buf); + if (compare_data (data_buf, data_pattern, 0, vec_len (data_pattern), &j)) + { + TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], + data_pattern[j]); + } + vec_reset_length (data_buf); + + /* + * Dequeue or drop all data + */ + if (drop) + { + svm_fifo_dequeue_drop (f, 0, vec_len (data_pattern)); + } + else + { + svm_fifo_dequeue_nowait (f, 0, vec_len (data_pattern), data_buf); + if (compare_data + (data_buf, data_pattern, 0, vec_len (data_pattern), &j)) + { + TCP_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j], + data_pattern[j]); + } + } + + TCP_TEST ((svm_fifo_max_dequeue (f) == 0), "fifo has %d bytes", + svm_fifo_max_dequeue (f)); - TCP_TEST ((rv == total_size), "retrieved %u expected %u", rv, total_size); - TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0), - "number of ooo segments %u", svm_fifo_number_ooo_segments (f)); svm_fifo_free (f); vec_free (data_pattern); + vec_free (data_buf); return 0; } @@ -669,6 +833,7 @@ static int tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input) { int res = 0; + char *str; /* Run all tests */ if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT) @@ -681,13 +846,35 @@ tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input) if (res) return res; - /* Run a number of fifo3 configs */ - unformat_init_cstring (input, "nsegs 3 overlap seed 123"); + /* + * Run a number of fifo3 configs + */ + str = "nsegs 10 overlap seed 123"; + unformat_init_cstring (input, str); + if (tcp_test_fifo3 (vm, input)) + return -1; + unformat_free (input); + + str = "nsegs 10 overlap seed 123 in-seq-all"; + unformat_init_cstring (input, str); + if (tcp_test_fifo3 (vm, input)) + return -1; + unformat_free (input); + + str = "nsegs 10 overlap seed 123 initial-offset 3917"; + unformat_init_cstring (input, str); + if (tcp_test_fifo3 (vm, input)) + return -1; + unformat_free (input); + + str = "nsegs 10 overlap seed 123 initial-offset 3917 drop"; + unformat_init_cstring (input, str); if (tcp_test_fifo3 (vm, input)) return -1; unformat_free (input); - unformat_init_cstring (input, "nsegs 10"); + str = "nsegs 10 seed 123 initial-offset 3917 drop no-randomize"; + unformat_init_cstring (input, str); if (tcp_test_fifo3 (vm, input)) return -1; unformat_free (input); -- cgit 1.2.3-korg