buffer: bug fix vlib_buffer_free_inline
[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
46 /** \file
47     vlib buffer access methods.
48 */
49
50 always_inline void
51 vlib_buffer_validate (vlib_main_t * vm, vlib_buffer_t * b)
52 {
53   vlib_buffer_main_t *bm = vm->buffer_main;
54   vlib_buffer_pool_t *bp;
55
56   /* reference count in allocated buffer always must be 1 or higher */
57   ASSERT (b->ref_count > 0);
58
59   /* verify that buffer pool index is valid */
60   bp = vec_elt_at_index (bm->buffer_pools, b->buffer_pool_index);
61   ASSERT (pointer_to_uword (b) >= bp->start);
62   ASSERT (pointer_to_uword (b) < bp->start + bp->size -
63           (bp->data_size + sizeof (vlib_buffer_t)));
64 }
65
66 always_inline void *
67 vlib_buffer_ptr_from_index (uword buffer_mem_start, u32 buffer_index,
68                             uword offset)
69 {
70   offset += ((uword) buffer_index) << CLIB_LOG2_CACHE_LINE_BYTES;
71   return uword_to_pointer (buffer_mem_start + offset, vlib_buffer_t *);
72 }
73
74 /** \brief Translate buffer index into buffer pointer
75
76     @param vm - (vlib_main_t *) vlib main data structure pointer
77     @param buffer_index - (u32) buffer index
78     @return - (vlib_buffer_t *) buffer pointer
79 */
80 always_inline vlib_buffer_t *
81 vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
82 {
83   vlib_buffer_main_t *bm = vm->buffer_main;
84   vlib_buffer_t *b;
85
86   b = vlib_buffer_ptr_from_index (bm->buffer_mem_start, buffer_index, 0);
87   vlib_buffer_validate (vm, b);
88   return b;
89 }
90
91 static_always_inline u32
92 vlib_buffer_get_default_data_size (vlib_main_t * vm)
93 {
94   return vm->buffer_main->default_data_size;
95 }
96
97 static_always_inline void
98 vlib_buffer_copy_indices (u32 * dst, u32 * src, u32 n_indices)
99 {
100   clib_memcpy_fast (dst, src, n_indices * sizeof (u32));
101 }
102
103 STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, template_end, 64);
104 static_always_inline void
105 vlib_buffer_copy_template (vlib_buffer_t * b, vlib_buffer_t * bt)
106 {
107 #if defined CLIB_HAVE_VEC512
108   b->as_u8x64[0] = bt->as_u8x64[0];
109 #elif defined (CLIB_HAVE_VEC256)
110   b->as_u8x32[0] = bt->as_u8x32[0];
111   b->as_u8x32[1] = bt->as_u8x32[1];
112 #elif defined (CLIB_HAVE_VEC128)
113   b->as_u8x16[0] = bt->as_u8x16[0];
114   b->as_u8x16[1] = bt->as_u8x16[1];
115   b->as_u8x16[2] = bt->as_u8x16[2];
116   b->as_u8x16[3] = bt->as_u8x16[3];
117 #else
118   clib_memcpy_fast (b, bt, 64);
119 #endif
120 }
121
122 always_inline u8
123 vlib_buffer_pool_get_default_for_numa (vlib_main_t * vm, u32 numa_node)
124 {
125   ASSERT (numa_node < vm->buffer_main->n_numa_nodes);
126   return numa_node;
127 }
128
129 /** \brief Translate array of buffer indices into buffer pointers with offset
130
131     @param vm - (vlib_main_t *) vlib main data structure pointer
132     @param bi - (u32 *) array of buffer indices
133     @param b - (void **) array to store buffer pointers
134     @param count - (uword) number of elements
135     @param offset - (i32) offset applied to each pointer
136 */
137 static_always_inline void
138 vlib_get_buffers_with_offset (vlib_main_t * vm, u32 * bi, void **b, int count,
139                               i32 offset)
140 {
141   uword buffer_mem_start = vm->buffer_main->buffer_mem_start;
142 #ifdef CLIB_HAVE_VEC256
143   u64x4 off = u64x4_splat (buffer_mem_start + offset);
144   /* if count is not const, compiler will not unroll while loop
145      se we maintain two-in-parallel variant */
146   while (count >= 8)
147     {
148       u64x4 b0 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi));
149       u64x4 b1 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi + 4));
150       /* shift and add to get vlib_buffer_t pointer */
151       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
152       u64x4_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 4);
153       b += 8;
154       bi += 8;
155       count -= 8;
156     }
157 #endif
158   while (count >= 4)
159     {
160 #ifdef CLIB_HAVE_VEC256
161       u64x4 b0 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi));
162       /* shift and add to get vlib_buffer_t pointer */
163       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
164 #elif defined (CLIB_HAVE_VEC128)
165       u64x2 off = u64x2_splat (buffer_mem_start + offset);
166       u32x4 bi4 = u32x4_load_unaligned (bi);
167       u64x2 b0 = u32x4_extend_to_u64x2 ((u32x4) bi4);
168 #if defined (__aarch64__)
169       u64x2 b1 = u32x4_extend_to_u64x2_high ((u32x4) bi4);
170 #else
171       bi4 = u32x4_shuffle (bi4, 2, 3, 0, 1);
172       u64x2 b1 = u32x4_extend_to_u64x2 ((u32x4) bi4);
173 #endif
174       u64x2_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
175       u64x2_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 2);
176 #else
177       b[0] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[0], offset);
178       b[1] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[1], offset);
179       b[2] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[2], offset);
180       b[3] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[3], offset);
181 #endif
182       b += 4;
183       bi += 4;
184       count -= 4;
185     }
186   while (count)
187     {
188       b[0] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[0], offset);
189       b += 1;
190       bi += 1;
191       count -= 1;
192     }
193 }
194
195 /** \brief Translate array of buffer indices into buffer pointers
196
197     @param vm - (vlib_main_t *) vlib main data structure pointer
198     @param bi - (u32 *) array of buffer indices
199     @param b - (vlib_buffer_t **) array to store buffer pointers
200     @param count - (uword) number of elements
201 */
202
203 static_always_inline void
204 vlib_get_buffers (vlib_main_t * vm, u32 * bi, vlib_buffer_t ** b, int count)
205 {
206   vlib_get_buffers_with_offset (vm, bi, (void **) b, count, 0);
207 }
208
209 /** \brief Translate buffer pointer into buffer index
210
211     @param vm - (vlib_main_t *) vlib main data structure pointer
212     @param p - (void *) buffer pointer
213     @return - (u32) buffer index
214 */
215
216 always_inline u32
217 vlib_get_buffer_index (vlib_main_t * vm, void *p)
218 {
219   vlib_buffer_main_t *bm = vm->buffer_main;
220   uword offset = pointer_to_uword (p) - bm->buffer_mem_start;
221   ASSERT (pointer_to_uword (p) >= bm->buffer_mem_start);
222   ASSERT (offset < bm->buffer_mem_size);
223   ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
224   return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
225 }
226
227 /** \brief Translate array of buffer pointers into buffer indices with offset
228
229     @param vm - (vlib_main_t *) vlib main data structure pointer
230     @param b - (void **) array of buffer pointers
231     @param bi - (u32 *) array to store buffer indices
232     @param count - (uword) number of elements
233     @param offset - (i32) offset applied to each pointer
234 */
235 static_always_inline void
236 vlib_get_buffer_indices_with_offset (vlib_main_t * vm, void **b, u32 * bi,
237                                      uword count, i32 offset)
238 {
239 #ifdef CLIB_HAVE_VEC256
240   u32x8 mask = { 0, 2, 4, 6, 1, 3, 5, 7 };
241   u64x4 off4 = u64x4_splat (vm->buffer_main->buffer_mem_start - offset);
242
243   while (count >= 8)
244     {
245       /* load 4 pointers into 256-bit register */
246       u64x4 v0 = u64x4_load_unaligned (b);
247       u64x4 v1 = u64x4_load_unaligned (b + 4);
248       u32x8 v2, v3;
249
250       v0 -= off4;
251       v1 -= off4;
252
253       v0 >>= CLIB_LOG2_CACHE_LINE_BYTES;
254       v1 >>= CLIB_LOG2_CACHE_LINE_BYTES;
255
256       /* permute 256-bit register so lower u32s of each buffer index are
257        * placed into lower 128-bits */
258       v2 = u32x8_permute ((u32x8) v0, mask);
259       v3 = u32x8_permute ((u32x8) v1, mask);
260
261       /* extract lower 128-bits and save them to the array of buffer indices */
262       u32x4_store_unaligned (u32x8_extract_lo (v2), bi);
263       u32x4_store_unaligned (u32x8_extract_lo (v3), bi + 4);
264       bi += 8;
265       b += 8;
266       count -= 8;
267     }
268 #endif
269   while (count >= 4)
270     {
271       /* equivalent non-nector implementation */
272       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
273       bi[1] = vlib_get_buffer_index (vm, ((u8 *) b[1]) + offset);
274       bi[2] = vlib_get_buffer_index (vm, ((u8 *) b[2]) + offset);
275       bi[3] = vlib_get_buffer_index (vm, ((u8 *) b[3]) + offset);
276       bi += 4;
277       b += 4;
278       count -= 4;
279     }
280   while (count)
281     {
282       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
283       bi += 1;
284       b += 1;
285       count -= 1;
286     }
287 }
288
289 /** \brief Translate array of buffer pointers into buffer indices
290
291     @param vm - (vlib_main_t *) vlib main data structure pointer
292     @param b - (vlib_buffer_t **) array of buffer pointers
293     @param bi - (u32 *) array to store buffer indices
294     @param count - (uword) number of elements
295 */
296 static_always_inline void
297 vlib_get_buffer_indices (vlib_main_t * vm, vlib_buffer_t ** b, u32 * bi,
298                          uword count)
299 {
300   vlib_get_buffer_indices_with_offset (vm, (void **) b, bi, count, 0);
301 }
302
303 /** \brief Get next buffer in buffer linklist, or zero for end of list.
304
305     @param vm - (vlib_main_t *) vlib main data structure pointer
306     @param b - (void *) buffer pointer
307     @return - (vlib_buffer_t *) next buffer, or NULL
308 */
309 always_inline vlib_buffer_t *
310 vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
311 {
312   return (b->flags & VLIB_BUFFER_NEXT_PRESENT
313           ? vlib_get_buffer (vm, b->next_buffer) : 0);
314 }
315
316 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
317                                              vlib_buffer_t * b_first);
318
319 /** \brief Get length in bytes of the buffer chain
320
321     @param vm - (vlib_main_t *) vlib main data structure pointer
322     @param b - (void *) buffer pointer
323     @return - (uword) length of buffer chain
324 */
325 always_inline uword
326 vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
327 {
328   uword len = b->current_length;
329
330   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
331     return len;
332
333   if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
334     return len + b->total_length_not_including_first_buffer;
335
336   return vlib_buffer_length_in_chain_slow_path (vm, b);
337 }
338
339 /** \brief Get length in bytes of the buffer index buffer chain
340
341     @param vm - (vlib_main_t *) vlib main data structure pointer
342     @param bi - (u32) buffer index
343     @return - (uword) length of buffer chain
344 */
345 always_inline uword
346 vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
347 {
348   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
349   return vlib_buffer_length_in_chain (vm, b);
350 }
351
352 /** \brief Copy buffer contents to memory
353
354     @param vm - (vlib_main_t *) vlib main data structure pointer
355     @param buffer_index - (u32) buffer index
356     @param contents - (u8 *) memory, <strong>must be large enough</strong>
357     @return - (uword) length of buffer chain
358 */
359 always_inline uword
360 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
361 {
362   uword content_len = 0;
363   uword l;
364   vlib_buffer_t *b;
365
366   while (1)
367     {
368       b = vlib_get_buffer (vm, buffer_index);
369       l = b->current_length;
370       clib_memcpy_fast (contents + content_len, b->data + b->current_data, l);
371       content_len += l;
372       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
373         break;
374       buffer_index = b->next_buffer;
375     }
376
377   return content_len;
378 }
379
380 always_inline uword
381 vlib_buffer_get_pa (vlib_main_t * vm, vlib_buffer_t * b)
382 {
383   return vlib_physmem_get_pa (vm, b->data);
384 }
385
386 always_inline uword
387 vlib_buffer_get_current_pa (vlib_main_t * vm, vlib_buffer_t * b)
388 {
389   return vlib_buffer_get_pa (vm, b) + b->current_data;
390 }
391
392 /** \brief Prefetch buffer metadata by buffer index
393     The first 64 bytes of buffer contains most header information
394
395     @param vm - (vlib_main_t *) vlib main data structure pointer
396     @param bi - (u32) buffer index
397     @param type - LOAD, STORE. In most cases, STORE is the right answer
398 */
399 /* Prefetch buffer header given index. */
400 #define vlib_prefetch_buffer_with_index(vm,bi,type)     \
401   do {                                                  \
402     vlib_buffer_t * _b = vlib_get_buffer (vm, bi);      \
403     vlib_prefetch_buffer_header (_b, type);             \
404   } while (0)
405
406 typedef enum
407 {
408   /* Index is unknown. */
409   VLIB_BUFFER_UNKNOWN,
410
411   /* Index is known and free/allocated. */
412   VLIB_BUFFER_KNOWN_FREE,
413   VLIB_BUFFER_KNOWN_ALLOCATED,
414 } vlib_buffer_known_state_t;
415
416 void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
417                                       uword n_buffers,
418                                       vlib_buffer_known_state_t
419                                       expected_state);
420
421 always_inline vlib_buffer_known_state_t
422 vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
423 {
424   vlib_buffer_main_t *bm = vm->buffer_main;
425
426   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
427   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
428   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
429   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
430 }
431
432 /* Validates sanity of a single buffer.
433    Returns format'ed vector with error message if any. */
434 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
435                           uword follow_chain);
436
437 static_always_inline vlib_buffer_pool_t *
438 vlib_get_buffer_pool (vlib_main_t * vm, u8 buffer_pool_index)
439 {
440   vlib_buffer_main_t *bm = vm->buffer_main;
441   return vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
442 }
443
444 static_always_inline uword
445 vlib_buffer_pool_get (vlib_main_t * vm, u8 buffer_pool_index, u32 * buffers,
446                       u32 n_buffers)
447 {
448   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
449   u32 len;
450
451   ASSERT (bp->buffers);
452
453   clib_spinlock_lock (&bp->lock);
454   len = vec_len (bp->buffers);
455   if (PREDICT_TRUE (n_buffers < len))
456     {
457       len -= n_buffers;
458       vlib_buffer_copy_indices (buffers, bp->buffers + len, n_buffers);
459       _vec_len (bp->buffers) = len;
460       clib_spinlock_unlock (&bp->lock);
461       return n_buffers;
462     }
463   else
464     {
465       vlib_buffer_copy_indices (buffers, bp->buffers, len);
466       _vec_len (bp->buffers) = 0;
467       clib_spinlock_unlock (&bp->lock);
468       return len;
469     }
470 }
471
472
473 /** \brief Allocate buffers from specific pool into supplied array
474
475     @param vm - (vlib_main_t *) vlib main data structure pointer
476     @param buffers - (u32 * ) buffer index array
477     @param n_buffers - (u32) number of buffers requested
478     @return - (u32) number of buffers actually allocated, may be
479     less than the number requested or zero
480 */
481
482 always_inline u32
483 vlib_buffer_alloc_from_pool (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
484                              u8 buffer_pool_index)
485 {
486   vlib_buffer_main_t *bm = vm->buffer_main;
487   vlib_buffer_pool_t *bp;
488   vlib_buffer_pool_thread_t *bpt;
489   u32 *src, *dst, len, n_left;
490
491   bp = vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
492   bpt = vec_elt_at_index (bp->threads, vm->thread_index);
493
494   dst = buffers;
495   n_left = n_buffers;
496   len = vec_len (bpt->cached_buffers);
497
498   /* per-thread cache contains enough buffers */
499   if (len >= n_buffers)
500     {
501       src = bpt->cached_buffers + len - n_buffers;
502       vlib_buffer_copy_indices (dst, src, n_buffers);
503       _vec_len (bpt->cached_buffers) -= n_buffers;
504
505       if (CLIB_DEBUG > 0)
506         vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
507                                          VLIB_BUFFER_KNOWN_FREE);
508       return n_buffers;
509     }
510
511   /* take everything available in the cache */
512   if (len)
513     {
514       vlib_buffer_copy_indices (dst, bpt->cached_buffers, len);
515       _vec_len (bpt->cached_buffers) = 0;
516       dst += len;
517       n_left -= len;
518     }
519
520   len = round_pow2 (n_left, 32);
521   vec_validate_aligned (bpt->cached_buffers, len - 1, CLIB_CACHE_LINE_BYTES);
522   len = vlib_buffer_pool_get (vm, buffer_pool_index, bpt->cached_buffers,
523                               len);
524   _vec_len (bpt->cached_buffers) = len;
525
526   if (len)
527     {
528       u32 n_copy = clib_min (len, n_left);
529       src = bpt->cached_buffers + len - n_copy;
530       vlib_buffer_copy_indices (dst, src, n_copy);
531       _vec_len (bpt->cached_buffers) -= n_copy;
532       n_left -= n_copy;
533     }
534
535   n_buffers -= n_left;
536
537   /* Verify that buffers are known free. */
538   if (CLIB_DEBUG > 0)
539     vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
540                                      VLIB_BUFFER_KNOWN_FREE);
541
542   return n_buffers;
543 }
544
545 /** \brief Allocate buffers from specific numa node into supplied array
546
547     @param vm - (vlib_main_t *) vlib main data structure pointer
548     @param buffers - (u32 * ) buffer index array
549     @param n_buffers - (u32) number of buffers requested
550     @param numa_node - (u32) numa node
551     @return - (u32) number of buffers actually allocated, may be
552     less than the number requested or zero
553 */
554 always_inline u32
555 vlib_buffer_alloc_on_numa (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
556                            u32 numa_node)
557 {
558   u8 index = vlib_buffer_pool_get_default_for_numa (vm, numa_node);
559   return vlib_buffer_alloc_from_pool (vm, buffers, n_buffers, index);
560 }
561
562 /** \brief Allocate buffers into supplied array
563
564     @param vm - (vlib_main_t *) vlib main data structure pointer
565     @param buffers - (u32 * ) buffer index array
566     @param n_buffers - (u32) number of buffers requested
567     @return - (u32) number of buffers actually allocated, may be
568     less than the number requested or zero
569 */
570
571 always_inline u32
572 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
573 {
574   return vlib_buffer_alloc_on_numa (vm, buffers, n_buffers, vm->numa_node);
575 }
576
577 /** \brief Allocate buffers into ring
578
579     @param vm - (vlib_main_t *) vlib main data structure pointer
580     @param buffers - (u32 * ) buffer index ring
581     @param start - (u32) first slot in the ring
582     @param ring_size - (u32) ring size
583     @param n_buffers - (u32) number of buffers requested
584     @return - (u32) number of buffers actually allocated, may be
585     less than the number requested or zero
586 */
587 always_inline u32
588 vlib_buffer_alloc_to_ring (vlib_main_t * vm, u32 * ring, u32 start,
589                            u32 ring_size, u32 n_buffers)
590 {
591   u32 n_alloc;
592
593   ASSERT (n_buffers <= ring_size);
594
595   if (PREDICT_TRUE (start + n_buffers <= ring_size))
596     return vlib_buffer_alloc (vm, ring + start, n_buffers);
597
598   n_alloc = vlib_buffer_alloc (vm, ring + start, ring_size - start);
599
600   if (PREDICT_TRUE (n_alloc == ring_size - start))
601     n_alloc += vlib_buffer_alloc (vm, ring, n_buffers - n_alloc);
602
603   return n_alloc;
604 }
605
606 /** \brief Allocate buffers into ring from specific buffer pool
607
608     @param vm - (vlib_main_t *) vlib main data structure pointer
609     @param buffers - (u32 * ) buffer index ring
610     @param start - (u32) first slot in the ring
611     @param ring_size - (u32) ring size
612     @param n_buffers - (u32) number of buffers requested
613     @return - (u32) number of buffers actually allocated, may be
614     less than the number requested or zero
615 */
616 always_inline u32
617 vlib_buffer_alloc_to_ring_from_pool (vlib_main_t * vm, u32 * ring, u32 start,
618                                      u32 ring_size, u32 n_buffers,
619                                      u8 buffer_pool_index)
620 {
621   u32 n_alloc;
622
623   ASSERT (n_buffers <= ring_size);
624
625   if (PREDICT_TRUE (start + n_buffers <= ring_size))
626     return vlib_buffer_alloc_from_pool (vm, ring + start, n_buffers,
627                                         buffer_pool_index);
628
629   n_alloc = vlib_buffer_alloc_from_pool (vm, ring + start, ring_size - start,
630                                          buffer_pool_index);
631
632   if (PREDICT_TRUE (n_alloc == ring_size - start))
633     n_alloc += vlib_buffer_alloc_from_pool (vm, ring, n_buffers - n_alloc,
634                                             buffer_pool_index);
635
636   return n_alloc;
637 }
638
639 static_always_inline void
640 vlib_buffer_pool_put (vlib_main_t * vm, u8 buffer_pool_index,
641                       u32 * buffers, u32 n_buffers)
642 {
643   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
644   vlib_buffer_pool_thread_t *bpt =
645     vec_elt_at_index (bp->threads, vm->thread_index);
646
647   if (CLIB_DEBUG > 0)
648     vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
649                                      VLIB_BUFFER_KNOWN_ALLOCATED);
650
651   vec_add_aligned (bpt->cached_buffers, buffers, n_buffers,
652                    CLIB_CACHE_LINE_BYTES);
653
654   if (vec_len (bpt->cached_buffers) > 4 * VLIB_FRAME_SIZE)
655     {
656       clib_spinlock_lock (&bp->lock);
657       /* keep last stored buffers, as they are more likely hot in the cache */
658       vec_add_aligned (bp->buffers, bpt->cached_buffers, VLIB_FRAME_SIZE,
659                        CLIB_CACHE_LINE_BYTES);
660       vec_delete (bpt->cached_buffers, VLIB_FRAME_SIZE, 0);
661       bpt->n_alloc -= VLIB_FRAME_SIZE;
662       clib_spinlock_unlock (&bp->lock);
663     }
664 }
665
666 static_always_inline void
667 vlib_buffer_free_inline (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
668                          int maybe_next)
669 {
670   const int queue_size = 128;
671   vlib_buffer_pool_t *bp = 0;
672   u8 buffer_pool_index = ~0;
673   u32 n_queue = 0, queue[queue_size + 4];
674   vlib_buffer_t bt = { };
675 #if defined(CLIB_HAVE_VEC128) && !__aarch64__
676   vlib_buffer_t bpi_mask = {.buffer_pool_index = ~0 };
677   vlib_buffer_t bpi_vec = {.buffer_pool_index = ~0 };
678   vlib_buffer_t flags_refs_mask = {
679     .flags = VLIB_BUFFER_NEXT_PRESENT,
680     .ref_count = ~0
681   };
682 #endif
683
684   while (n_buffers)
685     {
686       vlib_buffer_t *b[8];
687       u32 bi, sum = 0, flags, next;
688
689       if (n_buffers < 12)
690         goto one_by_one;
691
692       vlib_get_buffers (vm, buffers, b, 4);
693       vlib_get_buffers (vm, buffers + 8, b + 4, 4);
694
695       vlib_prefetch_buffer_header (b[4], LOAD);
696       vlib_prefetch_buffer_header (b[5], LOAD);
697       vlib_prefetch_buffer_header (b[6], LOAD);
698       vlib_prefetch_buffer_header (b[7], LOAD);
699
700 #if defined(CLIB_HAVE_VEC128) && !__aarch64__
701       u8x16 p0, p1, p2, p3, r;
702       p0 = u8x16_load_unaligned (b[0]);
703       p1 = u8x16_load_unaligned (b[1]);
704       p2 = u8x16_load_unaligned (b[2]);
705       p3 = u8x16_load_unaligned (b[3]);
706
707       r = p0 ^ bpi_vec.as_u8x16[0];
708       r |= p1 ^ bpi_vec.as_u8x16[0];
709       r |= p2 ^ bpi_vec.as_u8x16[0];
710       r |= p3 ^ bpi_vec.as_u8x16[0];
711       r &= bpi_mask.as_u8x16[0];
712       r |= (p0 | p1 | p2 | p3) & flags_refs_mask.as_u8x16[0];
713
714       sum = !u8x16_is_all_zero (r);
715 #else
716       sum |= b[0]->flags;
717       sum |= b[1]->flags;
718       sum |= b[2]->flags;
719       sum |= b[3]->flags;
720       sum &= VLIB_BUFFER_NEXT_PRESENT;
721       sum += b[0]->ref_count - 1;
722       sum += b[1]->ref_count - 1;
723       sum += b[2]->ref_count - 1;
724       sum += b[3]->ref_count - 1;
725       sum |= b[0]->buffer_pool_index ^ buffer_pool_index;
726       sum |= b[1]->buffer_pool_index ^ buffer_pool_index;
727       sum |= b[2]->buffer_pool_index ^ buffer_pool_index;
728       sum |= b[3]->buffer_pool_index ^ buffer_pool_index;
729 #endif
730
731       if (sum)
732         goto one_by_one;
733
734       vlib_buffer_copy_indices (queue + n_queue, buffers, 4);
735       vlib_buffer_copy_template (b[0], &bt);
736       vlib_buffer_copy_template (b[1], &bt);
737       vlib_buffer_copy_template (b[2], &bt);
738       vlib_buffer_copy_template (b[3], &bt);
739       n_queue += 4;
740
741       vlib_buffer_validate (vm, b[0]);
742       vlib_buffer_validate (vm, b[1]);
743       vlib_buffer_validate (vm, b[2]);
744       vlib_buffer_validate (vm, b[3]);
745
746       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
747       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
748       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
749       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
750
751       if (n_queue >= queue_size)
752         {
753           vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
754           n_queue = 0;
755         }
756       buffers += 4;
757       n_buffers -= 4;
758       continue;
759
760     one_by_one:
761       bi = buffers[0];
762
763     next_in_chain:
764       b[0] = vlib_get_buffer (vm, bi);
765       flags = b[0]->flags;
766       next = b[0]->next_buffer;
767
768       if (PREDICT_FALSE (buffer_pool_index != b[0]->buffer_pool_index))
769         {
770
771           if (n_queue)
772             {
773               vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
774               n_queue = 0;
775             }
776
777           buffer_pool_index = b[0]->buffer_pool_index;
778 #if defined(CLIB_HAVE_VEC128) && !__aarch64__
779           bpi_vec.buffer_pool_index = buffer_pool_index;
780 #endif
781           bp = vlib_get_buffer_pool (vm, buffer_pool_index);
782           vlib_buffer_copy_template (&bt, &bp->buffer_template);
783         }
784
785       vlib_buffer_validate (vm, b[0]);
786
787       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
788
789       if (clib_atomic_sub_fetch (&b[0]->ref_count, 1) == 0)
790         {
791           vlib_buffer_copy_template (b[0], &bt);
792           queue[n_queue++] = bi;
793         }
794
795       if (n_queue == queue_size)
796         {
797           vlib_buffer_pool_put (vm, buffer_pool_index, queue, queue_size);
798           n_queue = 0;
799         }
800
801       if (flags & VLIB_BUFFER_NEXT_PRESENT)
802         {
803           bi = next;
804           goto next_in_chain;
805         }
806
807       buffers++;
808       n_buffers--;
809     }
810
811   if (n_queue)
812     vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
813 }
814
815
816 /** \brief Free buffers
817     Frees the entire buffer chain for each buffer
818
819     @param vm - (vlib_main_t *) vlib main data structure pointer
820     @param buffers - (u32 * ) buffer index array
821     @param n_buffers - (u32) number of buffers to free
822
823 */
824 always_inline void
825 vlib_buffer_free (vlib_main_t * vm,
826                   /* pointer to first buffer */
827                   u32 * buffers,
828                   /* number of buffers to free */
829                   u32 n_buffers)
830 {
831   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 1);
832 }
833
834 /** \brief Free buffers, does not free the buffer chain for each buffer
835
836     @param vm - (vlib_main_t *) vlib main data structure pointer
837     @param buffers - (u32 * ) buffer index array
838     @param n_buffers - (u32) number of buffers to free
839
840 */
841 always_inline void
842 vlib_buffer_free_no_next (vlib_main_t * vm,
843                           /* pointer to first buffer */
844                           u32 * buffers,
845                           /* number of buffers to free */
846                           u32 n_buffers)
847 {
848   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 0);
849 }
850
851 /** \brief Free one buffer
852     Shorthand to free a single buffer chain.
853
854     @param vm - (vlib_main_t *) vlib main data structure pointer
855     @param buffer_index - (u32) buffer index to free
856 */
857 always_inline void
858 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
859 {
860   vlib_buffer_free_inline (vm, &buffer_index, 1, /* maybe next */ 1);
861 }
862
863 /** \brief Free buffers from ring
864
865     @param vm - (vlib_main_t *) vlib main data structure pointer
866     @param buffers - (u32 * ) buffer index ring
867     @param start - (u32) first slot in the ring
868     @param ring_size - (u32) ring size
869     @param n_buffers - (u32) number of buffers
870 */
871 always_inline void
872 vlib_buffer_free_from_ring (vlib_main_t * vm, u32 * ring, u32 start,
873                             u32 ring_size, u32 n_buffers)
874 {
875   ASSERT (n_buffers <= ring_size);
876
877   if (PREDICT_TRUE (start + n_buffers <= ring_size))
878     {
879       vlib_buffer_free (vm, ring + start, n_buffers);
880     }
881   else
882     {
883       vlib_buffer_free (vm, ring + start, ring_size - start);
884       vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
885     }
886 }
887
888 /** \brief Free buffers from ring without freeing tail buffers
889
890     @param vm - (vlib_main_t *) vlib main data structure pointer
891     @param buffers - (u32 * ) buffer index ring
892     @param start - (u32) first slot in the ring
893     @param ring_size - (u32) ring size
894     @param n_buffers - (u32) number of buffers
895 */
896 always_inline void
897 vlib_buffer_free_from_ring_no_next (vlib_main_t * vm, u32 * ring, u32 start,
898                                     u32 ring_size, u32 n_buffers)
899 {
900   ASSERT (n_buffers <= ring_size);
901
902   if (PREDICT_TRUE (start + n_buffers <= ring_size))
903     {
904       vlib_buffer_free_no_next (vm, ring + start, n_buffers);
905     }
906   else
907     {
908       vlib_buffer_free_no_next (vm, ring + start, ring_size - start);
909       vlib_buffer_free_no_next (vm, ring, n_buffers - (ring_size - start));
910     }
911 }
912
913 /* Append given data to end of buffer, possibly allocating new buffers. */
914 int vlib_buffer_add_data (vlib_main_t * vm, u32 * buffer_index, void *data,
915                           u32 n_data_bytes);
916
917 /* duplicate all buffers in chain */
918 always_inline vlib_buffer_t *
919 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
920 {
921   vlib_buffer_t *s, *d, *fd;
922   uword n_alloc, n_buffers = 1;
923   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
924   int i;
925
926   s = b;
927   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
928     {
929       n_buffers++;
930       s = vlib_get_buffer (vm, s->next_buffer);
931     }
932   u32 new_buffers[n_buffers];
933
934   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
935
936   /* No guarantee that we'll get all the buffers we asked for */
937   if (PREDICT_FALSE (n_alloc < n_buffers))
938     {
939       if (n_alloc > 0)
940         vlib_buffer_free (vm, new_buffers, n_alloc);
941       return 0;
942     }
943
944   /* 1st segment */
945   s = b;
946   fd = d = vlib_get_buffer (vm, new_buffers[0]);
947   d->current_data = s->current_data;
948   d->current_length = s->current_length;
949   d->flags = s->flags & flag_mask;
950   d->total_length_not_including_first_buffer =
951     s->total_length_not_including_first_buffer;
952   clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
953   clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
954   clib_memcpy_fast (vlib_buffer_get_current (d),
955                     vlib_buffer_get_current (s), s->current_length);
956
957   /* next segments */
958   for (i = 1; i < n_buffers; i++)
959     {
960       /* previous */
961       d->next_buffer = new_buffers[i];
962       /* current */
963       s = vlib_get_buffer (vm, s->next_buffer);
964       d = vlib_get_buffer (vm, new_buffers[i]);
965       d->current_data = s->current_data;
966       d->current_length = s->current_length;
967       clib_memcpy_fast (vlib_buffer_get_current (d),
968                         vlib_buffer_get_current (s), s->current_length);
969       d->flags = s->flags & flag_mask;
970     }
971
972   return fd;
973 }
974
975 /** \brief Create a maximum of 256 clones of buffer and store them
976     in the supplied array
977
978     @param vm - (vlib_main_t *) vlib main data structure pointer
979     @param src_buffer - (u32) source buffer index
980     @param buffers - (u32 * ) buffer index array
981     @param n_buffers - (u16) number of buffer clones requested (<=256)
982     @param head_end_offset - (u16) offset relative to current position
983            where packet head ends
984     @return - (u16) number of buffers actually cloned, may be
985     less than the number requested or zero
986 */
987 always_inline u16
988 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
989                        u16 n_buffers, u16 head_end_offset)
990 {
991   u16 i;
992   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
993
994   ASSERT (s->ref_count == 1);
995   ASSERT (n_buffers);
996   ASSERT (n_buffers <= 256);
997
998   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
999     {
1000       buffers[0] = src_buffer;
1001       for (i = 1; i < n_buffers; i++)
1002         {
1003           vlib_buffer_t *d;
1004           d = vlib_buffer_copy (vm, s);
1005           if (d == 0)
1006             return i;
1007           buffers[i] = vlib_get_buffer_index (vm, d);
1008
1009         }
1010       return n_buffers;
1011     }
1012
1013   if (PREDICT_FALSE (n_buffers == 1))
1014     {
1015       buffers[0] = src_buffer;
1016       return 1;
1017     }
1018
1019   n_buffers = vlib_buffer_alloc_from_pool (vm, buffers, n_buffers,
1020                                            s->buffer_pool_index);
1021
1022   for (i = 0; i < n_buffers; i++)
1023     {
1024       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
1025       d->current_data = s->current_data;
1026       d->current_length = head_end_offset;
1027       ASSERT (d->buffer_pool_index == s->buffer_pool_index);
1028
1029       d->total_length_not_including_first_buffer = s->current_length -
1030         head_end_offset;
1031       if (PREDICT_FALSE (s->flags & VLIB_BUFFER_NEXT_PRESENT))
1032         {
1033           d->total_length_not_including_first_buffer +=
1034             s->total_length_not_including_first_buffer;
1035         }
1036       d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
1037       d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
1038       clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
1039       clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
1040       clib_memcpy_fast (vlib_buffer_get_current (d),
1041                         vlib_buffer_get_current (s), head_end_offset);
1042       d->next_buffer = src_buffer;
1043     }
1044   vlib_buffer_advance (s, head_end_offset);
1045   s->ref_count = n_buffers;
1046   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1047     {
1048       s = vlib_get_buffer (vm, s->next_buffer);
1049       s->ref_count = n_buffers;
1050     }
1051
1052   return n_buffers;
1053 }
1054
1055 /** \brief Create multiple clones of buffer and store them
1056     in the supplied array
1057
1058     @param vm - (vlib_main_t *) vlib main data structure pointer
1059     @param src_buffer - (u32) source buffer index
1060     @param buffers - (u32 * ) buffer index array
1061     @param n_buffers - (u16) number of buffer clones requested (<=256)
1062     @param head_end_offset - (u16) offset relative to current position
1063            where packet head ends
1064     @return - (u16) number of buffers actually cloned, may be
1065     less than the number requested or zero
1066 */
1067 always_inline u16
1068 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1069                    u16 n_buffers, u16 head_end_offset)
1070 {
1071   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
1072   u16 n_cloned = 0;
1073
1074   while (n_buffers > 256)
1075     {
1076       vlib_buffer_t *copy;
1077       copy = vlib_buffer_copy (vm, s);
1078       n_cloned += vlib_buffer_clone_256 (vm,
1079                                          vlib_get_buffer_index (vm, copy),
1080                                          (buffers + n_cloned),
1081                                          256, head_end_offset);
1082       n_buffers -= 256;
1083     }
1084   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
1085                                      buffers + n_cloned,
1086                                      n_buffers, head_end_offset);
1087
1088   return n_cloned;
1089 }
1090
1091 /** \brief Attach cloned tail to the buffer
1092
1093     @param vm - (vlib_main_t *) vlib main data structure pointer
1094     @param head - (vlib_buffer_t *) head buffer
1095     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
1096 */
1097
1098 always_inline void
1099 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
1100                           vlib_buffer_t * tail)
1101 {
1102   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
1103   ASSERT (head->buffer_pool_index == tail->buffer_pool_index);
1104
1105   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
1106   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1107   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
1108   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
1109   head->next_buffer = vlib_get_buffer_index (vm, tail);
1110   head->total_length_not_including_first_buffer = tail->current_length +
1111     tail->total_length_not_including_first_buffer;
1112
1113 next_segment:
1114   clib_atomic_add_fetch (&tail->ref_count, 1);
1115
1116   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
1117     {
1118       tail = vlib_get_buffer (vm, tail->next_buffer);
1119       goto next_segment;
1120     }
1121 }
1122
1123 /* Initializes the buffer as an empty packet with no chained buffers. */
1124 always_inline void
1125 vlib_buffer_chain_init (vlib_buffer_t * first)
1126 {
1127   first->total_length_not_including_first_buffer = 0;
1128   first->current_length = 0;
1129   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1130   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
1131 }
1132
1133 /* The provided next_bi buffer index is appended to the end of the packet. */
1134 always_inline vlib_buffer_t *
1135 vlib_buffer_chain_buffer (vlib_main_t * vm, vlib_buffer_t * last, u32 next_bi)
1136 {
1137   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
1138   last->next_buffer = next_bi;
1139   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
1140   next_buffer->current_length = 0;
1141   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1142   return next_buffer;
1143 }
1144
1145 /* Increases or decreases the packet length.
1146  * It does not allocate or deallocate new buffers.
1147  * Therefore, the added length must be compatible
1148  * with the last buffer. */
1149 always_inline void
1150 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
1151                                    vlib_buffer_t * last, i32 len)
1152 {
1153   last->current_length += len;
1154   if (first != last)
1155     first->total_length_not_including_first_buffer += len;
1156 }
1157
1158 /* Copy data to the end of the packet and increases its length.
1159  * It does not allocate new buffers.
1160  * Returns the number of copied bytes. */
1161 always_inline u16
1162 vlib_buffer_chain_append_data (vlib_main_t * vm,
1163                                vlib_buffer_t * first,
1164                                vlib_buffer_t * last, void *data, u16 data_len)
1165 {
1166   u32 n_buffer_bytes = vlib_buffer_get_default_data_size (vm);
1167   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
1168   u16 len = clib_min (data_len,
1169                       n_buffer_bytes - last->current_length -
1170                       last->current_data);
1171   clib_memcpy_fast (vlib_buffer_get_current (last) + last->current_length,
1172                     data, len);
1173   vlib_buffer_chain_increase_length (first, last, len);
1174   return len;
1175 }
1176
1177 /* Copy data to the end of the packet and increases its length.
1178  * Allocates additional buffers from the free list if necessary.
1179  * Returns the number of copied bytes.
1180  * 'last' value is modified whenever new buffers are allocated and
1181  * chained and points to the last buffer in the chain. */
1182 u16
1183 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
1184                                           vlib_buffer_t * first,
1185                                           vlib_buffer_t ** last, void *data,
1186                                           u16 data_len);
1187 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
1188
1189 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
1190   format_vlib_buffer_contents;
1191
1192 typedef struct
1193 {
1194   /* Vector of packet data. */
1195   u8 *packet_data;
1196
1197   /* Number of buffers to allocate in each call to allocator. */
1198   u32 min_n_buffers_each_alloc;
1199
1200   u8 *name;
1201 } vlib_packet_template_t;
1202
1203 void vlib_packet_template_init (vlib_main_t * vm,
1204                                 vlib_packet_template_t * t,
1205                                 void *packet_data,
1206                                 uword n_packet_data_bytes,
1207                                 uword min_n_buffers_each_alloc,
1208                                 char *fmt, ...);
1209
1210 void *vlib_packet_template_get_packet (vlib_main_t * vm,
1211                                        vlib_packet_template_t * t,
1212                                        u32 * bi_result);
1213
1214 always_inline void
1215 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
1216 {
1217   vec_free (t->packet_data);
1218 }
1219
1220 /**
1221  * @brief compress buffer chain in a way where the first buffer is at least
1222  * VLIB_BUFFER_CLONE_HEAD_SIZE long
1223  *
1224  * @param[in] vm - vlib_main
1225  * @param[in,out] first - first buffer in chain
1226  * @param[in,out] discard_vector - vector of buffer indexes which were removed
1227  * from the chain
1228  */
1229 always_inline void
1230 vlib_buffer_chain_compress (vlib_main_t * vm,
1231                             vlib_buffer_t * first, u32 ** discard_vector)
1232 {
1233   if (first->current_length >= VLIB_BUFFER_CLONE_HEAD_SIZE ||
1234       !(first->flags & VLIB_BUFFER_NEXT_PRESENT))
1235     {
1236       /* this is already big enough or not a chain */
1237       return;
1238     }
1239
1240   u32 want_first_size = clib_min (VLIB_BUFFER_CLONE_HEAD_SIZE,
1241                                   vlib_buffer_get_default_data_size (vm) -
1242                                   first->current_data);
1243   do
1244     {
1245       vlib_buffer_t *second = vlib_get_buffer (vm, first->next_buffer);
1246       u32 need = want_first_size - first->current_length;
1247       u32 amount_to_copy = clib_min (need, second->current_length);
1248       clib_memcpy_fast (((u8 *) vlib_buffer_get_current (first)) +
1249                         first->current_length,
1250                         vlib_buffer_get_current (second), amount_to_copy);
1251       first->current_length += amount_to_copy;
1252       second->current_data += amount_to_copy;
1253       second->current_length -= amount_to_copy;
1254       if (first->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1255         {
1256           first->total_length_not_including_first_buffer -= amount_to_copy;
1257         }
1258       if (!second->current_length)
1259         {
1260           vec_add1 (*discard_vector, first->next_buffer);
1261           if (second->flags & VLIB_BUFFER_NEXT_PRESENT)
1262             {
1263               first->next_buffer = second->next_buffer;
1264             }
1265           else
1266             {
1267               first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1268             }
1269           second->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1270         }
1271     }
1272   while ((first->current_length < want_first_size) &&
1273          (first->flags & VLIB_BUFFER_NEXT_PRESENT));
1274 }
1275
1276 /**
1277  * @brief linearize buffer chain - the first buffer is filled, if needed,
1278  * buffers are allocated and filled, returns free space in last buffer or
1279  * negative on failure
1280  *
1281  * @param[in] vm - vlib_main
1282  * @param[in,out] first - first buffer in chain
1283  */
1284 always_inline int
1285 vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * first)
1286 {
1287   vlib_buffer_t *b = first;
1288   u32 buf_len = vlib_buffer_get_default_data_size (vm);
1289   // free buffer chain starting from the second buffer
1290   int free_count = (b->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
1291   u32 chain_to_free = b->next_buffer;
1292
1293   u32 len = vlib_buffer_length_in_chain (vm, b);
1294   u32 free_len = buf_len - b->current_data - b->current_length;
1295   int alloc_len = clib_max (len - free_len, 0); //use the free len in the first buffer
1296   int n_buffers = (alloc_len + buf_len - 1) / buf_len;
1297   u32 new_buffers[n_buffers];
1298
1299   u32 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
1300   if (n_alloc != n_buffers)
1301     {
1302       vlib_buffer_free_no_next (vm, new_buffers, n_alloc);
1303       return -1;
1304     }
1305
1306   vlib_buffer_t *s = b;
1307   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1308     {
1309       s = vlib_get_buffer (vm, s->next_buffer);
1310       int d_free_len = buf_len - b->current_data - b->current_length;
1311       ASSERT (d_free_len >= 0);
1312       // chain buf and split write
1313       u32 copy_len = clib_min (d_free_len, s->current_length);
1314       u8 *d = vlib_buffer_put_uninit (b, copy_len);
1315       clib_memcpy (d, vlib_buffer_get_current (s), copy_len);
1316       int rest = s->current_length - copy_len;
1317       if (rest > 0)
1318         {
1319           //prev buf is full
1320           ASSERT (vlib_buffer_get_tail (b) == b->data + buf_len);
1321           ASSERT (n_buffers > 0);
1322           b = vlib_buffer_chain_buffer (vm, b, new_buffers[--n_buffers]);
1323           //make full use of the new buffers
1324           b->current_data = 0;
1325           d = vlib_buffer_put_uninit (b, rest);
1326           clib_memcpy (d, vlib_buffer_get_current (s) + copy_len, rest);
1327         }
1328     }
1329   vlib_buffer_free (vm, &chain_to_free, free_count);
1330   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1331   if (b == first)               /* no buffers addeed */
1332     b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1333   ASSERT (len == vlib_buffer_length_in_chain (vm, first));
1334   ASSERT (n_buffers == 0);
1335   return buf_len - b->current_data - b->current_length;
1336 }
1337
1338 #endif /* included_vlib_buffer_funcs_h */
1339
1340 /*
1341  * fd.io coding-style-patch-verification: ON
1342  *
1343  * Local Variables:
1344  * eval: (c-set-style "gnu")
1345  * End:
1346  */