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