vlib: remove algned/unaligned buffers scheme
[vpp.git] / src / vlib / buffer.c
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 /**
41  * @file
42  *
43  * Allocate/free network buffers.
44  */
45
46 #include <vlib/vlib.h>
47
48 uword
49 vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
50                                        vlib_buffer_t * b_first)
51 {
52   vlib_buffer_t *b = b_first;
53   uword l_first = b_first->current_length;
54   uword l = 0;
55   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
56     {
57       b = vlib_get_buffer (vm, b->next_buffer);
58       l += b->current_length;
59     }
60   b_first->total_length_not_including_first_buffer = l;
61   b_first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
62   return l + l_first;
63 }
64
65 u8 *
66 format_vlib_buffer (u8 * s, va_list * args)
67 {
68   vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
69   uword indent = format_get_indent (s);
70
71   s = format (s, "current data %d, length %d, free-list %d",
72               b->current_data, b->current_length, b->free_list_index);
73
74   if (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
75     s = format (s, ", totlen-nifb %d",
76                 b->total_length_not_including_first_buffer);
77
78   if (b->flags & VLIB_BUFFER_IS_TRACED)
79     s = format (s, ", trace 0x%x", b->trace_index);
80
81   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
82     {
83       vlib_main_t *vm = vlib_get_main ();
84       u32 next_buffer = b->next_buffer;
85       b = vlib_get_buffer (vm, next_buffer);
86
87       s = format (s, "\n%Unext-buffer 0x%x, segment length %d",
88                   format_white_space, indent, next_buffer, b->current_length);
89     }
90
91   return s;
92 }
93
94 u8 *
95 format_vlib_buffer_and_data (u8 * s, va_list * args)
96 {
97   vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
98
99   s = format (s, "%U, %U",
100               format_vlib_buffer, b,
101               format_hex_bytes, vlib_buffer_get_current (b), 64);
102
103   return s;
104 }
105
106 static u8 *
107 format_vlib_buffer_known_state (u8 * s, va_list * args)
108 {
109   vlib_buffer_known_state_t state = va_arg (*args, vlib_buffer_known_state_t);
110   char *t;
111
112   switch (state)
113     {
114     case VLIB_BUFFER_UNKNOWN:
115       t = "unknown";
116       break;
117
118     case VLIB_BUFFER_KNOWN_ALLOCATED:
119       t = "known-allocated";
120       break;
121
122     case VLIB_BUFFER_KNOWN_FREE:
123       t = "known-free";
124       break;
125
126     default:
127       t = "invalid";
128       break;
129     }
130
131   return format (s, "%s", t);
132 }
133
134 u8 *
135 format_vlib_buffer_contents (u8 * s, va_list * va)
136 {
137   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
138   vlib_buffer_t *b = va_arg (*va, vlib_buffer_t *);
139
140   while (1)
141     {
142       vec_add (s, vlib_buffer_get_current (b), b->current_length);
143       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
144         break;
145       b = vlib_get_buffer (vm, b->next_buffer);
146     }
147
148   return s;
149 }
150
151 static u8 *
152 vlib_validate_buffer_helper (vlib_main_t * vm,
153                              u32 bi,
154                              uword follow_buffer_next, uword ** unique_hash)
155 {
156   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
157   vlib_buffer_main_t *bm = vm->buffer_main;
158   vlib_buffer_free_list_t *fl;
159
160   if (pool_is_free_index (bm->buffer_free_list_pool, b->free_list_index))
161     return format (0, "unknown free list 0x%x", b->free_list_index);
162
163   fl = pool_elt_at_index (bm->buffer_free_list_pool, b->free_list_index);
164
165   if ((signed) b->current_data < (signed) -VLIB_BUFFER_PRE_DATA_SIZE)
166     return format (0, "current data %d before pre-data", b->current_data);
167
168   if (b->current_data + b->current_length > fl->n_data_bytes)
169     return format (0, "%d-%d beyond end of buffer %d",
170                    b->current_data, b->current_length, fl->n_data_bytes);
171
172   if (follow_buffer_next && (b->flags & VLIB_BUFFER_NEXT_PRESENT))
173     {
174       vlib_buffer_known_state_t k;
175       u8 *msg, *result;
176
177       k = vlib_buffer_is_known (vm, b->next_buffer);
178       if (k != VLIB_BUFFER_KNOWN_ALLOCATED)
179         return format (0, "next 0x%x: %U",
180                        b->next_buffer, format_vlib_buffer_known_state, k);
181
182       if (unique_hash)
183         {
184           if (hash_get (*unique_hash, b->next_buffer))
185             return format (0, "duplicate buffer 0x%x", b->next_buffer);
186
187           hash_set1 (*unique_hash, b->next_buffer);
188         }
189
190       msg = vlib_validate_buffer (vm, b->next_buffer, follow_buffer_next);
191       if (msg)
192         {
193           result = format (0, "next 0x%x: %v", b->next_buffer, msg);
194           vec_free (msg);
195           return result;
196         }
197     }
198
199   return 0;
200 }
201
202 u8 *
203 vlib_validate_buffer (vlib_main_t * vm, u32 bi, uword follow_buffer_next)
204 {
205   return vlib_validate_buffer_helper (vm, bi, follow_buffer_next,
206                                       /* unique_hash */ 0);
207 }
208
209 u8 *
210 vlib_validate_buffers (vlib_main_t * vm,
211                        u32 * buffers,
212                        uword next_buffer_stride,
213                        uword n_buffers,
214                        vlib_buffer_known_state_t known_state,
215                        uword follow_buffer_next)
216 {
217   uword i, *hash;
218   u32 bi, *b = buffers;
219   vlib_buffer_known_state_t k;
220   u8 *msg = 0, *result = 0;
221
222   hash = hash_create (0, 0);
223   for (i = 0; i < n_buffers; i++)
224     {
225       bi = b[0];
226       b += next_buffer_stride;
227
228       /* Buffer is not unique. */
229       if (hash_get (hash, bi))
230         {
231           msg = format (0, "not unique");
232           goto done;
233         }
234
235       k = vlib_buffer_is_known (vm, bi);
236       if (k != known_state)
237         {
238           msg = format (0, "is %U; expected %U",
239                         format_vlib_buffer_known_state, k,
240                         format_vlib_buffer_known_state, known_state);
241           goto done;
242         }
243
244       msg = vlib_validate_buffer_helper (vm, bi, follow_buffer_next, &hash);
245       if (msg)
246         goto done;
247
248       hash_set1 (hash, bi);
249     }
250
251 done:
252   if (msg)
253     {
254       result = format (0, "0x%x: %v", bi, msg);
255       vec_free (msg);
256     }
257   hash_free (hash);
258   return result;
259 }
260
261 vlib_main_t **vlib_mains;
262
263 /* When dubugging validate that given buffers are either known allocated
264    or known free. */
265 static void __attribute__ ((unused))
266 vlib_buffer_validate_alloc_free (vlib_main_t * vm,
267                                  u32 * buffers,
268                                  uword n_buffers,
269                                  vlib_buffer_known_state_t expected_state)
270 {
271   u32 *b;
272   uword i, bi, is_free;
273
274   if (CLIB_DEBUG == 0)
275     return;
276
277   ASSERT (os_get_cpu_number () == 0);
278
279   /* smp disaster check */
280   if (vlib_mains)
281     ASSERT (vm == vlib_mains[0]);
282
283   is_free = expected_state == VLIB_BUFFER_KNOWN_ALLOCATED;
284   b = buffers;
285   for (i = 0; i < n_buffers; i++)
286     {
287       vlib_buffer_known_state_t known;
288
289       bi = b[0];
290       b += 1;
291       known = vlib_buffer_is_known (vm, bi);
292       if (known != expected_state)
293         {
294           ASSERT (0);
295           vlib_panic_with_msg
296             (vm, "%s %U buffer 0x%x",
297              is_free ? "freeing" : "allocating",
298              format_vlib_buffer_known_state, known, bi);
299         }
300
301       vlib_buffer_set_known_state
302         (vm, bi,
303          is_free ? VLIB_BUFFER_KNOWN_FREE : VLIB_BUFFER_KNOWN_ALLOCATED);
304     }
305 }
306
307 void
308 vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
309                               vlib_buffer_free_list_t * src)
310 {
311   uword l;
312   u32 *d;
313
314   l = vec_len (src->buffers);
315   if (l > 0)
316     {
317       vec_add2_aligned (dst->buffers, d, l, CLIB_CACHE_LINE_BYTES);
318       clib_memcpy (d, src->buffers, l * sizeof (d[0]));
319       vec_free (src->buffers);
320     }
321 }
322
323 /* Add buffer free list. */
324 static u32
325 vlib_buffer_create_free_list_helper (vlib_main_t * vm,
326                                      u32 n_data_bytes,
327                                      u32 is_public, u32 is_default, u8 * name)
328 {
329   vlib_buffer_main_t *bm = vm->buffer_main;
330   vlib_buffer_free_list_t *f;
331   int i;
332
333   ASSERT (os_get_cpu_number () == 0);
334
335   if (!is_default && pool_elts (bm->buffer_free_list_pool) == 0)
336     {
337       u32 default_free_free_list_index;
338
339       /* *INDENT-OFF* */
340       default_free_free_list_index =
341         vlib_buffer_create_free_list_helper
342         (vm,
343          /* default buffer size */ VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES,
344          /* is_public */ 1,
345          /* is_default */ 1,
346          (u8 *) "default");
347       /* *INDENT-ON* */
348       ASSERT (default_free_free_list_index ==
349               VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
350
351       if (n_data_bytes == VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES && is_public)
352         return default_free_free_list_index;
353     }
354
355   pool_get_aligned (bm->buffer_free_list_pool, f, CLIB_CACHE_LINE_BYTES);
356
357   memset (f, 0, sizeof (f[0]));
358   f->index = f - bm->buffer_free_list_pool;
359   f->n_data_bytes = vlib_buffer_round_size (n_data_bytes);
360   f->min_n_buffers_each_physmem_alloc = 16;
361   f->name = clib_mem_is_heap_object (name) ? name : format (0, "%s", name);
362
363   /* Setup free buffer template. */
364   f->buffer_init_template.free_list_index = f->index;
365
366   if (is_public)
367     {
368       uword *p = hash_get (bm->free_list_by_size, f->n_data_bytes);
369       if (!p)
370         hash_set (bm->free_list_by_size, f->n_data_bytes, f->index);
371     }
372
373   for (i = 1; i < vec_len (vlib_mains); i++)
374     {
375       vlib_buffer_main_t *wbm = vlib_mains[i]->buffer_main;
376       vlib_buffer_free_list_t *wf;
377       pool_get_aligned (wbm->buffer_free_list_pool,
378                         wf, CLIB_CACHE_LINE_BYTES);
379       ASSERT (f - bm->buffer_free_list_pool ==
380               wf - wbm->buffer_free_list_pool);
381       wf[0] = f[0];
382       wf->buffers = 0;
383       wf->n_alloc = 0;
384     }
385
386   return f->index;
387 }
388
389 u32
390 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
391                               char *fmt, ...)
392 {
393   va_list va;
394   u8 *name;
395
396   va_start (va, fmt);
397   name = va_format (0, fmt, &va);
398   va_end (va);
399
400   return vlib_buffer_create_free_list_helper (vm, n_data_bytes,
401                                               /* is_public */ 0,
402                                               /* is_default */ 0,
403                                               name);
404 }
405
406 u32
407 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
408                                      char *fmt, ...)
409 {
410   u32 i = vlib_buffer_get_free_list_with_size (vm, n_data_bytes);
411
412   if (i == ~0)
413     {
414       va_list va;
415       u8 *name;
416
417       va_start (va, fmt);
418       name = va_format (0, fmt, &va);
419       va_end (va);
420
421       i = vlib_buffer_create_free_list_helper (vm, n_data_bytes,
422                                                /* is_public */ 1,
423                                                /* is_default */ 0,
424                                                name);
425     }
426
427   return i;
428 }
429
430 static void
431 del_free_list (vlib_main_t * vm, vlib_buffer_free_list_t * f)
432 {
433   u32 i;
434
435   for (i = 0; i < vec_len (f->buffer_memory_allocated); i++)
436     vm->os_physmem_free (f->buffer_memory_allocated[i]);
437   vec_free (f->name);
438   vec_free (f->buffer_memory_allocated);
439   vec_free (f->buffers);
440 }
441
442 /* Add buffer free list. */
443 void
444 vlib_buffer_delete_free_list_internal (vlib_main_t * vm, u32 free_list_index)
445 {
446   vlib_buffer_main_t *bm = vm->buffer_main;
447   vlib_buffer_free_list_t *f;
448   u32 merge_index;
449   int i;
450
451   ASSERT (os_get_cpu_number () == 0);
452
453   f = vlib_buffer_get_free_list (vm, free_list_index);
454
455   ASSERT (vec_len (f->buffers) == f->n_alloc);
456   merge_index = vlib_buffer_get_free_list_with_size (vm, f->n_data_bytes);
457   if (merge_index != ~0 && merge_index != free_list_index)
458     {
459       vlib_buffer_merge_free_lists (pool_elt_at_index
460                                     (bm->buffer_free_list_pool, merge_index),
461                                     f);
462     }
463
464   del_free_list (vm, f);
465
466   /* Poison it. */
467   memset (f, 0xab, sizeof (f[0]));
468
469   pool_put (bm->buffer_free_list_pool, f);
470
471   for (i = 1; i < vec_len (vlib_mains); i++)
472     {
473       bm = vlib_mains[i]->buffer_main;
474       f = vlib_buffer_get_free_list (vlib_mains[i], free_list_index);;
475       memset (f, 0xab, sizeof (f[0]));
476       pool_put (bm->buffer_free_list_pool, f);
477     }
478 }
479
480 /* Make sure free list has at least given number of free buffers. */
481 static uword
482 fill_free_list (vlib_main_t * vm,
483                 vlib_buffer_free_list_t * fl, uword min_free_buffers)
484 {
485   vlib_buffer_t *buffers, *b;
486   int n, n_bytes, i;
487   u32 *bi;
488   u32 n_remaining, n_alloc, n_this_chunk;
489
490   /* Already have enough free buffers on free list? */
491   n = min_free_buffers - vec_len (fl->buffers);
492   if (n <= 0)
493     return min_free_buffers;
494
495   /* Always allocate round number of buffers. */
496   n = round_pow2 (n, CLIB_CACHE_LINE_BYTES / sizeof (u32));
497
498   /* Always allocate new buffers in reasonably large sized chunks. */
499   n = clib_max (n, fl->min_n_buffers_each_physmem_alloc);
500
501   n_remaining = n;
502   n_alloc = 0;
503   while (n_remaining > 0)
504     {
505       n_this_chunk = clib_min (n_remaining, 16);
506
507       n_bytes = n_this_chunk * (sizeof (b[0]) + fl->n_data_bytes);
508
509       /* drb: removed power-of-2 ASSERT */
510       buffers = vm->os_physmem_alloc_aligned (&vm->physmem_main,
511                                               n_bytes,
512                                               sizeof (vlib_buffer_t));
513       if (!buffers)
514         return n_alloc;
515
516       /* Record chunk as being allocated so we can free it later. */
517       vec_add1 (fl->buffer_memory_allocated, buffers);
518
519       fl->n_alloc += n_this_chunk;
520       n_alloc += n_this_chunk;
521       n_remaining -= n_this_chunk;
522
523       b = buffers;
524       vec_add2_aligned (fl->buffers, bi, n_this_chunk, CLIB_CACHE_LINE_BYTES);
525       for (i = 0; i < n_this_chunk; i++)
526         {
527           bi[i] = vlib_get_buffer_index (vm, b);
528
529           if (CLIB_DEBUG > 0)
530             vlib_buffer_set_known_state (vm, bi[i], VLIB_BUFFER_KNOWN_FREE);
531           b = vlib_buffer_next_contiguous (b, fl->n_data_bytes);
532         }
533
534       memset (buffers, 0, n_bytes);
535
536       /* Initialize all new buffers. */
537       b = buffers;
538       for (i = 0; i < n_this_chunk; i++)
539         {
540           vlib_buffer_init_for_free_list (b, fl);
541           b = vlib_buffer_next_contiguous (b, fl->n_data_bytes);
542         }
543
544       if (fl->buffer_init_function)
545         fl->buffer_init_function (vm, fl, bi, n_this_chunk);
546     }
547   return n_alloc;
548 }
549
550 static u32
551 alloc_from_free_list (vlib_main_t * vm,
552                       vlib_buffer_free_list_t * free_list,
553                       u32 * alloc_buffers, u32 n_alloc_buffers)
554 {
555   u32 *dst, *src;
556   uword len;
557   uword n_filled;
558
559   dst = alloc_buffers;
560
561   n_filled = fill_free_list (vm, free_list, n_alloc_buffers);
562   if (n_filled == 0)
563     return 0;
564
565   len = vec_len (free_list->buffers);
566   ASSERT (len >= n_alloc_buffers);
567
568   src = free_list->buffers + len - n_alloc_buffers;
569   clib_memcpy (dst, src, n_alloc_buffers * sizeof (u32));
570
571   _vec_len (free_list->buffers) -= n_alloc_buffers;
572
573   /* Verify that buffers are known free. */
574   vlib_buffer_validate_alloc_free (vm, alloc_buffers,
575                                    n_alloc_buffers, VLIB_BUFFER_KNOWN_FREE);
576
577   return n_alloc_buffers;
578 }
579
580
581 /* Allocate a given number of buffers into given array.
582    Returns number actually allocated which will be either zero or
583    number requested. */
584 static u32
585 vlib_buffer_alloc_internal (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
586 {
587   vlib_buffer_main_t *bm = vm->buffer_main;
588
589   return alloc_from_free_list
590     (vm,
591      pool_elt_at_index (bm->buffer_free_list_pool,
592                         VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX),
593      buffers, n_buffers);
594 }
595
596 static u32
597 vlib_buffer_alloc_from_free_list_internal (vlib_main_t * vm,
598                                            u32 * buffers,
599                                            u32 n_buffers, u32 free_list_index)
600 {
601   vlib_buffer_main_t *bm = vm->buffer_main;
602   vlib_buffer_free_list_t *f;
603   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
604   return alloc_from_free_list (vm, f, buffers, n_buffers);
605 }
606
607 void *
608 vlib_set_buffer_free_callback (vlib_main_t * vm, void *fp)
609 {
610   vlib_buffer_main_t *bm = vm->buffer_main;
611   void *rv = bm->buffer_free_callback;
612
613   bm->buffer_free_callback = fp;
614   return rv;
615 }
616
617 static_always_inline void
618 vlib_buffer_free_inline (vlib_main_t * vm,
619                          u32 * buffers, u32 n_buffers, u32 follow_buffer_next)
620 {
621   vlib_buffer_main_t *bm = vm->buffer_main;
622   vlib_buffer_free_list_t *fl;
623   static u32 *next_to_free[2];  /* smp bad */
624   u32 i_next_to_free, *b, *n, *f, fi;
625   uword n_left;
626   int i;
627   static vlib_buffer_free_list_t **announce_list;
628   vlib_buffer_free_list_t *fl0 = 0, *fl1 = 0;
629   u32 bi0 = (u32) ~ 0, bi1 = (u32) ~ 0, fi0, fi1 = (u32) ~ 0;
630   u8 free0, free1 = 0, free_next0, free_next1;
631   u32 (*cb) (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
632              u32 follow_buffer_next);
633
634   ASSERT (os_get_cpu_number () == 0);
635
636   cb = bm->buffer_free_callback;
637
638   if (PREDICT_FALSE (cb != 0))
639     n_buffers = (*cb) (vm, buffers, n_buffers, follow_buffer_next);
640
641   if (!n_buffers)
642     return;
643
644   /* Use first buffer to get default free list. */
645   {
646     u32 bi0 = buffers[0];
647     vlib_buffer_t *b0;
648
649     b0 = vlib_get_buffer (vm, bi0);
650     fl = vlib_buffer_get_buffer_free_list (vm, b0, &fi);
651     if (fl->buffers_added_to_freelist_function)
652       vec_add1 (announce_list, fl);
653   }
654
655   vec_validate (next_to_free[0], n_buffers - 1);
656   vec_validate (next_to_free[1], n_buffers - 1);
657
658   i_next_to_free = 0;
659   n_left = n_buffers;
660   b = buffers;
661
662 again:
663   /* Verify that buffers are known allocated. */
664   vlib_buffer_validate_alloc_free (vm, b,
665                                    n_left, VLIB_BUFFER_KNOWN_ALLOCATED);
666
667   vec_add2_aligned (fl->buffers, f, n_left, CLIB_CACHE_LINE_BYTES);
668
669   n = next_to_free[i_next_to_free];
670   while (n_left >= 4)
671     {
672       vlib_buffer_t *b0, *b1, *binit0, *binit1, dummy_buffers[2];
673
674       bi0 = b[0];
675       bi1 = b[1];
676
677       f[0] = bi0;
678       f[1] = bi1;
679       f += 2;
680       b += 2;
681       n_left -= 2;
682
683       /* Prefetch buffers for next iteration. */
684       vlib_prefetch_buffer_with_index (vm, b[0], WRITE);
685       vlib_prefetch_buffer_with_index (vm, b[1], WRITE);
686
687       b0 = vlib_get_buffer (vm, bi0);
688       b1 = vlib_get_buffer (vm, bi1);
689
690       free0 = (b0->flags & VLIB_BUFFER_RECYCLE) == 0;
691       free1 = (b1->flags & VLIB_BUFFER_RECYCLE) == 0;
692
693       /* Must be before init which will over-write buffer flags. */
694       if (follow_buffer_next)
695         {
696           n[0] = b0->next_buffer;
697           free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
698           n += free_next0;
699
700           n[0] = b1->next_buffer;
701           free_next1 = free1 && (b1->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
702           n += free_next1;
703         }
704       else
705         free_next0 = free_next1 = 0;
706
707       /* Must be before init which will over-write buffer free list. */
708       fi0 = b0->free_list_index;
709       fi1 = b1->free_list_index;
710
711       if (PREDICT_FALSE (fi0 != fi || fi1 != fi))
712         goto slow_path_x2;
713
714       binit0 = free0 ? b0 : &dummy_buffers[0];
715       binit1 = free1 ? b1 : &dummy_buffers[1];
716
717       vlib_buffer_init_two_for_free_list (binit0, binit1, fl);
718       continue;
719
720     slow_path_x2:
721       /* Backup speculation. */
722       f -= 2;
723       n -= free_next0 + free_next1;
724
725       _vec_len (fl->buffers) = f - fl->buffers;
726
727       fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
728       fl1 = pool_elt_at_index (bm->buffer_free_list_pool, fi1);
729
730       vlib_buffer_add_to_free_list (vm, fl0, bi0, free0);
731       if (PREDICT_FALSE (fl0->buffers_added_to_freelist_function != 0))
732         {
733           int i;
734           for (i = 0; i < vec_len (announce_list); i++)
735             if (fl0 == announce_list[i])
736               goto no_fl0;
737           vec_add1 (announce_list, fl0);
738         }
739     no_fl0:
740       if (PREDICT_FALSE (fl1->buffers_added_to_freelist_function != 0))
741         {
742           int i;
743           for (i = 0; i < vec_len (announce_list); i++)
744             if (fl1 == announce_list[i])
745               goto no_fl1;
746           vec_add1 (announce_list, fl1);
747         }
748
749     no_fl1:
750       vlib_buffer_add_to_free_list (vm, fl1, bi1, free1);
751
752       /* Possibly change current free list. */
753       if (fi0 != fi && fi1 != fi)
754         {
755           fi = fi1;
756           fl = pool_elt_at_index (bm->buffer_free_list_pool, fi);
757         }
758
759       vec_add2_aligned (fl->buffers, f, n_left, CLIB_CACHE_LINE_BYTES);
760     }
761
762   while (n_left >= 1)
763     {
764       vlib_buffer_t *b0, *binit0, dummy_buffers[1];
765
766       bi0 = b[0];
767       f[0] = bi0;
768       f += 1;
769       b += 1;
770       n_left -= 1;
771
772       b0 = vlib_get_buffer (vm, bi0);
773
774       free0 = (b0->flags & VLIB_BUFFER_RECYCLE) == 0;
775
776       /* Must be before init which will over-write buffer flags. */
777       if (follow_buffer_next)
778         {
779           n[0] = b0->next_buffer;
780           free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
781           n += free_next0;
782         }
783       else
784         free_next0 = 0;
785
786       /* Must be before init which will over-write buffer free list. */
787       fi0 = b0->free_list_index;
788
789       if (PREDICT_FALSE (fi0 != fi))
790         goto slow_path_x1;
791
792       binit0 = free0 ? b0 : &dummy_buffers[0];
793
794       vlib_buffer_init_for_free_list (binit0, fl);
795       continue;
796
797     slow_path_x1:
798       /* Backup speculation. */
799       f -= 1;
800       n -= free_next0;
801
802       _vec_len (fl->buffers) = f - fl->buffers;
803
804       fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
805
806       vlib_buffer_add_to_free_list (vm, fl0, bi0, free0);
807       if (PREDICT_FALSE (fl0->buffers_added_to_freelist_function != 0))
808         {
809           int i;
810           for (i = 0; i < vec_len (announce_list); i++)
811             if (fl0 == announce_list[i])
812               goto no_fl00;
813           vec_add1 (announce_list, fl0);
814         }
815
816     no_fl00:
817       fi = fi0;
818       fl = pool_elt_at_index (bm->buffer_free_list_pool, fi);
819
820       vec_add2_aligned (fl->buffers, f, n_left, CLIB_CACHE_LINE_BYTES);
821     }
822
823   if (follow_buffer_next && ((n_left = n - next_to_free[i_next_to_free]) > 0))
824     {
825       b = next_to_free[i_next_to_free];
826       i_next_to_free ^= 1;
827       goto again;
828     }
829
830   _vec_len (fl->buffers) = f - fl->buffers;
831
832   if (vec_len (announce_list))
833     {
834       vlib_buffer_free_list_t *fl;
835       for (i = 0; i < vec_len (announce_list); i++)
836         {
837           fl = announce_list[i];
838           fl->buffers_added_to_freelist_function (vm, fl);
839         }
840       _vec_len (announce_list) = 0;
841     }
842 }
843
844 static void
845 vlib_buffer_free_internal (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
846 {
847   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
848                            1);
849 }
850
851 static void
852 vlib_buffer_free_no_next_internal (vlib_main_t * vm, u32 * buffers,
853                                    u32 n_buffers)
854 {
855   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
856                            0);
857 }
858
859 /* Copy template packet data into buffers as they are allocated. */
860 static void __attribute__ ((unused))
861 vlib_packet_template_buffer_init (vlib_main_t * vm,
862                                   vlib_buffer_free_list_t * fl,
863                                   u32 * buffers, u32 n_buffers)
864 {
865   vlib_packet_template_t *t =
866     uword_to_pointer (fl->buffer_init_function_opaque,
867                       vlib_packet_template_t *);
868   uword i;
869
870   for (i = 0; i < n_buffers; i++)
871     {
872       vlib_buffer_t *b = vlib_get_buffer (vm, buffers[i]);
873       ASSERT (b->current_length == vec_len (t->packet_data));
874       clib_memcpy (vlib_buffer_get_current (b), t->packet_data,
875                    b->current_length);
876     }
877 }
878
879 void
880 vlib_packet_template_init (vlib_main_t * vm,
881                            vlib_packet_template_t * t,
882                            void *packet_data,
883                            uword n_packet_data_bytes,
884                            uword min_n_buffers_each_physmem_alloc,
885                            char *fmt, ...)
886 {
887   vlib_buffer_main_t *bm = vm->buffer_main;
888   va_list va;
889   __attribute__ ((unused)) u8 *name;
890   vlib_buffer_free_list_t *fl;
891
892   va_start (va, fmt);
893   name = va_format (0, fmt, &va);
894   va_end (va);
895
896   if (bm->cb.vlib_packet_template_init_cb)
897     bm->cb.vlib_packet_template_init_cb (vm, (void *) t, packet_data,
898                                          n_packet_data_bytes,
899                                          min_n_buffers_each_physmem_alloc,
900                                          name);
901
902   vlib_worker_thread_barrier_sync (vm);
903
904   memset (t, 0, sizeof (t[0]));
905
906   vec_add (t->packet_data, packet_data, n_packet_data_bytes);
907   t->min_n_buffers_each_physmem_alloc = min_n_buffers_each_physmem_alloc;
908
909   t->free_list_index = vlib_buffer_create_free_list_helper
910     (vm, n_packet_data_bytes,
911      /* is_public */ 1,
912      /* is_default */ 0,
913      name);
914
915   ASSERT (t->free_list_index != 0);
916   fl = vlib_buffer_get_free_list (vm, t->free_list_index);
917   fl->min_n_buffers_each_physmem_alloc = t->min_n_buffers_each_physmem_alloc;
918
919   fl->buffer_init_function = vlib_packet_template_buffer_init;
920   fl->buffer_init_function_opaque = pointer_to_uword (t);
921
922   fl->buffer_init_template.current_data = 0;
923   fl->buffer_init_template.current_length = n_packet_data_bytes;
924   fl->buffer_init_template.flags = 0;
925   vlib_worker_thread_barrier_release (vm);
926 }
927
928 void *
929 vlib_packet_template_get_packet (vlib_main_t * vm,
930                                  vlib_packet_template_t * t, u32 * bi_result)
931 {
932   u32 bi;
933   vlib_buffer_t *b;
934
935   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
936     return 0;
937
938   *bi_result = bi;
939
940   b = vlib_get_buffer (vm, bi);
941   clib_memcpy (vlib_buffer_get_current (b),
942                t->packet_data, vec_len (t->packet_data));
943   b->current_length = vec_len (t->packet_data);
944
945   return b->data;
946 }
947
948 void
949 vlib_packet_template_get_packet_helper (vlib_main_t * vm,
950                                         vlib_packet_template_t * t)
951 {
952   word n = t->min_n_buffers_each_physmem_alloc;
953   word l = vec_len (t->packet_data);
954   word n_alloc;
955
956   ASSERT (l > 0);
957   ASSERT (vec_len (t->free_buffers) == 0);
958
959   vec_validate (t->free_buffers, n - 1);
960   n_alloc = vlib_buffer_alloc_from_free_list (vm, t->free_buffers,
961                                               n, t->free_list_index);
962   _vec_len (t->free_buffers) = n_alloc;
963 }
964
965 /* Append given data to end of buffer, possibly allocating new buffers. */
966 u32
967 vlib_buffer_add_data (vlib_main_t * vm,
968                       u32 free_list_index,
969                       u32 buffer_index, void *data, u32 n_data_bytes)
970 {
971   u32 n_buffer_bytes, n_left, n_left_this_buffer, bi;
972   vlib_buffer_t *b;
973   void *d;
974
975   bi = buffer_index;
976   if (bi == 0
977       && 1 != vlib_buffer_alloc_from_free_list (vm, &bi, 1, free_list_index))
978     goto out_of_buffers;
979
980   d = data;
981   n_left = n_data_bytes;
982   n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
983
984   b = vlib_get_buffer (vm, bi);
985   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
986
987   /* Get to the end of the chain before we try to append data... */
988   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
989     b = vlib_get_buffer (vm, b->next_buffer);
990
991   while (1)
992     {
993       u32 n;
994
995       ASSERT (n_buffer_bytes >= b->current_length);
996       n_left_this_buffer =
997         n_buffer_bytes - (b->current_data + b->current_length);
998       n = clib_min (n_left_this_buffer, n_left);
999       clib_memcpy (vlib_buffer_get_current (b) + b->current_length, d, n);
1000       b->current_length += n;
1001       n_left -= n;
1002       if (n_left == 0)
1003         break;
1004
1005       d += n;
1006       if (1 !=
1007           vlib_buffer_alloc_from_free_list (vm, &b->next_buffer, 1,
1008                                             free_list_index))
1009         goto out_of_buffers;
1010
1011       b->flags |= VLIB_BUFFER_NEXT_PRESENT;
1012
1013       b = vlib_get_buffer (vm, b->next_buffer);
1014     }
1015
1016   return bi;
1017
1018 out_of_buffers:
1019   clib_error ("out of buffers");
1020   return bi;
1021 }
1022
1023 u16
1024 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
1025                                           u32 free_list_index,
1026                                           vlib_buffer_t * first,
1027                                           vlib_buffer_t ** last,
1028                                           void *data, u16 data_len)
1029 {
1030   vlib_buffer_t *l = *last;
1031   u32 n_buffer_bytes =
1032     vlib_buffer_free_list_buffer_size (vm, free_list_index);
1033   u16 copied = 0;
1034   ASSERT (n_buffer_bytes >= l->current_length + l->current_data);
1035   while (data_len)
1036     {
1037       u16 max = n_buffer_bytes - l->current_length - l->current_data;
1038       if (max == 0)
1039         {
1040           if (1 !=
1041               vlib_buffer_alloc_from_free_list (vm, &l->next_buffer, 1,
1042                                                 free_list_index))
1043             return copied;
1044           *last = l = vlib_buffer_chain_buffer (vm, first, l, l->next_buffer);
1045           max = n_buffer_bytes - l->current_length - l->current_data;
1046         }
1047
1048       u16 len = (data_len > max) ? max : data_len;
1049       clib_memcpy (vlib_buffer_get_current (l) + l->current_length,
1050                    data + copied, len);
1051       vlib_buffer_chain_increase_length (first, l, len);
1052       data_len -= len;
1053       copied += len;
1054     }
1055   return copied;
1056 }
1057
1058
1059 static u8 *
1060 format_vlib_buffer_free_list (u8 * s, va_list * va)
1061 {
1062   vlib_buffer_free_list_t *f = va_arg (*va, vlib_buffer_free_list_t *);
1063   u32 threadnum = va_arg (*va, u32);
1064   uword bytes_alloc, bytes_free, n_free, size;
1065
1066   if (!f)
1067     return format (s, "%=7s%=30s%=12s%=12s%=12s%=12s%=12s%=12s",
1068                    "Thread", "Name", "Index", "Size", "Alloc", "Free",
1069                    "#Alloc", "#Free");
1070
1071   size = sizeof (vlib_buffer_t) + f->n_data_bytes;
1072   n_free = vec_len (f->buffers);
1073   bytes_alloc = size * f->n_alloc;
1074   bytes_free = size * n_free;
1075
1076   s = format (s, "%7d%30s%12d%12d%=12U%=12U%=12d%=12d", threadnum,
1077               f->name, f->index, f->n_data_bytes,
1078               format_memory_size, bytes_alloc,
1079               format_memory_size, bytes_free, f->n_alloc, n_free);
1080
1081   return s;
1082 }
1083
1084 static clib_error_t *
1085 show_buffers (vlib_main_t * vm,
1086               unformat_input_t * input, vlib_cli_command_t * cmd)
1087 {
1088   vlib_buffer_main_t *bm;
1089   vlib_buffer_free_list_t *f;
1090   vlib_main_t *curr_vm;
1091   u32 vm_index = 0;
1092
1093   vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, 0, 0);
1094
1095   do
1096     {
1097       curr_vm = vec_len (vlib_mains) ? vlib_mains[vm_index] : vm;
1098       bm = curr_vm->buffer_main;
1099
1100     /* *INDENT-OFF* */
1101     pool_foreach (f, bm->buffer_free_list_pool, ({
1102       vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, f, vm_index);
1103     }));
1104     /* *INDENT-ON* */
1105
1106       vm_index++;
1107     }
1108   while (vm_index < vec_len (vlib_mains));
1109
1110   return 0;
1111 }
1112
1113 /* *INDENT-OFF* */
1114 VLIB_CLI_COMMAND (show_buffers_command, static) = {
1115   .path = "show buffers",
1116   .short_help = "Show packet buffer allocation",
1117   .function = show_buffers,
1118 };
1119 /* *INDENT-ON* */
1120
1121 void
1122 vlib_buffer_cb_init (struct vlib_main_t *vm)
1123 {
1124   vlib_buffer_main_t *bm = vm->buffer_main;
1125   bm->cb.vlib_buffer_alloc_cb = &vlib_buffer_alloc_internal;
1126   bm->cb.vlib_buffer_alloc_from_free_list_cb =
1127     &vlib_buffer_alloc_from_free_list_internal;
1128   bm->cb.vlib_buffer_free_cb = &vlib_buffer_free_internal;
1129   bm->cb.vlib_buffer_free_no_next_cb = &vlib_buffer_free_no_next_internal;
1130   bm->cb.vlib_buffer_delete_free_list_cb =
1131     &vlib_buffer_delete_free_list_internal;
1132   bm->extern_buffer_mgmt = 0;
1133 }
1134
1135 int
1136 vlib_buffer_cb_register (struct vlib_main_t *vm, vlib_buffer_callbacks_t * cb)
1137 {
1138   vlib_buffer_main_t *bm = vm->buffer_main;
1139   if (bm->extern_buffer_mgmt)
1140     return -1;
1141
1142 #define _(x) bm->cb.x = cb->x
1143   _(vlib_buffer_alloc_cb);
1144   _(vlib_buffer_alloc_from_free_list_cb);
1145   _(vlib_buffer_free_cb);
1146   _(vlib_buffer_free_no_next_cb);
1147   _(vlib_buffer_delete_free_list_cb);
1148 #undef _
1149   bm->extern_buffer_mgmt = 1;
1150   return 0;
1151 }
1152
1153 /** @endcond */
1154 /*
1155  * fd.io coding-style-patch-verification: ON
1156  *
1157  * Local Variables:
1158  * eval: (c-set-style "gnu")
1159  * End:
1160  */