IP6 SR multicast replicator
[vpp.git] / vlib / vlib / buffer_funcs.h
index 452cdcb..1c3ffe2 100644 (file)
 
 #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.
 */
@@ -138,7 +150,7 @@ vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
     {
       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;
@@ -241,7 +253,7 @@ u8 * vlib_validate_buffers (vlib_main_t * vm,
 
 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
 
@@ -398,6 +410,109 @@ u32 vlib_buffer_add_data (vlib_main_t * vm,
                          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 {
@@ -479,6 +594,11 @@ vlib_buffer_init_for_free_list (vlib_buffer_t * _dst,
   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);