7829986d6432544ff3152b7bdc01d2306e61fa1e
[vpp.git] / src / vlib / buffer_funcs.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_funcs.h: VLIB buffer related functions/inlines
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_funcs_h
41 #define included_vlib_buffer_funcs_h
42
43 #include <vppinfra/hash.h>
44 #include <vppinfra/fifo.h>
45 #include <vlib/buffer.h>
46 #include <vlib/physmem_funcs.h>
47 #include <vlib/main.h>
48 #include <vlib/node.h>
49
50 /** \file
51     vlib buffer access methods.
52 */
53
54 typedef void (vlib_buffer_enqueue_to_next_fn_t) (vlib_main_t *vm,
55                                                  vlib_node_runtime_t *node,
56                                                  u32 *buffers, u16 *nexts,
57                                                  uword count);
58 typedef void (vlib_buffer_enqueue_to_single_next_fn_t) (
59   vlib_main_t *vm, vlib_node_runtime_t *node, u32 *ers, u16 next_index,
60   u32 count);
61
62 typedef u32 (vlib_buffer_enqueue_to_thread_fn_t) (
63   vlib_main_t *vm, u32 frame_queue_index, u32 *buffer_indices,
64   u16 *thread_indices, u32 n_packets, int drop_on_congestion);
65 typedef struct
66 {
67   vlib_buffer_enqueue_to_next_fn_t *buffer_enqueue_to_next_fn;
68   vlib_buffer_enqueue_to_single_next_fn_t *buffer_enqueue_to_single_next_fn;
69   vlib_buffer_enqueue_to_thread_fn_t *buffer_enqueue_to_thread_fn;
70 } vlib_buffer_func_main_t;
71
72 extern vlib_buffer_func_main_t vlib_buffer_func_main;
73
74 always_inline void
75 vlib_buffer_validate (vlib_main_t * vm, vlib_buffer_t * b)
76 {
77   vlib_buffer_main_t *bm = vm->buffer_main;
78   vlib_buffer_pool_t *bp;
79
80   /* reference count in allocated buffer always must be 1 or higher */
81   ASSERT (b->ref_count > 0);
82
83   /* verify that buffer pool index is valid */
84   bp = vec_elt_at_index (bm->buffer_pools, b->buffer_pool_index);
85   ASSERT (pointer_to_uword (b) >= bp->start);
86   ASSERT (pointer_to_uword (b) < bp->start + bp->size -
87           (bp->data_size + sizeof (vlib_buffer_t)));
88 }
89
90 always_inline void *
91 vlib_buffer_ptr_from_index (uword buffer_mem_start, u32 buffer_index,
92                             uword offset)
93 {
94   offset += ((uword) buffer_index) << CLIB_LOG2_CACHE_LINE_BYTES;
95   return uword_to_pointer (buffer_mem_start + offset, vlib_buffer_t *);
96 }
97
98 /** \brief Translate buffer index into buffer pointer
99
100     @param vm - (vlib_main_t *) vlib main data structure pointer
101     @param buffer_index - (u32) buffer index
102     @return - (vlib_buffer_t *) buffer pointer
103 */
104 always_inline vlib_buffer_t *
105 vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
106 {
107   vlib_buffer_main_t *bm = vm->buffer_main;
108   vlib_buffer_t *b;
109
110   b = vlib_buffer_ptr_from_index (bm->buffer_mem_start, buffer_index, 0);
111   vlib_buffer_validate (vm, b);
112   return b;
113 }
114
115 static_always_inline u32
116 vlib_buffer_get_default_data_size (vlib_main_t * vm)
117 {
118   return vm->buffer_main->default_data_size;
119 }
120
121 static_always_inline void
122 vlib_buffer_copy_indices (u32 * dst, u32 * src, u32 n_indices)
123 {
124   clib_memcpy_u32 (dst, src, n_indices);
125 }
126
127 always_inline void
128 vlib_buffer_copy_indices_from_ring (u32 * dst, u32 * ring, u32 start,
129                                     u32 ring_size, u32 n_buffers)
130 {
131   ASSERT (n_buffers <= ring_size);
132
133   if (PREDICT_TRUE (start + n_buffers <= ring_size))
134     {
135       vlib_buffer_copy_indices (dst, ring + start, n_buffers);
136     }
137   else
138     {
139       u32 n = ring_size - start;
140       vlib_buffer_copy_indices (dst, ring + start, n);
141       vlib_buffer_copy_indices (dst + n, ring, n_buffers - n);
142     }
143 }
144
145 always_inline void
146 vlib_buffer_copy_indices_to_ring (u32 * ring, u32 * src, u32 start,
147                                   u32 ring_size, u32 n_buffers)
148 {
149   ASSERT (n_buffers <= ring_size);
150
151   if (PREDICT_TRUE (start + n_buffers <= ring_size))
152     {
153       vlib_buffer_copy_indices (ring + start, src, n_buffers);
154     }
155   else
156     {
157       u32 n = ring_size - start;
158       vlib_buffer_copy_indices (ring + start, src, n);
159       vlib_buffer_copy_indices (ring, src + n, n_buffers - n);
160     }
161 }
162
163 STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, template_end, 64);
164 static_always_inline void
165 vlib_buffer_copy_template (vlib_buffer_t * b, vlib_buffer_t * bt)
166 {
167 #if defined CLIB_HAVE_VEC512
168   b->as_u8x64[0] = bt->as_u8x64[0];
169 #elif defined (CLIB_HAVE_VEC256)
170   b->as_u8x32[0] = bt->as_u8x32[0];
171   b->as_u8x32[1] = bt->as_u8x32[1];
172 #elif defined (CLIB_HAVE_VEC128)
173   b->as_u8x16[0] = bt->as_u8x16[0];
174   b->as_u8x16[1] = bt->as_u8x16[1];
175   b->as_u8x16[2] = bt->as_u8x16[2];
176   b->as_u8x16[3] = bt->as_u8x16[3];
177 #else
178   clib_memcpy_fast (b, bt, 64);
179 #endif
180 }
181
182 always_inline u8
183 vlib_buffer_pool_get_default_for_numa (vlib_main_t * vm, u32 numa_node)
184 {
185   ASSERT (numa_node < VLIB_BUFFER_MAX_NUMA_NODES);
186   return vm->buffer_main->default_buffer_pool_index_for_numa[numa_node];
187 }
188
189 /** \brief Translate array of buffer indices into buffer pointers with offset
190
191     @param vm - (vlib_main_t *) vlib main data structure pointer
192     @param bi - (u32 *) array of buffer indices
193     @param b - (void **) array to store buffer pointers
194     @param count - (uword) number of elements
195     @param offset - (i32) offset applied to each pointer
196 */
197 static_always_inline void
198 vlib_get_buffers_with_offset (vlib_main_t * vm, u32 * bi, void **b, int count,
199                               i32 offset)
200 {
201   uword buffer_mem_start = vm->buffer_main->buffer_mem_start;
202 #ifdef CLIB_HAVE_VEC512
203   u64x8 of8 = u64x8_splat (buffer_mem_start + offset);
204   u64x4 off = u64x8_extract_lo (of8);
205   /* if count is not const, compiler will not unroll while loop
206      se we maintain two-in-parallel variant */
207   while (count >= 32)
208     {
209       u64x8 b0 = u64x8_from_u32x8 (u32x8_load_unaligned (bi));
210       u64x8 b1 = u64x8_from_u32x8 (u32x8_load_unaligned (bi + 8));
211       u64x8 b2 = u64x8_from_u32x8 (u32x8_load_unaligned (bi + 16));
212       u64x8 b3 = u64x8_from_u32x8 (u32x8_load_unaligned (bi + 24));
213       /* shift and add to get vlib_buffer_t pointer */
214       u64x8_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + of8, b);
215       u64x8_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + of8, b + 8);
216       u64x8_store_unaligned ((b2 << CLIB_LOG2_CACHE_LINE_BYTES) + of8, b + 16);
217       u64x8_store_unaligned ((b3 << CLIB_LOG2_CACHE_LINE_BYTES) + of8, b + 24);
218       b += 32;
219       bi += 32;
220       count -= 32;
221     }
222   while (count >= 8)
223     {
224       u64x8 b0 = u64x8_from_u32x8 (u32x8_load_unaligned (bi));
225       /* shift and add to get vlib_buffer_t pointer */
226       u64x8_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + of8, b);
227       b += 8;
228       bi += 8;
229       count -= 8;
230     }
231 #elif defined CLIB_HAVE_VEC256
232   u64x4 off = u64x4_splat (buffer_mem_start + offset);
233   /* if count is not const, compiler will not unroll while loop
234      se we maintain two-in-parallel variant */
235   while (count >= 32)
236     {
237       u64x4 b0 = u64x4_from_u32x4 (u32x4_load_unaligned (bi));
238       u64x4 b1 = u64x4_from_u32x4 (u32x4_load_unaligned (bi + 4));
239       u64x4 b2 = u64x4_from_u32x4 (u32x4_load_unaligned (bi + 8));
240       u64x4 b3 = u64x4_from_u32x4 (u32x4_load_unaligned (bi + 12));
241       u64x4 b4 = u64x4_from_u32x4 (u32x4_load_unaligned (bi + 16));
242       u64x4 b5 = u64x4_from_u32x4 (u32x4_load_unaligned (bi + 20));
243       u64x4 b6 = u64x4_from_u32x4 (u32x4_load_unaligned (bi + 24));
244       u64x4 b7 = u64x4_from_u32x4 (u32x4_load_unaligned (bi + 28));
245       /* shift and add to get vlib_buffer_t pointer */
246       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
247       u64x4_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 4);
248       u64x4_store_unaligned ((b2 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 8);
249       u64x4_store_unaligned ((b3 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 12);
250       u64x4_store_unaligned ((b4 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 16);
251       u64x4_store_unaligned ((b5 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 20);
252       u64x4_store_unaligned ((b6 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 24);
253       u64x4_store_unaligned ((b7 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 28);
254       b += 32;
255       bi += 32;
256       count -= 32;
257     }
258 #endif
259   while (count >= 4)
260     {
261 #ifdef CLIB_HAVE_VEC256
262       u64x4 b0 = u64x4_from_u32x4 (u32x4_load_unaligned (bi));
263       /* shift and add to get vlib_buffer_t pointer */
264       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
265 #elif defined (CLIB_HAVE_VEC128)
266       u64x2 off = u64x2_splat (buffer_mem_start + offset);
267       u32x4 bi4 = u32x4_load_unaligned (bi);
268       u64x2 b0 = u64x2_from_u32x4 ((u32x4) bi4);
269 #if defined (__aarch64__)
270       u64x2 b1 = u64x2_from_u32x4_high ((u32x4) bi4);
271 #else
272       bi4 = u32x4_shuffle (bi4, 2, 3, 0, 1);
273       u64x2 b1 = u64x2_from_u32x4 ((u32x4) bi4);
274 #endif
275       u64x2_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
276       u64x2_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 2);
277 #else
278       b[0] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[0], offset);
279       b[1] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[1], offset);
280       b[2] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[2], offset);
281       b[3] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[3], offset);
282 #endif
283       b += 4;
284       bi += 4;
285       count -= 4;
286     }
287   while (count)
288     {
289       b[0] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[0], offset);
290       b += 1;
291       bi += 1;
292       count -= 1;
293     }
294 }
295
296 /** \brief Translate array of buffer indices into buffer pointers
297
298     @param vm - (vlib_main_t *) vlib main data structure pointer
299     @param bi - (u32 *) array of buffer indices
300     @param b - (vlib_buffer_t **) array to store buffer pointers
301     @param count - (uword) number of elements
302 */
303
304 static_always_inline void
305 vlib_get_buffers (vlib_main_t * vm, u32 * bi, vlib_buffer_t ** b, int count)
306 {
307   vlib_get_buffers_with_offset (vm, bi, (void **) b, count, 0);
308 }
309
310 /** \brief Translate buffer pointer into buffer index
311
312     @param vm - (vlib_main_t *) vlib main data structure pointer
313     @param p - (void *) buffer pointer
314     @return - (u32) buffer index
315 */
316
317 always_inline u32
318 vlib_get_buffer_index (vlib_main_t * vm, void *p)
319 {
320   vlib_buffer_main_t *bm = vm->buffer_main;
321   uword offset = pointer_to_uword (p) - bm->buffer_mem_start;
322   ASSERT (pointer_to_uword (p) >= bm->buffer_mem_start);
323   ASSERT (offset < bm->buffer_mem_size);
324   ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
325   return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
326 }
327
328 /** \brief Translate array of buffer pointers into buffer indices with offset
329
330     @param vm - (vlib_main_t *) vlib main data structure pointer
331     @param b - (void **) array of buffer pointers
332     @param bi - (u32 *) array to store buffer indices
333     @param count - (uword) number of elements
334     @param offset - (i32) offset applied to each pointer
335 */
336 static_always_inline void
337 vlib_get_buffer_indices_with_offset (vlib_main_t * vm, void **b, u32 * bi,
338                                      uword count, i32 offset)
339 {
340 #ifdef CLIB_HAVE_VEC256
341   u32x8 mask = { 0, 2, 4, 6, 1, 3, 5, 7 };
342   u64x4 off4 = u64x4_splat (vm->buffer_main->buffer_mem_start - offset);
343
344   while (count >= 8)
345     {
346       /* load 4 pointers into 256-bit register */
347       u64x4 v0 = u64x4_load_unaligned (b);
348       u64x4 v1 = u64x4_load_unaligned (b + 4);
349       u32x8 v2, v3;
350
351       v0 -= off4;
352       v1 -= off4;
353
354       v0 >>= CLIB_LOG2_CACHE_LINE_BYTES;
355       v1 >>= CLIB_LOG2_CACHE_LINE_BYTES;
356
357       /* permute 256-bit register so lower u32s of each buffer index are
358        * placed into lower 128-bits */
359       v2 = u32x8_permute ((u32x8) v0, mask);
360       v3 = u32x8_permute ((u32x8) v1, mask);
361
362       /* extract lower 128-bits and save them to the array of buffer indices */
363       u32x4_store_unaligned (u32x8_extract_lo (v2), bi);
364       u32x4_store_unaligned (u32x8_extract_lo (v3), bi + 4);
365       bi += 8;
366       b += 8;
367       count -= 8;
368     }
369 #endif
370   while (count >= 4)
371     {
372       /* equivalent non-nector implementation */
373       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
374       bi[1] = vlib_get_buffer_index (vm, ((u8 *) b[1]) + offset);
375       bi[2] = vlib_get_buffer_index (vm, ((u8 *) b[2]) + offset);
376       bi[3] = vlib_get_buffer_index (vm, ((u8 *) b[3]) + offset);
377       bi += 4;
378       b += 4;
379       count -= 4;
380     }
381   while (count)
382     {
383       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
384       bi += 1;
385       b += 1;
386       count -= 1;
387     }
388 }
389
390 /** \brief Translate array of buffer pointers into buffer indices
391
392     @param vm - (vlib_main_t *) vlib main data structure pointer
393     @param b - (vlib_buffer_t **) array of buffer pointers
394     @param bi - (u32 *) array to store buffer indices
395     @param count - (uword) number of elements
396 */
397 static_always_inline void
398 vlib_get_buffer_indices (vlib_main_t * vm, vlib_buffer_t ** b, u32 * bi,
399                          uword count)
400 {
401   vlib_get_buffer_indices_with_offset (vm, (void **) b, bi, count, 0);
402 }
403
404 /** \brief Get next buffer in buffer linklist, or zero for end of list.
405
406     @param vm - (vlib_main_t *) vlib main data structure pointer
407     @param b - (void *) buffer pointer
408     @return - (vlib_buffer_t *) next buffer, or NULL
409 */
410 always_inline vlib_buffer_t *
411 vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
412 {
413   return (b->flags & VLIB_BUFFER_NEXT_PRESENT
414           ? vlib_get_buffer (vm, b->next_buffer) : 0);
415 }
416
417 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
418                                              vlib_buffer_t * b_first);
419
420 /** \brief Get length in bytes of the buffer chain
421
422     @param vm - (vlib_main_t *) vlib main data structure pointer
423     @param b - (void *) buffer pointer
424     @return - (uword) length of buffer chain
425 */
426 always_inline uword
427 vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
428 {
429   uword len = b->current_length;
430
431   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
432     return len;
433
434   if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
435     return len + b->total_length_not_including_first_buffer;
436
437   return vlib_buffer_length_in_chain_slow_path (vm, b);
438 }
439
440 /** \brief Get length in bytes of the buffer index buffer chain
441
442     @param vm - (vlib_main_t *) vlib main data structure pointer
443     @param bi - (u32) buffer index
444     @return - (uword) length of buffer chain
445 */
446 always_inline uword
447 vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
448 {
449   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
450   return vlib_buffer_length_in_chain (vm, b);
451 }
452
453 /** \brief Copy buffer contents to memory
454
455     @param vm - (vlib_main_t *) vlib main data structure pointer
456     @param buffer_index - (u32) buffer index
457     @param contents - (u8 *) memory, <strong>must be large enough</strong>
458     @return - (uword) length of buffer chain
459 */
460 always_inline uword
461 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
462 {
463   uword content_len = 0;
464   uword l;
465   vlib_buffer_t *b;
466
467   while (1)
468     {
469       b = vlib_get_buffer (vm, buffer_index);
470       l = b->current_length;
471       clib_memcpy_fast (contents + content_len, b->data + b->current_data, l);
472       content_len += l;
473       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
474         break;
475       buffer_index = b->next_buffer;
476     }
477
478   return content_len;
479 }
480
481 always_inline uword
482 vlib_buffer_get_pa (vlib_main_t * vm, vlib_buffer_t * b)
483 {
484   return vlib_physmem_get_pa (vm, b->data);
485 }
486
487 always_inline uword
488 vlib_buffer_get_current_pa (vlib_main_t * vm, vlib_buffer_t * b)
489 {
490   return vlib_buffer_get_pa (vm, b) + b->current_data;
491 }
492
493 /** \brief Prefetch buffer metadata by buffer index
494     The first 64 bytes of buffer contains most header information
495
496     @param vm - (vlib_main_t *) vlib main data structure pointer
497     @param bi - (u32) buffer index
498     @param type - LOAD, STORE. In most cases, STORE is the right answer
499 */
500 /* Prefetch buffer header given index. */
501 #define vlib_prefetch_buffer_with_index(vm,bi,type)     \
502   do {                                                  \
503     vlib_buffer_t * _b = vlib_get_buffer (vm, bi);      \
504     vlib_prefetch_buffer_header (_b, type);             \
505   } while (0)
506
507 typedef enum
508 {
509   /* Index is unknown. */
510   VLIB_BUFFER_UNKNOWN,
511
512   /* Index is known and free/allocated. */
513   VLIB_BUFFER_KNOWN_FREE,
514   VLIB_BUFFER_KNOWN_ALLOCATED,
515 } vlib_buffer_known_state_t;
516
517 void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
518                                       uword n_buffers,
519                                       vlib_buffer_known_state_t
520                                       expected_state);
521
522 always_inline vlib_buffer_known_state_t
523 vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
524 {
525   vlib_buffer_main_t *bm = vm->buffer_main;
526
527   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
528   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
529   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
530   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
531 }
532
533 /* Validates sanity of a single buffer.
534    Returns format'ed vector with error message if any. */
535 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
536                           uword follow_chain);
537
538 u8 *vlib_validate_buffers (vlib_main_t * vm,
539                            u32 * buffers,
540                            uword next_buffer_stride,
541                            uword n_buffers,
542                            vlib_buffer_known_state_t known_state,
543                            uword follow_buffer_next);
544
545 static_always_inline vlib_buffer_pool_t *
546 vlib_get_buffer_pool (vlib_main_t * vm, u8 buffer_pool_index)
547 {
548   vlib_buffer_main_t *bm = vm->buffer_main;
549   return vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
550 }
551
552 static_always_inline __clib_warn_unused_result uword
553 vlib_buffer_pool_get (vlib_main_t * vm, u8 buffer_pool_index, u32 * buffers,
554                       u32 n_buffers)
555 {
556   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
557   u32 len;
558
559   ASSERT (bp->buffers);
560
561   clib_spinlock_lock (&bp->lock);
562   len = bp->n_avail;
563   if (PREDICT_TRUE (n_buffers < len))
564     {
565       len -= n_buffers;
566       vlib_buffer_copy_indices (buffers, bp->buffers + len, n_buffers);
567       bp->n_avail = len;
568       clib_spinlock_unlock (&bp->lock);
569       return n_buffers;
570     }
571   else
572     {
573       vlib_buffer_copy_indices (buffers, bp->buffers, len);
574       bp->n_avail = 0;
575       clib_spinlock_unlock (&bp->lock);
576       return len;
577     }
578 }
579
580
581 /** \brief Allocate buffers from specific pool into supplied array
582
583     @param vm - (vlib_main_t *) vlib main data structure pointer
584     @param buffers - (u32 * ) buffer index array
585     @param n_buffers - (u32) number of buffers requested
586     @return - (u32) number of buffers actually allocated, may be
587     less than the number requested or zero
588 */
589
590 always_inline __clib_warn_unused_result u32
591 vlib_buffer_alloc_from_pool (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
592                              u8 buffer_pool_index)
593 {
594   vlib_buffer_main_t *bm = vm->buffer_main;
595   vlib_buffer_pool_t *bp;
596   vlib_buffer_pool_thread_t *bpt;
597   u32 *src, *dst, len, n_left;
598
599   /* If buffer allocation fault injection is configured */
600   if (VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0)
601     {
602       u32 vlib_buffer_alloc_may_fail (vlib_main_t *, u32);
603
604       /* See how many buffers we're willing to allocate */
605       n_buffers = vlib_buffer_alloc_may_fail (vm, n_buffers);
606       if (n_buffers == 0)
607         return (n_buffers);
608     }
609
610   bp = vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
611   bpt = vec_elt_at_index (bp->threads, vm->thread_index);
612
613   dst = buffers;
614   n_left = n_buffers;
615   len = bpt->n_cached;
616
617   /* per-thread cache contains enough buffers */
618   if (len >= n_buffers)
619     {
620       src = bpt->cached_buffers + len - n_buffers;
621       vlib_buffer_copy_indices (dst, src, n_buffers);
622       bpt->n_cached -= n_buffers;
623
624       if (CLIB_DEBUG > 0)
625         vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
626                                          VLIB_BUFFER_KNOWN_FREE);
627       return n_buffers;
628     }
629
630   /* alloc bigger than cache - take buffers directly from main pool */
631   if (n_buffers >= VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ)
632     {
633       n_buffers = vlib_buffer_pool_get (vm, buffer_pool_index, buffers,
634                                         n_buffers);
635
636       if (CLIB_DEBUG > 0)
637         vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
638                                          VLIB_BUFFER_KNOWN_FREE);
639       return n_buffers;
640     }
641
642   /* take everything available in the cache */
643   if (len)
644     {
645       vlib_buffer_copy_indices (dst, bpt->cached_buffers, len);
646       bpt->n_cached = 0;
647       dst += len;
648       n_left -= len;
649     }
650
651   len = round_pow2 (n_left, 32);
652   len = vlib_buffer_pool_get (vm, buffer_pool_index, bpt->cached_buffers,
653                               len);
654   bpt->n_cached = len;
655
656   if (len)
657     {
658       u32 n_copy = clib_min (len, n_left);
659       src = bpt->cached_buffers + len - n_copy;
660       vlib_buffer_copy_indices (dst, src, n_copy);
661       bpt->n_cached -= n_copy;
662       n_left -= n_copy;
663     }
664
665   n_buffers -= n_left;
666
667   /* Verify that buffers are known free. */
668   if (CLIB_DEBUG > 0)
669     vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
670                                      VLIB_BUFFER_KNOWN_FREE);
671
672   return n_buffers;
673 }
674
675 /** \brief Allocate buffers from specific numa node into supplied array
676
677     @param vm - (vlib_main_t *) vlib main data structure pointer
678     @param buffers - (u32 * ) buffer index array
679     @param n_buffers - (u32) number of buffers requested
680     @param numa_node - (u32) numa node
681     @return - (u32) number of buffers actually allocated, may be
682     less than the number requested or zero
683 */
684 always_inline __clib_warn_unused_result u32
685 vlib_buffer_alloc_on_numa (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
686                            u32 numa_node)
687 {
688   u8 index = vlib_buffer_pool_get_default_for_numa (vm, numa_node);
689   return vlib_buffer_alloc_from_pool (vm, buffers, n_buffers, index);
690 }
691
692 /** \brief Allocate buffers into supplied array
693
694     @param vm - (vlib_main_t *) vlib main data structure pointer
695     @param buffers - (u32 * ) buffer index array
696     @param n_buffers - (u32) number of buffers requested
697     @return - (u32) number of buffers actually allocated, may be
698     less than the number requested or zero
699 */
700
701 always_inline __clib_warn_unused_result u32
702 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
703 {
704   return vlib_buffer_alloc_on_numa (vm, buffers, n_buffers, vm->numa_node);
705 }
706
707 /** \brief Allocate buffers into ring
708
709     @param vm - (vlib_main_t *) vlib main data structure pointer
710     @param buffers - (u32 * ) buffer index ring
711     @param start - (u32) first slot in the ring
712     @param ring_size - (u32) ring size
713     @param n_buffers - (u32) number of buffers requested
714     @return - (u32) number of buffers actually allocated, may be
715     less than the number requested or zero
716 */
717 always_inline __clib_warn_unused_result u32
718 vlib_buffer_alloc_to_ring (vlib_main_t * vm, u32 * ring, u32 start,
719                            u32 ring_size, u32 n_buffers)
720 {
721   u32 n_alloc;
722
723   ASSERT (n_buffers <= ring_size);
724
725   if (PREDICT_TRUE (start + n_buffers <= ring_size))
726     return vlib_buffer_alloc (vm, ring + start, n_buffers);
727
728   n_alloc = vlib_buffer_alloc (vm, ring + start, ring_size - start);
729
730   if (PREDICT_TRUE (n_alloc == ring_size - start))
731     n_alloc += vlib_buffer_alloc (vm, ring, n_buffers - n_alloc);
732
733   return n_alloc;
734 }
735
736 /** \brief Allocate buffers into ring from specific buffer pool
737
738     @param vm - (vlib_main_t *) vlib main data structure pointer
739     @param buffers - (u32 * ) buffer index ring
740     @param start - (u32) first slot in the ring
741     @param ring_size - (u32) ring size
742     @param n_buffers - (u32) number of buffers requested
743     @return - (u32) number of buffers actually allocated, may be
744     less than the number requested or zero
745 */
746 always_inline __clib_warn_unused_result u32
747 vlib_buffer_alloc_to_ring_from_pool (vlib_main_t * vm, u32 * ring, u32 start,
748                                      u32 ring_size, u32 n_buffers,
749                                      u8 buffer_pool_index)
750 {
751   u32 n_alloc;
752
753   ASSERT (n_buffers <= ring_size);
754
755   if (PREDICT_TRUE (start + n_buffers <= ring_size))
756     return vlib_buffer_alloc_from_pool (vm, ring + start, n_buffers,
757                                         buffer_pool_index);
758
759   n_alloc = vlib_buffer_alloc_from_pool (vm, ring + start, ring_size - start,
760                                          buffer_pool_index);
761
762   if (PREDICT_TRUE (n_alloc == ring_size - start))
763     n_alloc += vlib_buffer_alloc_from_pool (vm, ring, n_buffers - n_alloc,
764                                             buffer_pool_index);
765
766   return n_alloc;
767 }
768
769 static_always_inline void
770 vlib_buffer_pool_put (vlib_main_t * vm, u8 buffer_pool_index,
771                       u32 * buffers, u32 n_buffers)
772 {
773   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
774   vlib_buffer_pool_thread_t *bpt = vec_elt_at_index (bp->threads,
775                                                      vm->thread_index);
776   u32 n_cached, n_empty;
777
778   if (CLIB_DEBUG > 0)
779     vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
780                                      VLIB_BUFFER_KNOWN_ALLOCATED);
781
782   n_cached = bpt->n_cached;
783   n_empty = VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ - n_cached;
784   if (n_buffers <= n_empty)
785     {
786       vlib_buffer_copy_indices (bpt->cached_buffers + n_cached,
787                                 buffers, n_buffers);
788       bpt->n_cached = n_cached + n_buffers;
789       return;
790     }
791
792   vlib_buffer_copy_indices (bpt->cached_buffers + n_cached,
793                             buffers + n_buffers - n_empty, n_empty);
794   bpt->n_cached = VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ;
795
796   clib_spinlock_lock (&bp->lock);
797   vlib_buffer_copy_indices (bp->buffers + bp->n_avail, buffers,
798                             n_buffers - n_empty);
799   bp->n_avail += n_buffers - n_empty;
800   clib_spinlock_unlock (&bp->lock);
801 }
802
803 static_always_inline void
804 vlib_buffer_free_inline (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
805                          int maybe_next)
806 {
807   const int queue_size = 128;
808   vlib_buffer_pool_t *bp = 0;
809   u8 buffer_pool_index = ~0;
810   u32 n_queue = 0, queue[queue_size + 4];
811   vlib_buffer_t bt = { };
812 #if defined(CLIB_HAVE_VEC128)
813   vlib_buffer_t bpi_mask = {.buffer_pool_index = ~0 };
814   vlib_buffer_t bpi_vec = {};
815   vlib_buffer_t flags_refs_mask = {
816     .flags = VLIB_BUFFER_NEXT_PRESENT,
817     .ref_count = ~1
818   };
819 #endif
820
821   if (PREDICT_FALSE (n_buffers == 0))
822     return;
823
824   vlib_buffer_t *b = vlib_get_buffer (vm, buffers[0]);
825   buffer_pool_index = b->buffer_pool_index;
826   bp = vlib_get_buffer_pool (vm, buffer_pool_index);
827   vlib_buffer_copy_template (&bt, &bp->buffer_template);
828 #if defined(CLIB_HAVE_VEC128)
829   bpi_vec.buffer_pool_index = buffer_pool_index;
830 #endif
831
832   while (n_buffers)
833     {
834       vlib_buffer_t *b[8];
835       u32 bi, sum = 0, flags, next;
836
837       if (n_buffers < 4)
838         goto one_by_one;
839
840       vlib_get_buffers (vm, buffers, b, 4);
841
842       if (n_buffers >= 12)
843         {
844           vlib_get_buffers (vm, buffers + 8, b + 4, 4);
845           vlib_prefetch_buffer_header (b[4], LOAD);
846           vlib_prefetch_buffer_header (b[5], LOAD);
847           vlib_prefetch_buffer_header (b[6], LOAD);
848           vlib_prefetch_buffer_header (b[7], LOAD);
849         }
850
851 #if defined(CLIB_HAVE_VEC128)
852       u8x16 p0, p1, p2, p3, r;
853       p0 = u8x16_load_unaligned (b[0]);
854       p1 = u8x16_load_unaligned (b[1]);
855       p2 = u8x16_load_unaligned (b[2]);
856       p3 = u8x16_load_unaligned (b[3]);
857
858       r = p0 ^ bpi_vec.as_u8x16[0];
859       r |= p1 ^ bpi_vec.as_u8x16[0];
860       r |= p2 ^ bpi_vec.as_u8x16[0];
861       r |= p3 ^ bpi_vec.as_u8x16[0];
862       r &= bpi_mask.as_u8x16[0];
863       r |= (p0 | p1 | p2 | p3) & flags_refs_mask.as_u8x16[0];
864
865       sum = !u8x16_is_all_zero (r);
866 #else
867       sum |= b[0]->flags;
868       sum |= b[1]->flags;
869       sum |= b[2]->flags;
870       sum |= b[3]->flags;
871       sum &= VLIB_BUFFER_NEXT_PRESENT;
872       sum += b[0]->ref_count - 1;
873       sum += b[1]->ref_count - 1;
874       sum += b[2]->ref_count - 1;
875       sum += b[3]->ref_count - 1;
876       sum |= b[0]->buffer_pool_index ^ buffer_pool_index;
877       sum |= b[1]->buffer_pool_index ^ buffer_pool_index;
878       sum |= b[2]->buffer_pool_index ^ buffer_pool_index;
879       sum |= b[3]->buffer_pool_index ^ buffer_pool_index;
880 #endif
881
882       if (sum)
883         goto one_by_one;
884
885       vlib_buffer_copy_indices (queue + n_queue, buffers, 4);
886       vlib_buffer_copy_template (b[0], &bt);
887       vlib_buffer_copy_template (b[1], &bt);
888       vlib_buffer_copy_template (b[2], &bt);
889       vlib_buffer_copy_template (b[3], &bt);
890       n_queue += 4;
891
892       vlib_buffer_validate (vm, b[0]);
893       vlib_buffer_validate (vm, b[1]);
894       vlib_buffer_validate (vm, b[2]);
895       vlib_buffer_validate (vm, b[3]);
896
897       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
898       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
899       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
900       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
901
902       if (n_queue >= queue_size)
903         {
904           vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
905           n_queue = 0;
906         }
907       buffers += 4;
908       n_buffers -= 4;
909       continue;
910
911     one_by_one:
912       bi = buffers[0];
913
914     next_in_chain:
915       b[0] = vlib_get_buffer (vm, bi);
916       flags = b[0]->flags;
917       next = b[0]->next_buffer;
918
919       if (PREDICT_FALSE (buffer_pool_index != b[0]->buffer_pool_index))
920         {
921
922           if (n_queue)
923             {
924               vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
925               n_queue = 0;
926             }
927
928           buffer_pool_index = b[0]->buffer_pool_index;
929 #if defined(CLIB_HAVE_VEC128)
930           bpi_vec.buffer_pool_index = buffer_pool_index;
931 #endif
932           bp = vlib_get_buffer_pool (vm, buffer_pool_index);
933           vlib_buffer_copy_template (&bt, &bp->buffer_template);
934         }
935
936       vlib_buffer_validate (vm, b[0]);
937
938       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
939
940       if (clib_atomic_sub_fetch (&b[0]->ref_count, 1) == 0)
941         {
942           vlib_buffer_copy_template (b[0], &bt);
943           queue[n_queue++] = bi;
944         }
945
946       if (n_queue == queue_size)
947         {
948           vlib_buffer_pool_put (vm, buffer_pool_index, queue, queue_size);
949           n_queue = 0;
950         }
951
952       if (maybe_next && (flags & VLIB_BUFFER_NEXT_PRESENT))
953         {
954           bi = next;
955           goto next_in_chain;
956         }
957
958       buffers++;
959       n_buffers--;
960     }
961
962   if (n_queue)
963     vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
964 }
965
966
967 /** \brief Free buffers
968     Frees the entire buffer chain for each buffer
969
970     @param vm - (vlib_main_t *) vlib main data structure pointer
971     @param buffers - (u32 * ) buffer index array
972     @param n_buffers - (u32) number of buffers to free
973
974 */
975 always_inline void
976 vlib_buffer_free (vlib_main_t * vm,
977                   /* pointer to first buffer */
978                   u32 * buffers,
979                   /* number of buffers to free */
980                   u32 n_buffers)
981 {
982   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 1);
983 }
984
985 /** \brief Free buffers, does not free the buffer chain for each buffer
986
987     @param vm - (vlib_main_t *) vlib main data structure pointer
988     @param buffers - (u32 * ) buffer index array
989     @param n_buffers - (u32) number of buffers to free
990
991 */
992 always_inline void
993 vlib_buffer_free_no_next (vlib_main_t * vm,
994                           /* pointer to first buffer */
995                           u32 * buffers,
996                           /* number of buffers to free */
997                           u32 n_buffers)
998 {
999   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 0);
1000 }
1001
1002 /** \brief Free one buffer
1003     Shorthand to free a single buffer chain.
1004
1005     @param vm - (vlib_main_t *) vlib main data structure pointer
1006     @param buffer_index - (u32) buffer index to free
1007 */
1008 always_inline void
1009 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
1010 {
1011   vlib_buffer_free_inline (vm, &buffer_index, 1, /* maybe next */ 1);
1012 }
1013
1014 /** \brief Free buffers from ring
1015
1016     @param vm - (vlib_main_t *) vlib main data structure pointer
1017     @param buffers - (u32 * ) buffer index ring
1018     @param start - (u32) first slot in the ring
1019     @param ring_size - (u32) ring size
1020     @param n_buffers - (u32) number of buffers
1021 */
1022 always_inline void
1023 vlib_buffer_free_from_ring (vlib_main_t * vm, u32 * ring, u32 start,
1024                             u32 ring_size, u32 n_buffers)
1025 {
1026   ASSERT (n_buffers <= ring_size);
1027
1028   if (PREDICT_TRUE (start + n_buffers <= ring_size))
1029     {
1030       vlib_buffer_free (vm, ring + start, n_buffers);
1031     }
1032   else
1033     {
1034       vlib_buffer_free (vm, ring + start, ring_size - start);
1035       vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
1036     }
1037 }
1038
1039 /** \brief Free buffers from ring without freeing tail buffers
1040
1041     @param vm - (vlib_main_t *) vlib main data structure pointer
1042     @param buffers - (u32 * ) buffer index ring
1043     @param start - (u32) first slot in the ring
1044     @param ring_size - (u32) ring size
1045     @param n_buffers - (u32) number of buffers
1046 */
1047 always_inline void
1048 vlib_buffer_free_from_ring_no_next (vlib_main_t * vm, u32 * ring, u32 start,
1049                                     u32 ring_size, u32 n_buffers)
1050 {
1051   ASSERT (n_buffers <= ring_size);
1052
1053   if (PREDICT_TRUE (start + n_buffers <= ring_size))
1054     {
1055       vlib_buffer_free_no_next (vm, ring + start, n_buffers);
1056     }
1057   else
1058     {
1059       vlib_buffer_free_no_next (vm, ring + start, ring_size - start);
1060       vlib_buffer_free_no_next (vm, ring, n_buffers - (ring_size - start));
1061     }
1062 }
1063
1064 /* Append given data to end of buffer, possibly allocating new buffers. */
1065 int vlib_buffer_add_data (vlib_main_t * vm, u32 * buffer_index, void *data,
1066                           u32 n_data_bytes);
1067
1068 /* Define vlib_buffer and vnet_buffer flags bits preserved for copy/clone */
1069 #define VLIB_BUFFER_COPY_CLONE_FLAGS_MASK                       \
1070   (VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID |  \
1071    VLIB_BUFFER_IS_TRACED | ~VLIB_BUFFER_FLAGS_ALL)
1072
1073 /* duplicate all buffers in chain */
1074 always_inline vlib_buffer_t *
1075 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
1076 {
1077   vlib_buffer_t *s, *d, *fd;
1078   uword n_alloc, n_buffers = 1;
1079   u32 flag_mask = VLIB_BUFFER_COPY_CLONE_FLAGS_MASK;
1080   int i;
1081
1082   s = b;
1083   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1084     {
1085       n_buffers++;
1086       s = vlib_get_buffer (vm, s->next_buffer);
1087     }
1088   u32 new_buffers[n_buffers];
1089
1090   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
1091
1092   /* No guarantee that we'll get all the buffers we asked for */
1093   if (PREDICT_FALSE (n_alloc < n_buffers))
1094     {
1095       if (n_alloc > 0)
1096         vlib_buffer_free (vm, new_buffers, n_alloc);
1097       return 0;
1098     }
1099
1100   /* 1st segment */
1101   s = b;
1102   fd = d = vlib_get_buffer (vm, new_buffers[0]);
1103   d->current_data = s->current_data;
1104   d->current_length = s->current_length;
1105   d->flags = s->flags & flag_mask;
1106   d->trace_handle = s->trace_handle;
1107   d->total_length_not_including_first_buffer =
1108     s->total_length_not_including_first_buffer;
1109   clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
1110   clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
1111   clib_memcpy_fast (vlib_buffer_get_current (d),
1112                     vlib_buffer_get_current (s), s->current_length);
1113
1114   /* next segments */
1115   for (i = 1; i < n_buffers; i++)
1116     {
1117       /* previous */
1118       d->next_buffer = new_buffers[i];
1119       /* current */
1120       s = vlib_get_buffer (vm, s->next_buffer);
1121       d = vlib_get_buffer (vm, new_buffers[i]);
1122       d->current_data = s->current_data;
1123       d->current_length = s->current_length;
1124       clib_memcpy_fast (vlib_buffer_get_current (d),
1125                         vlib_buffer_get_current (s), s->current_length);
1126       d->flags = s->flags & flag_mask;
1127     }
1128
1129   return fd;
1130 }
1131
1132 /* duplicate first buffer in chain */
1133 always_inline vlib_buffer_t *
1134 vlib_buffer_copy_no_chain (vlib_main_t * vm, vlib_buffer_t * b, u32 * di)
1135 {
1136   vlib_buffer_t *d;
1137
1138   if ((vlib_buffer_alloc (vm, di, 1)) != 1)
1139     return 0;
1140
1141   d = vlib_get_buffer (vm, *di);
1142   /* 1st segment */
1143   d->current_data = b->current_data;
1144   d->current_length = b->current_length;
1145   clib_memcpy_fast (d->opaque, b->opaque, sizeof (b->opaque));
1146   clib_memcpy_fast (d->opaque2, b->opaque2, sizeof (b->opaque2));
1147   clib_memcpy_fast (vlib_buffer_get_current (d),
1148                     vlib_buffer_get_current (b), b->current_length);
1149
1150   return d;
1151 }
1152
1153 /*  \brief Move packet from current position to offset position in buffer.
1154     Only work for small packet using one buffer with room to fit the move
1155     @param vm - (vlib_main_t *) vlib main data structure pointer
1156     @param b -  (vlib_buffer_t *) pointer to buffer
1157     @param offset - (i16) position to move the packet in buffer
1158  */
1159 always_inline void
1160 vlib_buffer_move (vlib_main_t * vm, vlib_buffer_t * b, i16 offset)
1161 {
1162   ASSERT ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
1163   ASSERT (offset + VLIB_BUFFER_PRE_DATA_SIZE >= 0);
1164   ASSERT (offset + b->current_length <
1165           vlib_buffer_get_default_data_size (vm));
1166
1167   u8 *source = vlib_buffer_get_current (b);
1168   b->current_data = offset;
1169   u8 *destination = vlib_buffer_get_current (b);
1170   u16 length = b->current_length;
1171
1172   if (source + length <= destination)   /* no overlap */
1173     clib_memcpy_fast (destination, source, length);
1174   else
1175     memmove (destination, source, length);
1176 }
1177
1178 /** \brief Create a maximum of 256 clones of buffer and store them
1179     in the supplied array
1180
1181     @param vm - (vlib_main_t *) vlib main data structure pointer
1182     @param src_buffer - (u32) source buffer index
1183     @param buffers - (u32 * ) buffer index array
1184     @param n_buffers - (u16) number of buffer clones requested (<=256)
1185     @param head_end_offset - (u16) offset relative to current position
1186            where packet head ends
1187     @param offset - (i16) copy packet head at current position if 0,
1188            else at offset position to change headroom space as specified
1189     @return - (u16) number of buffers actually cloned, may be
1190     less than the number requested or zero
1191 */
1192 always_inline u16
1193 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1194                        u16 n_buffers, u16 head_end_offset, i16 offset)
1195 {
1196   u16 i;
1197   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
1198
1199   ASSERT (s->ref_count == 1);
1200   ASSERT (n_buffers);
1201   ASSERT (n_buffers <= 256);
1202   ASSERT (offset + VLIB_BUFFER_PRE_DATA_SIZE >= 0);
1203   ASSERT ((offset + head_end_offset) <
1204           vlib_buffer_get_default_data_size (vm));
1205
1206   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
1207     {
1208       buffers[0] = src_buffer;
1209       if (offset)
1210         vlib_buffer_move (vm, s, offset);
1211
1212       for (i = 1; i < n_buffers; i++)
1213         {
1214           vlib_buffer_t *d;
1215           d = vlib_buffer_copy (vm, s);
1216           if (d == 0)
1217             return i;
1218           buffers[i] = vlib_get_buffer_index (vm, d);
1219
1220         }
1221       return n_buffers;
1222     }
1223
1224   if (PREDICT_FALSE ((n_buffers == 1) && (offset == 0)))
1225     {
1226       buffers[0] = src_buffer;
1227       return 1;
1228     }
1229
1230   n_buffers = vlib_buffer_alloc_from_pool (vm, buffers, n_buffers,
1231                                            s->buffer_pool_index);
1232
1233   for (i = 0; i < n_buffers; i++)
1234     {
1235       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
1236       if (offset)
1237         d->current_data = offset;
1238       else
1239         d->current_data = s->current_data;
1240
1241       d->current_length = head_end_offset;
1242       ASSERT (d->buffer_pool_index == s->buffer_pool_index);
1243
1244       d->total_length_not_including_first_buffer = s->current_length -
1245         head_end_offset;
1246       if (PREDICT_FALSE (s->flags & VLIB_BUFFER_NEXT_PRESENT))
1247         {
1248           d->total_length_not_including_first_buffer +=
1249             s->total_length_not_including_first_buffer;
1250         }
1251       d->flags = (s->flags & VLIB_BUFFER_COPY_CLONE_FLAGS_MASK) |
1252         VLIB_BUFFER_NEXT_PRESENT;
1253       d->trace_handle = s->trace_handle;
1254       clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
1255       clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
1256       clib_memcpy_fast (vlib_buffer_get_current (d),
1257                         vlib_buffer_get_current (s), head_end_offset);
1258       d->next_buffer = src_buffer;
1259     }
1260   vlib_buffer_advance (s, head_end_offset);
1261   s->ref_count = n_buffers ? n_buffers : s->ref_count;
1262   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1263     {
1264       s = vlib_get_buffer (vm, s->next_buffer);
1265       s->ref_count = n_buffers ? n_buffers : s->ref_count;
1266     }
1267
1268   return n_buffers;
1269 }
1270
1271 /** \brief Create multiple clones of buffer and store them
1272     in the supplied array
1273
1274     @param vm - (vlib_main_t *) vlib main data structure pointer
1275     @param src_buffer - (u32) source buffer index
1276     @param buffers - (u32 * ) buffer index array
1277     @param n_buffers - (u16) number of buffer clones requested (<=256)
1278     @param head_end_offset - (u16) offset relative to current position
1279            where packet head ends
1280     @param offset - (i16) copy packet head at current position if 0,
1281            else at offset position to change headroom space as specified
1282     @return - (u16) number of buffers actually cloned, may be
1283     less than the number requested or zero
1284 */
1285 always_inline u16
1286 vlib_buffer_clone_at_offset (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1287                              u16 n_buffers, u16 head_end_offset, i16 offset)
1288 {
1289   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
1290   u16 n_cloned = 0;
1291
1292   while (n_buffers > 256)
1293     {
1294       vlib_buffer_t *copy;
1295       copy = vlib_buffer_copy (vm, s);
1296       n_cloned += vlib_buffer_clone_256 (vm,
1297                                          vlib_get_buffer_index (vm, copy),
1298                                          (buffers + n_cloned),
1299                                          256, head_end_offset, offset);
1300       n_buffers -= 256;
1301     }
1302   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
1303                                      buffers + n_cloned,
1304                                      n_buffers, head_end_offset, offset);
1305
1306   return n_cloned;
1307 }
1308
1309 /** \brief Create multiple clones of buffer and store them
1310     in the supplied array
1311
1312     @param vm - (vlib_main_t *) vlib main data structure pointer
1313     @param src_buffer - (u32) source buffer index
1314     @param buffers - (u32 * ) buffer index array
1315     @param n_buffers - (u16) number of buffer clones requested (<=256)
1316     @param head_end_offset - (u16) offset relative to current position
1317            where packet head ends
1318     @return - (u16) number of buffers actually cloned, may be
1319     less than the number requested or zero
1320 */
1321 always_inline u16
1322 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1323                    u16 n_buffers, u16 head_end_offset)
1324 {
1325   return vlib_buffer_clone_at_offset (vm, src_buffer, buffers, n_buffers,
1326                                       head_end_offset, 0);
1327 }
1328
1329 /** \brief Attach cloned tail to the buffer
1330
1331     @param vm - (vlib_main_t *) vlib main data structure pointer
1332     @param head - (vlib_buffer_t *) head buffer
1333     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
1334 */
1335
1336 always_inline void
1337 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
1338                           vlib_buffer_t * tail)
1339 {
1340   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
1341   ASSERT (head->buffer_pool_index == tail->buffer_pool_index);
1342
1343   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
1344   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1345   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
1346   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
1347   head->next_buffer = vlib_get_buffer_index (vm, tail);
1348   head->total_length_not_including_first_buffer = tail->current_length +
1349     tail->total_length_not_including_first_buffer;
1350
1351 next_segment:
1352   clib_atomic_add_fetch (&tail->ref_count, 1);
1353
1354   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
1355     {
1356       tail = vlib_get_buffer (vm, tail->next_buffer);
1357       goto next_segment;
1358     }
1359 }
1360
1361 /* Initializes the buffer as an empty packet with no chained buffers. */
1362 always_inline void
1363 vlib_buffer_chain_init (vlib_buffer_t * first)
1364 {
1365   first->total_length_not_including_first_buffer = 0;
1366   first->current_length = 0;
1367   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1368   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
1369 }
1370
1371 /* The provided next_bi buffer index is appended to the end of the packet. */
1372 always_inline vlib_buffer_t *
1373 vlib_buffer_chain_buffer (vlib_main_t * vm, vlib_buffer_t * last, u32 next_bi)
1374 {
1375   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
1376   last->next_buffer = next_bi;
1377   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
1378   next_buffer->current_length = 0;
1379   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1380   return next_buffer;
1381 }
1382
1383 /* Increases or decreases the packet length.
1384  * It does not allocate or deallocate new buffers.
1385  * Therefore, the added length must be compatible
1386  * with the last buffer. */
1387 always_inline void
1388 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
1389                                    vlib_buffer_t * last, i32 len)
1390 {
1391   last->current_length += len;
1392   if (first != last)
1393     first->total_length_not_including_first_buffer += len;
1394 }
1395
1396 /* Copy data to the end of the packet and increases its length.
1397  * It does not allocate new buffers.
1398  * Returns the number of copied bytes. */
1399 always_inline u16
1400 vlib_buffer_chain_append_data (vlib_main_t * vm,
1401                                vlib_buffer_t * first,
1402                                vlib_buffer_t * last, void *data, u16 data_len)
1403 {
1404   u32 n_buffer_bytes = vlib_buffer_get_default_data_size (vm);
1405   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
1406   u16 len = clib_min (data_len,
1407                       n_buffer_bytes - last->current_length -
1408                       last->current_data);
1409   clib_memcpy_fast (vlib_buffer_get_current (last) + last->current_length,
1410                     data, len);
1411   vlib_buffer_chain_increase_length (first, last, len);
1412   return len;
1413 }
1414
1415 /* Copy data to the end of the packet and increases its length.
1416  * Allocates additional buffers from the free list if necessary.
1417  * Returns the number of copied bytes.
1418  * 'last' value is modified whenever new buffers are allocated and
1419  * chained and points to the last buffer in the chain. */
1420 u16
1421 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
1422                                           vlib_buffer_t * first,
1423                                           vlib_buffer_t ** last, void *data,
1424                                           u16 data_len);
1425 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
1426
1427 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
1428   format_vlib_buffer_contents, format_vlib_buffer_no_chain;
1429
1430 typedef struct
1431 {
1432   /* Vector of packet data. */
1433   u8 *packet_data;
1434
1435   /* Number of buffers to allocate in each call to allocator. */
1436   u32 min_n_buffers_each_alloc;
1437
1438   u8 *name;
1439 } vlib_packet_template_t;
1440
1441 void vlib_packet_template_init (vlib_main_t * vm,
1442                                 vlib_packet_template_t * t,
1443                                 void *packet_data,
1444                                 uword n_packet_data_bytes,
1445                                 uword min_n_buffers_each_alloc,
1446                                 char *fmt, ...);
1447
1448 void *vlib_packet_template_get_packet (vlib_main_t * vm,
1449                                        vlib_packet_template_t * t,
1450                                        u32 * bi_result);
1451
1452 always_inline void
1453 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
1454 {
1455   vec_free (t->packet_data);
1456 }
1457
1458 always_inline u32
1459 vlib_buffer_space_left_at_end (vlib_main_t * vm, vlib_buffer_t * b)
1460 {
1461   return b->data + vlib_buffer_get_default_data_size (vm) -
1462     ((u8 *) vlib_buffer_get_current (b) + b->current_length);
1463 }
1464
1465 always_inline u32
1466 vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * b)
1467 {
1468   vlib_buffer_t *db = b, *sb, *first = b;
1469   int is_cloned = 0;
1470   u32 bytes_left = 0, data_size;
1471   u16 src_left, dst_left, n_buffers = 1;
1472   u8 *dp, *sp;
1473   u32 to_free = 0;
1474
1475   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
1476     return 1;
1477
1478   data_size = vlib_buffer_get_default_data_size (vm);
1479
1480   dst_left = vlib_buffer_space_left_at_end (vm, b);
1481
1482   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1483     {
1484       b = vlib_get_buffer (vm, b->next_buffer);
1485       if (b->ref_count > 1)
1486         is_cloned = 1;
1487       bytes_left += b->current_length;
1488       n_buffers++;
1489     }
1490
1491   /* if buffer is cloned, create completely new chain - unless everything fits
1492    * into one buffer */
1493   if (is_cloned && bytes_left >= dst_left)
1494     {
1495       u32 len = 0;
1496       u32 space_needed = bytes_left - dst_left;
1497       u32 tail;
1498
1499       if (vlib_buffer_alloc (vm, &tail, 1) == 0)
1500         return 0;
1501
1502       ++n_buffers;
1503       len += data_size;
1504       b = vlib_get_buffer (vm, tail);
1505
1506       while (len < space_needed)
1507         {
1508           u32 bi;
1509           if (vlib_buffer_alloc (vm, &bi, 1) == 0)
1510             {
1511               vlib_buffer_free_one (vm, tail);
1512               return 0;
1513             }
1514           b->flags = VLIB_BUFFER_NEXT_PRESENT;
1515           b->next_buffer = bi;
1516           b = vlib_get_buffer (vm, bi);
1517           len += data_size;
1518           n_buffers++;
1519         }
1520       sb = vlib_get_buffer (vm, first->next_buffer);
1521       to_free = first->next_buffer;
1522       first->next_buffer = tail;
1523     }
1524   else
1525     sb = vlib_get_buffer (vm, first->next_buffer);
1526
1527   src_left = sb->current_length;
1528   sp = vlib_buffer_get_current (sb);
1529   dp = vlib_buffer_get_tail (db);
1530
1531   while (bytes_left)
1532     {
1533       u16 bytes_to_copy;
1534
1535       if (dst_left == 0)
1536         {
1537           db->current_length = dp - (u8 *) vlib_buffer_get_current (db);
1538           ASSERT (db->flags & VLIB_BUFFER_NEXT_PRESENT);
1539           db = vlib_get_buffer (vm, db->next_buffer);
1540           dst_left = data_size;
1541           if (db->current_data > 0)
1542             {
1543               db->current_data = 0;
1544             }
1545           else
1546             {
1547               dst_left += -db->current_data;
1548             }
1549           dp = vlib_buffer_get_current (db);
1550         }
1551
1552       while (src_left == 0)
1553         {
1554           ASSERT (sb->flags & VLIB_BUFFER_NEXT_PRESENT);
1555           sb = vlib_get_buffer (vm, sb->next_buffer);
1556           src_left = sb->current_length;
1557           sp = vlib_buffer_get_current (sb);
1558         }
1559
1560       bytes_to_copy = clib_min (dst_left, src_left);
1561
1562       if (dp != sp)
1563         {
1564           if (sb == db)
1565             bytes_to_copy = clib_min (bytes_to_copy, sp - dp);
1566
1567           clib_memcpy_fast (dp, sp, bytes_to_copy);
1568         }
1569
1570       src_left -= bytes_to_copy;
1571       dst_left -= bytes_to_copy;
1572       dp += bytes_to_copy;
1573       sp += bytes_to_copy;
1574       bytes_left -= bytes_to_copy;
1575     }
1576   if (db != first)
1577     db->current_data = 0;
1578   db->current_length = dp - (u8 *) vlib_buffer_get_current (db);
1579
1580   if (is_cloned && to_free)
1581     vlib_buffer_free_one (vm, to_free);
1582   else
1583     {
1584       if (db->flags & VLIB_BUFFER_NEXT_PRESENT)
1585         vlib_buffer_free_one (vm, db->next_buffer);
1586       db->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1587       b = first;
1588       n_buffers = 1;
1589       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1590         {
1591           b = vlib_get_buffer (vm, b->next_buffer);
1592           ++n_buffers;
1593         }
1594     }
1595
1596   first->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1597
1598   return n_buffers;
1599 }
1600
1601 #endif /* included_vlib_buffer_funcs_h */
1602
1603 /*
1604  * fd.io coding-style-patch-verification: ON
1605  *
1606  * Local Variables:
1607  * eval: (c-set-style "gnu")
1608  * End:
1609  */