buffers: make buffer data size configurable from startup config
[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_bufer_get_default_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           buffer_pool_index = b[0]->buffer_pool_index;
771 #if defined(CLIB_HAVE_VEC128) && !__aarch64__
772           bpi_vec.buffer_pool_index = buffer_pool_index;
773 #endif
774           bp = vlib_get_buffer_pool (vm, buffer_pool_index);
775           vlib_buffer_copy_template (&bt, &bp->buffer_template);
776
777           if (n_queue)
778             {
779               vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
780               n_queue = 0;
781             }
782         }
783
784       vlib_buffer_validate (vm, b[0]);
785
786       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
787
788       if (clib_atomic_sub_fetch (&b[0]->ref_count, 1) == 0)
789         {
790           vlib_buffer_copy_template (b[0], &bt);
791           queue[n_queue++] = bi;
792         }
793
794       if (n_queue == queue_size)
795         {
796           vlib_buffer_pool_put (vm, buffer_pool_index, queue, queue_size);
797           n_queue = 0;
798         }
799
800       if (flags & VLIB_BUFFER_NEXT_PRESENT)
801         {
802           bi = next;
803           goto next_in_chain;
804         }
805
806       buffers++;
807       n_buffers--;
808     }
809
810   if (n_queue)
811     vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
812 }
813
814
815 /** \brief Free buffers
816     Frees the entire buffer chain for each buffer
817
818     @param vm - (vlib_main_t *) vlib main data structure pointer
819     @param buffers - (u32 * ) buffer index array
820     @param n_buffers - (u32) number of buffers to free
821
822 */
823 always_inline void
824 vlib_buffer_free (vlib_main_t * vm,
825                   /* pointer to first buffer */
826                   u32 * buffers,
827                   /* number of buffers to free */
828                   u32 n_buffers)
829 {
830   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 1);
831 }
832
833 /** \brief Free buffers, does not free the buffer chain for each buffer
834
835     @param vm - (vlib_main_t *) vlib main data structure pointer
836     @param buffers - (u32 * ) buffer index array
837     @param n_buffers - (u32) number of buffers to free
838
839 */
840 always_inline void
841 vlib_buffer_free_no_next (vlib_main_t * vm,
842                           /* pointer to first buffer */
843                           u32 * buffers,
844                           /* number of buffers to free */
845                           u32 n_buffers)
846 {
847   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 0);
848 }
849
850 /** \brief Free one buffer
851     Shorthand to free a single buffer chain.
852
853     @param vm - (vlib_main_t *) vlib main data structure pointer
854     @param buffer_index - (u32) buffer index to free
855 */
856 always_inline void
857 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
858 {
859   vlib_buffer_free_inline (vm, &buffer_index, 1, /* maybe next */ 1);
860 }
861
862 /** \brief Free buffers from ring
863
864     @param vm - (vlib_main_t *) vlib main data structure pointer
865     @param buffers - (u32 * ) buffer index ring
866     @param start - (u32) first slot in the ring
867     @param ring_size - (u32) ring size
868     @param n_buffers - (u32) number of buffers
869 */
870 always_inline void
871 vlib_buffer_free_from_ring (vlib_main_t * vm, u32 * ring, u32 start,
872                             u32 ring_size, u32 n_buffers)
873 {
874   ASSERT (n_buffers <= ring_size);
875
876   if (PREDICT_TRUE (start + n_buffers <= ring_size))
877     {
878       vlib_buffer_free (vm, ring + start, n_buffers);
879     }
880   else
881     {
882       vlib_buffer_free (vm, ring + start, ring_size - start);
883       vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
884     }
885 }
886
887 /** \brief Free buffers from ring without freeing tail buffers
888
889     @param vm - (vlib_main_t *) vlib main data structure pointer
890     @param buffers - (u32 * ) buffer index ring
891     @param start - (u32) first slot in the ring
892     @param ring_size - (u32) ring size
893     @param n_buffers - (u32) number of buffers
894 */
895 always_inline void
896 vlib_buffer_free_from_ring_no_next (vlib_main_t * vm, u32 * ring, u32 start,
897                                     u32 ring_size, u32 n_buffers)
898 {
899   ASSERT (n_buffers <= ring_size);
900
901   if (PREDICT_TRUE (start + n_buffers <= ring_size))
902     {
903       vlib_buffer_free_no_next (vm, ring + start, n_buffers);
904     }
905   else
906     {
907       vlib_buffer_free_no_next (vm, ring + start, ring_size - start);
908       vlib_buffer_free_no_next (vm, ring, n_buffers - (ring_size - start));
909     }
910 }
911
912 /* Append given data to end of buffer, possibly allocating new buffers. */
913 int vlib_buffer_add_data (vlib_main_t * vm, u32 * buffer_index, void *data,
914                           u32 n_data_bytes);
915
916 /* duplicate all buffers in chain */
917 always_inline vlib_buffer_t *
918 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
919 {
920   vlib_buffer_t *s, *d, *fd;
921   uword n_alloc, n_buffers = 1;
922   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
923   int i;
924
925   s = b;
926   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
927     {
928       n_buffers++;
929       s = vlib_get_buffer (vm, s->next_buffer);
930     }
931   u32 new_buffers[n_buffers];
932
933   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
934
935   /* No guarantee that we'll get all the buffers we asked for */
936   if (PREDICT_FALSE (n_alloc < n_buffers))
937     {
938       if (n_alloc > 0)
939         vlib_buffer_free (vm, new_buffers, n_alloc);
940       return 0;
941     }
942
943   /* 1st segment */
944   s = b;
945   fd = d = vlib_get_buffer (vm, new_buffers[0]);
946   d->current_data = s->current_data;
947   d->current_length = s->current_length;
948   d->flags = s->flags & flag_mask;
949   d->total_length_not_including_first_buffer =
950     s->total_length_not_including_first_buffer;
951   clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
952   clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
953   clib_memcpy_fast (vlib_buffer_get_current (d),
954                     vlib_buffer_get_current (s), s->current_length);
955
956   /* next segments */
957   for (i = 1; i < n_buffers; i++)
958     {
959       /* previous */
960       d->next_buffer = new_buffers[i];
961       /* current */
962       s = vlib_get_buffer (vm, s->next_buffer);
963       d = vlib_get_buffer (vm, new_buffers[i]);
964       d->current_data = s->current_data;
965       d->current_length = s->current_length;
966       clib_memcpy_fast (vlib_buffer_get_current (d),
967                         vlib_buffer_get_current (s), s->current_length);
968       d->flags = s->flags & flag_mask;
969     }
970
971   return fd;
972 }
973
974 /** \brief Create a maximum of 256 clones of buffer and store them
975     in the supplied array
976
977     @param vm - (vlib_main_t *) vlib main data structure pointer
978     @param src_buffer - (u32) source buffer index
979     @param buffers - (u32 * ) buffer index array
980     @param n_buffers - (u16) number of buffer clones requested (<=256)
981     @param head_end_offset - (u16) offset relative to current position
982            where packet head ends
983     @return - (u16) number of buffers actually cloned, may be
984     less than the number requested or zero
985 */
986 always_inline u16
987 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
988                        u16 n_buffers, u16 head_end_offset)
989 {
990   u16 i;
991   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
992
993   ASSERT (s->ref_count == 1);
994   ASSERT (n_buffers);
995   ASSERT (n_buffers <= 256);
996
997   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
998     {
999       buffers[0] = src_buffer;
1000       for (i = 1; i < n_buffers; i++)
1001         {
1002           vlib_buffer_t *d;
1003           d = vlib_buffer_copy (vm, s);
1004           if (d == 0)
1005             return i;
1006           buffers[i] = vlib_get_buffer_index (vm, d);
1007
1008         }
1009       return n_buffers;
1010     }
1011
1012   if (PREDICT_FALSE (n_buffers == 1))
1013     {
1014       buffers[0] = src_buffer;
1015       return 1;
1016     }
1017
1018   n_buffers = vlib_buffer_alloc_from_pool (vm, buffers, n_buffers,
1019                                            s->buffer_pool_index);
1020
1021   for (i = 0; i < n_buffers; i++)
1022     {
1023       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
1024       d->current_data = s->current_data;
1025       d->current_length = head_end_offset;
1026       ASSERT (d->buffer_pool_index == s->buffer_pool_index);
1027
1028       d->total_length_not_including_first_buffer = s->current_length -
1029         head_end_offset;
1030       if (PREDICT_FALSE (s->flags & VLIB_BUFFER_NEXT_PRESENT))
1031         {
1032           d->total_length_not_including_first_buffer +=
1033             s->total_length_not_including_first_buffer;
1034         }
1035       d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
1036       d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
1037       clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
1038       clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
1039       clib_memcpy_fast (vlib_buffer_get_current (d),
1040                         vlib_buffer_get_current (s), head_end_offset);
1041       d->next_buffer = src_buffer;
1042     }
1043   vlib_buffer_advance (s, head_end_offset);
1044   s->ref_count = n_buffers;
1045   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1046     {
1047       s = vlib_get_buffer (vm, s->next_buffer);
1048       s->ref_count = n_buffers;
1049     }
1050
1051   return n_buffers;
1052 }
1053
1054 /** \brief Create multiple clones of buffer and store them
1055     in the supplied array
1056
1057     @param vm - (vlib_main_t *) vlib main data structure pointer
1058     @param src_buffer - (u32) source buffer index
1059     @param buffers - (u32 * ) buffer index array
1060     @param n_buffers - (u16) number of buffer clones requested (<=256)
1061     @param head_end_offset - (u16) offset relative to current position
1062            where packet head ends
1063     @return - (u16) number of buffers actually cloned, may be
1064     less than the number requested or zero
1065 */
1066 always_inline u16
1067 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1068                    u16 n_buffers, u16 head_end_offset)
1069 {
1070   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
1071   u16 n_cloned = 0;
1072
1073   while (n_buffers > 256)
1074     {
1075       vlib_buffer_t *copy;
1076       copy = vlib_buffer_copy (vm, s);
1077       n_cloned += vlib_buffer_clone_256 (vm,
1078                                          vlib_get_buffer_index (vm, copy),
1079                                          (buffers + n_cloned),
1080                                          256, head_end_offset);
1081       n_buffers -= 256;
1082     }
1083   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
1084                                      buffers + n_cloned,
1085                                      n_buffers, head_end_offset);
1086
1087   return n_cloned;
1088 }
1089
1090 /** \brief Attach cloned tail to the buffer
1091
1092     @param vm - (vlib_main_t *) vlib main data structure pointer
1093     @param head - (vlib_buffer_t *) head buffer
1094     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
1095 */
1096
1097 always_inline void
1098 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
1099                           vlib_buffer_t * tail)
1100 {
1101   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
1102   ASSERT (head->buffer_pool_index == tail->buffer_pool_index);
1103
1104   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
1105   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1106   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
1107   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
1108   head->next_buffer = vlib_get_buffer_index (vm, tail);
1109   head->total_length_not_including_first_buffer = tail->current_length +
1110     tail->total_length_not_including_first_buffer;
1111
1112 next_segment:
1113   clib_atomic_add_fetch (&tail->ref_count, 1);
1114
1115   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
1116     {
1117       tail = vlib_get_buffer (vm, tail->next_buffer);
1118       goto next_segment;
1119     }
1120 }
1121
1122 /* Initializes the buffer as an empty packet with no chained buffers. */
1123 always_inline void
1124 vlib_buffer_chain_init (vlib_buffer_t * first)
1125 {
1126   first->total_length_not_including_first_buffer = 0;
1127   first->current_length = 0;
1128   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1129   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
1130 }
1131
1132 /* The provided next_bi buffer index is appended to the end of the packet. */
1133 always_inline vlib_buffer_t *
1134 vlib_buffer_chain_buffer (vlib_main_t * vm, vlib_buffer_t * last, u32 next_bi)
1135 {
1136   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
1137   last->next_buffer = next_bi;
1138   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
1139   next_buffer->current_length = 0;
1140   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1141   return next_buffer;
1142 }
1143
1144 /* Increases or decreases the packet length.
1145  * It does not allocate or deallocate new buffers.
1146  * Therefore, the added length must be compatible
1147  * with the last buffer. */
1148 always_inline void
1149 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
1150                                    vlib_buffer_t * last, i32 len)
1151 {
1152   last->current_length += len;
1153   if (first != last)
1154     first->total_length_not_including_first_buffer += len;
1155 }
1156
1157 /* Copy data to the end of the packet and increases its length.
1158  * It does not allocate new buffers.
1159  * Returns the number of copied bytes. */
1160 always_inline u16
1161 vlib_buffer_chain_append_data (vlib_main_t * vm,
1162                                vlib_buffer_t * first,
1163                                vlib_buffer_t * last, void *data, u16 data_len)
1164 {
1165   u32 n_buffer_bytes = vlib_bufer_get_default_size (vm);
1166   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
1167   u16 len = clib_min (data_len,
1168                       n_buffer_bytes - last->current_length -
1169                       last->current_data);
1170   clib_memcpy_fast (vlib_buffer_get_current (last) + last->current_length,
1171                     data, len);
1172   vlib_buffer_chain_increase_length (first, last, len);
1173   return len;
1174 }
1175
1176 /* Copy data to the end of the packet and increases its length.
1177  * Allocates additional buffers from the free list if necessary.
1178  * Returns the number of copied bytes.
1179  * 'last' value is modified whenever new buffers are allocated and
1180  * chained and points to the last buffer in the chain. */
1181 u16
1182 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
1183                                           vlib_buffer_t * first,
1184                                           vlib_buffer_t ** last, void *data,
1185                                           u16 data_len);
1186 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
1187
1188 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
1189   format_vlib_buffer_contents;
1190
1191 typedef struct
1192 {
1193   /* Vector of packet data. */
1194   u8 *packet_data;
1195
1196   /* Number of buffers to allocate in each call to allocator. */
1197   u32 min_n_buffers_each_alloc;
1198
1199   u8 *name;
1200 } vlib_packet_template_t;
1201
1202 void vlib_packet_template_init (vlib_main_t * vm,
1203                                 vlib_packet_template_t * t,
1204                                 void *packet_data,
1205                                 uword n_packet_data_bytes,
1206                                 uword min_n_buffers_each_alloc,
1207                                 char *fmt, ...);
1208
1209 void *vlib_packet_template_get_packet (vlib_main_t * vm,
1210                                        vlib_packet_template_t * t,
1211                                        u32 * bi_result);
1212
1213 always_inline void
1214 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
1215 {
1216   vec_free (t->packet_data);
1217 }
1218
1219 /**
1220  * @brief compress buffer chain in a way where the first buffer is at least
1221  * VLIB_BUFFER_CLONE_HEAD_SIZE long
1222  *
1223  * @param[in] vm - vlib_main
1224  * @param[in,out] first - first buffer in chain
1225  * @param[in,out] discard_vector - vector of buffer indexes which were removed
1226  * from the chain
1227  */
1228 always_inline void
1229 vlib_buffer_chain_compress (vlib_main_t * vm,
1230                             vlib_buffer_t * first, u32 ** discard_vector)
1231 {
1232   if (first->current_length >= VLIB_BUFFER_CLONE_HEAD_SIZE ||
1233       !(first->flags & VLIB_BUFFER_NEXT_PRESENT))
1234     {
1235       /* this is already big enough or not a chain */
1236       return;
1237     }
1238
1239   u32 want_first_size = clib_min (VLIB_BUFFER_CLONE_HEAD_SIZE,
1240                                   vlib_bufer_get_default_size (vm) -
1241                                   first->current_data);
1242   do
1243     {
1244       vlib_buffer_t *second = vlib_get_buffer (vm, first->next_buffer);
1245       u32 need = want_first_size - first->current_length;
1246       u32 amount_to_copy = clib_min (need, second->current_length);
1247       clib_memcpy_fast (((u8 *) vlib_buffer_get_current (first)) +
1248                         first->current_length,
1249                         vlib_buffer_get_current (second), amount_to_copy);
1250       first->current_length += amount_to_copy;
1251       second->current_data += amount_to_copy;
1252       second->current_length -= amount_to_copy;
1253       if (first->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1254         {
1255           first->total_length_not_including_first_buffer -= amount_to_copy;
1256         }
1257       if (!second->current_length)
1258         {
1259           vec_add1 (*discard_vector, first->next_buffer);
1260           if (second->flags & VLIB_BUFFER_NEXT_PRESENT)
1261             {
1262               first->next_buffer = second->next_buffer;
1263             }
1264           else
1265             {
1266               first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1267             }
1268           second->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1269         }
1270     }
1271   while ((first->current_length < want_first_size) &&
1272          (first->flags & VLIB_BUFFER_NEXT_PRESENT));
1273 }
1274
1275 /**
1276  * @brief linearize buffer chain - the first buffer is filled, if needed,
1277  * buffers are allocated and filled, returns free space in last buffer or
1278  * negative on failure
1279  *
1280  * @param[in] vm - vlib_main
1281  * @param[in,out] first - first buffer in chain
1282  */
1283 always_inline int
1284 vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * first)
1285 {
1286   vlib_buffer_t *b = first;
1287   u32 buf_len = vlib_bufer_get_default_size (vm);
1288   // free buffer chain starting from the second buffer
1289   int free_count = (b->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
1290   u32 chain_to_free = b->next_buffer;
1291
1292   u32 len = vlib_buffer_length_in_chain (vm, b);
1293   u32 free_len = buf_len - b->current_data - b->current_length;
1294   int alloc_len = clib_max (len - free_len, 0); //use the free len in the first buffer
1295   int n_buffers = (alloc_len + buf_len - 1) / buf_len;
1296   u32 new_buffers[n_buffers];
1297
1298   u32 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
1299   if (n_alloc != n_buffers)
1300     {
1301       vlib_buffer_free_no_next (vm, new_buffers, n_alloc);
1302       return -1;
1303     }
1304
1305   vlib_buffer_t *s = b;
1306   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1307     {
1308       s = vlib_get_buffer (vm, s->next_buffer);
1309       int d_free_len = buf_len - b->current_data - b->current_length;
1310       ASSERT (d_free_len >= 0);
1311       // chain buf and split write
1312       u32 copy_len = clib_min (d_free_len, s->current_length);
1313       u8 *d = vlib_buffer_put_uninit (b, copy_len);
1314       clib_memcpy (d, vlib_buffer_get_current (s), copy_len);
1315       int rest = s->current_length - copy_len;
1316       if (rest > 0)
1317         {
1318           //prev buf is full
1319           ASSERT (vlib_buffer_get_tail (b) == b->data + buf_len);
1320           ASSERT (n_buffers > 0);
1321           b = vlib_buffer_chain_buffer (vm, b, new_buffers[--n_buffers]);
1322           //make full use of the new buffers
1323           b->current_data = 0;
1324           d = vlib_buffer_put_uninit (b, rest);
1325           clib_memcpy (d, vlib_buffer_get_current (s) + copy_len, rest);
1326         }
1327     }
1328   vlib_buffer_free (vm, &chain_to_free, free_count);
1329   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1330   if (b == first)               /* no buffers addeed */
1331     b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1332   ASSERT (len == vlib_buffer_length_in_chain (vm, first));
1333   ASSERT (n_buffers == 0);
1334   return buf_len - b->current_data - b->current_length;
1335 }
1336
1337 #endif /* included_vlib_buffer_funcs_h */
1338
1339 /*
1340  * fd.io coding-style-patch-verification: ON
1341  *
1342  * Local Variables:
1343  * eval: (c-set-style "gnu")
1344  * End:
1345  */