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