buffers: introduce vlib_buffer_template_t
[vpp.git] / src / vlib / buffer.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * buffer.h: VLIB buffers
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #ifndef included_vlib_buffer_h
41 #define included_vlib_buffer_h
42
43 #include <vppinfra/types.h>
44 #include <vppinfra/cache.h>
45 #include <vppinfra/serialize.h>
46 #include <vppinfra/vector.h>
47 #include <vppinfra/lock.h>
48 #include <vlib/error.h>         /* for vlib_error_t */
49
50 #include <vlib/config.h>        /* for __PRE_DATA_SIZE */
51 #define VLIB_BUFFER_PRE_DATA_SIZE       __PRE_DATA_SIZE
52
53 #define VLIB_BUFFER_DEFAULT_DATA_SIZE (2048)
54
55 /* Minimum buffer chain segment size. Does not apply to last buffer in chain.
56    Dataplane code can safely asume that specified amount of data is not split
57    into 2 chained buffers */
58 #define VLIB_BUFFER_MIN_CHAIN_SEG_SIZE  (128)
59
60 /* Amount of head buffer data copied to each replica head buffer */
61 #define VLIB_BUFFER_CLONE_HEAD_SIZE (256)
62
63 /** \file
64     vlib buffer structure definition and a few select
65     access methods. This structure and the buffer allocation
66     mechanism should perhaps live in vnet, but it would take a lot
67     of typing to make it so.
68 */
69
70 /**
71  * Buffer Flags
72  */
73 #define foreach_vlib_buffer_flag \
74   _( 0, IS_TRACED, 0)                                   \
75   _( 1, NEXT_PRESENT, "next-present")                   \
76   _( 2, TOTAL_LENGTH_VALID, 0)                          \
77   _( 3, EXT_HDR_VALID, "ext-hdr-valid")
78
79 /* NOTE: only buffer generic flags should be defined here, please consider
80    using user flags. i.e. src/vnet/buffer.h */
81
82 enum
83 {
84 #define _(bit, name, v) VLIB_BUFFER_##name  = (1 << (bit)),
85   foreach_vlib_buffer_flag
86 #undef _
87 };
88
89 enum
90 {
91 #define _(bit, name, v) VLIB_BUFFER_LOG2_##name  = (bit),
92   foreach_vlib_buffer_flag
93 #undef _
94 };
95
96   /* User defined buffer flags. */
97 #define LOG2_VLIB_BUFFER_FLAG_USER(n) (32 - (n))
98 #define VLIB_BUFFER_FLAG_USER(n) (1 << LOG2_VLIB_BUFFER_FLAG_USER(n))
99 #define VLIB_BUFFER_FLAGS_ALL (0x0f)
100
101 /** \brief Compile time buffer trajectory tracing option
102     Turn this on if you run into "bad monkey" contexts,
103     and you want to know exactly which nodes they've visited...
104     See vlib/main.c...
105 */
106 #ifndef VLIB_BUFFER_TRACE_TRAJECTORY
107 #define VLIB_BUFFER_TRACE_TRAJECTORY 0
108 #endif /* VLIB_BUFFER_TRACE_TRAJECTORY */
109
110 #define vlib_buffer_template_fields                                           \
111   /** signed offset in data[], pre_data[] that we are currently               \
112    * processing. If negative current header points into predata area.  */     \
113   i16 current_data;                                                           \
114                                                                               \
115   /** Nbytes between current data and the end of this buffer.  */             \
116   u16 current_length;                                                         \
117   /** buffer flags:                                                           \
118       <br> VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list     \
119      index, <br> VLIB_BUFFER_IS_TRACED: trace this buffer. <br>               \
120      VLIB_BUFFER_NEXT_PRESENT: this is a multi-chunk buffer. <br>             \
121      VLIB_BUFFER_TOTAL_LENGTH_VALID: as it says <br>                          \
122      VLIB_BUFFER_EXT_HDR_VALID: buffer contains valid external buffer manager \
123      header, set to avoid adding it to a flow report <br>                     \
124      VLIB_BUFFER_FLAG_USER(n): user-defined bit N                             \
125    */                                                                         \
126   u32 flags;                                                                  \
127                                                                               \
128   /** Generic flow identifier */                                              \
129   u32 flow_id;                                                                \
130                                                                               \
131   /** Reference count for this buffer. */                                     \
132   volatile u8 ref_count;                                                      \
133                                                                               \
134   /** index of buffer pool this buffer belongs. */                            \
135   u8 buffer_pool_index;                                                       \
136                                                                               \
137   /** Error code for buffers to be enqueued to error handler.  */             \
138   vlib_error_t error;                                                         \
139                                                                               \
140   /** Next buffer for this linked-list of buffers. Only valid if              \
141    * VLIB_BUFFER_NEXT_PRESENT flag is set. */                                 \
142   u32 next_buffer;                                                            \
143                                                                               \
144   /** The following fields can be in a union because once a packet enters     \
145    * the punt path, it is no longer on a feature arc */                       \
146   union                                                                       \
147   {                                                                           \
148     /** Used by feature subgraph arcs to visit enabled feature nodes */       \
149     u32 current_config_index;                                                 \
150     /* the reason the packet once punted */                                   \
151     u32 punt_reason;                                                          \
152   };                                                                          \
153                                                                               \
154   /** Opaque data used by sub-graphs for their own purposes. */               \
155   u32 opaque[10];
156
157 typedef struct
158 {
159   CLIB_ALIGN_MARK (align_mark, 64);
160   vlib_buffer_template_fields
161 } vlib_buffer_template_t;
162
163 STATIC_ASSERT_SIZEOF (vlib_buffer_template_t, 64);
164
165 /** VLIB buffer representation. */
166 typedef union
167 {
168   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
169   struct
170   {
171     union
172     {
173       struct
174       {
175         vlib_buffer_template_fields
176       };
177       vlib_buffer_template_t template;
178     };
179
180     /* Data above is initialized or zeroed on alloc, data bellow is not
181      * and it is app responsibility to ensure data is valid */
182
183     /** start of 2nd half (2nd cacheline on systems where cacheline size is 64) */
184       CLIB_ALIGN_MARK (second_half, 64);
185
186     /** Specifies trace buffer handle if VLIB_PACKET_IS_TRACED flag is
187       * set. */
188     u32 trace_handle;
189
190     /** Only valid for first buffer in chain. Current length plus total length
191       * given here give total number of bytes in buffer chain. */
192     u32 total_length_not_including_first_buffer;
193
194     /**< More opaque data, see ../vnet/vnet/buffer.h */
195     u32 opaque2[14];
196
197 #if VLIB_BUFFER_TRACE_TRAJECTORY > 0
198     /** trace trajectory data - we use a specific cacheline for that in the
199      * buffer when it is compiled-in */
200 #define VLIB_BUFFER_TRACE_TRAJECTORY_MAX     31
201 #define VLIB_BUFFER_TRACE_TRAJECTORY_SZ      64
202 #define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) (b)->trajectory_nb = 0
203     CLIB_ALIGN_MARK (trajectory, 64);
204     u16 trajectory_nb;
205     u16 trajectory_trace[VLIB_BUFFER_TRACE_TRAJECTORY_MAX];
206 #else /* VLIB_BUFFER_TRACE_TRAJECTORY */
207 #define VLIB_BUFFER_TRACE_TRAJECTORY_SZ 0
208 #define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
209 #endif /* VLIB_BUFFER_TRACE_TRAJECTORY */
210
211     /** start of buffer headroom */
212       CLIB_ALIGN_MARK (headroom, 64);
213
214     /** Space for inserting data before buffer start.  Packet rewrite string
215       * will be rewritten backwards and may extend back before
216       * buffer->data[0].  Must come directly before packet data.  */
217     u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE];
218
219     /** Packet data */
220     u8 data[];
221   };
222 #ifdef CLIB_HAVE_VEC128
223   u8x16 as_u8x16[4];
224 #endif
225 #ifdef CLIB_HAVE_VEC256
226   u8x32 as_u8x32[2];
227 #endif
228 #ifdef CLIB_HAVE_VEC512
229   u8x64 as_u8x64[1];
230 #endif
231 } vlib_buffer_t;
232
233 STATIC_ASSERT_SIZEOF (vlib_buffer_t, 128 + VLIB_BUFFER_TRACE_TRAJECTORY_SZ +
234                                        VLIB_BUFFER_PRE_DATA_SIZE);
235 STATIC_ASSERT (VLIB_BUFFER_PRE_DATA_SIZE % CLIB_CACHE_LINE_BYTES == 0,
236                "VLIB_BUFFER_PRE_DATA_SIZE must be divisible by cache line size");
237
238 #define VLIB_BUFFER_HDR_SIZE  (sizeof(vlib_buffer_t) - VLIB_BUFFER_PRE_DATA_SIZE)
239
240 /** \brief Prefetch buffer metadata.
241     The first 64 bytes of buffer contains most header information
242
243     @param b - (vlib_buffer_t *) pointer to the buffer
244     @param type - LOAD, STORE. In most cases, STORE is the right answer
245 */
246
247 #define vlib_prefetch_buffer_header(b,type) CLIB_PREFETCH (b, 64, type)
248 #define vlib_prefetch_buffer_data(b,type) \
249   CLIB_PREFETCH (vlib_buffer_get_current(b), CLIB_CACHE_LINE_BYTES, type)
250
251 always_inline void
252 vlib_buffer_struct_is_sane (vlib_buffer_t * b)
253 {
254   ASSERT (sizeof (b[0]) % 64 == 0);
255
256   /* Rewrite data must be before and contiguous with packet data. */
257   ASSERT (b->pre_data + VLIB_BUFFER_PRE_DATA_SIZE == b->data);
258 }
259
260 always_inline uword
261 vlib_buffer_get_va (vlib_buffer_t * b)
262 {
263   return pointer_to_uword (b->data);
264 }
265
266 /** \brief Get pointer to current data to process
267
268     @param b - (vlib_buffer_t *) pointer to the buffer
269     @return - (void *) (b->data + b->current_data)
270 */
271
272 always_inline void *
273 vlib_buffer_get_current (vlib_buffer_t * b)
274 {
275   /* Check bounds. */
276   ASSERT ((signed) b->current_data >= (signed) -VLIB_BUFFER_PRE_DATA_SIZE);
277   return b->data + b->current_data;
278 }
279
280 always_inline uword
281 vlib_buffer_get_current_va (vlib_buffer_t * b)
282 {
283   return vlib_buffer_get_va (b) + b->current_data;
284 }
285
286 /** \brief Advance current data pointer by the supplied (signed!) amount
287
288     @param b - (vlib_buffer_t *) pointer to the buffer
289     @param l - (word) signed increment
290 */
291 always_inline void
292 vlib_buffer_advance (vlib_buffer_t * b, word l)
293 {
294   ASSERT (b->current_length >= l);
295   b->current_data += l;
296   b->current_length -= l;
297
298   ASSERT ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0 ||
299           b->current_length >= VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
300 }
301
302 /** \brief Check if there is enough space in buffer to advance
303
304     @param b - (vlib_buffer_t *) pointer to the buffer
305     @param l - (word) size to check
306     @return - 0 if there is less space than 'l' in buffer
307 */
308 always_inline u8
309 vlib_buffer_has_space (vlib_buffer_t * b, word l)
310 {
311   return b->current_length >= l;
312 }
313
314 /** \brief Reset current header & length to state they were in when
315     packet was received.
316
317     @param b - (vlib_buffer_t *) pointer to the buffer
318 */
319
320 always_inline void
321 vlib_buffer_reset (vlib_buffer_t * b)
322 {
323   b->current_length += clib_max (b->current_data, 0);
324   b->current_data = 0;
325 }
326
327 /** \brief Get pointer to buffer's opaque data array
328
329     @param b - (vlib_buffer_t *) pointer to the buffer
330     @return - (void *) b->opaque
331 */
332 always_inline void *
333 vlib_get_buffer_opaque (vlib_buffer_t * b)
334 {
335   return (void *) b->opaque;
336 }
337
338 /** \brief Get pointer to buffer's opaque2 data array
339
340     @param b - (vlib_buffer_t *) pointer to the buffer
341     @return - (void *) b->opaque2
342 */
343 always_inline void *
344 vlib_get_buffer_opaque2 (vlib_buffer_t * b)
345 {
346   return (void *) b->opaque2;
347 }
348
349 /** \brief Get pointer to the end of buffer's data
350  * @param b     pointer to the buffer
351  * @return      pointer to tail of packet's data
352  */
353 always_inline u8 *
354 vlib_buffer_get_tail (vlib_buffer_t * b)
355 {
356   return b->data + b->current_data + b->current_length;
357 }
358
359 /** \brief Append uninitialized data to buffer
360  * @param b     pointer to the buffer
361  * @param size  number of uninitialized bytes
362  * @return      pointer to beginning of uninitialized data
363  */
364 always_inline void *
365 vlib_buffer_put_uninit (vlib_buffer_t * b, u16 size)
366 {
367   void *p = vlib_buffer_get_tail (b);
368   /* XXX make sure there's enough space */
369   b->current_length += size;
370   return p;
371 }
372
373 /** \brief Prepend uninitialized data to buffer
374  * @param b     pointer to the buffer
375  * @param size  number of uninitialized bytes
376  * @return      pointer to beginning of uninitialized data
377  */
378 always_inline void *
379 vlib_buffer_push_uninit (vlib_buffer_t * b, u8 size)
380 {
381   ASSERT (b->current_data + VLIB_BUFFER_PRE_DATA_SIZE >= size);
382   b->current_data -= size;
383   b->current_length += size;
384
385   return vlib_buffer_get_current (b);
386 }
387
388 /** \brief Make head room, typically for packet headers
389  * @param b     pointer to the buffer
390  * @param size  number of head room bytes
391  * @return      pointer to start of buffer (current data)
392  */
393 always_inline void *
394 vlib_buffer_make_headroom (vlib_buffer_t * b, u8 size)
395 {
396   b->current_data += size;
397   return vlib_buffer_get_current (b);
398 }
399
400 /** \brief Construct a trace handle from thread and pool index
401  * @param thread Thread id
402  * @param pool_index Pool index
403  * @return trace handle
404  */
405 always_inline u32
406 vlib_buffer_make_trace_handle (u32 thread, u32 pool_index)
407 {
408   u32 rv;
409   ASSERT (thread < 0xff);
410   ASSERT (pool_index < 0x00FFFFFF);
411   rv = (thread << 24) | (pool_index & 0x00FFFFFF);
412   return rv;
413 }
414
415 /** \brief Extract the thread id from a trace handle
416  * @param trace_handle the trace handle
417  * @return the thread id
418  */
419 always_inline u32
420 vlib_buffer_get_trace_thread (vlib_buffer_t * b)
421 {
422   u32 trace_handle = b->trace_handle;
423
424   return trace_handle >> 24;
425 }
426
427 /** \brief Extract the trace (pool) index from a trace handle
428  * @param trace_handle the trace handle
429  * @return the trace index
430  */
431 always_inline u32
432 vlib_buffer_get_trace_index (vlib_buffer_t * b)
433 {
434   u32 trace_handle = b->trace_handle;
435   return trace_handle & 0x00FFFFFF;
436 }
437
438 /** \brief Retrieve bytes from buffer head
439  * @param b     pointer to the buffer
440  * @param size  number of bytes to pull
441  * @return      pointer to start of buffer (current data)
442  */
443 always_inline void *
444 vlib_buffer_pull (vlib_buffer_t * b, u8 size)
445 {
446   if (b->current_length + VLIB_BUFFER_PRE_DATA_SIZE < size)
447     return 0;
448
449   void *data = vlib_buffer_get_current (b);
450   vlib_buffer_advance (b, size);
451   return data;
452 }
453
454 /* Forward declaration. */
455 struct vlib_main_t;
456
457 #define VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ 512
458
459 typedef struct
460 {
461   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
462   u32 cached_buffers[VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ];
463   u32 n_cached;
464 } vlib_buffer_pool_thread_t;
465
466 typedef struct
467 {
468   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
469   uword start;
470   uword size;
471   u8 log2_page_size;
472   u8 index;
473   u8 numa_node;
474   u32 physmem_map_index;
475   u32 data_size;
476   u32 alloc_size;
477   u32 n_buffers;
478   u32 n_avail;
479   u32 *buffers;
480   u8 *name;
481   clib_spinlock_t lock;
482
483   /* per-thread data */
484   vlib_buffer_pool_thread_t *threads;
485
486   /* buffer metadata template */
487   vlib_buffer_template_t buffer_template;
488 } vlib_buffer_pool_t;
489
490 #define VLIB_BUFFER_MAX_NUMA_NODES 32
491
492 typedef u32 (vlib_buffer_alloc_free_callback_t) (struct vlib_main_t *vm,
493                                                  u8 buffer_pool_index,
494                                                  u32 *buffers, u32 n_buffers);
495
496 typedef struct
497 {
498   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
499   /* Virtual memory address and size of buffer memory, used for calculating
500      buffer index */
501   uword buffer_mem_start;
502   uword buffer_mem_size;
503   vlib_buffer_pool_t *buffer_pools;
504
505   vlib_buffer_alloc_free_callback_t *alloc_callback_fn;
506   vlib_buffer_alloc_free_callback_t *free_callback_fn;
507
508   u8 default_buffer_pool_index_for_numa[VLIB_BUFFER_MAX_NUMA_NODES];
509
510   /* config */
511   u32 buffers_per_numa;
512   u16 ext_hdr_size;
513   u32 default_data_size;
514   clib_mem_page_sz_t log2_page_size;
515
516   /* Hash table mapping buffer index into number
517      0 => allocated but free, 1 => allocated and not-free.
518      If buffer index is not in hash table then this buffer
519      has never been allocated. */
520   uword *buffer_known_hash;
521   clib_spinlock_t buffer_known_hash_lockp;
522
523   /* logging */
524   vlib_log_class_t log_default;
525 } vlib_buffer_main_t;
526
527 clib_error_t *vlib_buffer_main_init (struct vlib_main_t *vm);
528
529 format_function_t format_vlib_buffer_pool_all;
530
531 int vlib_buffer_set_alloc_free_callback (
532   struct vlib_main_t *vm, vlib_buffer_alloc_free_callback_t *alloc_callback_fn,
533   vlib_buffer_alloc_free_callback_t *free_callback_fn);
534
535 extern u16 __vlib_buffer_external_hdr_size;
536 #define VLIB_BUFFER_SET_EXT_HDR_SIZE(x) \
537 static void __clib_constructor \
538 vnet_buffer_set_ext_hdr_size() \
539 { \
540   if (__vlib_buffer_external_hdr_size) \
541     clib_error ("buffer external header space already set"); \
542   __vlib_buffer_external_hdr_size = CLIB_CACHE_LINE_ROUND (x); \
543 }
544
545 #endif /* included_vlib_buffer_h */
546
547 /*
548  * fd.io coding-style-patch-verification: ON
549  *
550  * Local Variables:
551  * eval: (c-set-style "gnu")
552  * End:
553  */