Use rte_mempool private data for storing vlib_buffer_t
[vpp.git] / vlib / vlib / dpdk_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 #include <rte_config.h>
41
42 #include <rte_common.h>
43 #include <rte_log.h>
44 #include <rte_memory.h>
45 #include <rte_memcpy.h>
46 #include <rte_memzone.h>
47 #include <rte_tailq.h>
48 #include <rte_eal.h>
49 #include <rte_per_lcore.h>
50 #include <rte_launch.h>
51 #include <rte_atomic.h>
52 #include <rte_cycles.h>
53 #include <rte_prefetch.h>
54 #include <rte_lcore.h>
55 #include <rte_per_lcore.h>
56 #include <rte_branch_prediction.h>
57 #include <rte_interrupts.h>
58 #include <rte_pci.h>
59 #include <rte_random.h>
60 #include <rte_debug.h>
61 #include <rte_ether.h>
62 #include <rte_ethdev.h>
63 #include <rte_ring.h>
64 #include <rte_mempool.h>
65 #include <rte_mbuf.h>
66
67 #include <vlib/vlib.h>
68
69 #pragma weak rte_mem_virt2phy
70 #pragma weak rte_eal_has_hugepages
71 #pragma weak rte_socket_id
72 #pragma weak rte_pktmbuf_pool_create
73
74 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm, vlib_buffer_t * b_first)
75 {
76   vlib_buffer_t * b = b_first;
77   uword l_first = b_first->current_length;
78   uword l = 0;
79   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
80     {
81       b = vlib_get_buffer (vm, b->next_buffer);
82       l += b->current_length;
83     }
84   b_first->total_length_not_including_first_buffer = l;
85   b_first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
86   return l + l_first;
87 }
88
89 u8 * format_vlib_buffer (u8 * s, va_list * args)
90 {
91   vlib_buffer_t * b = va_arg (*args, vlib_buffer_t *);
92   uword indent = format_get_indent (s);
93
94   s = format (s, "current data %d, length %d, free-list %d",
95               b->current_data, b->current_length,
96               b->free_list_index);
97
98   if (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
99     s = format (s, ", totlen-nifb %d",
100                 b->total_length_not_including_first_buffer);
101
102   if (b->flags & VLIB_BUFFER_IS_TRACED)
103     s = format (s, ", trace 0x%x", b->trace_index);
104
105   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
106     {
107       vlib_main_t * vm = vlib_get_main();
108       u32 next_buffer = b->next_buffer;
109       b = vlib_get_buffer(vm, next_buffer);
110
111       s = format (s, "\n%Unext-buffer 0x%x, segment length %d",
112                   format_white_space, indent, next_buffer, b->current_length);
113     }
114
115
116   return s;
117 }
118
119 u8 * format_vlib_buffer_and_data (u8 * s, va_list * args)
120 {
121   vlib_buffer_t * b = va_arg (*args, vlib_buffer_t *);
122   
123   s = format (s, "%U, %U",
124               format_vlib_buffer, b,
125               format_hex_bytes, vlib_buffer_get_current (b), 64);
126
127   return s;
128 }
129
130 u8 * format_vlib_buffer_contents (u8 * s, va_list * va)
131 {
132   vlib_main_t * vm = va_arg (*va, vlib_main_t *);
133   vlib_buffer_t * b = va_arg (*va, vlib_buffer_t *);
134   
135   while (1)
136     {
137       vec_add (s, vlib_buffer_get_current (b),
138                b->current_length);
139       if (! (b->flags & VLIB_BUFFER_NEXT_PRESENT))
140         break;
141       b = vlib_get_buffer (vm, b->next_buffer);
142     }
143
144   return s;
145 }
146
147 vlib_main_t **vlib_mains;
148
149 /* Aligned copy routine. */
150 void
151 vlib_aligned_memcpy (void * _dst, void * _src, int n_bytes)
152 {
153   vlib_copy_unit_t * dst = _dst;
154   vlib_copy_unit_t * src = _src;
155
156   /* Arguments must be naturally aligned. */
157   ASSERT (pointer_to_uword (dst) % sizeof (dst[0]) == 0);
158   ASSERT (pointer_to_uword (src) % sizeof (src[0]) == 0);
159   ASSERT (n_bytes % sizeof (dst[0]) == 0);
160
161   if (4 * sizeof (dst[0]) == CLIB_CACHE_LINE_BYTES)
162     {
163       CLIB_PREFETCH (dst + 0, 4 * sizeof (dst[0]), WRITE);
164       CLIB_PREFETCH (src + 0, 4 * sizeof (src[0]), READ);
165
166       while (n_bytes >= 4 * sizeof (dst[0]))
167         {
168           dst += 4;
169           src += 4;
170           n_bytes -= 4 * sizeof (dst[0]);
171           CLIB_PREFETCH (dst, 4 * sizeof (dst[0]), WRITE);
172           CLIB_PREFETCH (src, 4 * sizeof (src[0]), READ);
173           dst[-4] = src[-4];
174           dst[-3] = src[-3];
175           dst[-2] = src[-2];
176           dst[-1] = src[-1];
177         }
178     }
179   else if (8 * sizeof (dst[0]) == CLIB_CACHE_LINE_BYTES)
180     {
181       CLIB_PREFETCH (dst + 0, 8 * sizeof (dst[0]), WRITE);
182       CLIB_PREFETCH (src + 0, 8 * sizeof (src[0]), READ);
183
184       while (n_bytes >= 8 * sizeof (dst[0]))
185         {
186           dst += 8;
187           src += 8;
188           n_bytes -= 8 * sizeof (dst[0]);
189           CLIB_PREFETCH (dst, 8 * sizeof (dst[0]), WRITE);
190           CLIB_PREFETCH (src, 8 * sizeof (src[0]), READ);
191           dst[-8] = src[-8];
192           dst[-7] = src[-7];
193           dst[-6] = src[-6];
194           dst[-5] = src[-5];
195           dst[-4] = src[-4];
196           dst[-3] = src[-3];
197           dst[-2] = src[-2];
198           dst[-1] = src[-1];
199         }
200     }
201   else
202     /* Cache line size unknown: fall back to slow version. */;
203
204   while (n_bytes > 0)
205     {
206       *dst++ = *src++;
207       n_bytes -= 1 * sizeof (dst[0]);
208     }
209 }
210
211 #define BUFFERS_PER_COPY (sizeof (vlib_copy_unit_t) / sizeof (u32))
212
213 /* Make sure we have at least given number of unaligned buffers. */
214 static void
215 fill_unaligned (vlib_main_t * vm,
216                 vlib_buffer_free_list_t * free_list,
217                 uword n_unaligned_buffers)
218 {
219   word la = vec_len (free_list->aligned_buffers);
220   word lu = vec_len (free_list->unaligned_buffers);
221
222   /* Aligned come in aligned copy-sized chunks. */
223   ASSERT (la % BUFFERS_PER_COPY == 0);
224
225   ASSERT (la >= n_unaligned_buffers);
226
227   while (lu < n_unaligned_buffers)
228     {
229       /* Copy 4 buffers from end of aligned vector to unaligned vector. */
230       vec_add (free_list->unaligned_buffers,
231                free_list->aligned_buffers + la - BUFFERS_PER_COPY,
232                BUFFERS_PER_COPY);
233       la -= BUFFERS_PER_COPY;
234       lu += BUFFERS_PER_COPY;
235     }
236   _vec_len (free_list->aligned_buffers) = la;
237 }
238
239 /* After free aligned buffers may not contain even sized chunks. */
240 static void
241 trim_aligned (vlib_buffer_free_list_t * f)
242 {
243   uword l, n_trim;
244
245   /* Add unaligned to aligned before trim. */
246   l = vec_len (f->unaligned_buffers);
247   if (l > 0)
248     {
249       vec_add_aligned (f->aligned_buffers, f->unaligned_buffers, l,
250                        /* align */ sizeof (vlib_copy_unit_t));
251
252       _vec_len (f->unaligned_buffers) = 0;
253     }
254
255   /* Remove unaligned buffers from end of aligned vector and save for next trim. */
256   l = vec_len (f->aligned_buffers);
257   n_trim = l % BUFFERS_PER_COPY;
258   if (n_trim)
259     {
260       /* Trim aligned -> unaligned. */
261       vec_add (f->unaligned_buffers, f->aligned_buffers + l - n_trim, n_trim);
262
263       /* Remove from aligned. */
264       _vec_len (f->aligned_buffers) = l - n_trim;
265     }
266 }
267
268 static void
269 merge_free_lists (vlib_buffer_free_list_t * dst,
270                   vlib_buffer_free_list_t * src)
271 {
272   uword l;
273   u32 * d;
274   
275   trim_aligned (src);
276   trim_aligned (dst);
277
278   l = vec_len (src->aligned_buffers);
279   if (l > 0)
280     {
281       vec_add2_aligned (dst->aligned_buffers, d, l,
282                         /* align */ sizeof (vlib_copy_unit_t));
283       vlib_aligned_memcpy (d, src->aligned_buffers, l * sizeof (d[0]));
284       vec_free (src->aligned_buffers);
285     }
286
287   l = vec_len (src->unaligned_buffers);
288   if (l > 0)
289     {
290       vec_add (dst->unaligned_buffers, src->unaligned_buffers, l);
291       vec_free (src->unaligned_buffers);
292     }
293 }
294
295 always_inline u32
296 vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
297 {
298   vlib_buffer_main_t * bm = vm->buffer_main;
299
300   size = vlib_buffer_round_size (size);
301   uword * p = hash_get (bm->free_list_by_size, size);
302   return p ? p[0] : ~0;
303 }
304
305 /* Add buffer free list. */
306 static u32
307 vlib_buffer_create_free_list_helper (vlib_main_t * vm,
308                                      u32 n_data_bytes,
309                                      u32 is_public,
310                                      u32 is_default,
311                                      u8 * name)
312 {
313   vlib_buffer_main_t * bm = vm->buffer_main;
314   vlib_buffer_free_list_t * f;
315
316   if (! is_default && pool_elts (bm->buffer_free_list_pool) == 0)
317     {
318       u32 default_free_free_list_index;
319
320       default_free_free_list_index =
321         vlib_buffer_create_free_list_helper (vm,
322                                              /* default buffer size */ VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES,
323                                              /* is_public */ 1,
324                                              /* is_default */ 1,
325                                              (u8 *) "default");
326       ASSERT (default_free_free_list_index == VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
327
328       if (n_data_bytes == VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES && is_public)
329         return default_free_free_list_index;
330     }
331
332   pool_get_aligned (bm->buffer_free_list_pool, f, CLIB_CACHE_LINE_BYTES);
333
334   memset (f, 0, sizeof (f[0]));
335   f->index = f - bm->buffer_free_list_pool;
336   f->n_data_bytes = vlib_buffer_round_size (n_data_bytes);
337   f->min_n_buffers_each_physmem_alloc = 16;
338   f->name = clib_mem_is_heap_object (name) ? name : format (0, "%s", name);
339
340   /* Setup free buffer template. */
341   f->buffer_init_template.free_list_index = f->index;
342
343   if (is_public)
344     {
345       uword * p = hash_get (bm->free_list_by_size, f->n_data_bytes);
346       if (! p)
347         hash_set (bm->free_list_by_size, f->n_data_bytes, f->index);
348     }
349
350   return f->index;
351 }
352
353 u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
354                                   char * fmt, ...)
355 {
356   va_list va;
357   u8 * name;
358
359   va_start (va, fmt);
360   name = va_format (0, fmt, &va);
361   va_end (va);
362
363   return vlib_buffer_create_free_list_helper (vm, n_data_bytes,
364                                               /* is_public */ 0,
365                                               /* is_default */ 0,
366                                               name);
367 }
368
369 u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
370                                          char * fmt, ...)
371 {
372   u32 i = vlib_buffer_get_free_list_with_size (vm, n_data_bytes);
373
374   if (i == ~0)
375     {
376       va_list va;
377       u8 * name;
378
379       va_start (va, fmt);
380       name = va_format (0, fmt, &va);
381       va_end (va);
382
383       i = vlib_buffer_create_free_list_helper (vm, n_data_bytes,
384                                                /* is_public */ 1,
385                                                /* is_default */ 0,
386                                                name);
387     }
388   
389   return i;
390 }
391
392 static void
393 del_free_list (vlib_main_t * vm, vlib_buffer_free_list_t * f)
394 {
395   u32 i;
396   struct rte_mbuf *mb;
397   vlib_buffer_t *b;
398
399   for (i = 0; i < vec_len (f->unaligned_buffers); i++) {
400       b = vlib_get_buffer (vm, f->unaligned_buffers[i]);
401       mb = rte_mbuf_from_vlib_buffer(b);
402       ASSERT(rte_mbuf_refcnt_read(mb) == 1);
403       rte_pktmbuf_free (mb);
404   }
405   for (i = 0; i < vec_len (f->aligned_buffers); i++) {
406       b = vlib_get_buffer (vm, f->aligned_buffers[i]);
407       mb = rte_mbuf_from_vlib_buffer(b);
408       ASSERT(rte_mbuf_refcnt_read(mb) == 1);
409       rte_pktmbuf_free (mb);
410   }
411   vec_free (f->name);
412   vec_free (f->unaligned_buffers);
413   vec_free (f->aligned_buffers);
414 }
415
416 /* Add buffer free list. */
417 void vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
418 {
419   vlib_buffer_main_t * bm = vm->buffer_main;
420   vlib_buffer_free_list_t * f;
421   u32 merge_index;
422
423   f = vlib_buffer_get_free_list (vm, free_list_index);
424
425   merge_index = vlib_buffer_get_free_list_with_size (vm, f->n_data_bytes);
426   if (merge_index != ~0 && merge_index != free_list_index)
427     {
428       merge_free_lists (pool_elt_at_index (bm->buffer_free_list_pool,
429                                            merge_index), f);
430     }
431
432   del_free_list (vm, f);
433
434   /* Poison it. */
435   memset (f, 0xab, sizeof (f[0]));
436
437   pool_put (bm->buffer_free_list_pool, f);
438 }
439
440 /* Make sure free list has at least given number of free buffers. */
441 static uword
442 fill_free_list (vlib_main_t * vm,
443                 vlib_buffer_free_list_t * fl,
444                 uword min_free_buffers)
445 {
446   vlib_buffer_t * b;
447   int n, i;
448   u32 bi;
449   u32 n_remaining = 0, n_alloc = 0;
450   unsigned socket_id = rte_socket_id ? rte_socket_id() : 0;
451   struct rte_mempool *rmp = vm->buffer_main->pktmbuf_pools[socket_id];
452   struct rte_mbuf *mb;
453       
454   /* Too early? */
455   if (PREDICT_FALSE(rmp == 0))
456     return 0;
457
458   trim_aligned (fl);
459
460   /* Already have enough free buffers on free list? */
461   n = min_free_buffers - vec_len (fl->aligned_buffers);
462   if (n <= 0)
463     return min_free_buffers;
464
465   /* Always allocate round number of buffers. */
466   n = round_pow2 (n, BUFFERS_PER_COPY);
467
468   /* Always allocate new buffers in reasonably large sized chunks. */
469   n = clib_max (n, fl->min_n_buffers_each_physmem_alloc);
470
471   vec_validate (vm->mbuf_alloc_list, n-1);
472   
473   if (rte_mempool_get_bulk (rmp, vm->mbuf_alloc_list, n) < 0)
474     return 0;
475
476   _vec_len (vm->mbuf_alloc_list) = n;
477
478   for (i = 0; i < n; i++)
479     {
480       mb = vm->mbuf_alloc_list[i];
481
482       ASSERT(rte_mbuf_refcnt_read(mb) == 0);
483       rte_mbuf_refcnt_set(mb, 1);
484       mb->next = NULL;
485       mb->data_off = RTE_PKTMBUF_HEADROOM;
486       mb->nb_segs = 1;
487
488       b = vlib_buffer_from_rte_mbuf(mb);
489       bi = vlib_get_buffer_index (vm, b);
490       
491       vec_add1_aligned (fl->aligned_buffers, bi, sizeof (vlib_copy_unit_t));
492       n_alloc++;
493       n_remaining--;
494
495       vlib_buffer_init_for_free_list (b, fl);
496       
497       if (fl->buffer_init_function)
498         fl->buffer_init_function (vm, fl, &bi, 1);
499     }
500
501   fl->n_alloc += n;
502
503   return n;
504 }
505
506 always_inline uword
507 copy_alignment (u32 * x)
508 { return (pointer_to_uword (x) / sizeof (x[0])) % BUFFERS_PER_COPY; }
509
510 static u32
511 alloc_from_free_list (vlib_main_t * vm,
512                       vlib_buffer_free_list_t * free_list,
513                       u32 * alloc_buffers,
514                       u32 n_alloc_buffers)
515 {
516   u32 * dst, * u_src;
517   uword u_len, n_left;
518   uword n_unaligned_start, n_unaligned_end, n_filled;
519
520   n_left = n_alloc_buffers;
521   dst = alloc_buffers;
522   n_unaligned_start = ((BUFFERS_PER_COPY - copy_alignment (dst))
523                        & (BUFFERS_PER_COPY - 1));
524
525   n_filled = fill_free_list (vm, free_list, n_alloc_buffers);
526   if (n_filled == 0)
527     return 0;
528   
529   n_left = n_filled < n_left ? n_filled : n_left;
530   n_alloc_buffers = n_left;
531
532   if (n_unaligned_start >= n_left)
533     {
534       n_unaligned_start = n_left;
535       n_unaligned_end = 0;
536     }
537   else
538     n_unaligned_end = copy_alignment (dst + n_alloc_buffers);
539
540   fill_unaligned (vm, free_list, n_unaligned_start + n_unaligned_end);
541
542   u_len = vec_len (free_list->unaligned_buffers);
543   u_src = free_list->unaligned_buffers + u_len - 1;
544
545   if (n_unaligned_start)
546     {
547       uword n_copy = n_unaligned_start;
548       if (n_copy > n_left)
549         n_copy = n_left;
550       n_left -= n_copy;
551
552       while (n_copy > 0)
553         {
554           *dst++ = *u_src--;
555           n_copy--;
556           u_len--;
557         }
558
559       /* Now dst should be aligned. */
560       if (n_left > 0)
561         ASSERT (pointer_to_uword (dst) % sizeof (vlib_copy_unit_t) == 0);
562     }
563
564   /* Aligned copy. */
565   {
566     vlib_copy_unit_t * d, * s;
567     uword n_copy;
568
569     if (vec_len(free_list->aligned_buffers) < ((n_left/BUFFERS_PER_COPY)*BUFFERS_PER_COPY))
570         abort();
571
572     n_copy = n_left / BUFFERS_PER_COPY;
573     n_left = n_left % BUFFERS_PER_COPY;
574
575     /* Remove buffers from aligned free list. */
576     _vec_len (free_list->aligned_buffers) -= n_copy * BUFFERS_PER_COPY;
577
578     s = (vlib_copy_unit_t *) vec_end (free_list->aligned_buffers);
579     d = (vlib_copy_unit_t *) dst;
580
581     /* Fast path loop. */
582     while (n_copy >= 4)
583       {
584         d[0] = s[0];
585         d[1] = s[1];
586         d[2] = s[2];
587         d[3] = s[3];
588         n_copy -= 4;
589         s += 4;
590         d += 4;
591       }
592
593     while (n_copy >= 1)
594       {
595         d[0] = s[0];
596         n_copy -= 1;
597         s += 1;
598         d += 1;
599       }
600
601     dst = (void *) d;
602   }
603
604   /* Unaligned copy. */
605   ASSERT (n_unaligned_end == n_left);
606   while (n_left > 0)
607     {
608       *dst++ = *u_src--;
609       n_left--;
610       u_len--;
611     }
612
613   if (! free_list->unaligned_buffers)
614     ASSERT (u_len == 0);
615   else
616     _vec_len (free_list->unaligned_buffers) = u_len;
617
618   return n_alloc_buffers;
619 }
620
621 /* Allocate a given number of buffers into given array.
622    Returns number actually allocated which will be either zero or
623    number requested. */
624 u32 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
625 {
626   vlib_buffer_main_t * bm = vm->buffer_main;
627
628   return alloc_from_free_list
629     (vm,
630      pool_elt_at_index (bm->buffer_free_list_pool,
631                         VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX),
632      buffers, n_buffers);
633 }
634
635 u32 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
636                                       u32 * buffers,
637                                       u32 n_buffers,
638                                       u32 free_list_index)
639 {
640   vlib_buffer_main_t * bm = vm->buffer_main;
641   vlib_buffer_free_list_t * f;
642   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
643   return alloc_from_free_list (vm, f, buffers, n_buffers);
644 }
645
646 always_inline void
647 add_buffer_to_free_list (vlib_main_t * vm,
648                          vlib_buffer_free_list_t * f,
649                          u32 buffer_index, u8 do_init)
650 {
651   vlib_buffer_t * b;
652   b = vlib_get_buffer (vm, buffer_index);
653   if (PREDICT_TRUE(do_init))
654       vlib_buffer_init_for_free_list (b, f);
655   vec_add1_aligned (f->aligned_buffers, buffer_index, sizeof (vlib_copy_unit_t));
656 }
657
658 always_inline vlib_buffer_free_list_t *
659 buffer_get_free_list (vlib_main_t * vm, vlib_buffer_t * b, u32 * index)
660 {
661   vlib_buffer_main_t * bm = vm->buffer_main;
662   u32 i;
663
664   *index = i = b->free_list_index;
665   return pool_elt_at_index (bm->buffer_free_list_pool, i);
666 }
667
668 void *vlib_set_buffer_free_callback (vlib_main_t *vm, void *fp)
669 {
670   vlib_buffer_main_t * bm = vm->buffer_main;
671   void * rv = bm->buffer_free_callback;
672
673   bm->buffer_free_callback = fp;
674   return rv;
675 }
676
677 static_always_inline void
678 vlib_buffer_free_inline (vlib_main_t * vm,
679                          u32 * buffers,
680                          u32 n_buffers,
681                          u32 follow_buffer_next)
682 {
683   vlib_buffer_main_t * bm = vm->buffer_main;
684   vlib_buffer_free_list_t * fl;
685   u32 fi;
686   int i;
687   u32 (*cb)(vlib_main_t * vm, u32 * buffers, u32 n_buffers,
688             u32 follow_buffer_next);
689
690   cb = bm->buffer_free_callback;
691
692   if (PREDICT_FALSE (cb != 0))
693     n_buffers = (*cb)(vm, buffers, n_buffers, follow_buffer_next);
694
695   if (! n_buffers)
696     return;
697
698   for (i = 0; i < n_buffers; i++) 
699     {
700       vlib_buffer_t * b;
701       struct rte_mbuf * mb;
702       
703       b = vlib_get_buffer (vm, buffers[i]);
704
705       fl = buffer_get_free_list (vm, b, &fi);
706       
707       /* The only current use of this callback: multicast recycle */
708       if (PREDICT_FALSE (fl->buffers_added_to_freelist_function != 0)) 
709         {
710           int j;
711           
712           add_buffer_to_free_list (vm, fl, buffers[i], b->clone_count == 0);
713           
714           for (j = 0; j < vec_len (bm->announce_list); j++)
715             {
716               if (fl == bm->announce_list[j])
717                 goto already_announced;
718             }
719           vec_add1 (bm->announce_list, fl);
720         already_announced:
721           ;
722         }
723       else
724         {
725           if (PREDICT_TRUE (b->clone_count == 0))
726             {
727               mb = rte_mbuf_from_vlib_buffer(b);
728               ASSERT(rte_mbuf_refcnt_read(mb) == 1);
729               rte_pktmbuf_free (mb);
730             }
731         }
732     }
733   if (vec_len(bm->announce_list))
734     {
735       vlib_buffer_free_list_t * fl;
736       for (i = 0; i < vec_len (bm->announce_list); i++)
737         {
738           fl = bm->announce_list[i];
739           fl->buffers_added_to_freelist_function (vm, fl);
740         }
741       _vec_len(bm->announce_list) = 0;
742     }
743 }
744
745 void vlib_buffer_free (vlib_main_t * vm,
746                        u32 * buffers,
747                        u32 n_buffers)
748 {
749   vlib_buffer_free_inline (vm, buffers, n_buffers, /* follow_buffer_next */ 1);
750 }
751
752 void vlib_buffer_free_no_next (vlib_main_t * vm,
753                                u32 * buffers,
754                                u32 n_buffers)
755 {
756   vlib_buffer_free_inline (vm, buffers, n_buffers, /* follow_buffer_next */ 0);
757 }
758
759 /* Copy template packet data into buffers as they are allocated. */
760 __attribute__((unused)) static void
761 vlib_packet_template_buffer_init (vlib_main_t * vm,
762                                   vlib_buffer_free_list_t * fl,
763                                   u32 * buffers,
764                                   u32 n_buffers)
765 {
766   vlib_packet_template_t * t = uword_to_pointer (fl->buffer_init_function_opaque,
767                                                  vlib_packet_template_t *);
768   uword i;
769
770   for (i = 0; i < n_buffers; i++)
771     {
772       vlib_buffer_t * b = vlib_get_buffer (vm, buffers[i]);
773       ASSERT (b->current_length == vec_len (t->packet_data));
774       memcpy (vlib_buffer_get_current (b), t->packet_data, b->current_length);
775     }
776 }
777
778 void vlib_packet_template_init (vlib_main_t * vm,
779                                 vlib_packet_template_t * t,
780                                 void * packet_data,
781                                 uword n_packet_data_bytes,
782                                 uword min_n_buffers_each_physmem_alloc,
783                                 char * fmt,
784                                 ...)
785 {
786   va_list va;
787   __attribute__((unused)) u8 * name;
788
789   va_start (va, fmt);
790   name = va_format (0, fmt, &va);
791   va_end (va);
792
793   vlib_worker_thread_barrier_sync(vm);
794   memset (t, 0, sizeof (t[0]));
795
796   vec_add (t->packet_data, packet_data, n_packet_data_bytes);
797
798   vlib_worker_thread_barrier_release(vm);
799 }
800
801 void *
802 vlib_packet_template_get_packet (vlib_main_t * vm, 
803                                  vlib_packet_template_t * t, 
804                                  u32 * bi_result)
805 {
806   u32 bi;
807   vlib_buffer_t * b;
808
809   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
810     return 0;
811
812   *bi_result = bi;
813
814   b = vlib_get_buffer (vm, bi);
815   memcpy (vlib_buffer_get_current (b),
816           t->packet_data, vec_len(t->packet_data));
817   b->current_length = vec_len(t->packet_data);
818
819   /* Fix up mbuf header length fields */
820   struct rte_mbuf * mb;
821   mb = rte_mbuf_from_vlib_buffer(b);
822   mb->data_len = b->current_length;
823   mb->pkt_len = b->current_length;
824
825   return b->data;
826 }
827
828 /* Append given data to end of buffer, possibly allocating new buffers. */
829 u32 vlib_buffer_add_data (vlib_main_t * vm,
830                           u32 free_list_index,
831                           u32 buffer_index,
832                           void * data, u32 n_data_bytes)
833 {
834   u32 n_buffer_bytes, n_left, n_left_this_buffer, bi;
835   vlib_buffer_t * b;
836   void * d;
837
838   bi = buffer_index;
839   if (bi == 0
840       && 1 != vlib_buffer_alloc_from_free_list (vm, &bi, 1, free_list_index))
841     goto out_of_buffers;
842
843   d = data;
844   n_left = n_data_bytes;
845   n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
846   
847   b = vlib_get_buffer (vm, bi);
848   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
849
850   /* Get to the end of the chain before we try to append data...*/
851   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
852     b = vlib_get_buffer (vm, b->next_buffer);
853
854   while (1)
855     {
856       u32 n;
857
858       ASSERT (n_buffer_bytes >= b->current_length);
859       n_left_this_buffer = n_buffer_bytes - (b->current_data + b->current_length);
860       n = clib_min (n_left_this_buffer, n_left);
861       memcpy (vlib_buffer_get_current (b) + b->current_length, d, n);
862       b->current_length += n;
863       n_left -= n;
864       if (n_left == 0)
865         break;
866
867       d += n;
868       if (1 != vlib_buffer_alloc_from_free_list (vm, &b->next_buffer, 1, free_list_index))
869         goto out_of_buffers;
870
871       b->flags |= VLIB_BUFFER_NEXT_PRESENT;
872
873       b = vlib_get_buffer (vm, b->next_buffer);
874     }
875
876   return bi;
877
878  out_of_buffers:
879   clib_error ("out of buffers");
880   return bi;
881 }
882
883 u16
884 vlib_buffer_chain_append_data_with_alloc(vlib_main_t *vm,
885                              u32 free_list_index,
886                              vlib_buffer_t *first,
887                              vlib_buffer_t **last,
888                              void * data, u16 data_len) {
889   vlib_buffer_t *l = *last;
890   u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
891   u16 copied = 0;
892   ASSERT(n_buffer_bytes >= l->current_length + l->current_data);
893   while (data_len) {
894     u16 max = n_buffer_bytes - l->current_length - l->current_data;
895     if (max == 0) {
896       if (1 != vlib_buffer_alloc_from_free_list (vm, &l->next_buffer, 1, free_list_index))
897         return copied;
898       *last = l = vlib_buffer_chain_buffer(vm, first, l, l->next_buffer);
899       max = n_buffer_bytes - l->current_length - l->current_data;
900     }
901
902     u16 len = (data_len > max)?max:data_len;
903     rte_memcpy(vlib_buffer_get_current (l) + l->current_length, data + copied, len);
904     vlib_buffer_chain_increase_length(first, l, len);
905     data_len -= len;
906     copied += len;
907   }
908   return copied;
909 }
910
911 /*
912  * Fills in the required rte_mbuf fields for chained buffers given a VLIB chain.
913  */
914 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * b_first)
915 {
916   vlib_buffer_t *b = b_first, *prev = b_first;
917   struct rte_mbuf *mb_prev, *mb, *mb_first;
918
919   mb_first = rte_mbuf_from_vlib_buffer(b_first);
920
921   mb_first->pkt_len = mb_first->data_len = b_first->current_length;
922   while (b->flags & VLIB_BUFFER_NEXT_PRESENT) {
923       b = vlib_get_buffer(vm, b->next_buffer);
924       mb = rte_mbuf_from_vlib_buffer(b);
925       mb_prev = rte_mbuf_from_vlib_buffer(prev);
926       mb_first->nb_segs++;
927       mb_first->pkt_len += b->current_length;
928       mb_prev->next = mb;
929       mb->data_len = b->current_length;
930       prev = b;
931   }
932 }
933
934 clib_error_t *
935 vlib_buffer_pool_create(vlib_main_t * vm, unsigned num_mbufs,
936                         unsigned socket_id)
937 {
938   vlib_buffer_main_t * bm = vm->buffer_main;
939   vlib_physmem_main_t * vpm = &vm->physmem_main;
940   struct rte_mempool * rmp;
941   uword new_start, new_size;
942   int i;
943
944   if (!rte_pktmbuf_pool_create)
945     return clib_error_return (0, "not linked with DPDK");
946
947   vec_validate_aligned(bm->pktmbuf_pools, socket_id, CLIB_CACHE_LINE_BYTES);
948
949   /* pool already exists, nothing to do */
950   if (bm->pktmbuf_pools[socket_id])
951     return 0;
952
953   u8 * pool_name = format(0, "mbuf_pool_socket%u%c",socket_id, 0);
954
955   rmp = rte_pktmbuf_pool_create((char *) pool_name,         /* pool name */
956                                  num_mbufs,                 /* number of mbufs */
957                                  512,                       /* cache size */
958                                  VLIB_BUFFER_HDR_SIZE,      /* priv size */
959                                  VLIB_BUFFER_PRE_DATA_SIZE
960                                  + VLIB_BUFFER_DATA_SIZE,   /* dataroom size */
961                                  socket_id);                /* cpu socket */
962
963   vec_free(pool_name);
964
965   if (rmp)
966     {
967       new_start = pointer_to_uword(rmp);
968       new_size = rmp->elt_va_end - new_start;
969
970       if (vpm->virtual.size > 0)
971         {
972           ASSERT(new_start != vpm->virtual.start);
973           if (new_start < vpm->virtual.start)
974             {
975               new_size = vpm->virtual.size + vpm->virtual.start - new_start;
976             }
977           else
978             {
979               new_size += new_start - vpm->virtual.start;
980               new_start = vpm->virtual.start;
981             }
982
983           /* check if fits into buffer index range */
984           if (new_size > ( (uword) 1 << (32 + CLIB_LOG2_CACHE_LINE_BYTES)))
985             rmp = 0;
986         }
987     }
988
989   if (rmp)
990     {
991       bm->pktmbuf_pools[socket_id] = rmp;
992       vpm->virtual.start = new_start;
993       vpm->virtual.size = new_size;
994       vpm->virtual.end = new_start + new_size;
995       return 0;
996     }
997
998   /* no usable pool for this socket, try to use pool from another one */
999   for (i = 0; i < vec_len(bm->pktmbuf_pools); i++)
1000     {
1001       if(bm->pktmbuf_pools[i])
1002        {
1003           clib_warning("WARNING: Failed to allocate mempool for CPU socket %u. "
1004                        "Threads running on socket %u will use socket %u mempool.",
1005                        socket_id, socket_id, i);
1006           bm->pktmbuf_pools[socket_id] = bm->pktmbuf_pools[i];
1007           return 0;
1008        }
1009     }
1010
1011   return clib_error_return (0, "failed to allocate mempool on socket %u",
1012                             socket_id);
1013 }
1014
1015
1016 static void vlib_serialize_tx (serialize_main_header_t * m, serialize_stream_t * s)
1017 {
1018   vlib_main_t * vm;
1019   vlib_serialize_buffer_main_t * sm;
1020   uword n, n_bytes_to_write;
1021   vlib_buffer_t * last;
1022
1023   n_bytes_to_write = s->current_buffer_index;
1024   sm = uword_to_pointer (s->data_function_opaque, vlib_serialize_buffer_main_t *);
1025   vm = sm->vlib_main;
1026
1027   ASSERT (sm->tx.max_n_data_bytes_per_chain > 0);
1028   if (serialize_stream_is_end_of_stream (s)
1029       || sm->tx.n_total_data_bytes + n_bytes_to_write > sm->tx.max_n_data_bytes_per_chain)
1030     {
1031       vlib_process_t * p = vlib_get_current_process (vm);
1032
1033       last = vlib_get_buffer (vm, sm->last_buffer);
1034       last->current_length = n_bytes_to_write;
1035
1036       vlib_set_next_frame_buffer (vm, &p->node_runtime, sm->tx.next_index, sm->first_buffer);
1037
1038       sm->first_buffer = sm->last_buffer = ~0;
1039       sm->tx.n_total_data_bytes = 0;
1040     }
1041
1042   else if (n_bytes_to_write == 0 && s->n_buffer_bytes == 0)
1043     {
1044       ASSERT (sm->first_buffer == ~0);
1045       ASSERT (sm->last_buffer == ~0);
1046       n = vlib_buffer_alloc_from_free_list (vm, &sm->first_buffer, 1, sm->tx.free_list_index);
1047       if (n != 1)
1048         serialize_error (m, clib_error_create ("vlib_buffer_alloc_from_free_list fails"));
1049       sm->last_buffer = sm->first_buffer;
1050       s->n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, sm->tx.free_list_index);
1051     }
1052
1053   if (n_bytes_to_write > 0)
1054     {
1055       vlib_buffer_t * prev = vlib_get_buffer (vm, sm->last_buffer);
1056       n = vlib_buffer_alloc_from_free_list (vm, &sm->last_buffer, 1, sm->tx.free_list_index);
1057       if (n != 1)
1058         serialize_error (m, clib_error_create ("vlib_buffer_alloc_from_free_list fails"));
1059       sm->tx.n_total_data_bytes += n_bytes_to_write;
1060       prev->current_length = n_bytes_to_write;
1061       prev->next_buffer = sm->last_buffer;
1062       prev->flags |= VLIB_BUFFER_NEXT_PRESENT;
1063     }
1064
1065   if (sm->last_buffer != ~0)
1066     {
1067       last = vlib_get_buffer (vm, sm->last_buffer);
1068       s->buffer = vlib_buffer_get_current (last);
1069       s->current_buffer_index = 0;
1070       ASSERT (last->current_data == s->current_buffer_index);
1071     }
1072 }
1073
1074 static void vlib_serialize_rx (serialize_main_header_t * m, serialize_stream_t * s)
1075 {
1076   vlib_main_t * vm;
1077   vlib_serialize_buffer_main_t * sm;
1078   vlib_buffer_t * last;
1079
1080   sm = uword_to_pointer (s->data_function_opaque, vlib_serialize_buffer_main_t *);
1081   vm = sm->vlib_main;
1082
1083   if (serialize_stream_is_end_of_stream (s))
1084     return;
1085
1086   if (sm->last_buffer != ~0)
1087     {
1088       last = vlib_get_buffer (vm, sm->last_buffer);
1089
1090       if (last->flags & VLIB_BUFFER_NEXT_PRESENT)
1091         sm->last_buffer = last->next_buffer;
1092       else
1093         {
1094           vlib_buffer_free (vm, &sm->first_buffer, /* count */ 1);
1095           sm->first_buffer = sm->last_buffer = ~0;
1096         }
1097     }
1098
1099   if (sm->last_buffer == ~0)
1100     {
1101       while (clib_fifo_elts (sm->rx.buffer_fifo) == 0)
1102         {
1103           sm->rx.ready_one_time_event = vlib_process_create_one_time_event (vm, vlib_current_process (vm), ~0);
1104           vlib_process_wait_for_one_time_event (vm, /* no event data */ 0, sm->rx.ready_one_time_event);
1105         }
1106
1107       clib_fifo_sub1 (sm->rx.buffer_fifo, sm->first_buffer);
1108       sm->last_buffer = sm->first_buffer;
1109     }
1110
1111   ASSERT (sm->last_buffer != ~0);
1112
1113   last = vlib_get_buffer (vm, sm->last_buffer);
1114   s->current_buffer_index = 0;
1115   s->buffer = vlib_buffer_get_current (last);
1116   s->n_buffer_bytes = last->current_length;
1117 }
1118
1119 static void
1120 serialize_open_vlib_helper (serialize_main_t * m,
1121                             vlib_main_t * vm,
1122                             vlib_serialize_buffer_main_t * sm,
1123                             uword is_read)
1124 {
1125   /* Initialize serialize main but save overflow buffer for re-use between calls. */
1126   {
1127     u8 * save = m->stream.overflow_buffer;
1128     memset (m, 0, sizeof (m[0]));
1129     m->stream.overflow_buffer = save;
1130     if (save)
1131       _vec_len (save) = 0;
1132   }
1133
1134   sm->first_buffer = sm->last_buffer = ~0;
1135   if (is_read)
1136     clib_fifo_reset (sm->rx.buffer_fifo);
1137   else
1138     sm->tx.n_total_data_bytes = 0;
1139   sm->vlib_main = vm;
1140   m->header.data_function = is_read ? vlib_serialize_rx : vlib_serialize_tx;
1141   m->stream.data_function_opaque = pointer_to_uword (sm);
1142 }
1143
1144 void serialize_open_vlib_buffer (serialize_main_t * m, vlib_main_t * vm, vlib_serialize_buffer_main_t * sm)
1145 { serialize_open_vlib_helper (m, vm, sm, /* is_read */ 0); }
1146
1147 void unserialize_open_vlib_buffer (serialize_main_t * m, vlib_main_t * vm, vlib_serialize_buffer_main_t * sm)
1148 { serialize_open_vlib_helper (m, vm, sm, /* is_read */ 1); }
1149
1150 u32 serialize_close_vlib_buffer (serialize_main_t * m)
1151 {
1152   vlib_serialize_buffer_main_t * sm
1153     = uword_to_pointer (m->stream.data_function_opaque, vlib_serialize_buffer_main_t *);
1154   vlib_buffer_t * last;
1155   serialize_stream_t * s = &m->stream;
1156
1157   last = vlib_get_buffer (sm->vlib_main, sm->last_buffer);
1158   last->current_length = s->current_buffer_index;
1159
1160   if (vec_len (s->overflow_buffer) > 0)
1161     {
1162       sm->last_buffer
1163         = vlib_buffer_add_data (sm->vlib_main, sm->tx.free_list_index,
1164                                 sm->last_buffer == ~0 ? 0 : sm->last_buffer,
1165                                 s->overflow_buffer,
1166                                 vec_len (s->overflow_buffer));
1167       _vec_len (s->overflow_buffer) = 0;
1168     }
1169
1170   return sm->first_buffer;
1171 }
1172
1173 void unserialize_close_vlib_buffer (serialize_main_t * m)
1174 {
1175   vlib_serialize_buffer_main_t * sm
1176     = uword_to_pointer (m->stream.data_function_opaque, vlib_serialize_buffer_main_t *);
1177   if (sm->first_buffer != ~0)
1178     vlib_buffer_free_one (sm->vlib_main, sm->first_buffer);
1179   clib_fifo_reset (sm->rx.buffer_fifo);
1180   if (m->stream.overflow_buffer)
1181     _vec_len (m->stream.overflow_buffer) = 0;
1182 }
1183
1184 static u8 * format_vlib_buffer_free_list (u8 * s, va_list * va)
1185 {
1186   vlib_buffer_free_list_t * f = va_arg (*va, vlib_buffer_free_list_t *);
1187   u32 threadnum= va_arg (*va, u32);
1188   uword bytes_alloc, bytes_free, n_free, size;
1189
1190   if (! f)
1191     return format (s, "%=7s%=30s%=12s%=12s%=12s%=12s%=12s%=12s",
1192                    "Thread", "Name", "Index", "Size", "Alloc", "Free", "#Alloc", "#Free");
1193
1194   size = sizeof (vlib_buffer_t) + f->n_data_bytes;
1195   n_free = vec_len (f->aligned_buffers) + vec_len (f->unaligned_buffers);
1196   bytes_alloc = size * f->n_alloc;
1197   bytes_free = size * n_free;
1198
1199   s = format (s, "%7d%30s%12d%12d%=12U%=12U%=12d%=12d",
1200               threadnum,
1201               f->name, f->index, f->n_data_bytes,
1202               format_memory_size, bytes_alloc,
1203               format_memory_size, bytes_free,
1204               f->n_alloc, n_free);
1205
1206   return s;
1207 }
1208
1209 static clib_error_t *
1210 show_buffers (vlib_main_t * vm,
1211               unformat_input_t * input,
1212               vlib_cli_command_t * cmd)
1213 {
1214   vlib_buffer_main_t * bm;
1215   vlib_buffer_free_list_t * f;
1216   vlib_main_t *curr_vm;
1217   u32 vm_index = 0;
1218
1219   vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, 0, 0);
1220
1221   do {
1222     curr_vm = vec_len(vlib_mains) ? vlib_mains[vm_index] : vm;
1223     bm = curr_vm->buffer_main;
1224   
1225     pool_foreach (f, bm->buffer_free_list_pool, ({
1226       vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, f, vm_index);
1227     }));
1228
1229     vm_index++;
1230   } while (vm_index < vec_len(vlib_mains));
1231
1232   return 0;
1233 }
1234
1235 VLIB_CLI_COMMAND (show_buffers_command, static) = {
1236   .path = "show buffers",
1237   .short_help = "Show packet buffer allocation",
1238   .function = show_buffers,
1239 };
1240
1241 #if CLIB_DEBUG > 0
1242
1243 u32 * vlib_buffer_state_validation_lock;
1244 uword * vlib_buffer_state_validation_hash;
1245 void * vlib_buffer_state_heap;
1246
1247 static clib_error_t * 
1248 buffer_state_validation_init (vlib_main_t * vm)
1249 {
1250   void * oldheap;
1251
1252   vlib_buffer_state_heap = mheap_alloc (0, 10<<20);
1253
1254   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
1255
1256   vlib_buffer_state_validation_hash = hash_create (0, sizeof(uword));
1257   vec_validate_aligned (vlib_buffer_state_validation_lock, 0, 
1258                         CLIB_CACHE_LINE_BYTES);
1259   clib_mem_set_heap (oldheap);
1260   return 0;
1261 }
1262
1263 VLIB_INIT_FUNCTION (buffer_state_validation_init);
1264 #endif