dpdk: remove duplicate code in buffers.c
[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 #define BUFFERS_PER_COPY (sizeof (vlib_copy_unit_t) / sizeof (u32))
308
309 /* Make sure we have at least given number of unaligned buffers. */
310 void
311 vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
312                                       vlib_buffer_free_list_t * free_list,
313                                       uword n_unaligned_buffers)
314 {
315   word la = vec_len (free_list->aligned_buffers);
316   word lu = vec_len (free_list->unaligned_buffers);
317
318   /* Aligned come in aligned copy-sized chunks. */
319   ASSERT (la % BUFFERS_PER_COPY == 0);
320
321   ASSERT (la >= n_unaligned_buffers);
322
323   while (lu < n_unaligned_buffers)
324     {
325       /* Copy 4 buffers from end of aligned vector to unaligned vector. */
326       vec_add (free_list->unaligned_buffers,
327                free_list->aligned_buffers + la - BUFFERS_PER_COPY,
328                BUFFERS_PER_COPY);
329       la -= BUFFERS_PER_COPY;
330       lu += BUFFERS_PER_COPY;
331     }
332   _vec_len (free_list->aligned_buffers) = la;
333 }
334
335 /* After free aligned buffers may not contain even sized chunks. */
336 void
337 vlib_buffer_free_list_trim_aligned (vlib_buffer_free_list_t * f)
338 {
339   uword l, n_trim;
340
341   /* Add unaligned to aligned before trim. */
342   l = vec_len (f->unaligned_buffers);
343   if (l > 0)
344     {
345       vec_add_aligned (f->aligned_buffers, f->unaligned_buffers, l,
346                        /* align */ sizeof (vlib_copy_unit_t));
347
348       _vec_len (f->unaligned_buffers) = 0;
349     }
350
351   /* Remove unaligned buffers from end of aligned vector and save for next trim. */
352   l = vec_len (f->aligned_buffers);
353   n_trim = l % BUFFERS_PER_COPY;
354   if (n_trim)
355     {
356       /* Trim aligned -> unaligned. */
357       vec_add (f->unaligned_buffers, f->aligned_buffers + l - n_trim, n_trim);
358
359       /* Remove from aligned. */
360       _vec_len (f->aligned_buffers) = l - n_trim;
361     }
362 }
363
364 void
365 vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
366                               vlib_buffer_free_list_t * src)
367 {
368   uword l;
369   u32 *d;
370
371   vlib_buffer_free_list_trim_aligned (src);
372   vlib_buffer_free_list_trim_aligned (dst);
373
374   l = vec_len (src->aligned_buffers);
375   if (l > 0)
376     {
377       vec_add2_aligned (dst->aligned_buffers, d, l,
378                         /* align */ sizeof (vlib_copy_unit_t));
379       clib_memcpy (d, src->aligned_buffers, l * sizeof (d[0]));
380       vec_free (src->aligned_buffers);
381     }
382
383   l = vec_len (src->unaligned_buffers);
384   if (l > 0)
385     {
386       vec_add (dst->unaligned_buffers, src->unaligned_buffers, l);
387       vec_free (src->unaligned_buffers);
388     }
389 }
390
391 /* Add buffer free list. */
392 static u32
393 vlib_buffer_create_free_list_helper (vlib_main_t * vm,
394                                      u32 n_data_bytes,
395                                      u32 is_public, u32 is_default, u8 * name)
396 {
397   vlib_buffer_main_t *bm = vm->buffer_main;
398   vlib_buffer_free_list_t *f;
399   int i;
400
401   ASSERT (os_get_cpu_number () == 0);
402
403   if (!is_default && pool_elts (bm->buffer_free_list_pool) == 0)
404     {
405       u32 default_free_free_list_index;
406
407       /* *INDENT-OFF* */
408       default_free_free_list_index =
409         vlib_buffer_create_free_list_helper
410         (vm,
411          /* default buffer size */ VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES,
412          /* is_public */ 1,
413          /* is_default */ 1,
414          (u8 *) "default");
415       /* *INDENT-ON* */
416       ASSERT (default_free_free_list_index ==
417               VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
418
419       if (n_data_bytes == VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES && is_public)
420         return default_free_free_list_index;
421     }
422
423   pool_get_aligned (bm->buffer_free_list_pool, f, CLIB_CACHE_LINE_BYTES);
424
425   memset (f, 0, sizeof (f[0]));
426   f->index = f - bm->buffer_free_list_pool;
427   f->n_data_bytes = vlib_buffer_round_size (n_data_bytes);
428   f->min_n_buffers_each_physmem_alloc = 16;
429   f->name = clib_mem_is_heap_object (name) ? name : format (0, "%s", name);
430
431   /* Setup free buffer template. */
432   f->buffer_init_template.free_list_index = f->index;
433
434   if (is_public)
435     {
436       uword *p = hash_get (bm->free_list_by_size, f->n_data_bytes);
437       if (!p)
438         hash_set (bm->free_list_by_size, f->n_data_bytes, f->index);
439     }
440
441   for (i = 1; i < vec_len (vlib_mains); i++)
442     {
443       vlib_buffer_main_t *wbm = vlib_mains[i]->buffer_main;
444       vlib_buffer_free_list_t *wf;
445       pool_get_aligned (wbm->buffer_free_list_pool,
446                         wf, CLIB_CACHE_LINE_BYTES);
447       ASSERT (f - bm->buffer_free_list_pool ==
448               wf - wbm->buffer_free_list_pool);
449       wf[0] = f[0];
450       wf->aligned_buffers = 0;
451       wf->unaligned_buffers = 0;
452       wf->n_alloc = 0;
453     }
454
455   return f->index;
456 }
457
458 u32
459 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
460                               char *fmt, ...)
461 {
462   va_list va;
463   u8 *name;
464
465   va_start (va, fmt);
466   name = va_format (0, fmt, &va);
467   va_end (va);
468
469   return vlib_buffer_create_free_list_helper (vm, n_data_bytes,
470                                               /* is_public */ 0,
471                                               /* is_default */ 0,
472                                               name);
473 }
474
475 u32
476 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
477                                      char *fmt, ...)
478 {
479   u32 i = vlib_buffer_get_free_list_with_size (vm, n_data_bytes);
480
481   if (i == ~0)
482     {
483       va_list va;
484       u8 *name;
485
486       va_start (va, fmt);
487       name = va_format (0, fmt, &va);
488       va_end (va);
489
490       i = vlib_buffer_create_free_list_helper (vm, n_data_bytes,
491                                                /* is_public */ 1,
492                                                /* is_default */ 0,
493                                                name);
494     }
495
496   return i;
497 }
498
499 static void
500 del_free_list (vlib_main_t * vm, vlib_buffer_free_list_t * f)
501 {
502   u32 i;
503
504   for (i = 0; i < vec_len (f->buffer_memory_allocated); i++)
505     vm->os_physmem_free (f->buffer_memory_allocated[i]);
506   vec_free (f->name);
507   vec_free (f->buffer_memory_allocated);
508   vec_free (f->unaligned_buffers);
509   vec_free (f->aligned_buffers);
510 }
511
512 /* Add buffer free list. */
513 void
514 vlib_buffer_delete_free_list_internal (vlib_main_t * vm, u32 free_list_index)
515 {
516   vlib_buffer_main_t *bm = vm->buffer_main;
517   vlib_buffer_free_list_t *f;
518   u32 merge_index;
519   int i;
520
521   ASSERT (os_get_cpu_number () == 0);
522
523   f = vlib_buffer_get_free_list (vm, free_list_index);
524
525   ASSERT (vec_len (f->unaligned_buffers) + vec_len (f->aligned_buffers) ==
526           f->n_alloc);
527   merge_index = vlib_buffer_get_free_list_with_size (vm, f->n_data_bytes);
528   if (merge_index != ~0 && merge_index != free_list_index)
529     {
530       vlib_buffer_merge_free_lists (pool_elt_at_index
531                                     (bm->buffer_free_list_pool, merge_index),
532                                     f);
533     }
534
535   del_free_list (vm, f);
536
537   /* Poison it. */
538   memset (f, 0xab, sizeof (f[0]));
539
540   pool_put (bm->buffer_free_list_pool, f);
541
542   for (i = 1; i < vec_len (vlib_mains); i++)
543     {
544       bm = vlib_mains[i]->buffer_main;
545       f = vlib_buffer_get_free_list (vlib_mains[i], free_list_index);;
546       memset (f, 0xab, sizeof (f[0]));
547       pool_put (bm->buffer_free_list_pool, f);
548     }
549 }
550
551 /* Make sure free list has at least given number of free buffers. */
552 static uword
553 fill_free_list (vlib_main_t * vm,
554                 vlib_buffer_free_list_t * fl, uword min_free_buffers)
555 {
556   vlib_buffer_t *buffers, *b;
557   int n, n_bytes, i;
558   u32 *bi;
559   u32 n_remaining, n_alloc, n_this_chunk;
560
561   vlib_buffer_free_list_trim_aligned (fl);
562
563   /* Already have enough free buffers on free list? */
564   n = min_free_buffers - vec_len (fl->aligned_buffers);
565   if (n <= 0)
566     return min_free_buffers;
567
568   /* Always allocate round number of buffers. */
569   n = round_pow2 (n, BUFFERS_PER_COPY);
570
571   /* Always allocate new buffers in reasonably large sized chunks. */
572   n = clib_max (n, fl->min_n_buffers_each_physmem_alloc);
573
574   n_remaining = n;
575   n_alloc = 0;
576   while (n_remaining > 0)
577     {
578       n_this_chunk = clib_min (n_remaining, 16);
579
580       n_bytes = n_this_chunk * (sizeof (b[0]) + fl->n_data_bytes);
581
582       /* drb: removed power-of-2 ASSERT */
583       buffers = vm->os_physmem_alloc_aligned (&vm->physmem_main,
584                                               n_bytes,
585                                               sizeof (vlib_buffer_t));
586       if (!buffers)
587         return n_alloc;
588
589       /* Record chunk as being allocated so we can free it later. */
590       vec_add1 (fl->buffer_memory_allocated, buffers);
591
592       fl->n_alloc += n_this_chunk;
593       n_alloc += n_this_chunk;
594       n_remaining -= n_this_chunk;
595
596       b = buffers;
597       vec_add2_aligned (fl->aligned_buffers, bi, n_this_chunk,
598                         sizeof (vlib_copy_unit_t));
599       for (i = 0; i < n_this_chunk; i++)
600         {
601           bi[i] = vlib_get_buffer_index (vm, b);
602
603           if (CLIB_DEBUG > 0)
604             vlib_buffer_set_known_state (vm, bi[i], VLIB_BUFFER_KNOWN_FREE);
605           b = vlib_buffer_next_contiguous (b, fl->n_data_bytes);
606         }
607
608       memset (buffers, 0, n_bytes);
609
610       /* Initialize all new buffers. */
611       b = buffers;
612       for (i = 0; i < n_this_chunk; i++)
613         {
614           vlib_buffer_init_for_free_list (b, fl);
615           b = vlib_buffer_next_contiguous (b, fl->n_data_bytes);
616         }
617
618       if (fl->buffer_init_function)
619         fl->buffer_init_function (vm, fl, bi, n_this_chunk);
620     }
621   return n_alloc;
622 }
623
624 always_inline uword
625 copy_alignment (u32 * x)
626 {
627   return (pointer_to_uword (x) / sizeof (x[0])) % BUFFERS_PER_COPY;
628 }
629
630
631 static u32
632 alloc_from_free_list (vlib_main_t * vm,
633                       vlib_buffer_free_list_t * free_list,
634                       u32 * alloc_buffers, u32 n_alloc_buffers)
635 {
636   u32 *dst, *u_src;
637   uword u_len, n_left;
638   uword n_unaligned_start, n_unaligned_end, n_filled;
639
640   n_left = n_alloc_buffers;
641   dst = alloc_buffers;
642   n_unaligned_start = ((BUFFERS_PER_COPY - copy_alignment (dst))
643                        & (BUFFERS_PER_COPY - 1));
644
645   n_filled = fill_free_list (vm, free_list, n_alloc_buffers);
646   if (n_filled == 0)
647     return 0;
648
649   n_left = n_filled < n_left ? n_filled : n_left;
650   n_alloc_buffers = n_left;
651
652   if (n_unaligned_start >= n_left)
653     {
654       n_unaligned_start = n_left;
655       n_unaligned_end = 0;
656     }
657   else
658     n_unaligned_end = copy_alignment (dst + n_alloc_buffers);
659
660   vlib_buffer_free_list_fill_unaligned (vm, free_list,
661                                         n_unaligned_start + n_unaligned_end);
662
663   u_len = vec_len (free_list->unaligned_buffers);
664   u_src = free_list->unaligned_buffers + u_len - 1;
665
666   if (n_unaligned_start)
667     {
668       uword n_copy = n_unaligned_start;
669       if (n_copy > n_left)
670         n_copy = n_left;
671       n_left -= n_copy;
672
673       while (n_copy > 0)
674         {
675           *dst++ = *u_src--;
676           n_copy--;
677           u_len--;
678         }
679
680       /* Now dst should be aligned. */
681       if (n_left > 0)
682         ASSERT (pointer_to_uword (dst) % sizeof (vlib_copy_unit_t) == 0);
683     }
684
685   /* Aligned copy. */
686   {
687     vlib_copy_unit_t *d, *s;
688     uword n_copy;
689
690     if (vec_len (free_list->aligned_buffers) <
691         ((n_left / BUFFERS_PER_COPY) * BUFFERS_PER_COPY))
692       abort ();
693
694     n_copy = n_left / BUFFERS_PER_COPY;
695     n_left = n_left % BUFFERS_PER_COPY;
696
697     /* Remove buffers from aligned free list. */
698     _vec_len (free_list->aligned_buffers) -= n_copy * BUFFERS_PER_COPY;
699
700     s = (vlib_copy_unit_t *) vec_end (free_list->aligned_buffers);
701     d = (vlib_copy_unit_t *) dst;
702
703     /* Fast path loop. */
704     while (n_copy >= 4)
705       {
706         d[0] = s[0];
707         d[1] = s[1];
708         d[2] = s[2];
709         d[3] = s[3];
710         n_copy -= 4;
711         s += 4;
712         d += 4;
713       }
714
715     while (n_copy >= 1)
716       {
717         d[0] = s[0];
718         n_copy -= 1;
719         s += 1;
720         d += 1;
721       }
722
723     dst = (void *) d;
724   }
725
726   /* Unaligned copy. */
727   ASSERT (n_unaligned_end == n_left);
728   while (n_left > 0)
729     {
730       *dst++ = *u_src--;
731       n_left--;
732       u_len--;
733     }
734
735   if (!free_list->unaligned_buffers)
736     ASSERT (u_len == 0);
737   else
738     _vec_len (free_list->unaligned_buffers) = u_len;
739
740   /* Verify that buffers are known free. */
741   vlib_buffer_validate_alloc_free (vm, alloc_buffers,
742                                    n_alloc_buffers, VLIB_BUFFER_KNOWN_FREE);
743
744   return n_alloc_buffers;
745 }
746
747
748 /* Allocate a given number of buffers into given array.
749    Returns number actually allocated which will be either zero or
750    number requested. */
751 static u32
752 vlib_buffer_alloc_internal (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
753 {
754   vlib_buffer_main_t *bm = vm->buffer_main;
755
756   return alloc_from_free_list
757     (vm,
758      pool_elt_at_index (bm->buffer_free_list_pool,
759                         VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX),
760      buffers, n_buffers);
761 }
762
763 static u32
764 vlib_buffer_alloc_from_free_list_internal (vlib_main_t * vm,
765                                            u32 * buffers,
766                                            u32 n_buffers, u32 free_list_index)
767 {
768   vlib_buffer_main_t *bm = vm->buffer_main;
769   vlib_buffer_free_list_t *f;
770   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
771   return alloc_from_free_list (vm, f, buffers, n_buffers);
772 }
773
774 void *
775 vlib_set_buffer_free_callback (vlib_main_t * vm, void *fp)
776 {
777   vlib_buffer_main_t *bm = vm->buffer_main;
778   void *rv = bm->buffer_free_callback;
779
780   bm->buffer_free_callback = fp;
781   return rv;
782 }
783
784 static_always_inline void
785 vlib_buffer_free_inline (vlib_main_t * vm,
786                          u32 * buffers, u32 n_buffers, u32 follow_buffer_next)
787 {
788   vlib_buffer_main_t *bm = vm->buffer_main;
789   vlib_buffer_free_list_t *fl;
790   static u32 *next_to_free[2];  /* smp bad */
791   u32 i_next_to_free, *b, *n, *f, fi;
792   uword n_left;
793   int i;
794   static vlib_buffer_free_list_t **announce_list;
795   vlib_buffer_free_list_t *fl0 = 0, *fl1 = 0;
796   u32 bi0 = (u32) ~ 0, bi1 = (u32) ~ 0, fi0, fi1 = (u32) ~ 0;
797   u8 free0, free1 = 0, free_next0, free_next1;
798   u32 (*cb) (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
799              u32 follow_buffer_next);
800
801   ASSERT (os_get_cpu_number () == 0);
802
803   cb = bm->buffer_free_callback;
804
805   if (PREDICT_FALSE (cb != 0))
806     n_buffers = (*cb) (vm, buffers, n_buffers, follow_buffer_next);
807
808   if (!n_buffers)
809     return;
810
811   /* Use first buffer to get default free list. */
812   {
813     u32 bi0 = buffers[0];
814     vlib_buffer_t *b0;
815
816     b0 = vlib_get_buffer (vm, bi0);
817     fl = vlib_buffer_get_buffer_free_list (vm, b0, &fi);
818     if (fl->buffers_added_to_freelist_function)
819       vec_add1 (announce_list, fl);
820   }
821
822   vec_validate (next_to_free[0], n_buffers - 1);
823   vec_validate (next_to_free[1], n_buffers - 1);
824
825   i_next_to_free = 0;
826   n_left = n_buffers;
827   b = buffers;
828
829 again:
830   /* Verify that buffers are known allocated. */
831   vlib_buffer_validate_alloc_free (vm, b,
832                                    n_left, VLIB_BUFFER_KNOWN_ALLOCATED);
833
834   vec_add2_aligned (fl->aligned_buffers, f, n_left,
835                     /* align */ sizeof (vlib_copy_unit_t));
836
837   n = next_to_free[i_next_to_free];
838   while (n_left >= 4)
839     {
840       vlib_buffer_t *b0, *b1, *binit0, *binit1, dummy_buffers[2];
841
842       bi0 = b[0];
843       bi1 = b[1];
844
845       f[0] = bi0;
846       f[1] = bi1;
847       f += 2;
848       b += 2;
849       n_left -= 2;
850
851       /* Prefetch buffers for next iteration. */
852       vlib_prefetch_buffer_with_index (vm, b[0], WRITE);
853       vlib_prefetch_buffer_with_index (vm, b[1], WRITE);
854
855       b0 = vlib_get_buffer (vm, bi0);
856       b1 = vlib_get_buffer (vm, bi1);
857
858       free0 = (b0->flags & VLIB_BUFFER_RECYCLE) == 0;
859       free1 = (b1->flags & VLIB_BUFFER_RECYCLE) == 0;
860
861       /* Must be before init which will over-write buffer flags. */
862       if (follow_buffer_next)
863         {
864           n[0] = b0->next_buffer;
865           free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
866           n += free_next0;
867
868           n[0] = b1->next_buffer;
869           free_next1 = free1 && (b1->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
870           n += free_next1;
871         }
872       else
873         free_next0 = free_next1 = 0;
874
875       /* Must be before init which will over-write buffer free list. */
876       fi0 = b0->free_list_index;
877       fi1 = b1->free_list_index;
878
879       if (PREDICT_FALSE (fi0 != fi || fi1 != fi))
880         goto slow_path_x2;
881
882       binit0 = free0 ? b0 : &dummy_buffers[0];
883       binit1 = free1 ? b1 : &dummy_buffers[1];
884
885       vlib_buffer_init_two_for_free_list (binit0, binit1, fl);
886       continue;
887
888     slow_path_x2:
889       /* Backup speculation. */
890       f -= 2;
891       n -= free_next0 + free_next1;
892
893       _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
894
895       fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
896       fl1 = pool_elt_at_index (bm->buffer_free_list_pool, fi1);
897
898       vlib_buffer_add_to_free_list (vm, fl0, bi0, free0);
899       if (PREDICT_FALSE (fl0->buffers_added_to_freelist_function != 0))
900         {
901           int i;
902           for (i = 0; i < vec_len (announce_list); i++)
903             if (fl0 == announce_list[i])
904               goto no_fl0;
905           vec_add1 (announce_list, fl0);
906         }
907     no_fl0:
908       if (PREDICT_FALSE (fl1->buffers_added_to_freelist_function != 0))
909         {
910           int i;
911           for (i = 0; i < vec_len (announce_list); i++)
912             if (fl1 == announce_list[i])
913               goto no_fl1;
914           vec_add1 (announce_list, fl1);
915         }
916
917     no_fl1:
918       vlib_buffer_add_to_free_list (vm, fl1, bi1, free1);
919
920       /* Possibly change current free list. */
921       if (fi0 != fi && fi1 != fi)
922         {
923           fi = fi1;
924           fl = pool_elt_at_index (bm->buffer_free_list_pool, fi);
925         }
926
927       vec_add2_aligned (fl->aligned_buffers, f, n_left,
928                         /* align */ sizeof (vlib_copy_unit_t));
929     }
930
931   while (n_left >= 1)
932     {
933       vlib_buffer_t *b0, *binit0, dummy_buffers[1];
934
935       bi0 = b[0];
936       f[0] = bi0;
937       f += 1;
938       b += 1;
939       n_left -= 1;
940
941       b0 = vlib_get_buffer (vm, bi0);
942
943       free0 = (b0->flags & VLIB_BUFFER_RECYCLE) == 0;
944
945       /* Must be before init which will over-write buffer flags. */
946       if (follow_buffer_next)
947         {
948           n[0] = b0->next_buffer;
949           free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
950           n += free_next0;
951         }
952       else
953         free_next0 = 0;
954
955       /* Must be before init which will over-write buffer free list. */
956       fi0 = b0->free_list_index;
957
958       if (PREDICT_FALSE (fi0 != fi))
959         goto slow_path_x1;
960
961       binit0 = free0 ? b0 : &dummy_buffers[0];
962
963       vlib_buffer_init_for_free_list (binit0, fl);
964       continue;
965
966     slow_path_x1:
967       /* Backup speculation. */
968       f -= 1;
969       n -= free_next0;
970
971       _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
972
973       fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
974
975       vlib_buffer_add_to_free_list (vm, fl0, bi0, free0);
976       if (PREDICT_FALSE (fl0->buffers_added_to_freelist_function != 0))
977         {
978           int i;
979           for (i = 0; i < vec_len (announce_list); i++)
980             if (fl0 == announce_list[i])
981               goto no_fl00;
982           vec_add1 (announce_list, fl0);
983         }
984
985     no_fl00:
986       fi = fi0;
987       fl = pool_elt_at_index (bm->buffer_free_list_pool, fi);
988
989       vec_add2_aligned (fl->aligned_buffers, f, n_left,
990                         /* align */ sizeof (vlib_copy_unit_t));
991     }
992
993   if (follow_buffer_next && ((n_left = n - next_to_free[i_next_to_free]) > 0))
994     {
995       b = next_to_free[i_next_to_free];
996       i_next_to_free ^= 1;
997       goto again;
998     }
999
1000   _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
1001
1002   if (vec_len (announce_list))
1003     {
1004       vlib_buffer_free_list_t *fl;
1005       for (i = 0; i < vec_len (announce_list); i++)
1006         {
1007           fl = announce_list[i];
1008           fl->buffers_added_to_freelist_function (vm, fl);
1009         }
1010       _vec_len (announce_list) = 0;
1011     }
1012 }
1013
1014 static void
1015 vlib_buffer_free_internal (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
1016 {
1017   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
1018                            1);
1019 }
1020
1021 static void
1022 vlib_buffer_free_no_next_internal (vlib_main_t * vm, u32 * buffers,
1023                                    u32 n_buffers)
1024 {
1025   vlib_buffer_free_inline (vm, buffers, n_buffers,      /* follow_buffer_next */
1026                            0);
1027 }
1028
1029 /* Copy template packet data into buffers as they are allocated. */
1030 static void __attribute__ ((unused))
1031 vlib_packet_template_buffer_init (vlib_main_t * vm,
1032                                   vlib_buffer_free_list_t * fl,
1033                                   u32 * buffers, u32 n_buffers)
1034 {
1035   vlib_packet_template_t *t =
1036     uword_to_pointer (fl->buffer_init_function_opaque,
1037                       vlib_packet_template_t *);
1038   uword i;
1039
1040   for (i = 0; i < n_buffers; i++)
1041     {
1042       vlib_buffer_t *b = vlib_get_buffer (vm, buffers[i]);
1043       ASSERT (b->current_length == vec_len (t->packet_data));
1044       clib_memcpy (vlib_buffer_get_current (b), t->packet_data,
1045                    b->current_length);
1046     }
1047 }
1048
1049 void
1050 vlib_packet_template_init (vlib_main_t * vm,
1051                            vlib_packet_template_t * t,
1052                            void *packet_data,
1053                            uword n_packet_data_bytes,
1054                            uword min_n_buffers_each_physmem_alloc,
1055                            char *fmt, ...)
1056 {
1057   vlib_buffer_main_t *bm = vm->buffer_main;
1058   va_list va;
1059   __attribute__ ((unused)) u8 *name;
1060   vlib_buffer_free_list_t *fl;
1061
1062   va_start (va, fmt);
1063   name = va_format (0, fmt, &va);
1064   va_end (va);
1065
1066   if (bm->cb.vlib_packet_template_init_cb)
1067     bm->cb.vlib_packet_template_init_cb (vm, (void *) t, packet_data,
1068                                          n_packet_data_bytes,
1069                                          min_n_buffers_each_physmem_alloc,
1070                                          name);
1071
1072   vlib_worker_thread_barrier_sync (vm);
1073
1074   memset (t, 0, sizeof (t[0]));
1075
1076   vec_add (t->packet_data, packet_data, n_packet_data_bytes);
1077   t->min_n_buffers_each_physmem_alloc = min_n_buffers_each_physmem_alloc;
1078
1079   t->free_list_index = vlib_buffer_create_free_list_helper
1080     (vm, n_packet_data_bytes,
1081      /* is_public */ 1,
1082      /* is_default */ 0,
1083      name);
1084
1085   ASSERT (t->free_list_index != 0);
1086   fl = vlib_buffer_get_free_list (vm, t->free_list_index);
1087   fl->min_n_buffers_each_physmem_alloc = t->min_n_buffers_each_physmem_alloc;
1088
1089   fl->buffer_init_function = vlib_packet_template_buffer_init;
1090   fl->buffer_init_function_opaque = pointer_to_uword (t);
1091
1092   fl->buffer_init_template.current_data = 0;
1093   fl->buffer_init_template.current_length = n_packet_data_bytes;
1094   fl->buffer_init_template.flags = 0;
1095   vlib_worker_thread_barrier_release (vm);
1096 }
1097
1098 void *
1099 vlib_packet_template_get_packet (vlib_main_t * vm,
1100                                  vlib_packet_template_t * t, u32 * bi_result)
1101 {
1102   u32 bi;
1103   vlib_buffer_t *b;
1104
1105   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
1106     return 0;
1107
1108   *bi_result = bi;
1109
1110   b = vlib_get_buffer (vm, bi);
1111   clib_memcpy (vlib_buffer_get_current (b),
1112                t->packet_data, vec_len (t->packet_data));
1113   b->current_length = vec_len (t->packet_data);
1114
1115   return b->data;
1116 }
1117
1118 void
1119 vlib_packet_template_get_packet_helper (vlib_main_t * vm,
1120                                         vlib_packet_template_t * t)
1121 {
1122   word n = t->min_n_buffers_each_physmem_alloc;
1123   word l = vec_len (t->packet_data);
1124   word n_alloc;
1125
1126   ASSERT (l > 0);
1127   ASSERT (vec_len (t->free_buffers) == 0);
1128
1129   vec_validate (t->free_buffers, n - 1);
1130   n_alloc = vlib_buffer_alloc_from_free_list (vm, t->free_buffers,
1131                                               n, t->free_list_index);
1132   _vec_len (t->free_buffers) = n_alloc;
1133 }
1134
1135 /* Append given data to end of buffer, possibly allocating new buffers. */
1136 u32
1137 vlib_buffer_add_data (vlib_main_t * vm,
1138                       u32 free_list_index,
1139                       u32 buffer_index, void *data, u32 n_data_bytes)
1140 {
1141   u32 n_buffer_bytes, n_left, n_left_this_buffer, bi;
1142   vlib_buffer_t *b;
1143   void *d;
1144
1145   bi = buffer_index;
1146   if (bi == 0
1147       && 1 != vlib_buffer_alloc_from_free_list (vm, &bi, 1, free_list_index))
1148     goto out_of_buffers;
1149
1150   d = data;
1151   n_left = n_data_bytes;
1152   n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
1153
1154   b = vlib_get_buffer (vm, bi);
1155   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1156
1157   /* Get to the end of the chain before we try to append data... */
1158   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1159     b = vlib_get_buffer (vm, b->next_buffer);
1160
1161   while (1)
1162     {
1163       u32 n;
1164
1165       ASSERT (n_buffer_bytes >= b->current_length);
1166       n_left_this_buffer =
1167         n_buffer_bytes - (b->current_data + b->current_length);
1168       n = clib_min (n_left_this_buffer, n_left);
1169       clib_memcpy (vlib_buffer_get_current (b) + b->current_length, d, n);
1170       b->current_length += n;
1171       n_left -= n;
1172       if (n_left == 0)
1173         break;
1174
1175       d += n;
1176       if (1 !=
1177           vlib_buffer_alloc_from_free_list (vm, &b->next_buffer, 1,
1178                                             free_list_index))
1179         goto out_of_buffers;
1180
1181       b->flags |= VLIB_BUFFER_NEXT_PRESENT;
1182
1183       b = vlib_get_buffer (vm, b->next_buffer);
1184     }
1185
1186   return bi;
1187
1188 out_of_buffers:
1189   clib_error ("out of buffers");
1190   return bi;
1191 }
1192
1193 u16
1194 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
1195                                           u32 free_list_index,
1196                                           vlib_buffer_t * first,
1197                                           vlib_buffer_t ** last,
1198                                           void *data, u16 data_len)
1199 {
1200   vlib_buffer_t *l = *last;
1201   u32 n_buffer_bytes =
1202     vlib_buffer_free_list_buffer_size (vm, free_list_index);
1203   u16 copied = 0;
1204   ASSERT (n_buffer_bytes >= l->current_length + l->current_data);
1205   while (data_len)
1206     {
1207       u16 max = n_buffer_bytes - l->current_length - l->current_data;
1208       if (max == 0)
1209         {
1210           if (1 !=
1211               vlib_buffer_alloc_from_free_list (vm, &l->next_buffer, 1,
1212                                                 free_list_index))
1213             return copied;
1214           *last = l = vlib_buffer_chain_buffer (vm, first, l, l->next_buffer);
1215           max = n_buffer_bytes - l->current_length - l->current_data;
1216         }
1217
1218       u16 len = (data_len > max) ? max : data_len;
1219       clib_memcpy (vlib_buffer_get_current (l) + l->current_length,
1220                    data + copied, len);
1221       vlib_buffer_chain_increase_length (first, l, len);
1222       data_len -= len;
1223       copied += len;
1224     }
1225   return copied;
1226 }
1227
1228
1229 static u8 *
1230 format_vlib_buffer_free_list (u8 * s, va_list * va)
1231 {
1232   vlib_buffer_free_list_t *f = va_arg (*va, vlib_buffer_free_list_t *);
1233   u32 threadnum = va_arg (*va, u32);
1234   uword bytes_alloc, bytes_free, n_free, size;
1235
1236   if (!f)
1237     return format (s, "%=7s%=30s%=12s%=12s%=12s%=12s%=12s%=12s",
1238                    "Thread", "Name", "Index", "Size", "Alloc", "Free",
1239                    "#Alloc", "#Free");
1240
1241   size = sizeof (vlib_buffer_t) + f->n_data_bytes;
1242   n_free = vec_len (f->aligned_buffers) + vec_len (f->unaligned_buffers);
1243   bytes_alloc = size * f->n_alloc;
1244   bytes_free = size * n_free;
1245
1246   s = format (s, "%7d%30s%12d%12d%=12U%=12U%=12d%=12d", threadnum,
1247               f->name, f->index, f->n_data_bytes,
1248               format_memory_size, bytes_alloc,
1249               format_memory_size, bytes_free, f->n_alloc, n_free);
1250
1251   return s;
1252 }
1253
1254 static clib_error_t *
1255 show_buffers (vlib_main_t * vm,
1256               unformat_input_t * input, vlib_cli_command_t * cmd)
1257 {
1258   vlib_buffer_main_t *bm;
1259   vlib_buffer_free_list_t *f;
1260   vlib_main_t *curr_vm;
1261   u32 vm_index = 0;
1262
1263   vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, 0, 0);
1264
1265   do
1266     {
1267       curr_vm = vec_len (vlib_mains) ? vlib_mains[vm_index] : vm;
1268       bm = curr_vm->buffer_main;
1269
1270     /* *INDENT-OFF* */
1271     pool_foreach (f, bm->buffer_free_list_pool, ({
1272       vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, f, vm_index);
1273     }));
1274     /* *INDENT-ON* */
1275
1276       vm_index++;
1277     }
1278   while (vm_index < vec_len (vlib_mains));
1279
1280   return 0;
1281 }
1282
1283 /* *INDENT-OFF* */
1284 VLIB_CLI_COMMAND (show_buffers_command, static) = {
1285   .path = "show buffers",
1286   .short_help = "Show packet buffer allocation",
1287   .function = show_buffers,
1288 };
1289 /* *INDENT-ON* */
1290
1291 void
1292 vlib_buffer_cb_init (struct vlib_main_t *vm)
1293 {
1294   vlib_buffer_main_t *bm = vm->buffer_main;
1295   bm->cb.vlib_buffer_alloc_cb = &vlib_buffer_alloc_internal;
1296   bm->cb.vlib_buffer_alloc_from_free_list_cb =
1297     &vlib_buffer_alloc_from_free_list_internal;
1298   bm->cb.vlib_buffer_free_cb = &vlib_buffer_free_internal;
1299   bm->cb.vlib_buffer_free_no_next_cb = &vlib_buffer_free_no_next_internal;
1300   bm->cb.vlib_buffer_delete_free_list_cb =
1301     &vlib_buffer_delete_free_list_internal;
1302   bm->extern_buffer_mgmt = 0;
1303 }
1304
1305 int
1306 vlib_buffer_cb_register (struct vlib_main_t *vm, vlib_buffer_callbacks_t * cb)
1307 {
1308   vlib_buffer_main_t *bm = vm->buffer_main;
1309   if (bm->extern_buffer_mgmt)
1310     return -1;
1311
1312 #define _(x) bm->cb.x = cb->x
1313   _(vlib_buffer_alloc_cb);
1314   _(vlib_buffer_alloc_from_free_list_cb);
1315   _(vlib_buffer_free_cb);
1316   _(vlib_buffer_free_no_next_cb);
1317   _(vlib_buffer_delete_free_list_cb);
1318 #undef _
1319   bm->extern_buffer_mgmt = 1;
1320   return 0;
1321 }
1322
1323 /** @endcond */
1324 /*
1325  * fd.io coding-style-patch-verification: ON
1326  *
1327  * Local Variables:
1328  * eval: (c-set-style "gnu")
1329  * End:
1330  */