FD.io VPP  v16.06
Vector Packet Processing
buffer.c
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.c: allocate/free network buffers.
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 #include <vlib/vlib.h>
41 
43 {
44  vlib_buffer_t * b = b_first;
45  uword l_first = b_first->current_length;
46  uword l = 0;
47  while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
48  {
49  b = vlib_get_buffer (vm, b->next_buffer);
50  l += b->current_length;
51  }
54  return l + l_first;
55 }
56 
57 u8 * format_vlib_buffer (u8 * s, va_list * args)
58 {
59  vlib_buffer_t * b = va_arg (*args, vlib_buffer_t *);
60 
61  s = format (s, "current data %d, length %d, free-list %d",
63  b->free_list_index);
64 
66  s = format (s, ", trace 0x%x", b->trace_index);
67 
69  s = format (s, ", next-buffer 0x%x", b->next_buffer);
70 
71  return s;
72 }
73 
74 u8 * format_vlib_buffer_and_data (u8 * s, va_list * args)
75 {
76  vlib_buffer_t * b = va_arg (*args, vlib_buffer_t *);
77 
78  s = format (s, "%U, %U",
81 
82  return s;
83 }
84 
85 static u8 * format_vlib_buffer_known_state (u8 * s, va_list * args)
86 {
88  char * t;
89 
90  switch (state)
91  {
93  t = "unknown";
94  break;
95 
97  t = "known-allocated";
98  break;
99 
101  t = "known-free";
102  break;
103 
104  default:
105  t = "invalid";
106  break;
107  }
108 
109  return format (s, "%s", t);
110 }
111 
112 u8 * format_vlib_buffer_contents (u8 * s, va_list * va)
113 {
114  vlib_main_t * vm = va_arg (*va, vlib_main_t *);
115  vlib_buffer_t * b = va_arg (*va, vlib_buffer_t *);
116 
117  while (1)
118  {
120  b->current_length);
121  if (! (b->flags & VLIB_BUFFER_NEXT_PRESENT))
122  break;
123  b = vlib_get_buffer (vm, b->next_buffer);
124  }
125 
126  return s;
127 }
128 
129 static u8 *
131  u32 bi,
132  uword follow_buffer_next,
133  uword ** unique_hash)
134 
135 {
136  vlib_buffer_t * b = vlib_get_buffer (vm, bi);
137  vlib_buffer_main_t * bm = vm->buffer_main;
139 
141  b->free_list_index))
142  return format (0, "unknown free list 0x%x", b->free_list_index);
143 
145  b->free_list_index);
146 
147  if ((signed) b->current_data < (signed) - VLIB_BUFFER_PRE_DATA_SIZE)
148  return format (0, "current data %d before pre-data", b->current_data);
149 #if DPDK == 0
150  if (b->current_data + b->current_length > fl->n_data_bytes)
151  return format (0, "%d-%d beyond end of buffer %d",
153  fl->n_data_bytes);
154 #endif
155 
156  if (follow_buffer_next
158  {
160  u8 * msg, * result;
161 
162  k = vlib_buffer_is_known (vm, b->next_buffer);
164  return format (0, "next 0x%x: %U",
165  b->next_buffer,
167 
168  if (unique_hash)
169  {
170  if (hash_get (*unique_hash, b->next_buffer))
171  return format (0, "duplicate buffer 0x%x", b->next_buffer);
172 
173  hash_set1 (*unique_hash, b->next_buffer);
174  }
175 
176  msg = vlib_validate_buffer (vm, b->next_buffer, follow_buffer_next);
177  if (msg)
178  {
179  result = format (0, "next 0x%x: %v", b->next_buffer, msg);
180  vec_free (msg);
181  return result;
182  }
183  }
184 
185  return 0;
186 }
187 
188 u8 *
189 vlib_validate_buffer (vlib_main_t * vm, u32 bi, uword follow_buffer_next)
190 { return vlib_validate_buffer_helper (vm, bi, follow_buffer_next, /* unique_hash */ 0); }
191 
192 u8 *
194  u32 * buffers,
195  uword next_buffer_stride,
196  uword n_buffers,
197  vlib_buffer_known_state_t known_state,
198  uword follow_buffer_next)
199 {
200  uword i, * hash;
201  u32 bi, * b = buffers;
203  u8 * msg = 0, * result = 0;
204 
205  hash = hash_create (0, 0);
206  for (i = 0; i < n_buffers; i++)
207  {
208  bi = b[0];
209  b += next_buffer_stride;
210 
211  /* Buffer is not unique. */
212  if (hash_get (hash, bi))
213  {
214  msg = format (0, "not unique");
215  goto done;
216  }
217 
218  k = vlib_buffer_is_known (vm, bi);
219  if (k != known_state)
220  {
221  msg = format (0, "is %U; expected %U",
223  format_vlib_buffer_known_state, known_state);
224  goto done;
225  }
226 
227  msg = vlib_validate_buffer_helper (vm, bi, follow_buffer_next, &hash);
228  if (msg)
229  goto done;
230 
231  hash_set1 (hash, bi);
232  }
233 
234  done:
235  if (msg)
236  {
237  result = format (0, "0x%x: %v", bi, msg);
238  vec_free (msg);
239  }
240  hash_free (hash);
241  return result;
242 }
243 
245 
246 /* When dubugging validate that given buffers are either known allocated
247  or known free. */
248 static void
250  u32 * buffers,
251  uword n_buffers,
252  vlib_buffer_known_state_t expected_state)
253 {
254  u32 * b;
255  uword i, bi, is_free;
256 
257  if (CLIB_DEBUG == 0)
258  return;
259 
260  ASSERT(os_get_cpu_number() == 0);
261 
262  /* smp disaster check */
263  if (vlib_mains)
264  ASSERT(vm == vlib_mains[0]);
265 
266  is_free = expected_state == VLIB_BUFFER_KNOWN_ALLOCATED;
267  b = buffers;
268  for (i = 0; i < n_buffers; i++)
269  {
271 
272  bi = b[0];
273  b += 1;
274  known = vlib_buffer_is_known (vm, bi);
275  if (known != expected_state)
276  {
277  ASSERT (0);
279  (vm, "%s %U buffer 0x%x",
280  is_free ? "freeing" : "allocating",
282  bi);
283  }
284 
286  (vm, bi,
288  }
289 }
290 
291 /* Aligned copy routine. */
292 void
293 vlib_aligned_memcpy (void * _dst, void * _src, int n_bytes)
294 {
295  vlib_copy_unit_t * dst = _dst;
296  vlib_copy_unit_t * src = _src;
297 
298  /* Arguments must be naturally aligned. */
299  ASSERT (pointer_to_uword (dst) % sizeof (dst[0]) == 0);
300  ASSERT (pointer_to_uword (src) % sizeof (src[0]) == 0);
301  ASSERT (n_bytes % sizeof (dst[0]) == 0);
302 
303  if (4 * sizeof (dst[0]) == CLIB_CACHE_LINE_BYTES)
304  {
305  CLIB_PREFETCH (dst + 0, 4 * sizeof (dst[0]), WRITE);
306  CLIB_PREFETCH (src + 0, 4 * sizeof (src[0]), READ);
307 
308  while (n_bytes >= 4 * sizeof (dst[0]))
309  {
310  dst += 4;
311  src += 4;
312  n_bytes -= 4 * sizeof (dst[0]);
313  CLIB_PREFETCH (dst, 4 * sizeof (dst[0]), WRITE);
314  CLIB_PREFETCH (src, 4 * sizeof (src[0]), READ);
315  dst[-4] = src[-4];
316  dst[-3] = src[-3];
317  dst[-2] = src[-2];
318  dst[-1] = src[-1];
319  }
320  }
321  else if (8 * sizeof (dst[0]) == CLIB_CACHE_LINE_BYTES)
322  {
323  CLIB_PREFETCH (dst + 0, 8 * sizeof (dst[0]), WRITE);
324  CLIB_PREFETCH (src + 0, 8 * sizeof (src[0]), READ);
325 
326  while (n_bytes >= 8 * sizeof (dst[0]))
327  {
328  dst += 8;
329  src += 8;
330  n_bytes -= 8 * sizeof (dst[0]);
331  CLIB_PREFETCH (dst, 8 * sizeof (dst[0]), WRITE);
332  CLIB_PREFETCH (src, 8 * sizeof (src[0]), READ);
333  dst[-8] = src[-8];
334  dst[-7] = src[-7];
335  dst[-6] = src[-6];
336  dst[-5] = src[-5];
337  dst[-4] = src[-4];
338  dst[-3] = src[-3];
339  dst[-2] = src[-2];
340  dst[-1] = src[-1];
341  }
342  }
343  else
344  /* Cache line size unknown: fall back to slow version. */;
345 
346  while (n_bytes > 0)
347  {
348  *dst++ = *src++;
349  n_bytes -= 1 * sizeof (dst[0]);
350  }
351 }
352 
353 #define BUFFERS_PER_COPY (sizeof (vlib_copy_unit_t) / sizeof (u32))
354 
355 /* Make sure we have at least given number of unaligned buffers. */
356 static void
358  vlib_buffer_free_list_t * free_list,
359  uword n_unaligned_buffers)
360 {
361  word la = vec_len (free_list->aligned_buffers);
362  word lu = vec_len (free_list->unaligned_buffers);
363 
364  /* Aligned come in aligned copy-sized chunks. */
365  ASSERT (la % BUFFERS_PER_COPY == 0);
366 
367  ASSERT (la >= n_unaligned_buffers);
368 
369  while (lu < n_unaligned_buffers)
370  {
371  /* Copy 4 buffers from end of aligned vector to unaligned vector. */
372  vec_add (free_list->unaligned_buffers,
373  free_list->aligned_buffers + la - BUFFERS_PER_COPY,
375  la -= BUFFERS_PER_COPY;
376  lu += BUFFERS_PER_COPY;
377  }
378  _vec_len (free_list->aligned_buffers) = la;
379 }
380 
381 /* After free aligned buffers may not contain even sized chunks. */
382 static void
384 {
385  uword l, n_trim;
386 
387  /* Add unaligned to aligned before trim. */
388  l = vec_len (f->unaligned_buffers);
389  if (l > 0)
390  {
392  /* align */ sizeof (vlib_copy_unit_t));
393 
394  _vec_len (f->unaligned_buffers) = 0;
395  }
396 
397  /* Remove unaligned buffers from end of aligned vector and save for next trim. */
398  l = vec_len (f->aligned_buffers);
399  n_trim = l % BUFFERS_PER_COPY;
400  if (n_trim)
401  {
402  /* Trim aligned -> unaligned. */
403  vec_add (f->unaligned_buffers, f->aligned_buffers + l - n_trim, n_trim);
404 
405  /* Remove from aligned. */
406  _vec_len (f->aligned_buffers) = l - n_trim;
407  }
408 }
409 
410 static void
413 {
414  uword l;
415  u32 * d;
416 
417  trim_aligned (src);
418  trim_aligned (dst);
419 
420  l = vec_len (src->aligned_buffers);
421  if (l > 0)
422  {
423  vec_add2_aligned (dst->aligned_buffers, d, l,
424  /* align */ sizeof (vlib_copy_unit_t));
425  vlib_aligned_memcpy (d, src->aligned_buffers, l * sizeof (d[0]));
426  vec_free (src->aligned_buffers);
427  }
428 
429  l = vec_len (src->unaligned_buffers);
430  if (l > 0)
431  {
434  }
435 }
436 
439 {
440  vlib_buffer_main_t * bm = vm->buffer_main;
441 
442  size = vlib_buffer_round_size (size);
443  uword * p = hash_get (bm->free_list_by_size, size);
444  return p ? p[0] : ~0;
445 }
446 
447 /* Add buffer free list. */
448 static u32
450  u32 n_data_bytes,
451  u32 is_public,
452  u32 is_default,
453  u8 * name)
454 {
455  vlib_buffer_main_t * bm = vm->buffer_main;
457 
458  if (! is_default && pool_elts (bm->buffer_free_list_pool) == 0)
459  {
460  u32 default_free_free_list_index;
461 
462  default_free_free_list_index =
464  /* default buffer size */ VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES,
465  /* is_public */ 1,
466  /* is_default */ 1,
467  (u8 *) "default");
468  ASSERT (default_free_free_list_index == VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
469 
470  if (n_data_bytes == VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES && is_public)
471  return default_free_free_list_index;
472  }
473 
475 
476  memset (f, 0, sizeof (f[0]));
477  f->index = f - bm->buffer_free_list_pool;
478  f->n_data_bytes = vlib_buffer_round_size (n_data_bytes);
480  f->name = clib_mem_is_heap_object (name) ? name : format (0, "%s", name);
481 
482  /* Setup free buffer template. */
484 
485  if (is_public)
486  {
488  if (! p)
490  }
491 
492  return f->index;
493 }
494 
496  char * fmt, ...)
497 {
498  va_list va;
499  u8 * name;
500 
501  va_start (va, fmt);
502  name = va_format (0, fmt, &va);
503  va_end (va);
504 
505  return vlib_buffer_create_free_list_helper (vm, n_data_bytes,
506  /* is_public */ 0,
507  /* is_default */ 0,
508  name);
509 }
510 
512  char * fmt, ...)
513 {
514  u32 i = vlib_buffer_get_free_list_with_size (vm, n_data_bytes);
515 
516  if (i == ~0)
517  {
518  va_list va;
519  u8 * name;
520 
521  va_start (va, fmt);
522  name = va_format (0, fmt, &va);
523  va_end (va);
524 
525  i = vlib_buffer_create_free_list_helper (vm, n_data_bytes,
526  /* is_public */ 1,
527  /* is_default */ 0,
528  name);
529  }
530 
531  return i;
532 }
533 
534 static void
536 {
537  u32 i;
538 
539  for (i = 0; i < vec_len (f->buffer_memory_allocated); i++)
541  vec_free (f->name);
545 }
546 
547 /* Add buffer free list. */
548 void vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
549 {
550  vlib_buffer_main_t * bm = vm->buffer_main;
552  u32 merge_index;
553 
554  f = vlib_buffer_get_free_list (vm, free_list_index);
555 
557  merge_index = vlib_buffer_get_free_list_with_size (vm, f->n_data_bytes);
558  if (merge_index != ~0 && merge_index != free_list_index)
559  {
561  merge_index), f);
562  }
563 
564  del_free_list (vm, f);
565 
566  /* Poison it. */
567  memset (f, 0xab, sizeof (f[0]));
568 
570 }
571 
572 /* Make sure free list has at least given number of free buffers. */
573 static uword
576  uword min_free_buffers)
577 {
578  vlib_buffer_t * buffers, * b;
579  int n, n_bytes, i;
580  u32 * bi;
581  u32 n_remaining, n_alloc, n_this_chunk;
582 
583  trim_aligned (fl);
584 
585  /* Already have enough free buffers on free list? */
586  n = min_free_buffers - vec_len (fl->aligned_buffers);
587  if (n <= 0)
588  return min_free_buffers;
589 
590  /* Always allocate round number of buffers. */
591  n = round_pow2 (n, BUFFERS_PER_COPY);
592 
593  /* Always allocate new buffers in reasonably large sized chunks. */
595 
596  n_remaining = n;
597  n_alloc = 0;
598  while (n_remaining > 0)
599  {
600  n_this_chunk = clib_min (n_remaining, 16);
601 
602  n_bytes = n_this_chunk * (sizeof (b[0]) + fl->n_data_bytes);
603 
604  /* drb: removed power-of-2 ASSERT */
605  buffers = vm->os_physmem_alloc_aligned (&vm->physmem_main,
606  n_bytes, sizeof (vlib_buffer_t));
607  if (! buffers)
608  return n_alloc;
609 
610  /* Record chunk as being allocated so we can free it later. */
611  vec_add1 (fl->buffer_memory_allocated, buffers);
612 
613  fl->n_alloc += n_this_chunk;
614  n_alloc += n_this_chunk;
615  n_remaining -= n_this_chunk;
616 
617  b = buffers;
618  vec_add2_aligned (fl->aligned_buffers, bi, n_this_chunk,
619  sizeof (vlib_copy_unit_t));
620  for (i = 0; i < n_this_chunk; i++)
621  {
622  bi[i] = vlib_get_buffer_index (vm, b);
623 
624  if (CLIB_DEBUG > 0)
627  }
628 
629  memset (buffers, 0, n_bytes);
630 
631  /* Initialize all new buffers. */
632  b = buffers;
633  for (i = 0; i < n_this_chunk; i++)
634  {
637  }
638 
639  if (fl->buffer_init_function)
640  fl->buffer_init_function (vm, fl, bi, n_this_chunk);
641  }
642  return n_alloc;
643 }
644 
647 { return (pointer_to_uword (x) / sizeof (x[0])) % BUFFERS_PER_COPY; }
648 
649 static u32
651  vlib_buffer_free_list_t * free_list,
652  u32 * alloc_buffers,
653  u32 n_alloc_buffers)
654 {
655  u32 * dst, * u_src;
656  uword u_len, n_left;
657  uword n_unaligned_start, n_unaligned_end, n_filled;
658 
659  ASSERT(os_get_cpu_number() == 0);
660 
661  n_left = n_alloc_buffers;
662  dst = alloc_buffers;
663  n_unaligned_start = ((BUFFERS_PER_COPY - copy_alignment (dst))
664  & (BUFFERS_PER_COPY - 1));
665 
666  n_filled = fill_free_list (vm, free_list, n_alloc_buffers);
667  if (n_filled == 0)
668  return 0;
669 
670  n_left = n_filled < n_left ? n_filled : n_left;
671  n_alloc_buffers = n_left;
672 
673  if (n_unaligned_start >= n_left)
674  {
675  n_unaligned_start = n_left;
676  n_unaligned_end = 0;
677  }
678  else
679  n_unaligned_end = copy_alignment (dst + n_alloc_buffers);
680 
681  fill_unaligned (vm, free_list, n_unaligned_start + n_unaligned_end);
682 
683  u_len = vec_len (free_list->unaligned_buffers);
684  u_src = free_list->unaligned_buffers + u_len - 1;
685 
686  if (n_unaligned_start)
687  {
688  uword n_copy = n_unaligned_start;
689  if (n_copy > n_left)
690  n_copy = n_left;
691  n_left -= n_copy;
692 
693  while (n_copy > 0)
694  {
695  *dst++ = *u_src--;
696  n_copy--;
697  u_len--;
698  }
699 
700  /* Now dst should be aligned. */
701  if (n_left > 0)
702  ASSERT (pointer_to_uword (dst) % sizeof (vlib_copy_unit_t) == 0);
703  }
704 
705  /* Aligned copy. */
706  {
707  vlib_copy_unit_t * d, * s;
708  uword n_copy;
709 
710  if (vec_len(free_list->aligned_buffers) < ((n_left/BUFFERS_PER_COPY)*BUFFERS_PER_COPY))
711  abort();
712 
713  n_copy = n_left / BUFFERS_PER_COPY;
714  n_left = n_left % BUFFERS_PER_COPY;
715 
716  /* Remove buffers from aligned free list. */
717  _vec_len (free_list->aligned_buffers) -= n_copy * BUFFERS_PER_COPY;
718 
719  s = (vlib_copy_unit_t *) vec_end (free_list->aligned_buffers);
720  d = (vlib_copy_unit_t *) dst;
721 
722  /* Fast path loop. */
723  while (n_copy >= 4)
724  {
725  d[0] = s[0];
726  d[1] = s[1];
727  d[2] = s[2];
728  d[3] = s[3];
729  n_copy -= 4;
730  s += 4;
731  d += 4;
732  }
733 
734  while (n_copy >= 1)
735  {
736  d[0] = s[0];
737  n_copy -= 1;
738  s += 1;
739  d += 1;
740  }
741 
742  dst = (void *) d;
743  }
744 
745  /* Unaligned copy. */
746  ASSERT (n_unaligned_end == n_left);
747  while (n_left > 0)
748  {
749  *dst++ = *u_src--;
750  n_left--;
751  u_len--;
752  }
753 
754  if (! free_list->unaligned_buffers)
755  ASSERT (u_len == 0);
756  else
757  _vec_len (free_list->unaligned_buffers) = u_len;
758 
759  /* Verify that buffers are known free. */
760  vlib_buffer_validate_alloc_free (vm, alloc_buffers,
761  n_alloc_buffers,
763 
764  return n_alloc_buffers;
765 }
766 
767 /* Allocate a given number of buffers into given array.
768  Returns number actually allocated which will be either zero or
769  number requested. */
770 u32 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
771 {
772  vlib_buffer_main_t * bm = vm->buffer_main;
773  ASSERT(os_get_cpu_number() == 0);
774 
775  return alloc_from_free_list
776  (vm,
779  buffers, n_buffers);
780 }
781 
783  u32 * buffers,
784  u32 n_buffers,
785  u32 free_list_index)
786 {
787  vlib_buffer_main_t * bm = vm->buffer_main;
789  f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
790  return alloc_from_free_list (vm, f, buffers, n_buffers);
791 }
792 
793 always_inline void
796  u32 buffer_index, u8 do_init)
797 {
798  vlib_buffer_t * b;
799  b = vlib_get_buffer (vm, buffer_index);
800  if (PREDICT_TRUE(do_init))
802  vec_add1_aligned (f->aligned_buffers, buffer_index, sizeof (vlib_copy_unit_t));
803 }
804 
807 {
808  vlib_buffer_main_t * bm = vm->buffer_main;
809  u32 i;
810 
811  *index = i = b->free_list_index;
813 }
814 
816 {
817  vlib_buffer_main_t * bm = vm->buffer_main;
818  void * rv = bm->buffer_free_callback;
819 
820  bm->buffer_free_callback = fp;
821  return rv;
822 }
823 
824 void vnet_buffer_free_dpdk_mb (vlib_buffer_t * b) __attribute__ ((weak));
826 
829  u32 * buffers,
830  u32 n_buffers,
831  u32 follow_buffer_next)
832 {
833  vlib_buffer_main_t * bm = vm->buffer_main;
835  static u32 * next_to_free[2]; /* smp bad */
836  u32 i_next_to_free, * b, * n, * f, fi;
837  uword n_left;
838  int i;
839  static vlib_buffer_free_list_t ** announce_list;
840  vlib_buffer_free_list_t * fl0 = 0, * fl1 = 0;
841  u32 bi0=(u32)~0, bi1=(u32)~0, fi0, fi1 = (u32)~0;
842  u8 free0, free1=0, free_next0, free_next1;
843  u32 (*cb)(vlib_main_t * vm, u32 * buffers, u32 n_buffers,
844  u32 follow_buffer_next);
845 
846  ASSERT(os_get_cpu_number() == 0);
847 
848  cb = bm->buffer_free_callback;
849 
850  if (PREDICT_FALSE (cb != 0))
851  n_buffers = (*cb)(vm, buffers, n_buffers, follow_buffer_next);
852 
853  if (! n_buffers)
854  return;
855 
856  /* Use first buffer to get default free list. */
857  {
858  u32 bi0 = buffers[0];
859  vlib_buffer_t * b0;
860 
861  b0 = vlib_get_buffer (vm, bi0);
862  fl = buffer_get_free_list (vm, b0, &fi);
864  vec_add1 (announce_list, fl);
865  }
866 
867  vec_validate (next_to_free[0], n_buffers - 1);
868  vec_validate (next_to_free[1], n_buffers - 1);
869 
870  i_next_to_free = 0;
871  n_left = n_buffers;
872  b = buffers;
873 
874  again:
875  /* Verify that buffers are known allocated. */
877  n_left,
879 
880  vec_add2_aligned (fl->aligned_buffers, f, n_left,
881  /* align */ sizeof (vlib_copy_unit_t));
882 
883  n = next_to_free[i_next_to_free];
884  while (n_left >= 4)
885  {
886  vlib_buffer_t * b0, * b1, * binit0, * binit1, dummy_buffers[2];
887 
888  bi0 = b[0];
889  bi1 = b[1];
890 
891  f[0] = bi0;
892  f[1] = bi1;
893  f += 2;
894  b += 2;
895  n_left -= 2;
896 
897  /* Prefetch buffers for next iteration. */
898  vlib_prefetch_buffer_with_index (vm, b[0], WRITE);
899  vlib_prefetch_buffer_with_index (vm, b[1], WRITE);
900 
901  b0 = vlib_get_buffer (vm, bi0);
902  b1 = vlib_get_buffer (vm, bi1);
903 
904  free0 = b0->clone_count == 0;
905  free1 = b1->clone_count == 0;
906 
907  /* Must be before init which will over-write buffer flags. */
908  if (follow_buffer_next)
909  {
910  n[0] = b0->next_buffer;
911  free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
912  n += free_next0;
913 
914  n[0] = b1->next_buffer;
915  free_next1 = free1 && (b1->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
916  n += free_next1;
917  }
918  else
919  free_next0 = free_next1 = 0;
920 
921  /* Must be before init which will over-write buffer free list. */
922  fi0 = b0->free_list_index;
923  fi1 = b1->free_list_index;
924 
925  if (PREDICT_FALSE (fi0 != fi || fi1 != fi))
926  goto slow_path_x2;
927 
928  binit0 = free0 ? b0 : &dummy_buffers[0];
929  binit1 = free1 ? b1 : &dummy_buffers[1];
930 
931  vlib_buffer_init_two_for_free_list (binit0, binit1, fl);
932  continue;
933 
934  slow_path_x2:
935  /* Backup speculation. */
936  f -= 2;
937  n -= free_next0 + free_next1;
938 
939  _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
940 
941  fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
942  fl1 = pool_elt_at_index (bm->buffer_free_list_pool, fi1);
943 
944  add_buffer_to_free_list (vm, fl0, bi0, free0);
946  {
947  int i;
948  for (i = 0; i < vec_len (announce_list); i++)
949  if (fl0 == announce_list[i])
950  goto no_fl0;
951  vec_add1(announce_list, fl0);
952  }
953  no_fl0:
954  if (PREDICT_FALSE(fl1->buffers_added_to_freelist_function != 0))
955  {
956  int i;
957  for (i = 0; i < vec_len (announce_list); i++)
958  if (fl1 == announce_list[i])
959  goto no_fl1;
960  vec_add1(announce_list, fl1);
961  }
962 
963  no_fl1:
964  add_buffer_to_free_list (vm, fl1, bi1, free1);
965 
966  /* Possibly change current free list. */
967  if (fi0 != fi && fi1 != fi)
968  {
969  fi = fi1;
971  }
972 
973  vec_add2_aligned (fl->aligned_buffers, f, n_left,
974  /* align */ sizeof (vlib_copy_unit_t));
975  }
976 
977  while (n_left >= 1)
978  {
979  vlib_buffer_t * b0, * binit0, dummy_buffers[1];
980 
981  bi0 = b[0];
982  f[0] = bi0;
983  f += 1;
984  b += 1;
985  n_left -= 1;
986 
987  b0 = vlib_get_buffer (vm, bi0);
988 
989  free0 = b0->clone_count == 0;
990 
991  /* Must be before init which will over-write buffer flags. */
992  if (follow_buffer_next)
993  {
994  n[0] = b0->next_buffer;
995  free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
996  n += free_next0;
997  }
998  else
999  free_next0 = 0;
1000 
1001  /* Must be before init which will over-write buffer free list. */
1002  fi0 = b0->free_list_index;
1003 
1004  if (PREDICT_FALSE (fi0 != fi))
1005  goto slow_path_x1;
1006 
1007  binit0 = free0 ? b0 : &dummy_buffers[0];
1008 
1009  vlib_buffer_init_for_free_list (binit0, fl);
1010  continue;
1011 
1012  slow_path_x1:
1013  /* Backup speculation. */
1014  f -= 1;
1015  n -= free_next0;
1016 
1017  _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
1018 
1019  fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
1020 
1021  add_buffer_to_free_list (vm, fl0, bi0, free0);
1023  {
1024  int i;
1025  for (i = 0; i < vec_len (announce_list); i++)
1026  if (fl0 == announce_list[i])
1027  goto no_fl00;
1028  vec_add1(announce_list, fl0);
1029  }
1030 
1031  no_fl00:
1032  fi = fi0;
1034 
1035  vec_add2_aligned (fl->aligned_buffers, f, n_left,
1036  /* align */ sizeof (vlib_copy_unit_t));
1037  }
1038 
1039  if (follow_buffer_next && ((n_left = n - next_to_free[i_next_to_free]) > 0))
1040  {
1041  b = next_to_free[i_next_to_free];
1042  i_next_to_free ^= 1;
1043  goto again;
1044  }
1045 
1046  _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
1047 
1048  if (vec_len(announce_list))
1049  {
1051  for (i = 0; i < vec_len (announce_list); i++)
1052  {
1053  fl = announce_list[i];
1055  }
1056  _vec_len(announce_list) = 0;
1057  }
1058 }
1059 
1061  u32 * buffers,
1062  u32 n_buffers)
1063 {
1064  vlib_buffer_free_inline (vm, buffers, n_buffers, /* follow_buffer_next */ 1);
1065 }
1066 
1068  u32 * buffers,
1069  u32 n_buffers)
1070 {
1071  vlib_buffer_free_inline (vm, buffers, n_buffers, /* follow_buffer_next */ 0);
1072 }
1073 
1074 /* Copy template packet data into buffers as they are allocated. */
1075 static void
1078  u32 * buffers,
1079  u32 n_buffers)
1080 {
1083  uword i;
1084 
1085  for (i = 0; i < n_buffers; i++)
1086  {
1087  vlib_buffer_t * b = vlib_get_buffer (vm, buffers[i]);
1090  }
1091 }
1092 
1095  void * packet_data,
1096  uword n_packet_data_bytes,
1097  uword min_n_buffers_each_physmem_alloc,
1098  char * fmt,
1099  ...)
1100 {
1102  va_list va;
1103  u8 * name;
1104 
1105  va_start (va, fmt);
1106  name = va_format (0, fmt, &va);
1107  va_end (va);
1108 
1109  memset (t, 0, sizeof (t[0]));
1110 
1111  vec_add (t->packet_data, packet_data, n_packet_data_bytes);
1112  t->min_n_buffers_each_physmem_alloc = min_n_buffers_each_physmem_alloc;
1113 
1115  (vm, n_packet_data_bytes,
1116  /* is_public */ 1,
1117  /* is_default */ 0,
1118  name);
1119 
1120  ASSERT (t->free_list_index != 0);
1123 
1126 
1128  fl->buffer_init_template.current_length = n_packet_data_bytes;
1129  fl->buffer_init_template.flags = 0;
1130 }
1131 
1132 void *
1135  u32 * bi_result)
1136 {
1137  u32 bi;
1138  vlib_buffer_t * b;
1139 
1140  if (vlib_buffer_alloc (vm, &bi, 1) != 1)
1141  return 0;
1142 
1143  *bi_result = bi;
1144 
1145  b = vlib_get_buffer (vm, bi);
1147  t->packet_data, vec_len(t->packet_data));
1149 
1150  return b->data;
1151 }
1152 
1154 {
1156  word l = vec_len (t->packet_data);
1157  word n_alloc;
1158 
1159  ASSERT (l > 0);
1160  ASSERT (vec_len (t->free_buffers) == 0);
1161 
1162  vec_validate (t->free_buffers, n - 1);
1164  n, t->free_list_index);
1165  _vec_len (t->free_buffers) = n_alloc;
1166 }
1167 
1168 /* Append given data to end of buffer, possibly allocating new buffers. */
1170  u32 free_list_index,
1171  u32 buffer_index,
1172  void * data, u32 n_data_bytes)
1173 {
1174  u32 n_buffer_bytes, n_left, n_left_this_buffer, bi;
1175  vlib_buffer_t * b;
1176  void * d;
1177 
1178  bi = buffer_index;
1179  if (bi == 0
1180  && 1 != vlib_buffer_alloc_from_free_list (vm, &bi, 1, free_list_index))
1181  goto out_of_buffers;
1182 
1183  d = data;
1184  n_left = n_data_bytes;
1185  n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
1186 
1187  b = vlib_get_buffer (vm, bi);
1189 
1190  /* Get to the end of the chain before we try to append data...*/
1191  while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1192  b = vlib_get_buffer (vm, b->next_buffer);
1193 
1194  while (1)
1195  {
1196  u32 n;
1197 
1198  ASSERT (n_buffer_bytes >= b->current_length);
1199  n_left_this_buffer = n_buffer_bytes - (b->current_data + b->current_length);
1200  n = clib_min (n_left_this_buffer, n_left);
1202  b->current_length += n;
1203  n_left -= n;
1204  if (n_left == 0)
1205  break;
1206 
1207  d += n;
1208  if (1 != vlib_buffer_alloc_from_free_list (vm, &b->next_buffer, 1, free_list_index))
1209  goto out_of_buffers;
1210 
1212 
1213  b = vlib_get_buffer (vm, b->next_buffer);
1214  }
1215 
1216  return bi;
1217 
1218  out_of_buffers:
1219  clib_error ("out of buffers");
1220  return bi;
1221 }
1222 
1223 u16
1225  u32 free_list_index,
1227  vlib_buffer_t **last,
1228  void * data, u16 data_len) {
1229  vlib_buffer_t *l = *last;
1230  u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
1231  u16 copied = 0;
1232  ASSERT(n_buffer_bytes >= l->current_length + l->current_data);
1233  while (data_len) {
1234  u16 max = n_buffer_bytes - l->current_length - l->current_data;
1235  if (max == 0) {
1236  if (1 != vlib_buffer_alloc_from_free_list (vm, &l->next_buffer, 1, free_list_index))
1237  return copied;
1238  *last = l = vlib_buffer_chain_buffer(vm, first, l, l->next_buffer);
1239  max = n_buffer_bytes - l->current_length - l->current_data;
1240  }
1241 
1242  u16 len = (data_len > max)?max:data_len;
1243  clib_memcpy(vlib_buffer_get_current (l) + l->current_length, data + copied, len);
1244  vlib_buffer_chain_increase_length(first, l, len);
1245  data_len -= len;
1246  copied += len;
1247  }
1248  return copied;
1249 }
1250 
1251 /*
1252  * Fills in the required rte_mbuf fields for chained buffers given a VLIB chain.
1253  */
1255 {
1256  return;
1257 }
1258 
1260 {
1261  vlib_main_t * vm;
1263  uword n, n_bytes_to_write;
1264  vlib_buffer_t * last;
1265 
1266  n_bytes_to_write = s->current_buffer_index;
1268  vm = sm->vlib_main;
1269 
1270  ASSERT (sm->tx.max_n_data_bytes_per_chain > 0);
1272  || sm->tx.n_total_data_bytes + n_bytes_to_write > sm->tx.max_n_data_bytes_per_chain)
1273  {
1275 
1276  last = vlib_get_buffer (vm, sm->last_buffer);
1277  last->current_length = n_bytes_to_write;
1278 
1279  vlib_set_next_frame_buffer (vm, &p->node_runtime, sm->tx.next_index, sm->first_buffer);
1280 
1281  sm->first_buffer = sm->last_buffer = ~0;
1282  sm->tx.n_total_data_bytes = 0;
1283  }
1284 
1285  else if (n_bytes_to_write == 0 && s->n_buffer_bytes == 0)
1286  {
1287  ASSERT (sm->first_buffer == ~0);
1288  ASSERT (sm->last_buffer == ~0);
1289  n = vlib_buffer_alloc_from_free_list (vm, &sm->first_buffer, 1, sm->tx.free_list_index);
1290  if (n != 1)
1291  serialize_error (m, clib_error_create ("vlib_buffer_alloc_from_free_list fails"));
1292  sm->last_buffer = sm->first_buffer;
1293  s->n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, sm->tx.free_list_index);
1294  }
1295 
1296  if (n_bytes_to_write > 0)
1297  {
1298  vlib_buffer_t * prev = vlib_get_buffer (vm, sm->last_buffer);
1299  n = vlib_buffer_alloc_from_free_list (vm, &sm->last_buffer, 1, sm->tx.free_list_index);
1300  if (n != 1)
1301  serialize_error (m, clib_error_create ("vlib_buffer_alloc_from_free_list fails"));
1302  sm->tx.n_total_data_bytes += n_bytes_to_write;
1303  prev->current_length = n_bytes_to_write;
1304  prev->next_buffer = sm->last_buffer;
1306  }
1307 
1308  if (sm->last_buffer != ~0)
1309  {
1310  last = vlib_get_buffer (vm, sm->last_buffer);
1311  s->buffer = vlib_buffer_get_current (last);
1312  s->current_buffer_index = 0;
1314  }
1315 }
1316 
1318 {
1319  vlib_main_t * vm;
1321  vlib_buffer_t * last;
1322 
1324  vm = sm->vlib_main;
1325 
1327  return;
1328 
1329  if (sm->last_buffer != ~0)
1330  {
1331  last = vlib_get_buffer (vm, sm->last_buffer);
1332 
1333  if (last->flags & VLIB_BUFFER_NEXT_PRESENT)
1334  sm->last_buffer = last->next_buffer;
1335  else
1336  {
1337  vlib_buffer_free (vm, &sm->first_buffer, /* count */ 1);
1338  sm->first_buffer = sm->last_buffer = ~0;
1339  }
1340  }
1341 
1342  if (sm->last_buffer == ~0)
1343  {
1344  while (clib_fifo_elts (sm->rx.buffer_fifo) == 0)
1345  {
1346  sm->rx.ready_one_time_event = vlib_process_create_one_time_event (vm, vlib_current_process (vm), ~0);
1347  vlib_process_wait_for_one_time_event (vm, /* no event data */ 0, sm->rx.ready_one_time_event);
1348  }
1349 
1350  clib_fifo_sub1 (sm->rx.buffer_fifo, sm->first_buffer);
1351  sm->last_buffer = sm->first_buffer;
1352  }
1353 
1354  ASSERT (sm->last_buffer != ~0);
1355 
1356  last = vlib_get_buffer (vm, sm->last_buffer);
1357  s->current_buffer_index = 0;
1358  s->buffer = vlib_buffer_get_current (last);
1359  s->n_buffer_bytes = last->current_length;
1360 }
1361 
1362 static void
1364  vlib_main_t * vm,
1366  uword is_read)
1367 {
1368  /* Initialize serialize main but save overflow buffer for re-use between calls. */
1369  {
1370  u8 * save = m->stream.overflow_buffer;
1371  memset (m, 0, sizeof (m[0]));
1372  m->stream.overflow_buffer = save;
1373  if (save)
1374  _vec_len (save) = 0;
1375  }
1376 
1377  sm->first_buffer = sm->last_buffer = ~0;
1378  if (is_read)
1379  clib_fifo_reset (sm->rx.buffer_fifo);
1380  else
1381  sm->tx.n_total_data_bytes = 0;
1382  sm->vlib_main = vm;
1385 }
1386 
1388 { serialize_open_vlib_helper (m, vm, sm, /* is_read */ 0); }
1389 
1391 { serialize_open_vlib_helper (m, vm, sm, /* is_read */ 1); }
1392 
1394 {
1397  vlib_buffer_t * last;
1398  serialize_stream_t * s = &m->stream;
1399 
1400  last = vlib_get_buffer (sm->vlib_main, sm->last_buffer);
1402 
1403  if (vec_len (s->overflow_buffer) > 0)
1404  {
1405  sm->last_buffer
1406  = vlib_buffer_add_data (sm->vlib_main, sm->tx.free_list_index,
1407  sm->last_buffer == ~0 ? 0 : sm->last_buffer,
1408  s->overflow_buffer,
1409  vec_len (s->overflow_buffer));
1410  _vec_len (s->overflow_buffer) = 0;
1411  }
1412 
1413  return sm->first_buffer;
1414 }
1415 
1417 {
1420  if (sm->first_buffer != ~0)
1422  clib_fifo_reset (sm->rx.buffer_fifo);
1423  if (m->stream.overflow_buffer)
1424  _vec_len (m->stream.overflow_buffer) = 0;
1425 }
1426 
1427 static u8 * format_vlib_buffer_free_list (u8 * s, va_list * va)
1428 {
1429  vlib_buffer_free_list_t * f = va_arg (*va, vlib_buffer_free_list_t *);
1430  uword bytes_alloc, bytes_free, n_free, size;
1431 
1432  if (! f)
1433  return format (s, "%=30s%=12s%=12s%=12s%=12s%=12s%=12s",
1434  "Name", "Index", "Size", "Alloc", "Free", "#Alloc", "#Free");
1435 
1436  size = sizeof (vlib_buffer_t) + f->n_data_bytes;
1437  n_free = vec_len (f->aligned_buffers) + vec_len (f->unaligned_buffers);
1438  bytes_alloc = size * f->n_alloc;
1439  bytes_free = size * n_free;
1440 
1441  s = format (s, "%30s%12d%12d%=12U%=12U%=12d%=12d",
1442  f->name, f->index, f->n_data_bytes,
1443  format_memory_size, bytes_alloc,
1444  format_memory_size, bytes_free,
1445  f->n_alloc, n_free);
1446 
1447  return s;
1448 }
1449 
1450 static clib_error_t *
1452  unformat_input_t * input,
1453  vlib_cli_command_t * cmd)
1454 {
1455  vlib_buffer_main_t * bm = vm->buffer_main;
1457 
1460  vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, f);
1461  }));
1462 
1463  return 0;
1464 }
1465 
1466 VLIB_CLI_COMMAND (show_buffers_command, static) = {
1467  .path = "show buffers",
1468  .short_help = "Show packet buffer allocation",
1469  .function = show_buffers,
1470 };
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
always_inline uword round_pow2(uword x, uword pow2)
Definition: clib.h:255
#define hash_set(h, key, value)
Definition: hash.h:237
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
always_inline void add_buffer_to_free_list(vlib_main_t *vm, vlib_buffer_free_list_t *f, u32 buffer_index, u8 do_init)
Definition: buffer.c:794
#define clib_min(x, y)
Definition: clib.h:295
always_inline uword vlib_process_create_one_time_event(vlib_main_t *vm, uword node_index, uword with_type_opaque)
Definition: node_funcs.h:593
static 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:249
static void del_free_list(vlib_main_t *vm, vlib_buffer_free_list_t *f)
Definition: buffer.c:535
vlib_node_runtime_t node_runtime
Definition: node.h:450
void * vlib_packet_template_get_packet(vlib_main_t *vm, vlib_packet_template_t *t, u32 *bi_result)
Definition: buffer.c:1133
u8 * vlib_validate_buffer(vlib_main_t *vm, u32 bi, uword follow_buffer_next)
Definition: buffer.c:189
void unserialize_close_vlib_buffer(serialize_main_t *m)
Definition: buffer.c:1416
always_inline u32 vlib_buffer_get_free_list_with_size(vlib_main_t *vm, u32 size)
Definition: buffer.c:438
u32 free_list_index
Buffer free list that this buffer was allocated from and will be freed to.
Definition: buffer.h:102
#define PREDICT_TRUE(x)
Definition: clib.h:98
vlib_physmem_main_t physmem_main
Definition: main.h:105
serialize_main_header_t header
Definition: serialize.h:137
u8 * format_vlib_buffer(u8 *s, va_list *args)
Definition: buffer.c:57
#define vec_add2_aligned(V, P, N, A)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:531
vlib_buffer_t buffer_init_template
Definition: buffer.h:241
struct vlib_main_t * vlib_main
Definition: buffer.h:319
static uword fill_free_list(vlib_main_t *vm, vlib_buffer_free_list_t *fl, uword min_free_buffers)
Definition: buffer.c:574
#define clib_error(format, args...)
Definition: error.h:62
void vlib_packet_template_get_packet_helper(vlib_main_t *vm, vlib_packet_template_t *t)
Definition: buffer.c:1153
void *(* os_physmem_alloc_aligned)(vlib_physmem_main_t *pm, uword n_bytes, uword alignment)
Definition: main.h:109
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
void ** buffer_memory_allocated
Definition: buffer.h:265
vlib_buffer_main_t * buffer_main
Definition: main.h:103
always_inline 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:435
u32 min_n_buffers_each_physmem_alloc
Definition: buffer.h:251
always_inline uword copy_alignment(u32 *x)
Definition: buffer.c:646
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
always_inline u32 vlib_buffer_free_list_buffer_size(vlib_main_t *vm, u32 free_list_index)
Definition: buffer_funcs.h:346
uword vlib_buffer_length_in_chain_slow_path(vlib_main_t *vm, vlib_buffer_t *b_first)
Definition: buffer.c:42
struct vlib_serialize_buffer_main_t::@27::@30 rx
always_inline void vlib_buffer_init_two_for_free_list(vlib_buffer_t *_dst0, vlib_buffer_t *_dst1, vlib_buffer_free_list_t *fl)
Definition: buffer_funcs.h:623
void vnet_buffer_free_dpdk_mb(vlib_buffer_t *b)
Definition: buffer.c:825
#define vec_add(V, E, N)
Add N elements to end of vector V (no header, unspecified alignment)
Definition: vec.h:557
#define vec_add1_aligned(V, E, A)
Add 1 element to end of vector (alignment specified).
Definition: vec.h:490
void(* buffers_added_to_freelist_function)(struct vlib_main_t *vm, struct vlib_buffer_free_list_t *fl)
Definition: buffer.h:279
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:77
#define static_always_inline
Definition: clib.h:85
#define pool_foreach(VAR, POOL, BODY)
Definition: pool.h:328
#define vlib_prefetch_buffer_with_index(vm, bi, type)
Prefetch buffer metadata by buffer index The first 64 bytes of buffer contains most header informatio...
Definition: buffer_funcs.h:181
always_inline heap_elt_t * last(heap_header_t *h)
Definition: heap.c:51
#define always_inline
Definition: clib.h:84
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.c:1067
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:79
static clib_error_t * show_buffers(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: buffer.c:1451
always_inline uword pool_elts(void *v)
Definition: pool.h:97
#define BUFFERS_PER_COPY
Definition: buffer.c:353
always_inline uword clib_fifo_elts(void *v)
Definition: fifo.h:63
static u32 alloc_from_free_list(vlib_main_t *vm, vlib_buffer_free_list_t *free_list, u32 *alloc_buffers, u32 n_alloc_buffers)
Definition: buffer.c:650
always_inline vlib_buffer_free_list_t * vlib_buffer_get_free_list(vlib_main_t *vm, u32 free_list_index)
Definition: buffer_funcs.h:332
#define vec_end(v)
End (last data address) of vector.
static uword pointer_to_uword(const void *p)
Definition: types.h:131
u32 serialize_close_vlib_buffer(serialize_main_t *m)
Definition: buffer.c:1393
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:93
always_inline void serialize_error(serialize_main_header_t *m, clib_error_t *error)
Definition: serialize.h:100
always_inline heap_elt_t * first(heap_header_t *h)
Definition: heap.c:54
static void serialize_open_vlib_helper(serialize_main_t *m, vlib_main_t *vm, vlib_serialize_buffer_main_t *sm, uword is_read)
Definition: buffer.c:1363
static u8 * format_vlib_buffer_known_state(u8 *s, va_list *args)
Definition: buffer.c:85
always_inline vlib_buffer_known_state_t vlib_buffer_is_known(vlib_main_t *vm, u32 buffer_index)
Definition: buffer_funcs.h:221
#define VLIB_BUFFER_PRE_DATA_SIZE
Definition: buffer.h:56
always_inline 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:319
#define hash_get(h, key)
Definition: hash.h:231
static void vlib_packet_template_buffer_init(vlib_main_t *vm, vlib_buffer_free_list_t *fl, u32 *buffers, u32 n_buffers)
Definition: buffer.c:1076
always_inline uword serialize_stream_is_end_of_stream(serialize_stream_t *s)
Definition: serialize.h:83
#define pool_elt_at_index(p, i)
Definition: pool.h:346
always_inline void vlib_buffer_chain_increase_length(vlib_buffer_t *first, vlib_buffer_t *last, i32 len)
Definition: buffer_funcs.h:466
always_inline void clib_fifo_reset(void *v)
Definition: fifo.h:83
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.c:1060
#define clib_fifo_sub1(f, e)
Definition: fifo.h:219
#define VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES
Definition: buffer.h:297
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
uword os_get_cpu_number(void)
Definition: unix-misc.c:206
#define hash_free(h)
Definition: hash.h:269
#define pool_put(P, E)
Definition: pool.h:200
always_inline uword vlib_process_wait_for_one_time_event(vlib_main_t *vm, uword **data_vector, uword with_type_index)
Definition: node_funcs.h:503
u32 vlib_buffer_alloc_from_free_list(vlib_main_t *vm, u32 *buffers, u32 n_buffers, u32 free_list_index)
Allocate buffers from specific freelist into supplied array.
Definition: buffer.c:782
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define clib_error_create(args...)
Definition: error.h:109
u32 vlib_buffer_add_data(vlib_main_t *vm, u32 free_list_index, u32 buffer_index, void *data, u32 n_data_bytes)
Definition: buffer.c:1169
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:538
u32 vlib_buffer_create_free_list(vlib_main_t *vm, u32 n_data_bytes, char *fmt,...)
Definition: buffer.c:495
#define uword_to_pointer(u, type)
Definition: types.h:134
#define pool_get_aligned(P, E, A)
Definition: pool.h:155
#define vec_add_aligned(V, E, N, A)
Add N elements to end of vector V (no header, specified alignment)
Definition: vec.h:567
u16 vlib_buffer_chain_append_data_with_alloc(vlib_main_t *vm, u32 free_list_index, vlib_buffer_t *first, vlib_buffer_t **last, void *data, u16 data_len)
Definition: buffer.c:1224
serialize_stream_t stream
Definition: serialize.h:138
u32 current_buffer_index
Definition: serialize.h:61
u32(* buffer_free_callback)(struct vlib_main_t *vm, u32 *buffers, u32 n_buffers, u32 follow_buffer_next)
Definition: buffer.h:287
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
u8 * va_format(u8 *s, char *fmt, va_list *va)
Definition: format.c:374
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
#define clib_memcpy(a, b, c)
Definition: string.h:63
serialize_data_function_t * data_function
Definition: serialize.h:90
#define VLIB_BUFFER_TOTAL_LENGTH_VALID
Definition: buffer.h:95
#define pool_is_free_index(P, I)
Definition: pool.h:197
vlib_buffer_known_state_t
Definition: buffer_funcs.h:211
uword data_function_opaque
Definition: serialize.h:73
static u8 * vlib_validate_buffer_helper(vlib_main_t *vm, u32 bi, uword follow_buffer_next, uword **unique_hash)
Definition: buffer.c:130
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:150
u8 * format_memory_size(u8 *s, va_list *va)
Definition: std-formats.c:185
#define hash_set1(h, key)
Definition: hash.h:240
#define VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX
Definition: buffer.h:296
#define hash_create(elts, value_bytes)
Definition: hash.h:615
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_physmem_alloc, char *fmt,...)
Definition: buffer.c:1093
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u32 vlib_buffer_get_or_create_free_list(vlib_main_t *vm, u32 n_data_bytes, char *fmt,...)
Definition: buffer.c:511
static_always_inline void vlib_buffer_free_inline(vlib_main_t *vm, u32 *buffers, u32 n_buffers, u32 follow_buffer_next)
Definition: buffer.c:828
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
static u32 vlib_buffer_create_free_list_helper(vlib_main_t *vm, u32 n_data_bytes, u32 is_public, u32 is_default, u8 *name)
Definition: buffer.c:449
vhost_vring_state_t state
Definition: vhost-user.h:77
static u8 * format_vlib_buffer_free_list(u8 *s, va_list *va)
Definition: buffer.c:1427
u32 size
Definition: vhost-user.h:74
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:112
void vlib_aligned_memcpy(void *_dst, void *_src, int n_bytes)
Definition: buffer.c:293
u64 vlib_copy_unit_t
Definition: buffer.h:62
u32 clone_count
Specifies whether this buffer should be reinitialized when freed.
Definition: buffer.h:121
static void trim_aligned(vlib_buffer_free_list_t *f)
Definition: buffer.c:383
u32 vlib_buffer_alloc(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Allocate buffers into supplied array.
Definition: buffer.c:770
always_inline vlib_buffer_free_list_t * buffer_get_free_list(vlib_main_t *vm, vlib_buffer_t *b, u32 *index)
Definition: buffer.c:806
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:91
#define clib_max(x, y)
Definition: clib.h:288
always_inline void vlib_buffer_init_for_free_list(vlib_buffer_t *_dst, vlib_buffer_free_list_t *fl)
Definition: buffer_funcs.h:591
u64 uword
Definition: types.h:112
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:106
u8 * vlib_validate_buffers(vlib_main_t *vm, u32 *buffers, uword next_buffer_stride, uword n_buffers, vlib_buffer_known_state_t known_state, uword follow_buffer_next)
Definition: buffer.c:193
unsigned short u16
Definition: types.h:57
i64 word
Definition: types.h:111
always_inline uword clib_mem_is_heap_object(void *p)
Definition: mem.h:133
always_inline void vlib_buffer_set_known_state(vlib_main_t *vm, u32 buffer_index, vlib_buffer_known_state_t state)
Definition: buffer_funcs.h:231
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
void(* buffer_init_function)(struct vlib_main_t *vm, struct vlib_buffer_free_list_t *fl, u32 *buffers, u32 n_buffers)
Definition: buffer.h:272
vlib_buffer_free_list_t * buffer_free_list_pool
Definition: buffer.h:295
static void vlib_serialize_tx(serialize_main_header_t *m, serialize_stream_t *s)
Definition: buffer.c:1259
always_inline void vlib_set_next_frame_buffer(vlib_main_t *vm, vlib_node_runtime_t *node, u32 next_index, u32 buffer_index)
Definition: node_funcs.h:292
u8 * format_vlib_buffer_and_data(u8 *s, va_list *args)
Definition: buffer.c:74
always_inline uword vlib_current_process(vlib_main_t *vm)
Definition: node_funcs.h:317
u8 data[0]
Packet data.
Definition: buffer.h:150
always_inline vlib_process_t * vlib_get_current_process(vlib_main_t *vm)
Definition: node_funcs.h:306
always_inline vlib_buffer_t * vlib_buffer_next_contiguous(vlib_buffer_t *b, u32 buffer_bytes)
Definition: buffer.h:165
always_inline u32 vlib_buffer_round_size(u32 size)
Definition: buffer_funcs.h:269
u8 * format_vlib_buffer_contents(u8 *s, va_list *va)
Definition: buffer.c:112
uword buffer_init_function_opaque
Definition: buffer.h:282
void vlib_buffer_chain_validate(vlib_main_t *vm, vlib_buffer_t *b_first)
Definition: buffer.c:1254
struct _unformat_input_t unformat_input_t
static void merge_free_lists(vlib_buffer_free_list_t *dst, vlib_buffer_free_list_t *src)
Definition: buffer.c:411
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
void(* os_physmem_free)(void *x)
Definition: main.h:112
static void fill_unaligned(vlib_main_t *vm, vlib_buffer_free_list_t *free_list, uword n_unaligned_buffers)
Definition: buffer.c:357
void unserialize_open_vlib_buffer(serialize_main_t *m, vlib_main_t *vm, vlib_serialize_buffer_main_t *sm)
Definition: buffer.c:1390
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
void serialize_open_vlib_buffer(serialize_main_t *m, vlib_main_t *vm, vlib_serialize_buffer_main_t *sm)
Definition: buffer.c:1387
always_inline u32 vlib_get_buffer_index(vlib_main_t *vm, void *p)
Translate buffer pointer into buffer index.
Definition: buffer_funcs.h:82
u32 trace_index
Specifies index into trace buffer if VLIB_PACKET_IS_TRACED flag is set.
Definition: buffer.h:116
uword * free_list_by_size
Definition: buffer.h:301
vlib_main_t ** vlib_mains
Definition: buffer.c:244
#define vlib_panic_with_msg(vm, args...)
Definition: main.h:229
void * vlib_set_buffer_free_callback(vlib_main_t *vm, void *fp)
Definition: buffer.c:815
void vlib_buffer_delete_free_list(vlib_main_t *vm, u32 free_list_index)
Definition: buffer.c:548
struct vlib_serialize_buffer_main_t::@27::@29 tx
static void vlib_serialize_rx(serialize_main_header_t *m, serialize_stream_t *s)
Definition: buffer.c:1317