FD.io VPP  v18.04-17-g3a0d853
Vector Packet Processing
buffer_funcs.h
Go to the documentation of this file.
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 */
57 vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
58 {
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 buffer pointer into buffer index
67 
68  @param vm - (vlib_main_t *) vlib main data structure pointer
69  @param p - (void *) buffer pointer
70  @return - (u32) buffer index
71 */
72 
75 {
79  ASSERT (offset < bm->buffer_mem_size);
80  ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
81  return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
82 }
83 
84 /** \brief Get next buffer in buffer linklist, or zero for end of list.
85 
86  @param vm - (vlib_main_t *) vlib main data structure pointer
87  @param b - (void *) buffer pointer
88  @return - (vlib_buffer_t *) next buffer, or NULL
89 */
92 {
93  return (b->flags & VLIB_BUFFER_NEXT_PRESENT
94  ? vlib_get_buffer (vm, b->next_buffer) : 0);
95 }
96 
98  vlib_buffer_t * b_first);
99 
100 /** \brief Get length in bytes of the buffer chain
101 
102  @param vm - (vlib_main_t *) vlib main data structure pointer
103  @param b - (void *) buffer pointer
104  @return - (uword) length of buffer chain
105 */
108 {
109  uword len = b->current_length;
110 
111  if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
112  return len;
113 
114  if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
116 
118 }
119 
120 /** \brief Get length in bytes of the buffer index buffer chain
121 
122  @param vm - (vlib_main_t *) vlib main data structure pointer
123  @param bi - (u32) buffer index
124  @return - (uword) length of buffer chain
125 */
128 {
129  vlib_buffer_t *b = vlib_get_buffer (vm, bi);
130  return vlib_buffer_length_in_chain (vm, b);
131 }
132 
133 /** \brief Copy buffer contents to memory
134 
135  @param vm - (vlib_main_t *) vlib main data structure pointer
136  @param buffer_index - (u32) buffer index
137  @param contents - (u8 *) memory, <strong>must be large enough</strong>
138  @return - (uword) length of buffer chain
139 */
141 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
142 {
143  uword content_len = 0;
144  uword l;
145  vlib_buffer_t *b;
146 
147  while (1)
148  {
149  b = vlib_get_buffer (vm, buffer_index);
150  l = b->current_length;
151  clib_memcpy (contents + content_len, b->data + b->current_data, l);
152  content_len += l;
153  if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
154  break;
155  buffer_index = b->next_buffer;
156  }
157 
158  return content_len;
159 }
160 
161 /* Return physical address of buffer->data start. */
164 {
166  vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
168  b->buffer_pool_index);
169 
171 }
172 
173 /** \brief Prefetch buffer metadata by buffer index
174  The first 64 bytes of buffer contains most header information
175 
176  @param vm - (vlib_main_t *) vlib main data structure pointer
177  @param bi - (u32) buffer index
178  @param type - LOAD, STORE. In most cases, STORE is the right answer
179 */
180 /* Prefetch buffer header given index. */
181 #define vlib_prefetch_buffer_with_index(vm,bi,type) \
182  do { \
183  vlib_buffer_t * _b = vlib_get_buffer (vm, bi); \
184  vlib_prefetch_buffer_header (_b, type); \
185  } while (0)
186 
187 #if 0
188 /* Iterate over known allocated vlib bufs. You probably do not want
189  * to do this!
190  @param vm the vlib_main_t
191  @param bi found allocated buffer index
192  @param body operation to perform on buffer index
193  function executes body for each allocated buffer index
194  */
195 #define vlib_buffer_foreach_allocated(vm,bi,body) \
196 do { \
197  vlib_main_t * _vmain = (vm); \
198  vlib_buffer_main_t * _bmain = &_vmain->buffer_main; \
199  hash_pair_t * _vbpair; \
200  hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({ \
201  if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) { \
202  (bi) = _vbpair->key; \
203  body; \
204  } \
205  })); \
206 } while (0)
207 #endif
208 
209 typedef enum
210 {
211  /* Index is unknown. */
213 
214  /* Index is known and free/allocated. */
218 
219 void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
220  uword n_buffers,
222  expected_state);
223 
225 vlib_buffer_is_known (u32 buffer_index)
226 {
228 
230  uword *p = hash_get (bm->buffer_known_hash, buffer_index);
232  return p ? p[0] : VLIB_BUFFER_UNKNOWN;
233 }
234 
235 always_inline void
238 {
240 
242  hash_set (bm->buffer_known_hash, buffer_index, state);
244 }
245 
246 /* Validates sanity of a single buffer.
247  Returns format'ed vector with error message if any. */
248 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
249  uword follow_chain);
250 
253 {
254  return round_pow2 (size, sizeof (vlib_buffer_t));
255 }
256 
259 {
260  if (PREDICT_FALSE (b->flags & VLIB_BUFFER_NON_DEFAULT_FREELIST))
261  return b->free_list_index;
262 
263  return 0;
264 }
265 
266 always_inline void
269 {
270  if (PREDICT_FALSE (index))
271  {
272  b->flags |= VLIB_BUFFER_NON_DEFAULT_FREELIST;
273  b->free_list_index = index;
274  }
275  else
276  b->flags &= ~VLIB_BUFFER_NON_DEFAULT_FREELIST;
277 }
278 
279 /** \brief Allocate buffers from specific freelist into supplied array
280 
281  @param vm - (vlib_main_t *) vlib main data structure pointer
282  @param buffers - (u32 * ) buffer index array
283  @param n_buffers - (u32) number of buffers requested
284  @return - (u32) number of buffers actually allocated, may be
285  less than the number requested or zero
286 */
289  u32 * buffers,
290  u32 n_buffers,
292 {
295  u32 *src;
296  uword len;
297 
299 
300  fl = pool_elt_at_index (vm->buffer_free_list_pool, index);
301 
302  len = vec_len (fl->buffers);
303 
304  if (PREDICT_FALSE (len < n_buffers))
305  {
306  bm->cb.vlib_buffer_fill_free_list_cb (vm, fl, n_buffers);
307  if (PREDICT_FALSE ((len = vec_len (fl->buffers)) == 0))
308  return 0;
309 
310  /* even if fill free list didn't manage to refill free list
311  we should give what we have */
312  n_buffers = clib_min (len, n_buffers);
313 
314  /* following code is intentionaly duplicated to allow compiler
315  to optimize fast path when n_buffers is constant value */
316  src = fl->buffers + len - n_buffers;
317  clib_memcpy (buffers, src, n_buffers * sizeof (u32));
318  _vec_len (fl->buffers) -= n_buffers;
319 
320  /* Verify that buffers are known free. */
321  vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
323 
324  return n_buffers;
325  }
326 
327  src = fl->buffers + len - n_buffers;
328  clib_memcpy (buffers, src, n_buffers * sizeof (u32));
329  _vec_len (fl->buffers) -= n_buffers;
330 
331  /* Verify that buffers are known free. */
332  vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
334 
335  return n_buffers;
336 }
337 
338 /** \brief Allocate buffers into supplied array
339 
340  @param vm - (vlib_main_t *) vlib main data structure pointer
341  @param buffers - (u32 * ) buffer index array
342  @param n_buffers - (u32) number of buffers requested
343  @return - (u32) number of buffers actually allocated, may be
344  less than the number requested or zero
345 */
347 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
348 {
349  return vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
351 }
352 
353 /** \brief Allocate buffers into ring
354 
355  @param vm - (vlib_main_t *) vlib main data structure pointer
356  @param buffers - (u32 * ) buffer index ring
357  @param start - (u32) first slot in the ring
358  @param ring_size - (u32) ring size
359  @param n_buffers - (u32) number of buffers requested
360  @return - (u32) number of buffers actually allocated, may be
361  less than the number requested or zero
362 */
365  u32 ring_size, u32 n_buffers)
366 {
367  u32 n_alloc;
368 
369  ASSERT (n_buffers <= ring_size);
370 
371  if (PREDICT_TRUE (start + n_buffers <= ring_size))
372  return vlib_buffer_alloc (vm, ring + start, n_buffers);
373 
374  n_alloc = vlib_buffer_alloc (vm, ring + start, ring_size - start);
375 
376  if (PREDICT_TRUE (n_alloc == ring_size - start))
377  n_alloc += vlib_buffer_alloc (vm, ring, n_buffers - n_alloc);
378 
379  return n_alloc;
380 }
381 
382 /** \brief Free buffers
383  Frees the entire buffer chain for each buffer
384 
385  @param vm - (vlib_main_t *) vlib main data structure pointer
386  @param buffers - (u32 * ) buffer index array
387  @param n_buffers - (u32) number of buffers to free
388 
389 */
390 always_inline void
392  /* pointer to first buffer */
393  u32 * buffers,
394  /* number of buffers to free */
395  u32 n_buffers)
396 {
398 
400 
401  return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
402 }
403 
404 /** \brief Free buffers, does not free the buffer chain for each buffer
405 
406  @param vm - (vlib_main_t *) vlib main data structure pointer
407  @param buffers - (u32 * ) buffer index array
408  @param n_buffers - (u32) number of buffers to free
409 
410 */
411 always_inline void
413  /* pointer to first buffer */
414  u32 * buffers,
415  /* number of buffers to free */
416  u32 n_buffers)
417 {
419 
421 
422  return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
423 }
424 
425 /** \brief Free one buffer
426  Shorthand to free a single buffer chain.
427 
428  @param vm - (vlib_main_t *) vlib main data structure pointer
429  @param buffer_index - (u32) buffer index to free
430 */
431 always_inline void
433 {
434  vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
435 }
436 
437 /** \brief Free buffers from ring
438 
439  @param vm - (vlib_main_t *) vlib main data structure pointer
440  @param buffers - (u32 * ) buffer index ring
441  @param start - (u32) first slot in the ring
442  @param ring_size - (u32) ring size
443  @param n_buffers - (u32) number of buffers
444 */
445 always_inline void
447  u32 ring_size, u32 n_buffers)
448 {
449  ASSERT (n_buffers <= ring_size);
450 
451  if (PREDICT_TRUE (start + n_buffers <= ring_size))
452  {
453  vlib_buffer_free (vm, ring + start, n_buffers);
454  }
455  else
456  {
457  vlib_buffer_free (vm, ring + start, ring_size - start);
458  vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
459  }
460 }
461 
462 /** \brief Free buffers from ring without freeing tail buffers
463 
464  @param vm - (vlib_main_t *) vlib main data structure pointer
465  @param buffers - (u32 * ) buffer index ring
466  @param start - (u32) first slot in the ring
467  @param ring_size - (u32) ring size
468  @param n_buffers - (u32) number of buffers
469 */
470 always_inline void
472  u32 ring_size, u32 n_buffers)
473 {
474  ASSERT (n_buffers <= ring_size);
475 
476  if (PREDICT_TRUE (start + n_buffers <= ring_size))
477  {
478  vlib_buffer_free (vm, ring + start, n_buffers);
479  }
480  else
481  {
482  vlib_buffer_free_no_next (vm, ring + start, ring_size - start);
483  vlib_buffer_free_no_next (vm, ring, n_buffers - (ring_size - start));
484  }
485 }
486 
487 /* Add/delete buffer free lists. */
489  u32 n_data_bytes,
490  char *fmt, ...);
491 always_inline void
493  vlib_buffer_free_list_index_t free_list_index)
494 {
496 
498 
499  bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
500 }
501 
502 /* Make sure we have at least given number of unaligned buffers. */
505  free_list,
506  uword n_unaligned_buffers);
507 
511 {
513 
514  *index = i = vlib_buffer_get_free_list_index (b);
516 }
517 
520  vlib_buffer_free_list_index_t free_list_index)
521 {
523 
524  f = pool_elt_at_index (vm->buffer_free_list_pool, free_list_index);
525 
526  /* Sanity: indices must match. */
527  ASSERT (f->index == free_list_index);
528 
529  return f;
530 }
531 
535 {
537  return f->n_data_bytes;
538 }
539 
540 void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
541 
542 /* Reasonably fast buffer copy routine. */
543 always_inline void
544 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
545 {
546  while (n >= 4)
547  {
548  dst[0] = src[0];
549  dst[1] = src[1];
550  dst[2] = src[2];
551  dst[3] = src[3];
552  dst += 4;
553  src += 4;
554  n -= 4;
555  }
556  while (n > 0)
557  {
558  dst[0] = src[0];
559  dst += 1;
560  src += 1;
561  n -= 1;
562  }
563 }
564 
565 /* Append given data to end of buffer, possibly allocating new buffers. */
567  vlib_buffer_free_list_index_t free_list_index,
568  u32 buffer_index, void *data, u32 n_data_bytes);
569 
570 /* duplicate all buffers in chain */
573 {
574  vlib_buffer_t *s, *d, *fd;
575  uword n_alloc, n_buffers = 1;
576  u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
577  int i;
578 
579  s = b;
580  while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
581  {
582  n_buffers++;
583  s = vlib_get_buffer (vm, s->next_buffer);
584  }
585  u32 new_buffers[n_buffers];
586 
587  n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
588 
589  /* No guarantee that we'll get all the buffers we asked for */
590  if (PREDICT_FALSE (n_alloc < n_buffers))
591  {
592  if (n_alloc > 0)
593  vlib_buffer_free (vm, new_buffers, n_alloc);
594  return 0;
595  }
596 
597  /* 1st segment */
598  s = b;
599  fd = d = vlib_get_buffer (vm, new_buffers[0]);
600  d->current_data = s->current_data;
602  d->flags = s->flags & flag_mask;
605  clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
608 
609  /* next segments */
610  for (i = 1; i < n_buffers; i++)
611  {
612  /* previous */
613  d->next_buffer = new_buffers[i];
614  /* current */
615  s = vlib_get_buffer (vm, s->next_buffer);
616  d = vlib_get_buffer (vm, new_buffers[i]);
617  d->current_data = s->current_data;
621  d->flags = s->flags & flag_mask;
622  }
623 
624  return fd;
625 }
626 
627 /** \brief Create a maximum of 256 clones of buffer and store them
628  in the supplied array
629 
630  @param vm - (vlib_main_t *) vlib main data structure pointer
631  @param src_buffer - (u32) source buffer index
632  @param buffers - (u32 * ) buffer index array
633  @param n_buffers - (u16) number of buffer clones requested (<=256)
634  @param head_end_offset - (u16) offset relative to current position
635  where packet head ends
636  @return - (u16) number of buffers actually cloned, may be
637  less than the number requested or zero
638 */
640 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
641  u16 n_buffers, u16 head_end_offset)
642 {
643  u16 i;
644  vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
645 
646  ASSERT (s->n_add_refs == 0);
647  ASSERT (n_buffers);
648  ASSERT (n_buffers <= 256);
649 
650  if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
651  {
652  buffers[0] = src_buffer;
653  for (i = 1; i < n_buffers; i++)
654  {
655  vlib_buffer_t *d;
656  d = vlib_buffer_copy (vm, s);
657  if (d == 0)
658  return i;
659  buffers[i] = vlib_get_buffer_index (vm, d);
660 
661  }
662  return n_buffers;
663  }
664 
665  if (PREDICT_FALSE (n_buffers == 1))
666  {
667  buffers[0] = src_buffer;
668  return 1;
669  }
670 
671  n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
673  (s));
674 
675  for (i = 0; i < n_buffers; i++)
676  {
677  vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
678  d->current_data = s->current_data;
679  d->current_length = head_end_offset;
684  head_end_offset;
685  d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
686  d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
687  clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
689  head_end_offset);
690  d->next_buffer = src_buffer;
691  }
692  vlib_buffer_advance (s, head_end_offset);
693  s->n_add_refs = n_buffers - 1;
694  while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
695  {
696  s = vlib_get_buffer (vm, s->next_buffer);
697  s->n_add_refs = n_buffers - 1;
698  }
699 
700  return n_buffers;
701 }
702 
703 /** \brief Create multiple clones of buffer and store them
704  in the supplied array
705 
706  @param vm - (vlib_main_t *) vlib main data structure pointer
707  @param src_buffer - (u32) source buffer index
708  @param buffers - (u32 * ) buffer index array
709  @param n_buffers - (u16) number of buffer clones requested (<=256)
710  @param head_end_offset - (u16) offset relative to current position
711  where packet head ends
712  @return - (u16) number of buffers actually cloned, may be
713  less than the number requested or zero
714 */
716 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
717  u16 n_buffers, u16 head_end_offset)
718 {
719  vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
720  u16 n_cloned = 0;
721 
722  while (n_buffers > 256)
723  {
724  vlib_buffer_t *copy;
725  copy = vlib_buffer_copy (vm, s);
726  n_cloned += vlib_buffer_clone_256 (vm,
727  vlib_get_buffer_index (vm, copy),
728  (buffers + n_cloned),
729  256, head_end_offset);
730  n_buffers -= 256;
731  }
732  n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
733  buffers + n_cloned,
734  n_buffers, head_end_offset);
735 
736  return n_cloned;
737 }
738 
739 /** \brief Attach cloned tail to the buffer
740 
741  @param vm - (vlib_main_t *) vlib main data structure pointer
742  @param head - (vlib_buffer_t *) head buffer
743  @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
744 */
745 
746 always_inline void
748  vlib_buffer_t * tail)
749 {
750  ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
753 
754  head->flags |= VLIB_BUFFER_NEXT_PRESENT;
755  head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
756  head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
757  head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
758  head->next_buffer = vlib_get_buffer_index (vm, tail);
761 
762 next_segment:
763  __sync_add_and_fetch (&tail->n_add_refs, 1);
764 
765  if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
766  {
767  tail = vlib_get_buffer (vm, tail->next_buffer);
768  goto next_segment;
769  }
770 }
771 
772 /* Initializes the buffer as an empty packet with no chained buffers. */
773 always_inline void
775 {
777  first->current_length = 0;
778  first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
779  first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
780 }
781 
782 /* The provided next_bi buffer index is appended to the end of the packet. */
785  vlib_buffer_t * first,
786  vlib_buffer_t * last, u32 next_bi)
787 {
788  vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
789  last->next_buffer = next_bi;
790  last->flags |= VLIB_BUFFER_NEXT_PRESENT;
791  next_buffer->current_length = 0;
792  next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
793  return next_buffer;
794 }
795 
796 /* Increases or decreases the packet length.
797  * It does not allocate or deallocate new buffers.
798  * Therefore, the added length must be compatible
799  * with the last buffer. */
800 always_inline void
802  vlib_buffer_t * last, i32 len)
803 {
804  last->current_length += len;
805  if (first != last)
807 }
808 
809 /* Copy data to the end of the packet and increases its length.
810  * It does not allocate new buffers.
811  * Returns the number of copied bytes. */
814  vlib_buffer_free_list_index_t free_list_index,
815  vlib_buffer_t * first,
816  vlib_buffer_t * last, void *data, u16 data_len)
817 {
818  u32 n_buffer_bytes =
819  vlib_buffer_free_list_buffer_size (vm, free_list_index);
820  ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
821  u16 len = clib_min (data_len,
822  n_buffer_bytes - last->current_length -
823  last->current_data);
824  clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
825  len);
826  vlib_buffer_chain_increase_length (first, last, len);
827  return len;
828 }
829 
830 /* Copy data to the end of the packet and increases its length.
831  * Allocates additional buffers from the free list if necessary.
832  * Returns the number of copied bytes.
833  * 'last' value is modified whenever new buffers are allocated and
834  * chained and points to the last buffer in the chain. */
835 u16
838  free_list_index,
839  vlib_buffer_t * first,
840  vlib_buffer_t ** last, void *data,
841  u16 data_len);
843 
846 
847 typedef struct
848 {
849  /* Vector of packet data. */
851 
852  /* Number of buffers to allocate in each call to allocator. */
854 
855  /* Buffer free list for this template. */
857 
860 
863 
866  void *packet_data,
867  uword n_packet_data_bytes,
868  uword min_n_buffers_each_alloc,
869  char *fmt, ...);
870 
873  u32 * bi_result);
874 
875 always_inline void
877 {
878  vec_free (t->packet_data);
879 }
880 
883 {
884  serialize_stream_t *s = &m->stream;
888  vlib_main_t *vm = sm->vlib_main;
889  u32 n, *f;
890 
892  if (sm->last_buffer != ~0)
893  {
895  while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
896  {
897  b = vlib_get_buffer (vm, b->next_buffer);
898  n += b->current_length;
899  }
900  }
901 
902  /* *INDENT-OFF* */
903  clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
904  n += vlib_buffer_index_length_in_chain (vm, f[0]);
905  }));
906 /* *INDENT-ON* */
907 
908  return n;
909 }
910 
911 /* Set a buffer quickly into "uninitialized" state. We want this to
912  be extremely cheap and arrange for all fields that need to be
913  initialized to be in the first 128 bits of the buffer. */
914 always_inline void
917 {
919 
920  /* Make sure vlib_buffer_t is cacheline aligned and sized */
921  ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
922  ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
924  ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
926 
927  /* Make sure buffer template is sane. */
929 
930  clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
931  STRUCT_MARK_PTR (src, template_start),
932  STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
933  STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
934 
935  /* Not in the first 16 octets. */
936  dst->n_add_refs = src->n_add_refs;
938 
939  /* Make sure it really worked. */
940 #define _(f) ASSERT (dst->f == src->f);
941  _(current_data);
942  _(current_length);
943  _(flags);
944 #undef _
945  /* ASSERT (dst->total_length_not_including_first_buffer == 0); */
946  /* total_length_not_including_first_buffer is not in the template anymore
947  * so it may actually not zeroed for some buffers. One option is to
948  * uncomment the line lower (comes at a cost), the other, is to just not
949  * care */
950  /* dst->total_length_not_including_first_buffer = 0; */
951  ASSERT (dst->n_add_refs == 0);
952 }
953 
954 always_inline void
957  u32 buffer_index, u8 do_init)
958 {
960  vlib_buffer_t *b;
961  b = vlib_get_buffer (vm, buffer_index);
962  if (PREDICT_TRUE (do_init))
964  vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
965 
966  if (vec_len (f->buffers) > 4 * VLIB_FRAME_SIZE)
967  {
968  clib_spinlock_lock (&bp->lock);
969  /* keep last stored buffers, as they are more likely hot in the cache */
973  f->n_alloc -= VLIB_FRAME_SIZE;
974  clib_spinlock_unlock (&bp->lock);
975  }
976 }
977 
978 #if CLIB_DEBUG > 0
981 extern void *vlib_buffer_state_heap;
982 #endif
983 
984 static inline void
986 {
987 #if CLIB_DEBUG > 0
988  uword *p;
989  void *oldheap;
990 
992 
993  while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
994  ;
995 
997 
998  /* If we don't know about b, declare it to be in the expected state */
999  if (!p)
1000  {
1002  goto out;
1003  }
1004 
1005  if (p[0] != expected)
1006  {
1007  void cj_stop (void);
1008  u32 bi;
1010 
1011  cj_stop ();
1012 
1013  bi = vlib_get_buffer_index (vm, b);
1014 
1015  clib_mem_set_heap (oldheap);
1016  clib_warning ("%.6f buffer %llx (%d): %s, not %s",
1017  vlib_time_now (vm), bi,
1018  p[0] ? "busy" : "free", expected ? "busy" : "free");
1019  os_panic ();
1020  }
1021 out:
1024  clib_mem_set_heap (oldheap);
1025 #endif
1026 }
1027 
1028 static inline void
1030 {
1031 #if CLIB_DEBUG > 0
1032  void *oldheap;
1033 
1035 
1036  while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
1037  ;
1038 
1040 
1043  clib_mem_set_heap (oldheap);
1044 #endif
1045 }
1046 
1047 /** minimum data size of first buffer in a buffer chain */
1048 #define VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE (256)
1049 
1050 /**
1051  * @brief compress buffer chain in a way where the first buffer is at least
1052  * VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE long
1053  *
1054  * @param[in] vm - vlib_main
1055  * @param[in,out] first - first buffer in chain
1056  * @param[in,out] discard_vector - vector of buffer indexes which were removed
1057  * from the chain
1058  */
1059 always_inline void
1061  vlib_buffer_t * first, u32 ** discard_vector)
1062 {
1064  !(first->flags & VLIB_BUFFER_NEXT_PRESENT))
1065  {
1066  /* this is already big enough or not a chain */
1067  return;
1068  }
1069  /* probe free list to find allocated buffer size to avoid overfill */
1071  vlib_buffer_free_list_t *free_list =
1072  vlib_buffer_get_buffer_free_list (vm, first, &index);
1073 
1075  free_list->n_data_bytes -
1076  first->current_data);
1077  do
1078  {
1079  vlib_buffer_t *second = vlib_get_buffer (vm, first->next_buffer);
1080  u32 need = want_first_size - first->current_length;
1081  u32 amount_to_copy = clib_min (need, second->current_length);
1082  clib_memcpy (((u8 *) vlib_buffer_get_current (first)) +
1083  first->current_length,
1084  vlib_buffer_get_current (second), amount_to_copy);
1085  first->current_length += amount_to_copy;
1086  vlib_buffer_advance (second, amount_to_copy);
1087  if (first->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1088  {
1089  first->total_length_not_including_first_buffer -= amount_to_copy;
1090  }
1091  if (!second->current_length)
1092  {
1093  vec_add1 (*discard_vector, first->next_buffer);
1094  if (second->flags & VLIB_BUFFER_NEXT_PRESENT)
1095  {
1096  first->next_buffer = second->next_buffer;
1097  }
1098  else
1099  {
1100  first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1101  }
1102  second->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1103  }
1104  }
1105  while ((first->current_length < want_first_size) &&
1106  (first->flags & VLIB_BUFFER_NEXT_PRESENT));
1107 }
1108 
1109 #endif /* included_vlib_buffer_funcs_h */
1110 
1111 /*
1112  * fd.io coding-style-patch-verification: ON
1113  *
1114  * Local Variables:
1115  * eval: (c-set-style "gnu")
1116  * End:
1117  */
vlib_physmem_region_index_t physmem_region
Definition: buffer.h:420
vlib_main_t vlib_global_main
Definition: main.c:1642
#define hash_set(h, key, value)
Definition: hash.h:254
#define clib_min(x, y)
Definition: clib.h:340
static_always_inline void clib_spinlock_unlock(clib_spinlock_t *p)
Definition: lock.h:89
static_always_inline void clib_spinlock_lock(clib_spinlock_t *p)
Definition: lock.h:74
uword vlib_buffer_length_in_chain_slow_path(vlib_main_t *vm, vlib_buffer_t *b_first)
Definition: buffer.c:55
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer_funcs.h:391
struct vlib_serialize_buffer_main_t::@30::@33 rx
#define STRUCT_MARK_PTR(v, f)
Definition: clib.h:68
format_function_t format_vlib_buffer_contents
Definition: buffer_funcs.h:844
u32 opaque[10]
Opaque data used by sub-graphs for their own purposes.
Definition: buffer.h:149
#define PREDICT_TRUE(x)
Definition: clib.h:106
format_function_t format_vlib_buffer
Definition: buffer_funcs.h:844
static void vlib_buffer_chain_compress(vlib_main_t *vm, vlib_buffer_t *first, u32 **discard_vector)
compress buffer chain in a way where the first buffer is at least VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SI...
vlib_buffer_callbacks_t cb
Definition: buffer.h:461
static void vlib_buffer_attach_clone(vlib_main_t *vm, vlib_buffer_t *head, vlib_buffer_t *tail)
Attach cloned tail to the buffer.
Definition: buffer_funcs.h:747
static void vlib_validate_buffer_in_use(vlib_buffer_t *b, u32 expected)
Definition: buffer_funcs.h:985
static vlib_buffer_t * vlib_buffer_chain_buffer(vlib_main_t *vm, vlib_buffer_t *first, vlib_buffer_t *last, u32 next_bi)
Definition: buffer_funcs.h:784
static f64 vlib_time_now(vlib_main_t *vm)
Definition: main.h:227
static void vlib_buffer_chain_increase_length(vlib_buffer_t *first, vlib_buffer_t *last, i32 len)
Definition: buffer_funcs.h:801
vlib_buffer_t buffer_init_template
Definition: buffer.h:351
void os_panic(void)
Definition: unix-misc.c:174
struct vlib_main_t * vlib_main
Definition: buffer.h:482
#define CLIB_LOG2_CACHE_LINE_BYTES
Definition: cache.h:50
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:520
u8 buffer_pool_index
index of buffer pool this buffer belongs.
Definition: buffer.h:143
int i
#define STRUCT_OFFSET_OF(t, f)
Definition: clib.h:62
static void vlib_buffer_delete_free_list(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index)
Definition: buffer_funcs.h:492
u8 *( format_function_t)(u8 *s, va_list *args)
Definition: format.h:48
u16 vlib_buffer_chain_append_data_with_alloc(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index, vlib_buffer_t *first, vlib_buffer_t **last, void *data, u16 data_len)
Definition: buffer.c:868
uword * vlib_buffer_state_validation_hash
Definition: buffer.c:629
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:107
vlib_buffer_free_list_index_t index
Definition: buffer.h:354
static u64 vlib_get_buffer_data_physical_address(vlib_main_t *vm, u32 buffer_index)
Definition: buffer_funcs.h:163
static vlib_buffer_t * vlib_buffer_copy(vlib_main_t *vm, vlib_buffer_t *b)
Definition: buffer_funcs.h:572
vlib_buffer_free_list_index_t free_list_index
Definition: buffer_funcs.h:856
void cj_stop(void)
Definition: cj.c:58
#define vec_add1_aligned(V, E, A)
Add 1 element to end of vector (alignment specified).
Definition: vec.h:530
static u16 vlib_buffer_clone_256(vlib_main_t *vm, u32 src_buffer, u32 *buffers, u16 n_buffers, u16 head_end_offset)
Create a maximum of 256 clones of buffer and store them in the supplied array.
Definition: buffer_funcs.h:640
u32 vlib_buffer_add_data(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index, u32 buffer_index, void *data, u32 n_data_bytes)
Definition: buffer.c:811
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:104
#define always_inline
Definition: clib.h:92
int i32
Definition: types.h:81
void vlib_aligned_memcpy(void *_dst, void *_src, int n_bytes)
vlib_buffer_free_no_next_cb_t * vlib_buffer_free_no_next_cb
Definition: buffer.h:400
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE
minimum data size of first buffer in a buffer chain
u32 * vlib_buffer_state_validation_lock
Definition: buffer.c:628
unsigned long u64
Definition: types.h:89
static void vlib_copy_buffers(u32 *dst, u32 *src, u32 n)
Definition: buffer_funcs.h:544
#define VLIB_FRAME_SIZE
Definition: node.h:328
static uword pointer_to_uword(const void *p)
Definition: types.h:131
static u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:74
#define fl(x, y)
static void vlib_buffer_free_from_ring(vlib_main_t *vm, u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
Free buffers from ring.
Definition: buffer_funcs.h:446
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
u32 size
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:108
u8 * vlib_validate_buffer(vlib_main_t *vm, u32 buffer_index, uword follow_chain)
Definition: buffer.c:225
format_function_t format_vlib_buffer_and_data
Definition: buffer_funcs.h:844
void(* vlib_buffer_delete_free_list_cb)(struct vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index)
Definition: buffer.h:407
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:209
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:446
vlib_buffer_pool_t * buffer_pools
Definition: buffer.h:440
#define PREDICT_FALSE(x)
Definition: clib.h:105
vlib_buffer_free_list_t * buffer_free_list_pool
Definition: main.h:108
#define clib_fifo_foreach(v, f, body)
Definition: fifo.h:279
static void vlib_buffer_add_to_free_list(vlib_main_t *vm, vlib_buffer_free_list_t *f, u32 buffer_index, u8 do_init)
Definition: buffer_funcs.h:955
#define uword_to_pointer(u, type)
Definition: types.h:136
static uword vlib_buffer_contents(vlib_main_t *vm, u32 buffer_index, u8 *contents)
Copy buffer contents to memory.
Definition: buffer_funcs.h:141
static void vlib_buffer_set_known_state(u32 buffer_index, vlib_buffer_known_state_t state)
Definition: buffer_funcs.h:236
static void vlib_buffer_chain_init(vlib_buffer_t *first)
Definition: buffer_funcs.h:774
#define vec_add_aligned(V, E, N, A)
Add N elements to end of vector V (no header, specified alignment)
Definition: vec.h:607
serialize_stream_t stream
Definition: serialize.h:147
clib_spinlock_t buffer_known_hash_lockp
Definition: buffer.h:458
vlib_buffer_fill_free_list_cb_t * vlib_buffer_fill_free_list_cb
Definition: buffer.h:398
static void vlib_buffer_free_no_next(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers, does not free the buffer chain for each buffer.
Definition: buffer_funcs.h:412
static u16 vlib_buffer_clone(vlib_main_t *vm, u32 src_buffer, u32 *buffers, u16 n_buffers, u16 head_end_offset)
Create multiple clones of buffer and store them in the supplied array.
Definition: buffer_funcs.h:716
u32 current_buffer_index
Definition: serialize.h:62
void vlib_buffer_chain_validate(vlib_main_t *vm, vlib_buffer_t *first)
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
static void * clib_mem_set_heap(void *heap)
Definition: mem.h:226
#define clib_warning(format, args...)
Definition: error.h:59
#define clib_memcpy(a, b, c)
Definition: string.h:75
clib_spinlock_t lock
Definition: buffer.h:430
static vlib_buffer_t * vlib_get_next_buffer(vlib_main_t *vm, vlib_buffer_t *b)
Get next buffer in buffer linklist, or zero for end of list.
Definition: buffer_funcs.h:91
void vlib_buffer_validate_alloc_free(vlib_main_t *vm, u32 *buffers, uword n_buffers, vlib_buffer_known_state_t expected_state)
Definition: buffer.c:309
static uword round_pow2(uword x, uword pow2)
Definition: clib.h:286
vlib_buffer_known_state_t
Definition: buffer_funcs.h:209
uword data_function_opaque
Definition: serialize.h:74
static void vlib_validate_buffer_set_in_use(vlib_buffer_t *b, u32 expected)
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:783
vlib_buffer_free_cb_t * vlib_buffer_free_cb
Definition: buffer.h:399
static vlib_buffer_free_list_index_t vlib_buffer_get_free_list_index(vlib_buffer_t *b)
Definition: buffer_funcs.h:258
void vlib_buffer_free_list_fill_unaligned(vlib_main_t *vm, vlib_buffer_free_list_t *free_list, uword n_unaligned_buffers)
vhost_vring_state_t state
Definition: vhost-user.h:82
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:126
static vlib_buffer_free_list_t * vlib_buffer_get_buffer_free_list(vlib_main_t *vm, vlib_buffer_t *b, vlib_buffer_free_list_index_t *index)
Definition: buffer_funcs.h:509
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:222
vlib_buffer_free_list_index_t vlib_buffer_create_free_list(vlib_main_t *vm, u32 n_data_bytes, char *fmt,...)
Definition: buffer.c:415
static uword vlib_buffer_index_length_in_chain(vlib_main_t *vm, u32 bi)
Get length in bytes of the buffer index buffer chain.
Definition: buffer_funcs.h:127
u8 n_add_refs
Number of additional references to this buffer.
Definition: buffer.h:141
void * vlib_buffer_state_heap
Definition: buffer.c:630
static u32 vlib_buffer_alloc_from_free_list(vlib_main_t *vm, u32 *buffers, u32 n_buffers, vlib_buffer_free_list_index_t index)
Allocate buffers from specific freelist into supplied array.
Definition: buffer_funcs.h:288
u64 uword
Definition: types.h:112
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:159
template key/value backing page structure
Definition: bihash_doc.h:44
static u16 vlib_buffer_chain_append_data(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index, vlib_buffer_t *first, vlib_buffer_t *last, void *data, u16 data_len)
Definition: buffer_funcs.h:813
static u32 vlib_buffer_alloc_to_ring(vlib_main_t *vm, u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
Allocate buffers into ring.
Definition: buffer_funcs.h:364
unsigned short u16
Definition: types.h:57
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static u64 vlib_physmem_virtual_to_physical(vlib_main_t *vm, vlib_physmem_region_index_t idx, void *mem)
uword buffer_mem_start
Definition: buffer.h:438
uword * buffer_known_hash
Definition: buffer.h:457
static u32 vlib_buffer_free_list_buffer_size(vlib_main_t *vm, vlib_buffer_free_list_index_t index)
Definition: buffer_funcs.h:533
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:773
static void vlib_buffer_init_for_free_list(vlib_buffer_t *dst, vlib_buffer_free_list_t *fl)
Definition: buffer_funcs.h:915
static vlib_buffer_known_state_t vlib_buffer_is_known(u32 buffer_index)
Definition: buffer_funcs.h:225
vlib_buffer_main_t buffer_main
Definition: buffer.c:52
u8 data[0]
Packet data.
Definition: buffer.h:179
static void vlib_buffer_set_free_list_index(vlib_buffer_t *b, vlib_buffer_free_list_index_t index)
Definition: buffer_funcs.h:267
static_always_inline vlib_buffer_pool_t * vlib_buffer_pool_get(u8 buffer_pool_index)
Definition: buffer.h:468
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:109
u8 vlib_buffer_free_list_index_t
Definition: buffer.h:54
static void vlib_packet_template_free(vlib_main_t *vm, vlib_packet_template_t *t)
Definition: buffer_funcs.h:876
static void vlib_buffer_free_one(vlib_main_t *vm, u32 buffer_index)
Free one buffer Shorthand to free a single buffer chain.
Definition: buffer_funcs.h:432
void vlib_packet_template_get_packet_helper(vlib_main_t *vm, vlib_packet_template_t *t)
Definition: buffer.c:793
static vlib_buffer_free_list_t * vlib_buffer_get_free_list(vlib_main_t *vm, vlib_buffer_free_list_index_t free_list_index)
Definition: buffer_funcs.h:519
u32 flags
Definition: vhost-user.h:77
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
void vlib_packet_template_init(vlib_main_t *vm, vlib_packet_template_t *t, void *packet_data, uword n_packet_data_bytes, uword min_n_buffers_each_alloc, char *fmt,...)
Definition: buffer.c:725
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:111
static u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer_funcs.h:347
static void vlib_buffer_free_from_ring_no_next(vlib_main_t *vm, u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
Free buffers from ring without freeing tail buffers.
Definition: buffer_funcs.h:471
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
static u32 vlib_buffer_round_size(u32 size)
Definition: buffer_funcs.h:252
static u32 unserialize_vlib_buffer_n_bytes(serialize_main_t *m)
Definition: buffer_funcs.h:882
vlib_buffer_free_list_index_t free_list_index
Definition: buffer.h:163