aboutsummaryrefslogtreecommitdiffstats
path: root/src/vlib
diff options
context:
space:
mode:
authorEyal Bari <ebari@cisco.com>2018-11-05 13:29:25 +0200
committerJohn Lo <loj@cisco.com>2018-11-20 02:52:39 +0000
commitd3d424180fcd98561d656d5c2189e9e59ef2b2b9 (patch)
treea9288e7e960b97072de833fb3453303c1d242198 /src/vlib
parentc7b03fe8f3fd2753d97ffdf8e7ebd85e2c527085 (diff)
dhcp4:(VPP-1483) linearize chained packets before handling
dhcp packets might (when flooded) arrive in chains of cloned buffers Change-Id: Ifddecd656b6a5d6ba8cd94184f5c021684e35548 Signed-off-by: Eyal Bari <ebari@cisco.com>
Diffstat (limited to 'src/vlib')
-rw-r--r--src/vlib/buffer.h2
-rw-r--r--src/vlib/buffer_funcs.h64
2 files changed, 65 insertions, 1 deletions
diff --git a/src/vlib/buffer.h b/src/vlib/buffer.h
index 493d111041e..02b170907ba 100644
--- a/src/vlib/buffer.h
+++ b/src/vlib/buffer.h
@@ -302,7 +302,7 @@ vlib_buffer_get_tail (vlib_buffer_t * b)
* @return pointer to beginning of uninitialized data
*/
always_inline void *
-vlib_buffer_put_uninit (vlib_buffer_t * b, u8 size)
+vlib_buffer_put_uninit (vlib_buffer_t * b, u16 size)
{
void *p = vlib_buffer_get_tail (b);
/* XXX make sure there's enough space */
diff --git a/src/vlib/buffer_funcs.h b/src/vlib/buffer_funcs.h
index d15ef5702f8..e8ccc86f1a9 100644
--- a/src/vlib/buffer_funcs.h
+++ b/src/vlib/buffer_funcs.h
@@ -1267,6 +1267,70 @@ vlib_buffer_chain_compress (vlib_main_t * vm,
(first->flags & VLIB_BUFFER_NEXT_PRESENT));
}
+/**
+ * @brief linearize buffer chain - the first buffer is filled, if needed,
+ * buffers are allocated and filled, returns free space in last buffer or
+ * negative on failure
+ *
+ * @param[in] vm - vlib_main
+ * @param[in,out] first - first buffer in chain
+ */
+always_inline int
+vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * first)
+{
+ vlib_buffer_t *b = first;
+ vlib_buffer_free_list_t *fl =
+ vlib_buffer_get_free_list (vm, vlib_buffer_get_free_list_index (b));
+ u32 buf_len = fl->n_data_bytes;
+ // free buffer chain starting from the second buffer
+ int free_count = (b->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
+ u32 chain_to_free = b->next_buffer;
+
+ u32 len = vlib_buffer_length_in_chain (vm, b);
+ u32 free_len = buf_len - b->current_data - b->current_length;
+ int alloc_len = clib_max (len - free_len, 0); //use the free len in the first buffer
+ int n_buffers = (alloc_len + buf_len - 1) / buf_len;
+ u32 new_buffers[n_buffers];
+
+ u32 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
+ if (n_alloc != n_buffers)
+ {
+ vlib_buffer_free_no_next (vm, new_buffers, n_alloc);
+ return -1;
+ }
+
+ vlib_buffer_t *s = b;
+ while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
+ {
+ s = vlib_get_buffer (vm, s->next_buffer);
+ int d_free_len = buf_len - b->current_data - b->current_length;
+ ASSERT (d_free_len >= 0);
+ // chain buf and split write
+ u32 copy_len = clib_min (d_free_len, s->current_length);
+ u8 *d = vlib_buffer_put_uninit (b, copy_len);
+ clib_memcpy (d, vlib_buffer_get_current (s), copy_len);
+ int rest = s->current_length - copy_len;
+ if (rest > 0)
+ {
+ //prev buf is full
+ ASSERT (vlib_buffer_get_tail (b) == b->data + buf_len);
+ ASSERT (n_buffers > 0);
+ b = vlib_buffer_chain_buffer (vm, b, new_buffers[--n_buffers]);
+ //make full use of the new buffers
+ b->current_data = 0;
+ d = vlib_buffer_put_uninit (b, rest);
+ clib_memcpy (d, vlib_buffer_get_current (s) + copy_len, rest);
+ }
+ }
+ vlib_buffer_free (vm, &chain_to_free, free_count);
+ b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
+ if (b == first) /* no buffers addeed */
+ b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
+ ASSERT (len == vlib_buffer_length_in_chain (vm, first));
+ ASSERT (n_buffers == 0);
+ return buf_len - b->current_data - b->current_length;
+}
+
#endif /* included_vlib_buffer_funcs_h */
/*