X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlib%2Fbuffer.h;h=7d45689ed19a70d3b9ac8e1876201e2e415539d3;hb=e8ea6be8dfb626b5bb4ff3355ce8037724ce1d83;hp=095c09d10f6db3e64a24c9e7bc25a3db7b74643e;hpb=9a8a12a06e9e67c4ef339d3002cdc5151341826d;p=vpp.git diff --git a/src/vlib/buffer.h b/src/vlib/buffer.h index 095c09d10f6..7d45689ed19 100644 --- a/src/vlib/buffer.h +++ b/src/vlib/buffer.h @@ -47,9 +47,9 @@ #include #include /* for vlib_error_t */ -#include /* for __PRE_DATA_SIZE */ -#define VLIB_BUFFER_DATA_SIZE (2048) -#define VLIB_BUFFER_PRE_DATA_SIZE __PRE_DATA_SIZE +#include /* for VLIB_BUFFER_PRE_DATA_SIZE */ + +#define VLIB_BUFFER_DEFAULT_DATA_SIZE (2048) /* Minimum buffer chain segment size. Does not apply to last buffer in chain. Dataplane code can safely asume that specified amount of data is not split @@ -59,8 +59,6 @@ /* Amount of head buffer data copied to each replica head buffer */ #define VLIB_BUFFER_CLONE_HEAD_SIZE (256) -typedef u8 vlib_buffer_free_list_index_t; - /** \file vlib buffer structure definition and a few select access methods. This structure and the buffer allocation @@ -73,7 +71,7 @@ typedef u8 vlib_buffer_free_list_index_t; */ #define foreach_vlib_buffer_flag \ _( 0, IS_TRACED, 0) \ - _( 1, NEXT_PRESENT, 0) \ + _( 1, NEXT_PRESENT, "next-present") \ _( 2, TOTAL_LENGTH_VALID, 0) \ _( 3, EXT_HDR_VALID, "ext-hdr-valid") @@ -99,62 +97,94 @@ enum #define VLIB_BUFFER_FLAG_USER(n) (1 << LOG2_VLIB_BUFFER_FLAG_USER(n)) #define VLIB_BUFFER_FLAGS_ALL (0x0f) +/** \brief Compile time buffer trajectory tracing option + Turn this on if you run into "bad monkey" contexts, + and you want to know exactly which nodes they've visited... + See vlib/main.c... +*/ +#ifndef VLIB_BUFFER_TRACE_TRAJECTORY +#define VLIB_BUFFER_TRACE_TRAJECTORY 0 +#endif /* VLIB_BUFFER_TRACE_TRAJECTORY */ + +#define vlib_buffer_template_fields \ + /** signed offset in data[], pre_data[] that we are currently \ + * processing. If negative current header points into predata area. */ \ + i16 current_data; \ + \ + /** Nbytes between current data and the end of this buffer. */ \ + u16 current_length; \ + /** buffer flags: \ +
VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list \ + index,
VLIB_BUFFER_IS_TRACED: trace this buffer.
\ + VLIB_BUFFER_NEXT_PRESENT: this is a multi-chunk buffer.
\ + VLIB_BUFFER_TOTAL_LENGTH_VALID: as it says
\ + VLIB_BUFFER_EXT_HDR_VALID: buffer contains valid external buffer manager \ + header, set to avoid adding it to a flow report
\ + VLIB_BUFFER_FLAG_USER(n): user-defined bit N \ + */ \ + u32 flags; \ + \ + /** Generic flow identifier */ \ + u32 flow_id; \ + \ + /** Reference count for this buffer. */ \ + volatile u8 ref_count; \ + \ + /** index of buffer pool this buffer belongs. */ \ + u8 buffer_pool_index; \ + \ + /** Error code for buffers to be enqueued to error handler. */ \ + vlib_error_t error; \ + \ + /** Next buffer for this linked-list of buffers. Only valid if \ + * VLIB_BUFFER_NEXT_PRESENT flag is set. */ \ + u32 next_buffer; \ + \ + /** The following fields can be in a union because once a packet enters \ + * the punt path, it is no longer on a feature arc */ \ + union \ + { \ + /** Used by feature subgraph arcs to visit enabled feature nodes */ \ + u32 current_config_index; \ + /* the reason the packet once punted */ \ + u32 punt_reason; \ + }; \ + \ + /** Opaque data used by sub-graphs for their own purposes. */ \ + u32 opaque[10]; + +typedef struct +{ + CLIB_ALIGN_MARK (align_mark, 64); + vlib_buffer_template_fields +} vlib_buffer_template_t; + +STATIC_ASSERT_SIZEOF (vlib_buffer_template_t, 64); + /** VLIB buffer representation. */ typedef union { + CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); struct { - CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - - /** signed offset in data[], pre_data[] that we are currently - * processing. If negative current header points into predata area. */ - i16 current_data; - - /** Nbytes between current data and the end of this buffer. */ - u16 current_length; - - /** buffer flags: -
VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, -
VLIB_BUFFER_IS_TRACED: trace this buffer. -
VLIB_BUFFER_NEXT_PRESENT: this is a multi-chunk buffer. -
VLIB_BUFFER_TOTAL_LENGTH_VALID: as it says -
VLIB_BUFFER_EXT_HDR_VALID: buffer contains valid external buffer manager header, - set to avoid adding it to a flow report -
VLIB_BUFFER_FLAG_USER(n): user-defined bit N - */ - u32 flags; - - /** Generic flow identifier */ - u32 flow_id; - - /** Number of additional references to this buffer. */ - u8 n_add_refs; - - /** index of buffer pool this buffer belongs. */ - u8 buffer_pool_index; - - /** Error code for buffers to be enqueued to error handler. */ - vlib_error_t error; - - /** Next buffer for this linked-list of buffers. Only valid if - * VLIB_BUFFER_NEXT_PRESENT flag is set. */ - u32 next_buffer; - - /** Used by feature subgraph arcs to visit enabled feature nodes */ - u32 current_config_index; - - /** Opaque data used by sub-graphs for their own purposes. */ - u32 opaque[10]; - - /** part of buffer metadata which is initialized on alloc ends here. */ - STRUCT_MARK (template_end); - - /** start of 2nd cache line */ - CLIB_CACHE_LINE_ALIGN_MARK (cacheline1); - - /** Specifies index into trace buffer if VLIB_PACKET_IS_TRACED flag is + union + { + struct + { + vlib_buffer_template_fields + }; + vlib_buffer_template_t template; + }; + + /* Data above is initialized or zeroed on alloc, data bellow is not + * and it is app responsibility to ensure data is valid */ + + /** start of 2nd half (2nd cacheline on systems where cacheline size is 64) */ + CLIB_ALIGN_MARK (second_half, 64); + + /** Specifies trace buffer handle if VLIB_PACKET_IS_TRACED flag is * set. */ - u32 trace_index; + u32 trace_handle; /** Only valid for first buffer in chain. Current length plus total length * given here give total number of bytes in buffer chain. */ @@ -163,8 +193,22 @@ typedef union /**< More opaque data, see ../vnet/vnet/buffer.h */ u32 opaque2[14]; - /** start of third cache line */ - CLIB_CACHE_LINE_ALIGN_MARK (cacheline2); +#if VLIB_BUFFER_TRACE_TRAJECTORY > 0 + /** trace trajectory data - we use a specific cacheline for that in the + * buffer when it is compiled-in */ +#define VLIB_BUFFER_TRACE_TRAJECTORY_MAX 31 +#define VLIB_BUFFER_TRACE_TRAJECTORY_SZ 64 +#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) (b)->trajectory_nb = 0 + CLIB_ALIGN_MARK (trajectory, 64); + u16 trajectory_nb; + u16 trajectory_trace[VLIB_BUFFER_TRACE_TRAJECTORY_MAX]; +#else /* VLIB_BUFFER_TRACE_TRAJECTORY */ +#define VLIB_BUFFER_TRACE_TRAJECTORY_SZ 0 +#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) +#endif /* VLIB_BUFFER_TRACE_TRAJECTORY */ + + /** start of buffer headroom */ + CLIB_ALIGN_MARK (headroom, 64); /** Space for inserting data before buffer start. Packet rewrite string * will be rewritten backwards and may extend back before @@ -172,20 +216,26 @@ typedef union u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE]; /** Packet data */ - u8 data[0]; + u8 data[]; }; #ifdef CLIB_HAVE_VEC128 u8x16 as_u8x16[4]; #endif #ifdef CLIB_HAVE_VEC256 - u8x16 as_u8x32[2]; + u8x32 as_u8x32[2]; #endif #ifdef CLIB_HAVE_VEC512 - u8x16 as_u8x64[1]; + u8x64 as_u8x64[1]; #endif } vlib_buffer_t; +STATIC_ASSERT_SIZEOF (vlib_buffer_t, 128 + VLIB_BUFFER_TRACE_TRAJECTORY_SZ + + VLIB_BUFFER_PRE_DATA_SIZE); +STATIC_ASSERT (VLIB_BUFFER_PRE_DATA_SIZE % CLIB_CACHE_LINE_BYTES == 0, + "VLIB_BUFFER_PRE_DATA_SIZE must be divisible by cache line size"); + #define VLIB_BUFFER_HDR_SIZE (sizeof(vlib_buffer_t) - VLIB_BUFFER_PRE_DATA_SIZE) +#define VLIB_BUFFER_INVALID_INDEX 0xffffffff /** \brief Prefetch buffer metadata. The first 64 bytes of buffer contains most header information @@ -343,11 +393,48 @@ vlib_buffer_push_uninit (vlib_buffer_t * b, u8 size) always_inline void * vlib_buffer_make_headroom (vlib_buffer_t * b, u8 size) { - ASSERT (b->current_data + VLIB_BUFFER_PRE_DATA_SIZE >= size); b->current_data += size; return vlib_buffer_get_current (b); } +/** \brief Construct a trace handle from thread and pool index + * @param thread Thread id + * @param pool_index Pool index + * @return trace handle + */ +always_inline u32 +vlib_buffer_make_trace_handle (u32 thread, u32 pool_index) +{ + u32 rv; + ASSERT (thread < 0xff); + ASSERT (pool_index < 0x00FFFFFF); + rv = (thread << 24) | (pool_index & 0x00FFFFFF); + return rv; +} + +/** \brief Extract the thread id from a trace handle + * @param trace_handle the trace handle + * @return the thread id + */ +always_inline u32 +vlib_buffer_get_trace_thread (vlib_buffer_t * b) +{ + u32 trace_handle = b->trace_handle; + + return trace_handle >> 24; +} + +/** \brief Extract the trace (pool) index from a trace handle + * @param trace_handle the trace handle + * @return the trace index + */ +always_inline u32 +vlib_buffer_get_trace_index (vlib_buffer_t * b) +{ + u32 trace_handle = b->trace_handle; + return trace_handle & 0x00FFFFFF; +} + /** \brief Retrieve bytes from buffer head * @param b pointer to the buffer * @param size number of bytes to pull @@ -367,68 +454,45 @@ vlib_buffer_pull (vlib_buffer_t * b, u8 size) /* Forward declaration. */ struct vlib_main_t; -typedef struct vlib_buffer_free_list_t -{ - /* Template buffer used to initialize first 16 bytes of buffers - allocated on this free list. */ - vlib_buffer_t buffer_init_template; - - /* Our index into vlib_main_t's buffer_free_list_pool. */ - vlib_buffer_free_list_index_t index; - - /* Number of buffers to allocate when we need to allocate new buffers */ - u32 min_n_buffers_each_alloc; - - /* Total number of buffers allocated from this free list. */ - u32 n_alloc; - - /* Vector of free buffers. Each element is a byte offset into I/O heap. */ - u32 *buffers; - - /* index of buffer pool used to get / put buffers */ - u8 buffer_pool_index; - - /* Free list name. */ - u8 *name; - - /* Callback functions to initialize newly allocated buffers. - If null buffers are zeroed. */ - void (*buffer_init_function) (struct vlib_main_t * vm, - struct vlib_buffer_free_list_t * fl, - u32 * buffers, u32 n_buffers); - - uword buffer_init_function_opaque; -} __attribute__ ((aligned (16))) vlib_buffer_free_list_t; - -typedef uword (vlib_buffer_fill_free_list_cb_t) (struct vlib_main_t * vm, - vlib_buffer_free_list_t * fl, - uword min_free_buffers); -typedef void (vlib_buffer_free_cb_t) (struct vlib_main_t * vm, u32 * buffers, - u32 n_buffers); -typedef void (vlib_buffer_free_no_next_cb_t) (struct vlib_main_t * vm, - u32 * buffers, u32 n_buffers); +#define VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ 512 typedef struct { - vlib_buffer_fill_free_list_cb_t *vlib_buffer_fill_free_list_cb; - vlib_buffer_free_cb_t *vlib_buffer_free_cb; - vlib_buffer_free_no_next_cb_t *vlib_buffer_free_no_next_cb; -} vlib_buffer_callbacks_t; - -extern vlib_buffer_callbacks_t *vlib_buffer_callbacks; + CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); + u32 cached_buffers[VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ]; + u32 n_cached; +} vlib_buffer_pool_thread_t; typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); uword start; uword size; - uword log2_page_size; + u8 log2_page_size; + u8 index; + u8 numa_node; u32 physmem_map_index; - u32 buffer_size; + u32 data_size; + u32 alloc_size; + u32 n_buffers; + u32 n_avail; u32 *buffers; + u8 *name; clib_spinlock_t lock; + + /* per-thread data */ + vlib_buffer_pool_thread_t *threads; + + /* buffer metadata template */ + vlib_buffer_template_t buffer_template; } vlib_buffer_pool_t; +#define VLIB_BUFFER_MAX_NUMA_NODES 32 + +typedef u32 (vlib_buffer_alloc_free_callback_t) (struct vlib_main_t *vm, + u8 buffer_pool_index, + u32 *buffers, u32 n_buffers); + typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); @@ -438,15 +502,16 @@ typedef struct uword buffer_mem_size; vlib_buffer_pool_t *buffer_pools; - /* Buffer free callback, for subversive activities */ - u32 (*buffer_free_callback) (struct vlib_main_t * vm, - u32 * buffers, - u32 n_buffers, u32 follow_buffer_next); -#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX (0) + vlib_buffer_alloc_free_callback_t *alloc_callback_fn; + vlib_buffer_alloc_free_callback_t *free_callback_fn; + + u8 default_buffer_pool_index_for_numa[VLIB_BUFFER_MAX_NUMA_NODES]; - /* Hash table mapping buffer size (rounded to next unit of - sizeof (vlib_buffer_t)) to free list index. */ - uword *free_list_by_size; + /* config */ + u32 buffers_per_numa; + u16 ext_hdr_size; + u32 default_data_size; + clib_mem_page_sz_t log2_page_size; /* Hash table mapping buffer index into number 0 => allocated but free, 1 => allocated and not-free. @@ -455,57 +520,30 @@ typedef struct uword *buffer_known_hash; clib_spinlock_t buffer_known_hash_lockp; - /* Callbacks */ - vlib_buffer_callbacks_t cb; - int callbacks_registered; + /* logging */ + vlib_log_class_t log_default; } vlib_buffer_main_t; -u8 vlib_buffer_register_physmem_map (struct vlib_main_t *vm, - u32 physmem_map_index); - clib_error_t *vlib_buffer_main_init (struct vlib_main_t *vm); +format_function_t format_vlib_buffer_pool_all; -void *vlib_set_buffer_free_callback (struct vlib_main_t *vm, void *fp); +int vlib_buffer_set_alloc_free_callback ( + struct vlib_main_t *vm, vlib_buffer_alloc_free_callback_t *alloc_callback_fn, + vlib_buffer_alloc_free_callback_t *free_callback_fn); -/* - */ - -/** \brief Compile time buffer trajectory tracing option - Turn this on if you run into "bad monkey" contexts, - and you want to know exactly which nodes they've visited... - See vlib/main.c... -*/ -#define VLIB_BUFFER_TRACE_TRAJECTORY 0 - -#if VLIB_BUFFER_TRACE_TRAJECTORY > 0 -extern void (*vlib_buffer_trace_trajectory_cb) (vlib_buffer_t * b, u32 index); -extern void (*vlib_buffer_trace_trajectory_init_cb) (vlib_buffer_t * b); -extern void vlib_buffer_trace_trajectory_init (vlib_buffer_t * b); -#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) \ - vlib_buffer_trace_trajectory_init (b); -#else -#define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) -#endif /* VLIB_BUFFER_TRACE_TRAJECTORY */ +extern u16 __vlib_buffer_external_hdr_size; +#define VLIB_BUFFER_SET_EXT_HDR_SIZE(x) \ +static void __clib_constructor \ +vnet_buffer_set_ext_hdr_size() \ +{ \ + if (__vlib_buffer_external_hdr_size) \ + clib_error ("buffer external header space already set"); \ + __vlib_buffer_external_hdr_size = CLIB_CACHE_LINE_ROUND (x); \ +} #endif /* included_vlib_buffer_h */ -#define VLIB_BUFFER_REGISTER_CALLBACKS(x,...) \ - __VA_ARGS__ vlib_buffer_callbacks_t __##x##_buffer_callbacks; \ -static void __vlib_add_buffer_callbacks_t_##x (void) \ - __attribute__((__constructor__)) ; \ -static void __vlib_add_buffer_callbacks_t_##x (void) \ -{ \ - if (vlib_buffer_callbacks) \ - clib_panic ("vlib buffer callbacks already registered"); \ - vlib_buffer_callbacks = &__##x##_buffer_callbacks; \ -} \ -static void __vlib_rm_buffer_callbacks_t_##x (void) \ - __attribute__((__destructor__)) ; \ -static void __vlib_rm_buffer_callbacks_t_##x (void) \ -{ vlib_buffer_callbacks = 0; } \ -__VA_ARGS__ vlib_buffer_callbacks_t __##x##_buffer_callbacks - /* * fd.io coding-style-patch-verification: ON *