#include <vppinfra/hash.h>
+#if DPDK == 1
+#undef always_inline // dpdk and clib use conflicting always_inline macros.
+#include <rte_config.h>
+#include <rte_mbuf.h>
+
+#if CLIB_DEBUG > 0
+#define always_inline static inline
+#else
+#define always_inline static inline __attribute__ ((__always_inline__))
+#endif
+#endif
+
/** \file
vlib buffer access methods.
*/
{
b = vlib_get_buffer (vm, buffer_index);
l = b->current_length;
- memcpy (contents + content_len, b->data + b->current_data, l);
+ clib_memcpy (contents + content_len, b->data + b->current_data, l);
content_len += l;
if (! (b->flags & VLIB_BUFFER_NEXT_PRESENT))
break;
clib_error_t *
vlib_buffer_pool_create(vlib_main_t * vm, unsigned num_mbufs,
- unsigned mbuf_size, unsigned socket_id);
+ unsigned socket_id);
/** \brief Allocate buffers into supplied array
u32 buffer_index,
void * data, u32 n_data_bytes);
+/*
+ * vlib_buffer_chain_* functions provide a way to create long buffers.
+ * When DPDK is enabled, the 'hidden' DPDK header is taken care of transparently.
+ */
+
+/* Initializes the buffer as an empty packet with no chained buffers. */
+always_inline void
+vlib_buffer_chain_init(vlib_buffer_t *first)
+{
+ first->total_length_not_including_first_buffer = 0;
+ first->current_length = 0;
+ first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
+ first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
+#if DPDK == 1
+ struct rte_mbuf * mb = rte_mbuf_from_vlib_buffer(first);
+ rte_pktmbuf_reset(mb);
+ mb->data_off = VLIB_BUFFER_PRE_DATA_SIZE + first->current_data;
+#endif
+}
+
+/* The provided next_bi buffer index is appended to the end of the packet. */
+always_inline vlib_buffer_t *
+vlib_buffer_chain_buffer(vlib_main_t *vm,
+ vlib_buffer_t *first,
+ vlib_buffer_t *last,
+ u32 next_bi)
+{
+ vlib_buffer_t *next_buffer = vlib_get_buffer(vm, next_bi);
+ last->next_buffer = next_bi;
+ last->flags |= VLIB_BUFFER_NEXT_PRESENT;
+ next_buffer->current_length = 0;
+ next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
+#if DPDK == 1
+ struct rte_mbuf * mb;
+ mb = rte_mbuf_from_vlib_buffer(first);
+ mb->nb_segs++;
+
+ mb = rte_mbuf_from_vlib_buffer(last);
+ mb->next = rte_mbuf_from_vlib_buffer(next_buffer);
+
+ mb = rte_mbuf_from_vlib_buffer(next_buffer);
+ mb->data_len = 0;
+ mb->data_off = VLIB_BUFFER_PRE_DATA_SIZE + next_buffer->current_data;
+ mb->next = 0;
+#endif
+ return next_buffer;
+}
+
+/* Increases or decreases the packet length.
+ * It does not allocate or deallocate new buffers.
+ * Therefore, the added length must be compatible
+ * with the last buffer. */
+always_inline void
+vlib_buffer_chain_increase_length(vlib_buffer_t *first,
+ vlib_buffer_t *last,
+ i32 len)
+{
+ last->current_length += len;
+ if (first != last)
+ first->total_length_not_including_first_buffer += len;
+#if DPDK == 1
+ struct rte_mbuf * mb_first = rte_mbuf_from_vlib_buffer(first);
+ struct rte_mbuf * mb_last = rte_mbuf_from_vlib_buffer(last);
+ mb_first->pkt_len += len;
+ mb_last->data_len += len;
+#endif
+}
+
+/* Copy data to the end of the packet and increases its length.
+ * It does not allocate new buffers.
+ * Returns the number of copied bytes. */
+always_inline u16
+vlib_buffer_chain_append_data(vlib_main_t *vm,
+ u32 free_list_index,
+ vlib_buffer_t *first,
+ vlib_buffer_t *last,
+ void *data, u16 data_len)
+{
+ u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
+ ASSERT(n_buffer_bytes >= last->current_length + last->current_data);
+ u16 len = clib_min(data_len, n_buffer_bytes - last->current_length - last->current_data);
+#if DPDK == 1
+ clib_memcpy(vlib_buffer_get_current (last) + last->current_length, data, len);
+#else
+ clib_memcpy(vlib_buffer_get_current (last) + last->current_length, data, len);
+#endif
+ vlib_buffer_chain_increase_length(first, last, len);
+ return len;
+}
+
+/* Copy data to the end of the packet and increases its length.
+ * Allocates additional buffers from the free list if necessary.
+ * Returns the number of copied bytes.
+ * 'last' value is modified whenever new buffers are allocated and
+ * chained and points to the last buffer in the chain. */
+u16
+vlib_buffer_chain_append_data_with_alloc(vlib_main_t *vm,
+ u32 free_list_index,
+ vlib_buffer_t *first,
+ vlib_buffer_t **last,
+ void * data, u16 data_len);
+void vlib_buffer_chain_validate(vlib_main_t *vm, vlib_buffer_t *first);
+
format_function_t format_vlib_buffer, format_vlib_buffer_and_data, format_vlib_buffer_contents;
typedef struct {
vlib_buffer_union_t * dst = (vlib_buffer_union_t *) _dst;
vlib_buffer_union_t * src = (vlib_buffer_union_t *) &fl->buffer_init_template;
+ /* Make sure vlib_buffer_t is cacheline aligned and sized */
+ ASSERT(STRUCT_OFFSET_OF(vlib_buffer_t, cacheline0) == 0);
+ ASSERT(STRUCT_OFFSET_OF(vlib_buffer_t, cacheline1) == CLIB_CACHE_LINE_BYTES);
+ ASSERT(STRUCT_OFFSET_OF(vlib_buffer_t, cacheline2) == CLIB_CACHE_LINE_BYTES * 2);
+
/* Make sure buffer template is sane. */
ASSERT (fl->index == fl->buffer_init_template.free_list_index);