http: fix client parse error handling
[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 <vppinfra/bitmap.h>
47 #include <vppinfra/unix.h>
48 #include <vlib/vlib.h>
49 #include <vlib/unix/unix.h>
50 #include <vlib/stats/stats.h>
51
52 #define VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA 16384
53 #define VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA_UNPRIV 8192
54
55 #ifdef CLIB_HAVE_VEC128
56 /* Assumptions by vlib_buffer_free_inline: */
57 STATIC_ASSERT_FITS_IN (vlib_buffer_t, flags, 16);
58 STATIC_ASSERT_FITS_IN (vlib_buffer_t, ref_count, 16);
59 STATIC_ASSERT_FITS_IN (vlib_buffer_t, buffer_pool_index, 16);
60 #endif
61
62 u16 __vlib_buffer_external_hdr_size = 0;
63
64 uword
65 vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
66                                        vlib_buffer_t * b_first)
67 {
68   vlib_buffer_t *b = b_first;
69   uword l_first = b_first->current_length;
70   uword l = 0;
71   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
72     {
73       b = vlib_get_buffer (vm, b->next_buffer);
74       l += b->current_length;
75     }
76   b_first->total_length_not_including_first_buffer = l;
77   b_first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
78   return l + l_first;
79 }
80
81 u8 *
82 format_vlib_buffer_no_chain (u8 * s, va_list * args)
83 {
84   vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
85   u32 indent = format_get_indent (s);
86   u8 *a = 0;
87
88 #define _(bit, name, v) \
89   if (v && (b->flags & VLIB_BUFFER_##name)) \
90     a = format (a, "%s ", v);
91   foreach_vlib_buffer_flag
92 #undef _
93     s = format (s, "current data %d, length %d, buffer-pool %d, "
94                 "ref-count %u", b->current_data, b->current_length,
95                 b->buffer_pool_index, b->ref_count);
96
97   if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
98     s = format (s, ", totlen-nifb %d",
99                 b->total_length_not_including_first_buffer);
100
101   if (b->flags & VLIB_BUFFER_IS_TRACED)
102     s = format (s, ", trace handle 0x%x", b->trace_handle);
103
104   if (a)
105     s = format (s, "\n%U%v", format_white_space, indent, a);
106   vec_free (a);
107
108   return s;
109 }
110
111 u8 *
112 format_vlib_buffer (u8 * s, va_list * args)
113 {
114   vlib_main_t *vm = vlib_get_main ();
115   vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
116   u32 indent = format_get_indent (s);
117
118   s = format (s, "%U", format_vlib_buffer_no_chain, b);
119
120   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
121     {
122       u32 next_buffer = b->next_buffer;
123       b = vlib_get_buffer (vm, next_buffer);
124
125       s =
126         format (s, "\n%Unext-buffer 0x%x, segment length %d, ref-count %u",
127                 format_white_space, indent, next_buffer, b->current_length,
128                 b->ref_count);
129     }
130
131   return s;
132 }
133
134 u8 *
135 format_vlib_buffer_and_data (u8 * s, va_list * args)
136 {
137   vlib_buffer_t *b = va_arg (*args, vlib_buffer_t *);
138
139   s = format (s, "%U, %U",
140               format_vlib_buffer, b,
141               format_hex_bytes, vlib_buffer_get_current (b), 64);
142
143   return s;
144 }
145
146 static u8 *
147 format_vlib_buffer_known_state (u8 * s, va_list * args)
148 {
149   vlib_buffer_known_state_t state = va_arg (*args, vlib_buffer_known_state_t);
150   char *t;
151
152   switch (state)
153     {
154     case VLIB_BUFFER_UNKNOWN:
155       t = "unknown";
156       break;
157
158     case VLIB_BUFFER_KNOWN_ALLOCATED:
159       t = "known-allocated";
160       break;
161
162     case VLIB_BUFFER_KNOWN_FREE:
163       t = "known-free";
164       break;
165
166     default:
167       t = "invalid";
168       break;
169     }
170
171   return format (s, "%s", t);
172 }
173
174 u8 *
175 format_vlib_buffer_contents (u8 * s, va_list * va)
176 {
177   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
178   vlib_buffer_t *b = va_arg (*va, vlib_buffer_t *);
179
180   while (1)
181     {
182       vec_add (s, vlib_buffer_get_current (b), b->current_length);
183       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
184         break;
185       b = vlib_get_buffer (vm, b->next_buffer);
186     }
187
188   return s;
189 }
190
191 static u8 *
192 vlib_validate_buffer_helper (vlib_main_t * vm,
193                              u32 bi,
194                              uword follow_buffer_next, uword ** unique_hash)
195 {
196   vlib_buffer_main_t *bm = vm->buffer_main;
197   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
198
199   if (vec_len (bm->buffer_pools) <= b->buffer_pool_index)
200     return format (0, "unknown buffer pool 0x%x", b->buffer_pool_index);
201
202   if ((signed) b->current_data < (signed) -VLIB_BUFFER_PRE_DATA_SIZE)
203     return format (0, "current data %d before pre-data", b->current_data);
204
205   if (b->current_data + b->current_length >
206       vlib_buffer_get_default_data_size (vm))
207     return format (0, "%d-%d beyond end of buffer %d", b->current_data,
208                    b->current_length, vlib_buffer_get_default_data_size (vm));
209
210   if (follow_buffer_next && (b->flags & VLIB_BUFFER_NEXT_PRESENT))
211     {
212       vlib_buffer_known_state_t k;
213       u8 *msg, *result;
214
215       k = vlib_buffer_is_known (vm, b->next_buffer);
216       if (k != VLIB_BUFFER_KNOWN_ALLOCATED)
217         return format (0, "next 0x%x: %U",
218                        b->next_buffer, format_vlib_buffer_known_state, k);
219
220       if (unique_hash)
221         {
222           if (hash_get (*unique_hash, b->next_buffer))
223             return format (0, "duplicate buffer 0x%x", b->next_buffer);
224
225           hash_set1 (*unique_hash, b->next_buffer);
226         }
227
228       msg = vlib_validate_buffer (vm, b->next_buffer, follow_buffer_next);
229       if (msg)
230         {
231           result = format (0, "next 0x%x: %v", b->next_buffer, msg);
232           vec_free (msg);
233           return result;
234         }
235     }
236
237   return 0;
238 }
239
240 u8 *
241 vlib_validate_buffer (vlib_main_t * vm, u32 bi, uword follow_buffer_next)
242 {
243   return vlib_validate_buffer_helper (vm, bi, follow_buffer_next,
244                                       /* unique_hash */ 0);
245 }
246
247 u8 *
248 vlib_validate_buffers (vlib_main_t * vm,
249                        u32 * buffers,
250                        uword next_buffer_stride,
251                        uword n_buffers,
252                        vlib_buffer_known_state_t known_state,
253                        uword follow_buffer_next)
254 {
255   uword i, *hash;
256   u32 bi, *b = buffers;
257   vlib_buffer_known_state_t k;
258   u8 *msg = 0, *result = 0;
259
260   hash = hash_create (0, 0);
261   for (i = 0; i < n_buffers; i++)
262     {
263       bi = b[0];
264       b += next_buffer_stride;
265
266       /* Buffer is not unique. */
267       if (hash_get (hash, bi))
268         {
269           msg = format (0, "not unique");
270           goto done;
271         }
272
273       k = vlib_buffer_is_known (vm, bi);
274       if (k != known_state)
275         {
276           msg = format (0, "is %U; expected %U",
277                         format_vlib_buffer_known_state, k,
278                         format_vlib_buffer_known_state, known_state);
279           goto done;
280         }
281
282       msg = vlib_validate_buffer_helper (vm, bi, follow_buffer_next, &hash);
283       if (msg)
284         goto done;
285
286       hash_set1 (hash, bi);
287     }
288
289 done:
290   if (msg)
291     {
292       result = format (0, "0x%x: %v", bi, msg);
293       vec_free (msg);
294     }
295   hash_free (hash);
296   return result;
297 }
298
299 /* When debugging validate that given buffers are either known allocated
300    or known free. */
301 void
302 vlib_buffer_validate_alloc_free (vlib_main_t * vm,
303                                  u32 * buffers,
304                                  uword n_buffers,
305                                  vlib_buffer_known_state_t expected_state)
306 {
307   vlib_buffer_main_t *bm = vm->buffer_main;
308   u32 *b;
309   uword i, bi, is_free;
310
311   if (CLIB_DEBUG == 0)
312     return;
313
314   is_free = expected_state == VLIB_BUFFER_KNOWN_ALLOCATED;
315   b = buffers;
316   for (i = 0; i < n_buffers; i++)
317     {
318       vlib_buffer_known_state_t known;
319
320       bi = b[0];
321       b += 1;
322       known = vlib_buffer_is_known (vm, bi);
323
324       if (known == VLIB_BUFFER_UNKNOWN &&
325           expected_state == VLIB_BUFFER_KNOWN_FREE)
326         known = VLIB_BUFFER_KNOWN_FREE;
327
328       if (known != expected_state)
329         {
330           clib_panic ("%s %U buffer 0x%x", is_free ? "freeing" : "allocating",
331                       format_vlib_buffer_known_state, known, bi);
332         }
333
334       clib_spinlock_lock (&bm->buffer_known_hash_lockp);
335       hash_set (bm->buffer_known_hash, bi, is_free ? VLIB_BUFFER_KNOWN_FREE :
336                 VLIB_BUFFER_KNOWN_ALLOCATED);
337       clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
338     }
339 }
340
341 void
342 vlib_packet_template_init (vlib_main_t * vm,
343                            vlib_packet_template_t * t,
344                            void *packet_data,
345                            uword n_packet_data_bytes,
346                            uword min_n_buffers_each_alloc, char *fmt, ...)
347 {
348   va_list va;
349
350   va_start (va, fmt);
351   t->name = va_format (0, fmt, &va);
352   va_end (va);
353
354   vlib_worker_thread_barrier_sync (vm);
355
356   clib_memset (t, 0, sizeof (t[0]));
357
358   vec_add (t->packet_data, packet_data, n_packet_data_bytes);
359   t->min_n_buffers_each_alloc = min_n_buffers_each_alloc;
360   vlib_worker_thread_barrier_release (vm);
361 }
362
363 void *
364 vlib_packet_template_get_packet (vlib_main_t * vm,
365                                  vlib_packet_template_t * t, u32 * bi_result)
366 {
367   u32 bi;
368   vlib_buffer_t *b;
369
370   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
371     return 0;
372
373   *bi_result = bi;
374
375   b = vlib_get_buffer (vm, bi);
376   clib_memcpy_fast (vlib_buffer_get_current (b),
377                     t->packet_data, vec_len (t->packet_data));
378   b->current_length = vec_len (t->packet_data);
379
380   return b->data;
381 }
382
383 /* Append given data to end of buffer, possibly allocating new buffers. */
384 int
385 vlib_buffer_add_data (vlib_main_t * vm, u32 * buffer_index, void *data,
386                       u32 n_data_bytes)
387 {
388   u32 n_buffer_bytes, n_left, n_left_this_buffer, bi;
389   vlib_buffer_t *b;
390   void *d;
391
392   bi = *buffer_index;
393   if (bi == ~0 && 1 != vlib_buffer_alloc (vm, &bi, 1))
394     goto out_of_buffers;
395
396   d = data;
397   n_left = n_data_bytes;
398   n_buffer_bytes = vlib_buffer_get_default_data_size (vm);
399
400   b = vlib_get_buffer (vm, bi);
401   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
402
403   /* Get to the end of the chain before we try to append data... */
404   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
405     b = vlib_get_buffer (vm, b->next_buffer);
406
407   while (1)
408     {
409       u32 n;
410
411       ASSERT (n_buffer_bytes >= b->current_length);
412       n_left_this_buffer =
413         n_buffer_bytes - (b->current_data + b->current_length);
414       n = clib_min (n_left_this_buffer, n_left);
415       clib_memcpy_fast (vlib_buffer_get_current (b) + b->current_length, d,
416                         n);
417       b->current_length += n;
418       n_left -= n;
419       if (n_left == 0)
420         break;
421
422       d += n;
423       if (1 != vlib_buffer_alloc (vm, &b->next_buffer, 1))
424         goto out_of_buffers;
425
426       b->flags |= VLIB_BUFFER_NEXT_PRESENT;
427
428       b = vlib_get_buffer (vm, b->next_buffer);
429     }
430
431   *buffer_index = bi;
432   return 0;
433
434 out_of_buffers:
435   clib_warning ("out of buffers");
436   return 1;
437 }
438
439 u16
440 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
441                                           vlib_buffer_t * first,
442                                           vlib_buffer_t ** last, void *data,
443                                           u16 data_len)
444 {
445   vlib_buffer_t *l = *last;
446   u32 n_buffer_bytes = vlib_buffer_get_default_data_size (vm);
447   u16 copied = 0;
448   ASSERT (n_buffer_bytes >= l->current_length + l->current_data);
449   while (data_len)
450     {
451       u16 max = n_buffer_bytes - l->current_length - l->current_data;
452       if (max == 0)
453         {
454           if (1 != vlib_buffer_alloc_from_pool (vm, &l->next_buffer, 1,
455                                                 first->buffer_pool_index))
456             return copied;
457           *last = l = vlib_buffer_chain_buffer (vm, l, l->next_buffer);
458           max = n_buffer_bytes - l->current_length - l->current_data;
459         }
460
461       u16 len = (data_len > max) ? max : data_len;
462       clib_memcpy_fast (vlib_buffer_get_current (l) + l->current_length,
463                         data + copied, len);
464       vlib_buffer_chain_increase_length (first, l, len);
465       data_len -= len;
466       copied += len;
467     }
468   return copied;
469 }
470
471 static uword
472 vlib_buffer_alloc_size (uword ext_hdr_size, uword data_size)
473 {
474   uword alloc_size = ext_hdr_size + sizeof (vlib_buffer_t) + data_size;
475   alloc_size = round_pow2 (alloc_size, VLIB_BUFFER_ALIGN);
476
477   /* in case when we have even number of 'cachelines', we add one more for
478    * better cache occupancy */
479   alloc_size |= VLIB_BUFFER_ALIGN;
480
481   return alloc_size;
482 }
483
484 u8
485 vlib_buffer_pool_create (vlib_main_t *vm, u32 data_size, u32 physmem_map_index,
486                          char *fmt, ...)
487 {
488   vlib_buffer_main_t *bm = vm->buffer_main;
489   vlib_buffer_pool_t *bp;
490   vlib_physmem_map_t *m = vlib_physmem_get_map (vm, physmem_map_index);
491   uword start = pointer_to_uword (m->base);
492   uword size = (uword) m->n_pages << m->log2_page_size;
493   uword page_mask = ~pow2_mask (m->log2_page_size);
494   u8 *p;
495   u32 alloc_size;
496   va_list va;
497
498   if (vec_len (bm->buffer_pools) >= 255)
499     return ~0;
500
501   vec_add2_aligned (bm->buffer_pools, bp, 1, CLIB_CACHE_LINE_BYTES);
502
503   if (bm->buffer_mem_size == 0)
504     {
505       bm->buffer_mem_start = start;
506       bm->buffer_mem_size = size;
507     }
508   else if (start < bm->buffer_mem_start)
509     {
510       bm->buffer_mem_size += bm->buffer_mem_start - start;
511       bm->buffer_mem_start = start;
512       if (size > bm->buffer_mem_size)
513         bm->buffer_mem_size = size;
514     }
515   else if (start > bm->buffer_mem_start)
516     {
517       uword new_size = start - bm->buffer_mem_start + size;
518       if (new_size > bm->buffer_mem_size)
519         bm->buffer_mem_size = new_size;
520     }
521
522   if ((u64) bm->buffer_mem_size >
523       ((u64) 1 << (32 + CLIB_LOG2_CACHE_LINE_BYTES)))
524     {
525       clib_panic ("buffer memory size out of range!");
526     }
527
528   bp->start = start;
529   bp->size = size;
530   bp->index = bp - bm->buffer_pools;
531   bp->buffer_template.buffer_pool_index = bp->index;
532   bp->buffer_template.ref_count = 1;
533   bp->physmem_map_index = physmem_map_index;
534   bp->data_size = data_size;
535   bp->numa_node = m->numa_node;
536   bp->log2_page_size = m->log2_page_size;
537
538   va_start (va, fmt);
539   bp->name = va_format (0, fmt, &va);
540   va_end (va);
541
542   vec_validate_aligned (bp->threads, vlib_get_n_threads () - 1,
543                         CLIB_CACHE_LINE_BYTES);
544
545   alloc_size = vlib_buffer_alloc_size (bm->ext_hdr_size, data_size);
546   bp->alloc_size = alloc_size;
547
548   /* preallocate buffer indices memory */
549   bp->buffers = clib_mem_alloc_aligned (
550     round_pow2 ((size / alloc_size) * sizeof (u32), CLIB_CACHE_LINE_BYTES),
551     CLIB_CACHE_LINE_BYTES);
552
553   clib_spinlock_init (&bp->lock);
554
555   p = m->base;
556
557   /* start with naturally aligned address */
558   p += alloc_size - (uword) p % alloc_size;
559
560   /*
561    * Waste 1 buffer (maximum) so that 0 is never a valid buffer index.
562    * Allows various places to ASSERT (bi != 0). Much easier
563    * than debugging downstream crashes in successor nodes.
564    */
565   if (p == m->base)
566     p += alloc_size;
567
568   for (; p < (u8 *) m->base + size - alloc_size; p += alloc_size)
569     {
570       vlib_buffer_t *b;
571       u32 bi;
572
573       /* skip if buffer spans across page boundary */
574       if (((uword) p & page_mask) != ((uword) (p + alloc_size) & page_mask))
575         continue;
576
577       b = (vlib_buffer_t *) (p + bm->ext_hdr_size);
578       b->template = bp->buffer_template;
579       bi = vlib_get_buffer_index (vm, b);
580       bp->buffers[bp->n_avail++] = bi;
581       vlib_get_buffer (vm, bi);
582     }
583
584   bp->n_buffers = bp->n_avail;
585
586   return bp->index;
587 }
588
589 static u8 *
590 format_vlib_buffer_pool (u8 * s, va_list * va)
591 {
592   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
593   vlib_buffer_pool_t *bp = va_arg (*va, vlib_buffer_pool_t *);
594   vlib_buffer_pool_thread_t *bpt;
595   u32 cached = 0;
596
597   if (!bp)
598     return format (s, "%-20s%=6s%=6s%=6s%=11s%=6s%=8s%=8s%=8s",
599                    "Pool Name", "Index", "NUMA", "Size", "Data Size",
600                    "Total", "Avail", "Cached", "Used");
601
602   vec_foreach (bpt, bp->threads)
603     cached += bpt->n_cached;
604
605   s = format (s, "%-20v%=6d%=6d%=6u%=11u%=6u%=8u%=8u%=8u", bp->name, bp->index,
606               bp->numa_node,
607               bp->data_size + sizeof (vlib_buffer_t) +
608                 vm->buffer_main->ext_hdr_size,
609               bp->data_size, bp->n_buffers, bp->n_avail, cached,
610               bp->n_buffers - bp->n_avail - cached);
611
612   return s;
613 }
614
615 u8 *
616 format_vlib_buffer_pool_all (u8 *s, va_list *va)
617 {
618   vlib_main_t *vm = va_arg (*va, vlib_main_t *);
619   vlib_buffer_main_t *bm = vm->buffer_main;
620   vlib_buffer_pool_t *bp;
621
622   s = format (s, "%U", format_vlib_buffer_pool, vm, 0);
623
624   vec_foreach (bp, bm->buffer_pools)
625     s = format (s, "\n%U", format_vlib_buffer_pool, vm, bp);
626
627   return s;
628 }
629
630 static clib_error_t *
631 show_buffers (vlib_main_t *vm, unformat_input_t *input,
632               vlib_cli_command_t *cmd)
633 {
634   vlib_cli_output (vm, "%U", format_vlib_buffer_pool_all, vm);
635   return 0;
636 }
637
638 VLIB_CLI_COMMAND (show_buffers_command, static) = {
639   .path = "show buffers",
640   .short_help = "Show packet buffer allocation",
641   .function = show_buffers,
642 };
643
644 clib_error_t *
645 vlib_buffer_num_workers_change (vlib_main_t *vm)
646 {
647   vlib_buffer_main_t *bm = vm->buffer_main;
648   vlib_buffer_pool_t *bp;
649
650   vec_foreach (bp, bm->buffer_pools)
651     vec_validate_aligned (bp->threads, vlib_get_n_threads () - 1,
652                           CLIB_CACHE_LINE_BYTES);
653
654   return 0;
655 }
656
657 VLIB_NUM_WORKERS_CHANGE_FN (vlib_buffer_num_workers_change);
658
659 static clib_error_t *
660 vlib_buffer_main_init_numa_alloc (struct vlib_main_t *vm, u32 numa_node,
661                                   u32 * physmem_map_index,
662                                   clib_mem_page_sz_t log2_page_size,
663                                   u8 unpriv)
664 {
665   vlib_buffer_main_t *bm = vm->buffer_main;
666   u32 buffers_per_numa = bm->buffers_per_numa;
667   clib_error_t *error;
668   u32 buffer_size;
669   uword n_pages, pagesize;
670   u8 *name = 0;
671
672   ASSERT (log2_page_size != CLIB_MEM_PAGE_SZ_UNKNOWN);
673
674   pagesize = clib_mem_page_bytes (log2_page_size);
675   buffer_size = vlib_buffer_alloc_size (bm->ext_hdr_size,
676                                         vlib_buffer_get_default_data_size
677                                         (vm));
678   if (buffer_size > pagesize)
679     return clib_error_return (0, "buffer size (%llu) is greater than page "
680                               "size (%llu)", buffer_size, pagesize);
681
682   if (buffers_per_numa == 0)
683     buffers_per_numa = unpriv ? VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA_UNPRIV :
684       VLIB_BUFFER_DEFAULT_BUFFERS_PER_NUMA;
685
686   name = format (0, "buffers-numa-%d%c", numa_node, 0);
687   n_pages = (buffers_per_numa - 1) / (pagesize / buffer_size) + 1;
688   error = vlib_physmem_shared_map_create (vm, (char *) name,
689                                           n_pages * pagesize,
690                                           min_log2 (pagesize), numa_node,
691                                           physmem_map_index);
692   vec_free (name);
693   return error;
694 }
695
696 static clib_error_t *
697 vlib_buffer_main_init_numa_node (struct vlib_main_t *vm, u32 numa_node,
698                                  u8 * index)
699 {
700   vlib_buffer_main_t *bm = vm->buffer_main;
701   u32 physmem_map_index;
702   clib_error_t *error;
703
704   if (bm->log2_page_size == CLIB_MEM_PAGE_SZ_UNKNOWN)
705     {
706       error = vlib_buffer_main_init_numa_alloc (vm, numa_node,
707                                                 &physmem_map_index,
708                                                 CLIB_MEM_PAGE_SZ_DEFAULT_HUGE,
709                                                 0 /* unpriv */ );
710       if (!error)
711         goto buffer_pool_create;
712
713       /* If alloc failed, retry without hugepages */
714       vlib_log_warn (bm->log_default,
715                      "numa[%u] falling back to non-hugepage backed "
716                      "buffer pool (%U)", numa_node, format_clib_error, error);
717       clib_error_free (error);
718
719       error = vlib_buffer_main_init_numa_alloc (vm, numa_node,
720                                                 &physmem_map_index,
721                                                 CLIB_MEM_PAGE_SZ_DEFAULT,
722                                                 1 /* unpriv */ );
723     }
724   else
725     error = vlib_buffer_main_init_numa_alloc (vm, numa_node,
726                                               &physmem_map_index,
727                                               bm->log2_page_size,
728                                               0 /* unpriv */ );
729   if (error)
730     return error;
731
732 buffer_pool_create:
733   *index =
734     vlib_buffer_pool_create (vm, vlib_buffer_get_default_data_size (vm),
735                              physmem_map_index, "default-numa-%d", numa_node);
736
737   if (*index == (u8) ~ 0)
738     error = clib_error_return (0, "maximum number of buffer pools reached");
739
740
741   return error;
742 }
743
744 void
745 vlib_buffer_main_alloc (vlib_main_t * vm)
746 {
747   vlib_buffer_main_t *bm;
748
749   if (vm->buffer_main)
750     return;
751
752   vm->buffer_main = bm = clib_mem_alloc (sizeof (bm[0]));
753   clib_memset (vm->buffer_main, 0, sizeof (bm[0]));
754   bm->default_data_size = VLIB_BUFFER_DEFAULT_DATA_SIZE;
755 }
756
757 static u32
758 buffer_get_cached (vlib_buffer_pool_t * bp)
759 {
760   u32 cached = 0;
761   vlib_buffer_pool_thread_t *bpt;
762
763   clib_spinlock_lock (&bp->lock);
764
765   vec_foreach (bpt, bp->threads)
766     cached += bpt->n_cached;
767
768   clib_spinlock_unlock (&bp->lock);
769
770   return cached;
771 }
772
773 static vlib_buffer_pool_t *
774 buffer_get_by_index (vlib_buffer_main_t * bm, u32 index)
775 {
776   vlib_buffer_pool_t *bp;
777   if (!bm->buffer_pools || vec_len (bm->buffer_pools) < index)
778     return 0;
779   bp = vec_elt_at_index (bm->buffer_pools, index);
780
781   return bp;
782 }
783
784 static void
785 buffer_gauges_collect_used_fn (vlib_stats_collector_data_t *d)
786 {
787   vlib_main_t *vm = vlib_get_main ();
788   vlib_buffer_pool_t *bp =
789     buffer_get_by_index (vm->buffer_main, d->private_data);
790   if (!bp)
791     return;
792
793   d->entry->value = bp->n_buffers - bp->n_avail - buffer_get_cached (bp);
794 }
795
796 static void
797 buffer_gauges_collect_available_fn (vlib_stats_collector_data_t *d)
798 {
799   vlib_main_t *vm = vlib_get_main ();
800   vlib_buffer_pool_t *bp =
801     buffer_get_by_index (vm->buffer_main, d->private_data);
802   if (!bp)
803     return;
804
805   d->entry->value = bp->n_avail;
806 }
807
808 static void
809 buffer_gauges_collect_cached_fn (vlib_stats_collector_data_t *d)
810 {
811   vlib_main_t *vm = vlib_get_main ();
812   vlib_buffer_pool_t *bp =
813     buffer_get_by_index (vm->buffer_main, d->private_data);
814   if (!bp)
815     return;
816
817   d->entry->value = buffer_get_cached (bp);
818 }
819
820 clib_error_t *
821 vlib_buffer_main_init (struct vlib_main_t * vm)
822 {
823   vlib_buffer_main_t *bm;
824   clib_error_t *err;
825   clib_bitmap_t *bmp = 0, *bmp_has_memory = 0;
826   u32 numa_node;
827   vlib_buffer_pool_t *bp;
828   u8 *name = 0, first_valid_buffer_pool_index = ~0;
829
830   vlib_buffer_main_alloc (vm);
831
832   bm = vm->buffer_main;
833   bm->log_default = vlib_log_register_class ("buffer", 0);
834   bm->ext_hdr_size = __vlib_buffer_external_hdr_size;
835
836   clib_spinlock_init (&bm->buffer_known_hash_lockp);
837
838   bmp = os_get_online_cpu_node_bitmap ();
839   bmp_has_memory = os_get_cpu_with_memory_bitmap ();
840
841   if (bmp && bmp_has_memory)
842     bmp = clib_bitmap_and (bmp, bmp_has_memory);
843
844   /* no info from sysfs, assuming that only numa 0 exists */
845   if (bmp == 0)
846     bmp = clib_bitmap_set (bmp, 0, 1);
847
848   if (clib_bitmap_last_set (bmp) >= VLIB_BUFFER_MAX_NUMA_NODES)
849     clib_panic ("system have more than %u NUMA nodes",
850                 VLIB_BUFFER_MAX_NUMA_NODES);
851
852   clib_bitmap_foreach (numa_node, bmp)
853     {
854       u8 *index = bm->default_buffer_pool_index_for_numa + numa_node;
855       index[0] = ~0;
856       if ((err = vlib_buffer_main_init_numa_node (vm, numa_node, index)))
857         {
858           clib_error_report (err);
859           clib_error_free (err);
860           continue;
861         }
862
863       if (first_valid_buffer_pool_index == 0xff)
864         first_valid_buffer_pool_index = index[0];
865     }
866
867   if (first_valid_buffer_pool_index == (u8) ~ 0)
868     {
869       err = clib_error_return (0, "failed to allocate buffer pool(s)");
870       goto done;
871     }
872
873   clib_bitmap_foreach (numa_node, bmp)
874     {
875       if (bm->default_buffer_pool_index_for_numa[numa_node]  == (u8) ~0)
876         bm->default_buffer_pool_index_for_numa[numa_node] =
877           first_valid_buffer_pool_index;
878     }
879
880   vec_foreach (bp, bm->buffer_pools)
881   {
882     vlib_stats_collector_reg_t reg = { .private_data = bp - bm->buffer_pools };
883     if (bp->n_buffers == 0)
884       continue;
885
886     reg.entry_index =
887       vlib_stats_add_gauge ("/buffer-pools/%v/cached", bp->name);
888     reg.collect_fn = buffer_gauges_collect_cached_fn;
889     vlib_stats_register_collector_fn (&reg);
890
891     reg.entry_index = vlib_stats_add_gauge ("/buffer-pools/%v/used", bp->name);
892     reg.collect_fn = buffer_gauges_collect_used_fn;
893     vlib_stats_register_collector_fn (&reg);
894
895     reg.entry_index =
896       vlib_stats_add_gauge ("/buffer-pools/%v/available", bp->name);
897     reg.collect_fn = buffer_gauges_collect_available_fn;
898     vlib_stats_register_collector_fn (&reg);
899   }
900
901 done:
902   vec_free (bmp);
903   vec_free (bmp_has_memory);
904   vec_free (name);
905   return err;
906 }
907
908 static clib_error_t *
909 vlib_buffers_configure (vlib_main_t * vm, unformat_input_t * input)
910 {
911   vlib_buffer_main_t *bm;
912
913   vlib_buffer_main_alloc (vm);
914
915   bm = vm->buffer_main;
916   bm->log2_page_size = CLIB_MEM_PAGE_SZ_UNKNOWN;
917
918   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
919     {
920       if (unformat (input, "buffers-per-numa %u", &bm->buffers_per_numa))
921         ;
922       else if (unformat (input, "page-size %U", unformat_log2_page_size,
923                          &bm->log2_page_size))
924         ;
925       else if (unformat (input, "default data-size %u",
926                          &bm->default_data_size))
927         ;
928       else
929         return unformat_parse_error (input);
930     }
931
932   unformat_free (input);
933   return 0;
934 }
935
936 VLIB_EARLY_CONFIG_FUNCTION (vlib_buffers_configure, "buffers");
937
938 #if VLIB_BUFFER_ALLOC_FAULT_INJECTOR > 0
939 u32
940 vlib_buffer_alloc_may_fail (vlib_main_t * vm, u32 n_buffers)
941 {
942   f64 r;
943
944   r = random_f64 (&vm->buffer_alloc_success_seed);
945
946   /* Fail this request? */
947   if (r > vm->buffer_alloc_success_rate)
948     n_buffers--;
949   /* 5% chance of returning nothing at all */
950   if (r > vm->buffer_alloc_success_rate && r > 0.95)
951     n_buffers = 0;
952
953   return n_buffers;
954 }
955 #endif
956
957 __clib_export int
958 vlib_buffer_set_alloc_free_callback (
959   vlib_main_t *vm, vlib_buffer_alloc_free_callback_t *alloc_callback_fn,
960   vlib_buffer_alloc_free_callback_t *free_callback_fn)
961 {
962   vlib_buffer_main_t *bm = vm->buffer_main;
963   if ((alloc_callback_fn && bm->alloc_callback_fn) ||
964       (free_callback_fn && bm->free_callback_fn))
965     return 1;
966   bm->alloc_callback_fn = alloc_callback_fn;
967   bm->free_callback_fn = free_callback_fn;
968   return 0;
969 }
970
971 /** @endcond */
972 /*
973  * fd.io coding-style-patch-verification: ON
974  *
975  * Local Variables:
976  * eval: (c-set-style "gnu")
977  * End:
978  */