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