buffers: fix vector types
[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_DATA_SIZE           (2048)
52 #define VLIB_BUFFER_PRE_DATA_SIZE       __PRE_DATA_SIZE
53
54 /* Minimum buffer chain segment size. Does not apply to last buffer in chain.
55    Dataplane code can safely asume that specified amount of data is not split
56    into 2 chained buffers */
57 #define VLIB_BUFFER_MIN_CHAIN_SEG_SIZE  (128)
58
59 /* Amount of head buffer data copied to each replica head buffer */
60 #define VLIB_BUFFER_CLONE_HEAD_SIZE (256)
61
62 typedef u8 vlib_buffer_free_list_index_t;
63
64 /** \file
65     vlib buffer structure definition and a few select
66     access methods. This structure and the buffer allocation
67     mechanism should perhaps live in vnet, but it would take a lot
68     of typing to make it so.
69 */
70
71 /**
72  * Buffer Flags
73  */
74 #define foreach_vlib_buffer_flag \
75   _( 0, IS_TRACED, 0)                                   \
76   _( 1, NEXT_PRESENT, 0)                                \
77   _( 2, TOTAL_LENGTH_VALID, 0)                          \
78   _( 3, EXT_HDR_VALID, "ext-hdr-valid")
79
80 /* NOTE: only buffer generic flags should be defined here, please consider
81    using user flags. i.e. src/vnet/buffer.h */
82
83 enum
84 {
85 #define _(bit, name, v) VLIB_BUFFER_##name  = (1 << (bit)),
86   foreach_vlib_buffer_flag
87 #undef _
88 };
89
90 enum
91 {
92 #define _(bit, name, v) VLIB_BUFFER_LOG2_##name  = (bit),
93   foreach_vlib_buffer_flag
94 #undef _
95 };
96
97   /* User defined buffer flags. */
98 #define LOG2_VLIB_BUFFER_FLAG_USER(n) (32 - (n))
99 #define VLIB_BUFFER_FLAG_USER(n) (1 << LOG2_VLIB_BUFFER_FLAG_USER(n))
100 #define VLIB_BUFFER_FLAGS_ALL (0x0f)
101
102 /** VLIB buffer representation. */
103 typedef union
104 {
105   struct
106   {
107     CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
108
109     /** signed offset in data[], pre_data[] that we are currently
110       * processing. If negative current header points into predata area.  */
111     i16 current_data;
112
113     /** Nbytes between current data and the end of this buffer.  */
114     u16 current_length;
115
116     /** buffer flags:
117         <br> VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index,
118         <br> VLIB_BUFFER_IS_TRACED: trace this buffer.
119         <br> VLIB_BUFFER_NEXT_PRESENT: this is a multi-chunk buffer.
120         <br> VLIB_BUFFER_TOTAL_LENGTH_VALID: as it says
121         <br> VLIB_BUFFER_EXT_HDR_VALID: buffer contains valid external buffer manager header,
122         set to avoid adding it to a flow report
123         <br> VLIB_BUFFER_FLAG_USER(n): user-defined bit N
124      */
125     u32 flags;
126
127     /** Generic flow identifier */
128     u32 flow_id;
129
130     /** Number of additional references to this buffer. */
131     u8 n_add_refs;
132
133     /** index of buffer pool this buffer belongs. */
134     u8 buffer_pool_index;
135
136     /** Error code for buffers to be enqueued to error handler.  */
137     vlib_error_t error;
138
139     /** Next buffer for this linked-list of buffers. Only valid if
140       * VLIB_BUFFER_NEXT_PRESENT flag is set. */
141     u32 next_buffer;
142
143     /** Used by feature subgraph arcs to visit enabled feature nodes */
144     u32 current_config_index;
145
146     /** Opaque data used by sub-graphs for their own purposes. */
147     u32 opaque[10];
148
149     /** part of buffer metadata which is initialized on alloc ends here. */
150       STRUCT_MARK (template_end);
151
152     /** start of 2nd cache line */
153       CLIB_CACHE_LINE_ALIGN_MARK (cacheline1);
154
155     /** Specifies index into trace buffer if VLIB_PACKET_IS_TRACED flag is
156       * set. */
157     u32 trace_index;
158
159     /** Only valid for first buffer in chain. Current length plus total length
160       * given here give total number of bytes in buffer chain. */
161     u32 total_length_not_including_first_buffer;
162
163     /**< More opaque data, see ../vnet/vnet/buffer.h */
164     u32 opaque2[14];
165
166     /** start of third cache line */
167       CLIB_CACHE_LINE_ALIGN_MARK (cacheline2);
168
169     /** Space for inserting data before buffer start.  Packet rewrite string
170       * will be rewritten backwards and may extend back before
171       * buffer->data[0].  Must come directly before packet data.  */
172     u8 pre_data[VLIB_BUFFER_PRE_DATA_SIZE];
173
174     /** Packet data */
175     u8 data[0];
176   };
177 #ifdef CLIB_HAVE_VEC128
178   u8x16 as_u8x16[4];
179 #endif
180 #ifdef CLIB_HAVE_VEC256
181   u8x32 as_u8x32[2];
182 #endif
183 #ifdef CLIB_HAVE_VEC512
184   u8x64 as_u8x64[1];
185 #endif
186 } vlib_buffer_t;
187
188 #define VLIB_BUFFER_HDR_SIZE  (sizeof(vlib_buffer_t) - VLIB_BUFFER_PRE_DATA_SIZE)
189
190 /** \brief Prefetch buffer metadata.
191     The first 64 bytes of buffer contains most header information
192
193     @param b - (vlib_buffer_t *) pointer to the buffer
194     @param type - LOAD, STORE. In most cases, STORE is the right answer
195 */
196
197 #define vlib_prefetch_buffer_header(b,type) CLIB_PREFETCH (b, 64, type)
198 #define vlib_prefetch_buffer_data(b,type) \
199   CLIB_PREFETCH (vlib_buffer_get_current(b), CLIB_CACHE_LINE_BYTES, type)
200
201 always_inline void
202 vlib_buffer_struct_is_sane (vlib_buffer_t * b)
203 {
204   ASSERT (sizeof (b[0]) % 64 == 0);
205
206   /* Rewrite data must be before and contiguous with packet data. */
207   ASSERT (b->pre_data + VLIB_BUFFER_PRE_DATA_SIZE == b->data);
208 }
209
210 always_inline uword
211 vlib_buffer_get_va (vlib_buffer_t * b)
212 {
213   return pointer_to_uword (b->data);
214 }
215
216 /** \brief Get pointer to current data to process
217
218     @param b - (vlib_buffer_t *) pointer to the buffer
219     @return - (void *) (b->data + b->current_data)
220 */
221
222 always_inline void *
223 vlib_buffer_get_current (vlib_buffer_t * b)
224 {
225   /* Check bounds. */
226   ASSERT ((signed) b->current_data >= (signed) -VLIB_BUFFER_PRE_DATA_SIZE);
227   return b->data + b->current_data;
228 }
229
230 always_inline uword
231 vlib_buffer_get_current_va (vlib_buffer_t * b)
232 {
233   return vlib_buffer_get_va (b) + b->current_data;
234 }
235
236 /** \brief Advance current data pointer by the supplied (signed!) amount
237
238     @param b - (vlib_buffer_t *) pointer to the buffer
239     @param l - (word) signed increment
240 */
241 always_inline void
242 vlib_buffer_advance (vlib_buffer_t * b, word l)
243 {
244   ASSERT (b->current_length >= l);
245   b->current_data += l;
246   b->current_length -= l;
247
248   ASSERT ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0 ||
249           b->current_length >= VLIB_BUFFER_MIN_CHAIN_SEG_SIZE);
250 }
251
252 /** \brief Check if there is enough space in buffer to advance
253
254     @param b - (vlib_buffer_t *) pointer to the buffer
255     @param l - (word) size to check
256     @return - 0 if there is less space than 'l' in buffer
257 */
258 always_inline u8
259 vlib_buffer_has_space (vlib_buffer_t * b, word l)
260 {
261   return b->current_length >= l;
262 }
263
264 /** \brief Reset current header & length to state they were in when
265     packet was received.
266
267     @param b - (vlib_buffer_t *) pointer to the buffer
268 */
269
270 always_inline void
271 vlib_buffer_reset (vlib_buffer_t * b)
272 {
273   b->current_length += clib_max (b->current_data, 0);
274   b->current_data = 0;
275 }
276
277 /** \brief Get pointer to buffer's opaque data array
278
279     @param b - (vlib_buffer_t *) pointer to the buffer
280     @return - (void *) b->opaque
281 */
282 always_inline void *
283 vlib_get_buffer_opaque (vlib_buffer_t * b)
284 {
285   return (void *) b->opaque;
286 }
287
288 /** \brief Get pointer to buffer's opaque2 data array
289
290     @param b - (vlib_buffer_t *) pointer to the buffer
291     @return - (void *) b->opaque2
292 */
293 always_inline void *
294 vlib_get_buffer_opaque2 (vlib_buffer_t * b)
295 {
296   return (void *) b->opaque2;
297 }
298
299 /** \brief Get pointer to the end of buffer's data
300  * @param b     pointer to the buffer
301  * @return      pointer to tail of packet's data
302  */
303 always_inline u8 *
304 vlib_buffer_get_tail (vlib_buffer_t * b)
305 {
306   return b->data + b->current_data + b->current_length;
307 }
308
309 /** \brief Append uninitialized data to buffer
310  * @param b     pointer to the buffer
311  * @param size  number of uninitialized bytes
312  * @return      pointer to beginning of uninitialized data
313  */
314 always_inline void *
315 vlib_buffer_put_uninit (vlib_buffer_t * b, u16 size)
316 {
317   void *p = vlib_buffer_get_tail (b);
318   /* XXX make sure there's enough space */
319   b->current_length += size;
320   return p;
321 }
322
323 /** \brief Prepend uninitialized data to buffer
324  * @param b     pointer to the buffer
325  * @param size  number of uninitialized bytes
326  * @return      pointer to beginning of uninitialized data
327  */
328 always_inline void *
329 vlib_buffer_push_uninit (vlib_buffer_t * b, u8 size)
330 {
331   ASSERT (b->current_data + VLIB_BUFFER_PRE_DATA_SIZE >= size);
332   b->current_data -= size;
333   b->current_length += size;
334
335   return vlib_buffer_get_current (b);
336 }
337
338 /** \brief Make head room, typically for packet headers
339  * @param b     pointer to the buffer
340  * @param size  number of head room bytes
341  * @return      pointer to start of buffer (current data)
342  */
343 always_inline void *
344 vlib_buffer_make_headroom (vlib_buffer_t * b, u8 size)
345 {
346   ASSERT (b->current_data + VLIB_BUFFER_PRE_DATA_SIZE >= size);
347   b->current_data += size;
348   return vlib_buffer_get_current (b);
349 }
350
351 /** \brief Retrieve bytes from buffer head
352  * @param b     pointer to the buffer
353  * @param size  number of bytes to pull
354  * @return      pointer to start of buffer (current data)
355  */
356 always_inline void *
357 vlib_buffer_pull (vlib_buffer_t * b, u8 size)
358 {
359   if (b->current_length + VLIB_BUFFER_PRE_DATA_SIZE < size)
360     return 0;
361
362   void *data = vlib_buffer_get_current (b);
363   vlib_buffer_advance (b, size);
364   return data;
365 }
366
367 /* Forward declaration. */
368 struct vlib_main_t;
369
370 typedef struct vlib_buffer_free_list_t
371 {
372   /* Template buffer used to initialize first 16 bytes of buffers
373      allocated on this free list. */
374   vlib_buffer_t buffer_init_template;
375
376   /* Our index into vlib_main_t's buffer_free_list_pool. */
377   vlib_buffer_free_list_index_t index;
378
379   /* Number of buffers to allocate when we need to allocate new buffers */
380   u32 min_n_buffers_each_alloc;
381
382   /* Total number of buffers allocated from this free list. */
383   u32 n_alloc;
384
385   /* Vector of free buffers.  Each element is a byte offset into I/O heap. */
386   u32 *buffers;
387
388   /* index of buffer pool used to get / put buffers */
389   u8 buffer_pool_index;
390
391   /* Free list name. */
392   u8 *name;
393
394   /* Callback functions to initialize newly allocated buffers.
395      If null buffers are zeroed. */
396   void (*buffer_init_function) (struct vlib_main_t * vm,
397                                 struct vlib_buffer_free_list_t * fl,
398                                 u32 * buffers, u32 n_buffers);
399
400   uword buffer_init_function_opaque;
401 } __attribute__ ((aligned (16))) vlib_buffer_free_list_t;
402
403 typedef uword (vlib_buffer_fill_free_list_cb_t) (struct vlib_main_t * vm,
404                                                  vlib_buffer_free_list_t * fl,
405                                                  uword min_free_buffers);
406 typedef void (vlib_buffer_free_cb_t) (struct vlib_main_t * vm, u32 * buffers,
407                                       u32 n_buffers);
408 typedef void (vlib_buffer_free_no_next_cb_t) (struct vlib_main_t * vm,
409                                               u32 * buffers, u32 n_buffers);
410
411 typedef struct
412 {
413   vlib_buffer_fill_free_list_cb_t *vlib_buffer_fill_free_list_cb;
414   vlib_buffer_free_cb_t *vlib_buffer_free_cb;
415   vlib_buffer_free_no_next_cb_t *vlib_buffer_free_no_next_cb;
416 } vlib_buffer_callbacks_t;
417
418 extern vlib_buffer_callbacks_t *vlib_buffer_callbacks;
419
420 typedef struct
421 {
422   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
423   uword start;
424   uword size;
425   uword log2_page_size;
426   u32 physmem_map_index;
427   u32 buffer_size;
428   u32 *buffers;
429   clib_spinlock_t lock;
430 } vlib_buffer_pool_t;
431
432 typedef struct
433 {
434   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
435   /* Virtual memory address and size of buffer memory, used for calculating
436      buffer index */
437   uword buffer_mem_start;
438   uword buffer_mem_size;
439   vlib_buffer_pool_t *buffer_pools;
440
441   /* Buffer free callback, for subversive activities */
442     u32 (*buffer_free_callback) (struct vlib_main_t * vm,
443                                  u32 * buffers,
444                                  u32 n_buffers, u32 follow_buffer_next);
445 #define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX (0)
446
447   /* Hash table mapping buffer size (rounded to next unit of
448      sizeof (vlib_buffer_t)) to free list index. */
449   uword *free_list_by_size;
450
451   /* Hash table mapping buffer index into number
452      0 => allocated but free, 1 => allocated and not-free.
453      If buffer index is not in hash table then this buffer
454      has never been allocated. */
455   uword *buffer_known_hash;
456   clib_spinlock_t buffer_known_hash_lockp;
457
458   /* Callbacks */
459   vlib_buffer_callbacks_t cb;
460   int callbacks_registered;
461 } vlib_buffer_main_t;
462
463 u8 vlib_buffer_register_physmem_map (struct vlib_main_t *vm,
464                                      u32 physmem_map_index);
465
466 clib_error_t *vlib_buffer_main_init (struct vlib_main_t *vm);
467
468
469 void *vlib_set_buffer_free_callback (struct vlib_main_t *vm, void *fp);
470
471 /*
472  */
473
474 /** \brief Compile time buffer trajectory tracing option
475     Turn this on if you run into "bad monkey" contexts,
476     and you want to know exactly which nodes they've visited...
477     See vlib/main.c...
478 */
479 #define VLIB_BUFFER_TRACE_TRAJECTORY 0
480
481 #if VLIB_BUFFER_TRACE_TRAJECTORY > 0
482 extern void (*vlib_buffer_trace_trajectory_cb) (vlib_buffer_t * b, u32 index);
483 extern void (*vlib_buffer_trace_trajectory_init_cb) (vlib_buffer_t * b);
484 extern void vlib_buffer_trace_trajectory_init (vlib_buffer_t * b);
485 #define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b) \
486   vlib_buffer_trace_trajectory_init (b);
487 #else
488 #define VLIB_BUFFER_TRACE_TRAJECTORY_INIT(b)
489 #endif /* VLIB_BUFFER_TRACE_TRAJECTORY */
490
491 #endif /* included_vlib_buffer_h */
492
493 #define VLIB_BUFFER_REGISTER_CALLBACKS(x,...)                           \
494     __VA_ARGS__ vlib_buffer_callbacks_t __##x##_buffer_callbacks;       \
495 static void __vlib_add_buffer_callbacks_t_##x (void)                    \
496     __attribute__((__constructor__)) ;                                  \
497 static void __vlib_add_buffer_callbacks_t_##x (void)                    \
498 {                                                                       \
499     if (vlib_buffer_callbacks)                                          \
500       clib_panic ("vlib buffer callbacks already registered");          \
501     vlib_buffer_callbacks = &__##x##_buffer_callbacks;                  \
502 }                                                                       \
503 static void __vlib_rm_buffer_callbacks_t_##x (void)                     \
504     __attribute__((__destructor__)) ;                                   \
505 static void __vlib_rm_buffer_callbacks_t_##x (void)                     \
506 { vlib_buffer_callbacks = 0; }                                          \
507 __VA_ARGS__ vlib_buffer_callbacks_t __##x##_buffer_callbacks
508
509 /*
510  * fd.io coding-style-patch-verification: ON
511  *
512  * Local Variables:
513  * eval: (c-set-style "gnu")
514  * End:
515  */