summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/svm/svm_fifo.c100
-rw-r--r--src/vnet/tcp/tcp_test.c305
2 files changed, 292 insertions, 113 deletions
diff --git a/src/svm/svm_fifo.c b/src/svm/svm_fifo.c
index bd968aeac4c..f428d3eced7 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 12579632e3d..890e50b9b24 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);