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