Add jumbo frames support to non-dpdk vhost interfaces.
[vpp.git] / vlib / 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 #include <vlib/vlib.h>
41
42 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm, vlib_buffer_t * b_first)
43 {
44   vlib_buffer_t * b = b_first;
45   uword l_first = b_first->current_length;
46   uword l = 0;
47   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
48     {
49       b = vlib_get_buffer (vm, b->next_buffer);
50       l += b->current_length;
51     }
52   b_first->total_length_not_including_first_buffer = l;
53   b_first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
54   return l + l_first;
55 }
56
57 u8 * format_vlib_buffer (u8 * s, va_list * args)
58 {
59   vlib_buffer_t * b = va_arg (*args, vlib_buffer_t *);
60   
61   s = format (s, "current data %d, length %d, free-list %d",
62               b->current_data, b->current_length,
63               b->free_list_index);
64
65   if (b->flags & VLIB_BUFFER_IS_TRACED)
66     s = format (s, ", trace 0x%x", b->trace_index);
67
68   if (b->flags & VLIB_BUFFER_NEXT_PRESENT)
69     s = format (s, ", next-buffer 0x%x", b->next_buffer);
70
71   return s;
72 }
73
74 u8 * format_vlib_buffer_and_data (u8 * s, va_list * args)
75 {
76   vlib_buffer_t * b = va_arg (*args, vlib_buffer_t *);
77   
78   s = format (s, "%U, %U",
79               format_vlib_buffer, b,
80               format_hex_bytes, vlib_buffer_get_current (b), 64);
81
82   return s;
83 }
84
85 static u8 * format_vlib_buffer_known_state (u8 * s, va_list * args)
86 {
87   vlib_buffer_known_state_t state = va_arg (*args, vlib_buffer_known_state_t);
88   char * t;
89
90   switch (state)
91     {
92     case VLIB_BUFFER_UNKNOWN:
93       t = "unknown";
94       break;
95
96     case VLIB_BUFFER_KNOWN_ALLOCATED:
97       t = "known-allocated";
98       break;
99
100     case VLIB_BUFFER_KNOWN_FREE:
101       t = "known-free";
102       break;
103
104     default:
105       t = "invalid";
106       break;
107     }
108
109   return format (s, "%s", t);
110 }
111
112 u8 * format_vlib_buffer_contents (u8 * s, va_list * va)
113 {
114   vlib_main_t * vm = va_arg (*va, vlib_main_t *);
115   vlib_buffer_t * b = va_arg (*va, vlib_buffer_t *);
116   
117   while (1)
118     {
119       vec_add (s, vlib_buffer_get_current (b),
120                b->current_length);
121       if (! (b->flags & VLIB_BUFFER_NEXT_PRESENT))
122         break;
123       b = vlib_get_buffer (vm, b->next_buffer);
124     }
125
126   return s;
127 }
128
129 static u8 *
130 vlib_validate_buffer_helper (vlib_main_t * vm,
131                              u32 bi,
132                              uword follow_buffer_next,
133                              uword ** unique_hash)
134                       
135 {
136   vlib_buffer_t * b = vlib_get_buffer (vm, bi);
137   vlib_buffer_main_t * bm = vm->buffer_main;
138   vlib_buffer_free_list_t * fl;
139
140   if (pool_is_free_index (bm->buffer_free_list_pool,
141                           b->free_list_index))
142     return format (0, "unknown free list 0x%x", b->free_list_index);
143
144   fl = pool_elt_at_index (bm->buffer_free_list_pool,
145                           b->free_list_index);
146
147   if ((signed) b->current_data < (signed) - VLIB_BUFFER_PRE_DATA_SIZE)
148     return format (0, "current data %d before pre-data", b->current_data);
149 #if DPDK == 0
150   if (b->current_data + b->current_length > fl->n_data_bytes)
151     return format (0, "%d-%d beyond end of buffer %d",
152                    b->current_data, b->current_length,
153                    fl->n_data_bytes);
154 #endif
155
156   if (follow_buffer_next
157       && (b->flags & VLIB_BUFFER_NEXT_PRESENT))
158     {
159       vlib_buffer_known_state_t k;
160       u8 * msg, * result;
161
162       k = vlib_buffer_is_known (vm, b->next_buffer);
163       if (k != VLIB_BUFFER_KNOWN_ALLOCATED)
164         return format (0, "next 0x%x: %U",
165                        b->next_buffer,
166                        format_vlib_buffer_known_state, k);
167
168       if (unique_hash)
169         {
170           if (hash_get (*unique_hash, b->next_buffer))
171             return format (0, "duplicate buffer 0x%x", b->next_buffer);
172
173           hash_set1 (*unique_hash, b->next_buffer);
174         }
175
176       msg = vlib_validate_buffer (vm, b->next_buffer, follow_buffer_next);
177       if (msg)
178         {
179           result = format (0, "next 0x%x: %v", b->next_buffer, msg);
180           vec_free (msg);
181           return result;
182         }
183     }
184
185   return 0;
186 }
187
188 u8 *
189 vlib_validate_buffer (vlib_main_t * vm, u32 bi, uword follow_buffer_next)
190 { return vlib_validate_buffer_helper (vm, bi, follow_buffer_next, /* unique_hash */ 0); }
191
192 u8 *
193 vlib_validate_buffers (vlib_main_t * vm,
194                        u32 * buffers,
195                        uword next_buffer_stride,
196                        uword n_buffers,
197                        vlib_buffer_known_state_t known_state,
198                        uword follow_buffer_next)
199 {
200   uword i, * hash;
201   u32 bi, * b = buffers;
202   vlib_buffer_known_state_t k;
203   u8 * msg = 0, * result = 0;
204
205   hash = hash_create (0, 0);
206   for (i = 0; i < n_buffers; i++)
207     {
208       bi = b[0];
209       b += next_buffer_stride;
210
211       /* Buffer is not unique. */
212       if (hash_get (hash, bi))
213         {
214           msg = format (0, "not unique");
215           goto done;
216         }
217
218       k = vlib_buffer_is_known (vm, bi);
219       if (k != known_state)
220         {
221           msg = format (0, "is %U; expected %U",
222                         format_vlib_buffer_known_state, k,
223                         format_vlib_buffer_known_state, known_state);
224           goto done;
225         }
226
227       msg = vlib_validate_buffer_helper (vm, bi, follow_buffer_next, &hash);
228       if (msg)
229         goto done;
230
231       hash_set1 (hash, bi);
232     }
233
234  done:
235   if (msg)
236     {
237       result = format (0, "0x%x: %v", bi, msg);
238       vec_free (msg);
239     }
240   hash_free (hash);
241   return result;
242 }
243
244 vlib_main_t **vlib_mains;
245
246 /* When dubugging validate that given buffers are either known allocated
247    or known free. */
248 static void
249 vlib_buffer_validate_alloc_free (vlib_main_t * vm,
250                                  u32 * buffers,
251                                  uword n_buffers,
252                                  vlib_buffer_known_state_t expected_state)
253 {
254   u32 * b;
255   uword i, bi, is_free;
256
257   if (CLIB_DEBUG == 0)
258     return;
259
260   ASSERT(os_get_cpu_number() == 0);
261
262   /* smp disaster check */
263   if (vlib_mains)
264       ASSERT(vm == vlib_mains[0]);
265
266   is_free = expected_state == VLIB_BUFFER_KNOWN_ALLOCATED;
267   b = buffers;
268   for (i = 0; i < n_buffers; i++)
269     {
270       vlib_buffer_known_state_t known;
271         
272       bi = b[0];
273       b += 1;
274       known = vlib_buffer_is_known (vm, bi);
275       if (known != expected_state)
276         {
277           ASSERT (0);
278           vlib_panic_with_msg
279             (vm, "%s %U buffer 0x%x",
280              is_free ? "freeing" : "allocating",
281              format_vlib_buffer_known_state, known,
282              bi);
283         }
284
285       vlib_buffer_set_known_state
286         (vm, bi,
287          is_free ? VLIB_BUFFER_KNOWN_FREE : VLIB_BUFFER_KNOWN_ALLOCATED);
288     }
289 }
290
291 /* Aligned copy routine. */
292 void
293 vlib_aligned_memcpy (void * _dst, void * _src, int n_bytes)
294 {
295   vlib_copy_unit_t * dst = _dst;
296   vlib_copy_unit_t * src = _src;
297
298   /* Arguments must be naturally aligned. */
299   ASSERT (pointer_to_uword (dst) % sizeof (dst[0]) == 0);
300   ASSERT (pointer_to_uword (src) % sizeof (src[0]) == 0);
301   ASSERT (n_bytes % sizeof (dst[0]) == 0);
302
303   if (4 * sizeof (dst[0]) == CLIB_CACHE_LINE_BYTES)
304     {
305       CLIB_PREFETCH (dst + 0, 4 * sizeof (dst[0]), WRITE);
306       CLIB_PREFETCH (src + 0, 4 * sizeof (src[0]), READ);
307
308       while (n_bytes >= 4 * sizeof (dst[0]))
309         {
310           dst += 4;
311           src += 4;
312           n_bytes -= 4 * sizeof (dst[0]);
313           CLIB_PREFETCH (dst, 4 * sizeof (dst[0]), WRITE);
314           CLIB_PREFETCH (src, 4 * sizeof (src[0]), READ);
315           dst[-4] = src[-4];
316           dst[-3] = src[-3];
317           dst[-2] = src[-2];
318           dst[-1] = src[-1];
319         }
320     }
321   else if (8 * sizeof (dst[0]) == CLIB_CACHE_LINE_BYTES)
322     {
323       CLIB_PREFETCH (dst + 0, 8 * sizeof (dst[0]), WRITE);
324       CLIB_PREFETCH (src + 0, 8 * sizeof (src[0]), READ);
325
326       while (n_bytes >= 8 * sizeof (dst[0]))
327         {
328           dst += 8;
329           src += 8;
330           n_bytes -= 8 * sizeof (dst[0]);
331           CLIB_PREFETCH (dst, 8 * sizeof (dst[0]), WRITE);
332           CLIB_PREFETCH (src, 8 * sizeof (src[0]), READ);
333           dst[-8] = src[-8];
334           dst[-7] = src[-7];
335           dst[-6] = src[-6];
336           dst[-5] = src[-5];
337           dst[-4] = src[-4];
338           dst[-3] = src[-3];
339           dst[-2] = src[-2];
340           dst[-1] = src[-1];
341         }
342     }
343   else
344     /* Cache line size unknown: fall back to slow version. */;
345
346   while (n_bytes > 0)
347     {
348       *dst++ = *src++;
349       n_bytes -= 1 * sizeof (dst[0]);
350     }
351 }
352
353 #define BUFFERS_PER_COPY (sizeof (vlib_copy_unit_t) / sizeof (u32))
354
355 /* Make sure we have at least given number of unaligned buffers. */
356 static void
357 fill_unaligned (vlib_main_t * vm,
358                 vlib_buffer_free_list_t * free_list,
359                 uword n_unaligned_buffers)
360 {
361   word la = vec_len (free_list->aligned_buffers);
362   word lu = vec_len (free_list->unaligned_buffers);
363
364   /* Aligned come in aligned copy-sized chunks. */
365   ASSERT (la % BUFFERS_PER_COPY == 0);
366
367   ASSERT (la >= n_unaligned_buffers);
368
369   while (lu < n_unaligned_buffers)
370     {
371       /* Copy 4 buffers from end of aligned vector to unaligned vector. */
372       vec_add (free_list->unaligned_buffers,
373                free_list->aligned_buffers + la - BUFFERS_PER_COPY,
374                BUFFERS_PER_COPY);
375       la -= BUFFERS_PER_COPY;
376       lu += BUFFERS_PER_COPY;
377     }
378   _vec_len (free_list->aligned_buffers) = la;
379 }
380
381 /* After free aligned buffers may not contain even sized chunks. */
382 static void
383 trim_aligned (vlib_buffer_free_list_t * f)
384 {
385   uword l, n_trim;
386
387   /* Add unaligned to aligned before trim. */
388   l = vec_len (f->unaligned_buffers);
389   if (l > 0)
390     {
391       vec_add_aligned (f->aligned_buffers, f->unaligned_buffers, l,
392                        /* align */ sizeof (vlib_copy_unit_t));
393
394       _vec_len (f->unaligned_buffers) = 0;
395     }
396
397   /* Remove unaligned buffers from end of aligned vector and save for next trim. */
398   l = vec_len (f->aligned_buffers);
399   n_trim = l % BUFFERS_PER_COPY;
400   if (n_trim)
401     {
402       /* Trim aligned -> unaligned. */
403       vec_add (f->unaligned_buffers, f->aligned_buffers + l - n_trim, n_trim);
404
405       /* Remove from aligned. */
406       _vec_len (f->aligned_buffers) = l - n_trim;
407     }
408 }
409
410 static void
411 merge_free_lists (vlib_buffer_free_list_t * dst,
412                   vlib_buffer_free_list_t * src)
413 {
414   uword l;
415   u32 * d;
416   
417   trim_aligned (src);
418   trim_aligned (dst);
419
420   l = vec_len (src->aligned_buffers);
421   if (l > 0)
422     {
423       vec_add2_aligned (dst->aligned_buffers, d, l,
424                         /* align */ sizeof (vlib_copy_unit_t));
425       vlib_aligned_memcpy (d, src->aligned_buffers, l * sizeof (d[0]));
426       vec_free (src->aligned_buffers);
427     }
428
429   l = vec_len (src->unaligned_buffers);
430   if (l > 0)
431     {
432       vec_add (dst->unaligned_buffers, src->unaligned_buffers, l);
433       vec_free (src->unaligned_buffers);
434     }
435 }
436
437 always_inline u32
438 vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
439 {
440   vlib_buffer_main_t * bm = vm->buffer_main;
441
442   size = vlib_buffer_round_size (size);
443   uword * p = hash_get (bm->free_list_by_size, size);
444   return p ? p[0] : ~0;
445 }
446
447 /* Add buffer free list. */
448 static u32
449 vlib_buffer_create_free_list_helper (vlib_main_t * vm,
450                                      u32 n_data_bytes,
451                                      u32 is_public,
452                                      u32 is_default,
453                                      u8 * name)
454 {
455   vlib_buffer_main_t * bm = vm->buffer_main;
456   vlib_buffer_free_list_t * f;
457
458   if (! is_default && pool_elts (bm->buffer_free_list_pool) == 0)
459     {
460       u32 default_free_free_list_index;
461
462       default_free_free_list_index =
463         vlib_buffer_create_free_list_helper (vm,
464                                              /* default buffer size */ VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES,
465                                              /* is_public */ 1,
466                                              /* is_default */ 1,
467                                              (u8 *) "default");
468       ASSERT (default_free_free_list_index == VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
469
470       if (n_data_bytes == VLIB_BUFFER_DEFAULT_FREE_LIST_BYTES && is_public)
471         return default_free_free_list_index;
472     }
473
474   pool_get_aligned (bm->buffer_free_list_pool, f, CLIB_CACHE_LINE_BYTES);
475
476   memset (f, 0, sizeof (f[0]));
477   f->index = f - bm->buffer_free_list_pool;
478   f->n_data_bytes = vlib_buffer_round_size (n_data_bytes);
479   f->min_n_buffers_each_physmem_alloc = 256;
480   f->name = clib_mem_is_heap_object (name) ? name : format (0, "%s", name);
481
482   /* Setup free buffer template. */
483   f->buffer_init_template.free_list_index = f->index;
484
485   if (is_public)
486     {
487       uword * p = hash_get (bm->free_list_by_size, f->n_data_bytes);
488       if (! p)
489         hash_set (bm->free_list_by_size, f->n_data_bytes, f->index);
490     }
491
492   return f->index;
493 }
494
495 u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
496                                   char * fmt, ...)
497 {
498   va_list va;
499   u8 * name;
500
501   va_start (va, fmt);
502   name = va_format (0, fmt, &va);
503   va_end (va);
504
505   return vlib_buffer_create_free_list_helper (vm, n_data_bytes,
506                                               /* is_public */ 0,
507                                               /* is_default */ 0,
508                                               name);
509 }
510
511 u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
512                                          char * fmt, ...)
513 {
514   u32 i = vlib_buffer_get_free_list_with_size (vm, n_data_bytes);
515
516   if (i == ~0)
517     {
518       va_list va;
519       u8 * name;
520
521       va_start (va, fmt);
522       name = va_format (0, fmt, &va);
523       va_end (va);
524
525       i = vlib_buffer_create_free_list_helper (vm, n_data_bytes,
526                                                /* is_public */ 1,
527                                                /* is_default */ 0,
528                                                name);
529     }
530   
531   return i;
532 }
533
534 static void
535 del_free_list (vlib_main_t * vm, vlib_buffer_free_list_t * f)
536 {
537   u32 i;
538
539   for (i = 0; i < vec_len (f->buffer_memory_allocated); i++)
540     vm->os_physmem_free (f->buffer_memory_allocated[i]);
541   vec_free (f->name);
542   vec_free (f->buffer_memory_allocated);
543   vec_free (f->unaligned_buffers);
544   vec_free (f->aligned_buffers);
545 }
546
547 /* Add buffer free list. */
548 void vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
549 {
550   vlib_buffer_main_t * bm = vm->buffer_main;
551   vlib_buffer_free_list_t * f;
552   u32 merge_index;
553
554   f = vlib_buffer_get_free_list (vm, free_list_index);
555
556   ASSERT (vec_len (f->unaligned_buffers) + vec_len (f->aligned_buffers) == f->n_alloc);
557   merge_index = vlib_buffer_get_free_list_with_size (vm, f->n_data_bytes);
558   if (merge_index != ~0 && merge_index != free_list_index)
559     {
560       merge_free_lists (pool_elt_at_index (bm->buffer_free_list_pool,
561                                            merge_index), f);
562     }
563
564   del_free_list (vm, f);
565
566   /* Poison it. */
567   memset (f, 0xab, sizeof (f[0]));
568
569   pool_put (bm->buffer_free_list_pool, f);
570 }
571
572 /* Make sure free list has at least given number of free buffers. */
573 static uword
574 fill_free_list (vlib_main_t * vm,
575                 vlib_buffer_free_list_t * fl,
576                 uword min_free_buffers)
577 {
578   vlib_buffer_t * buffers, * b;
579   int n, n_bytes, i;
580   u32 * bi;
581   u32 n_remaining, n_alloc, n_this_chunk;
582
583   trim_aligned (fl);
584
585   /* Already have enough free buffers on free list? */
586   n = min_free_buffers - vec_len (fl->aligned_buffers);
587   if (n <= 0)
588     return min_free_buffers;
589
590   /* Always allocate round number of buffers. */
591   n = round_pow2 (n, BUFFERS_PER_COPY);
592
593   /* Always allocate new buffers in reasonably large sized chunks. */
594   n = clib_max (n, fl->min_n_buffers_each_physmem_alloc);
595
596   n_remaining = n;
597   n_alloc = 0;
598   while (n_remaining > 0)
599     {
600       n_this_chunk = clib_min (n_remaining, 16);
601       
602       n_bytes = n_this_chunk * (sizeof (b[0]) + fl->n_data_bytes);
603
604       /* drb: removed power-of-2 ASSERT */
605       buffers = vm->os_physmem_alloc_aligned (&vm->physmem_main,
606                                               n_bytes, sizeof (vlib_buffer_t));
607       if (! buffers)
608         return n_alloc;
609
610       /* Record chunk as being allocated so we can free it later. */
611       vec_add1 (fl->buffer_memory_allocated, buffers);
612
613       fl->n_alloc += n_this_chunk;
614       n_alloc += n_this_chunk;
615       n_remaining -= n_this_chunk;
616
617       b = buffers;
618       vec_add2_aligned (fl->aligned_buffers, bi, n_this_chunk, 
619                         sizeof (vlib_copy_unit_t));
620       for (i = 0; i < n_this_chunk; i++)
621         {
622           bi[i] = vlib_get_buffer_index (vm, b);
623
624           if (CLIB_DEBUG > 0)
625             vlib_buffer_set_known_state (vm, bi[i], VLIB_BUFFER_KNOWN_FREE);
626           b = vlib_buffer_next_contiguous (b, fl->n_data_bytes);
627         }
628
629       memset (buffers, 0, n_bytes);
630
631       /* Initialize all new buffers. */
632       b = buffers;
633       for (i = 0; i < n_this_chunk; i++)
634         {
635           vlib_buffer_init_for_free_list (b, fl);
636           b = vlib_buffer_next_contiguous (b, fl->n_data_bytes);
637         }
638       
639       if (fl->buffer_init_function)
640         fl->buffer_init_function (vm, fl, bi, n_this_chunk);
641     }
642   return n_alloc;
643 }
644
645 always_inline uword
646 copy_alignment (u32 * x)
647 { return (pointer_to_uword (x) / sizeof (x[0])) % BUFFERS_PER_COPY; }
648
649 static u32
650 alloc_from_free_list (vlib_main_t * vm,
651                       vlib_buffer_free_list_t * free_list,
652                       u32 * alloc_buffers,
653                       u32 n_alloc_buffers)
654 {
655   u32 * dst, * u_src;
656   uword u_len, n_left;
657   uword n_unaligned_start, n_unaligned_end, n_filled;
658
659   ASSERT(os_get_cpu_number() == 0);
660
661   n_left = n_alloc_buffers;
662   dst = alloc_buffers;
663   n_unaligned_start = ((BUFFERS_PER_COPY - copy_alignment (dst))
664                        & (BUFFERS_PER_COPY - 1));
665
666   n_filled = fill_free_list (vm, free_list, n_alloc_buffers);
667   if (n_filled == 0)
668     return 0;
669   
670   n_left = n_filled < n_left ? n_filled : n_left;
671   n_alloc_buffers = n_left;
672
673   if (n_unaligned_start >= n_left)
674     {
675       n_unaligned_start = n_left;
676       n_unaligned_end = 0;
677     }
678   else
679     n_unaligned_end = copy_alignment (dst + n_alloc_buffers);
680
681   fill_unaligned (vm, free_list, n_unaligned_start + n_unaligned_end);
682
683   u_len = vec_len (free_list->unaligned_buffers);
684   u_src = free_list->unaligned_buffers + u_len - 1;
685
686   if (n_unaligned_start)
687     {
688       uword n_copy = n_unaligned_start;
689       if (n_copy > n_left)
690         n_copy = n_left;
691       n_left -= n_copy;
692
693       while (n_copy > 0)
694         {
695           *dst++ = *u_src--;
696           n_copy--;
697           u_len--;
698         }
699
700       /* Now dst should be aligned. */
701       if (n_left > 0)
702         ASSERT (pointer_to_uword (dst) % sizeof (vlib_copy_unit_t) == 0);
703     }
704
705   /* Aligned copy. */
706   {
707     vlib_copy_unit_t * d, * s;
708     uword n_copy;
709
710     if (vec_len(free_list->aligned_buffers) < ((n_left/BUFFERS_PER_COPY)*BUFFERS_PER_COPY))
711         abort();
712
713     n_copy = n_left / BUFFERS_PER_COPY;
714     n_left = n_left % BUFFERS_PER_COPY;
715
716     /* Remove buffers from aligned free list. */
717     _vec_len (free_list->aligned_buffers) -= n_copy * BUFFERS_PER_COPY;
718
719     s = (vlib_copy_unit_t *) vec_end (free_list->aligned_buffers);
720     d = (vlib_copy_unit_t *) dst;
721
722     /* Fast path loop. */
723     while (n_copy >= 4)
724       {
725         d[0] = s[0];
726         d[1] = s[1];
727         d[2] = s[2];
728         d[3] = s[3];
729         n_copy -= 4;
730         s += 4;
731         d += 4;
732       }
733
734     while (n_copy >= 1)
735       {
736         d[0] = s[0];
737         n_copy -= 1;
738         s += 1;
739         d += 1;
740       }
741
742     dst = (void *) d;
743   }
744
745   /* Unaligned copy. */
746   ASSERT (n_unaligned_end == n_left);
747   while (n_left > 0)
748     {
749       *dst++ = *u_src--;
750       n_left--;
751       u_len--;
752     }
753
754   if (! free_list->unaligned_buffers)
755     ASSERT (u_len == 0);
756   else
757     _vec_len (free_list->unaligned_buffers) = u_len;
758
759   /* Verify that buffers are known free. */
760   vlib_buffer_validate_alloc_free (vm, alloc_buffers,
761                                    n_alloc_buffers,
762                                    VLIB_BUFFER_KNOWN_FREE);
763
764   return n_alloc_buffers;
765 }
766
767 /* Allocate a given number of buffers into given array.
768    Returns number actually allocated which will be either zero or
769    number requested. */
770 u32 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
771 {
772   vlib_buffer_main_t * bm = vm->buffer_main;
773   ASSERT(os_get_cpu_number() == 0);
774
775   return alloc_from_free_list
776     (vm,
777      pool_elt_at_index (bm->buffer_free_list_pool,
778                         VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX),
779      buffers, n_buffers);
780 }
781
782 u32 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
783                                       u32 * buffers,
784                                       u32 n_buffers,
785                                       u32 free_list_index)
786 {
787   vlib_buffer_main_t * bm = vm->buffer_main;
788   vlib_buffer_free_list_t * f;
789   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
790   return alloc_from_free_list (vm, f, buffers, n_buffers);
791 }
792
793 always_inline void
794 add_buffer_to_free_list (vlib_main_t * vm,
795                          vlib_buffer_free_list_t * f,
796                          u32 buffer_index, u8 do_init)
797 {
798   vlib_buffer_t * b;
799   b = vlib_get_buffer (vm, buffer_index);
800   if (PREDICT_TRUE(do_init))
801       vlib_buffer_init_for_free_list (b, f);
802   vec_add1_aligned (f->aligned_buffers, buffer_index, sizeof (vlib_copy_unit_t));
803 }
804
805 always_inline vlib_buffer_free_list_t *
806 buffer_get_free_list (vlib_main_t * vm, vlib_buffer_t * b, u32 * index)
807 {
808   vlib_buffer_main_t * bm = vm->buffer_main;
809   u32 i;
810
811   *index = i = b->free_list_index;
812   return pool_elt_at_index (bm->buffer_free_list_pool, i);
813 }
814
815 void *vlib_set_buffer_free_callback (vlib_main_t *vm, void *fp)
816 {
817   vlib_buffer_main_t * bm = vm->buffer_main;
818   void * rv = bm->buffer_free_callback;
819
820   bm->buffer_free_callback = fp;
821   return rv;
822 }
823
824 void vnet_buffer_free_dpdk_mb (vlib_buffer_t * b) __attribute__ ((weak));
825 void vnet_buffer_free_dpdk_mb (vlib_buffer_t * b) { }
826
827 static_always_inline void
828 vlib_buffer_free_inline (vlib_main_t * vm,
829                          u32 * buffers,
830                          u32 n_buffers,
831                          u32 follow_buffer_next)
832 {
833   vlib_buffer_main_t * bm = vm->buffer_main;
834   vlib_buffer_free_list_t * fl;
835   static u32 * next_to_free[2]; /* smp bad */
836   u32 i_next_to_free, * b, * n, * f, fi;
837   uword n_left;
838   int i;
839   static vlib_buffer_free_list_t ** announce_list;
840   vlib_buffer_free_list_t * fl0 = 0, * fl1 = 0;
841   u32 bi0=(u32)~0, bi1=(u32)~0, fi0, fi1 = (u32)~0;
842   u8 free0, free1=0, free_next0, free_next1;
843   u32 (*cb)(vlib_main_t * vm, u32 * buffers, u32 n_buffers,
844             u32 follow_buffer_next);
845
846   ASSERT(os_get_cpu_number() == 0);
847   
848   cb = bm->buffer_free_callback;
849
850   if (PREDICT_FALSE (cb != 0))
851     n_buffers = (*cb)(vm, buffers, n_buffers, follow_buffer_next);
852
853   if (! n_buffers)
854     return;
855
856   /* Use first buffer to get default free list. */
857   {
858     u32 bi0 = buffers[0];
859     vlib_buffer_t * b0;
860
861     b0 = vlib_get_buffer (vm, bi0);
862     fl = buffer_get_free_list (vm, b0, &fi);
863     if (fl->buffers_added_to_freelist_function)
864         vec_add1 (announce_list, fl);
865   }
866
867   vec_validate (next_to_free[0], n_buffers - 1);
868   vec_validate (next_to_free[1], n_buffers - 1);
869
870   i_next_to_free = 0;
871   n_left = n_buffers;
872   b = buffers;
873
874  again:
875   /* Verify that buffers are known allocated. */
876   vlib_buffer_validate_alloc_free (vm, b,
877                                    n_left,
878                                    VLIB_BUFFER_KNOWN_ALLOCATED);
879
880   vec_add2_aligned (fl->aligned_buffers, f, n_left,
881                     /* align */ sizeof (vlib_copy_unit_t));
882
883   n = next_to_free[i_next_to_free];
884   while (n_left >= 4)
885     {
886       vlib_buffer_t * b0, * b1, * binit0, * binit1, dummy_buffers[2];
887
888       bi0 = b[0];
889       bi1 = b[1];
890
891       f[0] = bi0;
892       f[1] = bi1;
893       f += 2;
894       b += 2;
895       n_left -= 2;
896
897       /* Prefetch buffers for next iteration. */
898       vlib_prefetch_buffer_with_index (vm, b[0], WRITE);
899       vlib_prefetch_buffer_with_index (vm, b[1], WRITE);
900
901       b0 = vlib_get_buffer (vm, bi0);
902       b1 = vlib_get_buffer (vm, bi1);
903
904       free0 = b0->clone_count == 0;
905       free1 = b1->clone_count == 0;
906
907       /* Must be before init which will over-write buffer flags. */
908       if (follow_buffer_next)
909         {
910           n[0] = b0->next_buffer;
911           free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
912           n += free_next0;
913
914           n[0] = b1->next_buffer;
915           free_next1 = free1 && (b1->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
916           n += free_next1;
917         }
918       else
919         free_next0 = free_next1 = 0;
920
921       /* Must be before init which will over-write buffer free list. */
922       fi0 = b0->free_list_index;
923       fi1 = b1->free_list_index;
924
925       if (PREDICT_FALSE (fi0 != fi || fi1 != fi))
926         goto slow_path_x2;
927
928       binit0 = free0 ? b0 : &dummy_buffers[0];
929       binit1 = free1 ? b1 : &dummy_buffers[1];
930
931       vlib_buffer_init_two_for_free_list (binit0, binit1, fl);
932       continue;
933
934     slow_path_x2:
935       /* Backup speculation. */
936       f -= 2;
937       n -= free_next0 + free_next1;
938
939       _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
940
941       fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
942       fl1 = pool_elt_at_index (bm->buffer_free_list_pool, fi1);
943
944       add_buffer_to_free_list (vm, fl0, bi0, free0);
945       if (PREDICT_FALSE(fl0->buffers_added_to_freelist_function != 0))
946         {
947           int i;
948           for (i = 0; i < vec_len (announce_list); i++)
949             if (fl0 == announce_list[i])
950               goto no_fl0;
951           vec_add1(announce_list, fl0);
952         }
953     no_fl0:
954       if (PREDICT_FALSE(fl1->buffers_added_to_freelist_function != 0))
955         {
956           int i;
957           for (i = 0; i < vec_len (announce_list); i++)
958             if (fl1 == announce_list[i])
959               goto no_fl1;
960           vec_add1(announce_list, fl1);
961         }
962
963     no_fl1:
964       add_buffer_to_free_list (vm, fl1, bi1, free1);
965
966       /* Possibly change current free list. */
967       if (fi0 != fi && fi1 != fi)
968         {
969           fi = fi1;
970           fl = pool_elt_at_index (bm->buffer_free_list_pool, fi);
971         }
972
973       vec_add2_aligned (fl->aligned_buffers, f, n_left,
974                         /* align */ sizeof (vlib_copy_unit_t));
975     }
976
977   while (n_left >= 1)
978     {
979       vlib_buffer_t * b0, * binit0, dummy_buffers[1];
980
981       bi0 = b[0];
982       f[0] = bi0;
983       f += 1;
984       b += 1;
985       n_left -= 1;
986
987       b0 = vlib_get_buffer (vm, bi0);
988
989       free0 = b0->clone_count == 0;
990
991       /* Must be before init which will over-write buffer flags. */
992       if (follow_buffer_next)
993         {
994           n[0] = b0->next_buffer;
995           free_next0 = free0 && (b0->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
996           n += free_next0;
997         }
998       else
999         free_next0 = 0;
1000
1001       /* Must be before init which will over-write buffer free list. */
1002       fi0 = b0->free_list_index;
1003
1004       if (PREDICT_FALSE (fi0 != fi))
1005         goto slow_path_x1;
1006
1007       binit0 = free0 ? b0 : &dummy_buffers[0];
1008
1009       vlib_buffer_init_for_free_list (binit0, fl);
1010       continue;
1011
1012     slow_path_x1:
1013       /* Backup speculation. */
1014       f -= 1;
1015       n -= free_next0;
1016
1017       _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
1018
1019       fl0 = pool_elt_at_index (bm->buffer_free_list_pool, fi0);
1020
1021       add_buffer_to_free_list (vm, fl0, bi0, free0);
1022       if (PREDICT_FALSE(fl0->buffers_added_to_freelist_function != 0))
1023         {
1024           int i;
1025           for (i = 0; i < vec_len (announce_list); i++)
1026             if (fl0 == announce_list[i])
1027               goto no_fl00;
1028           vec_add1(announce_list, fl0);
1029         }
1030       
1031     no_fl00:
1032       fi = fi0;
1033       fl = pool_elt_at_index (bm->buffer_free_list_pool, fi);
1034
1035       vec_add2_aligned (fl->aligned_buffers, f, n_left,
1036                         /* align */ sizeof (vlib_copy_unit_t));
1037     }
1038
1039   if (follow_buffer_next && ((n_left = n - next_to_free[i_next_to_free]) > 0))
1040     {
1041       b = next_to_free[i_next_to_free];
1042       i_next_to_free ^= 1;
1043       goto again;
1044     }
1045
1046   _vec_len (fl->aligned_buffers) = f - fl->aligned_buffers;
1047
1048   if (vec_len(announce_list))
1049     {
1050       vlib_buffer_free_list_t * fl;
1051       for (i = 0; i < vec_len (announce_list); i++)
1052         {
1053           fl = announce_list[i];
1054           fl->buffers_added_to_freelist_function (vm, fl);
1055         }
1056       _vec_len(announce_list) = 0;
1057     }
1058 }
1059
1060 void vlib_buffer_free (vlib_main_t * vm,
1061                        u32 * buffers,
1062                        u32 n_buffers)
1063 {
1064   vlib_buffer_free_inline (vm, buffers, n_buffers, /* follow_buffer_next */ 1);
1065 }
1066
1067 void vlib_buffer_free_no_next (vlib_main_t * vm,
1068                                u32 * buffers,
1069                                u32 n_buffers)
1070 {
1071   vlib_buffer_free_inline (vm, buffers, n_buffers, /* follow_buffer_next */ 0);
1072 }
1073
1074 /* Copy template packet data into buffers as they are allocated. */
1075 static void
1076 vlib_packet_template_buffer_init (vlib_main_t * vm,
1077                                   vlib_buffer_free_list_t * fl,
1078                                   u32 * buffers,
1079                                   u32 n_buffers)
1080 {
1081   vlib_packet_template_t * t = uword_to_pointer (fl->buffer_init_function_opaque,
1082                                                  vlib_packet_template_t *);
1083   uword i;
1084
1085   for (i = 0; i < n_buffers; i++)
1086     {
1087       vlib_buffer_t * b = vlib_get_buffer (vm, buffers[i]);
1088       ASSERT (b->current_length == vec_len (t->packet_data));
1089       memcpy (vlib_buffer_get_current (b), t->packet_data, b->current_length);
1090     }
1091 }
1092
1093 void vlib_packet_template_init (vlib_main_t * vm,
1094                                 vlib_packet_template_t * t,
1095                                 void * packet_data,
1096                                 uword n_packet_data_bytes,
1097                                 uword min_n_buffers_each_physmem_alloc,
1098                                 char * fmt,
1099                                 ...)
1100 {
1101   vlib_buffer_free_list_t * fl;
1102   va_list va;
1103   u8 * name;
1104
1105   va_start (va, fmt);
1106   name = va_format (0, fmt, &va);
1107   va_end (va);
1108
1109   memset (t, 0, sizeof (t[0]));
1110
1111   vec_add (t->packet_data, packet_data, n_packet_data_bytes);
1112   t->min_n_buffers_each_physmem_alloc = min_n_buffers_each_physmem_alloc;
1113
1114   t->free_list_index = vlib_buffer_create_free_list_helper
1115     (vm, n_packet_data_bytes,
1116      /* is_public */ 1,
1117      /* is_default */ 0,
1118      name);
1119
1120   ASSERT (t->free_list_index != 0);
1121   fl = vlib_buffer_get_free_list (vm, t->free_list_index);
1122   fl->min_n_buffers_each_physmem_alloc = t->min_n_buffers_each_physmem_alloc;
1123
1124   fl->buffer_init_function = vlib_packet_template_buffer_init;
1125   fl->buffer_init_function_opaque = pointer_to_uword (t);
1126
1127   fl->buffer_init_template.current_data = 0;
1128   fl->buffer_init_template.current_length = n_packet_data_bytes;
1129   fl->buffer_init_template.flags = 0;
1130 }
1131
1132 void *
1133 vlib_packet_template_get_packet (vlib_main_t * vm, 
1134                                  vlib_packet_template_t * t, 
1135                                  u32 * bi_result)
1136 {
1137   u32 bi;
1138   vlib_buffer_t * b;
1139
1140   if (vlib_buffer_alloc (vm, &bi, 1) != 1)
1141     return 0;
1142
1143   *bi_result = bi;
1144
1145   b = vlib_get_buffer (vm, bi);
1146   memcpy (vlib_buffer_get_current (b),
1147           t->packet_data, vec_len(t->packet_data));
1148   b->current_length = vec_len(t->packet_data);
1149
1150   return b->data;
1151 }
1152
1153 void vlib_packet_template_get_packet_helper (vlib_main_t * vm, vlib_packet_template_t * t)
1154 {
1155   word n = t->min_n_buffers_each_physmem_alloc;
1156   word l = vec_len (t->packet_data);
1157   word n_alloc;
1158
1159   ASSERT (l > 0);
1160   ASSERT (vec_len (t->free_buffers) == 0);
1161
1162   vec_validate (t->free_buffers, n - 1);
1163   n_alloc = vlib_buffer_alloc_from_free_list (vm, t->free_buffers,
1164                                               n, t->free_list_index);
1165   _vec_len (t->free_buffers) = n_alloc;
1166 }
1167
1168 /* Append given data to end of buffer, possibly allocating new buffers. */
1169 u32 vlib_buffer_add_data (vlib_main_t * vm,
1170                           u32 free_list_index,
1171                           u32 buffer_index,
1172                           void * data, u32 n_data_bytes)
1173 {
1174   u32 n_buffer_bytes, n_left, n_left_this_buffer, bi;
1175   vlib_buffer_t * b;
1176   void * d;
1177
1178   bi = buffer_index;
1179   if (bi == 0
1180       && 1 != vlib_buffer_alloc_from_free_list (vm, &bi, 1, free_list_index))
1181     goto out_of_buffers;
1182
1183   d = data;
1184   n_left = n_data_bytes;
1185   n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
1186   
1187   b = vlib_get_buffer (vm, bi);
1188   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1189
1190   /* Get to the end of the chain before we try to append data...*/
1191   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1192     b = vlib_get_buffer (vm, b->next_buffer);
1193
1194   while (1)
1195     {
1196       u32 n;
1197
1198       ASSERT (n_buffer_bytes >= b->current_length);
1199       n_left_this_buffer = n_buffer_bytes - (b->current_data + b->current_length);
1200       n = clib_min (n_left_this_buffer, n_left);
1201       memcpy (vlib_buffer_get_current (b) + b->current_length, d, n);
1202       b->current_length += n;
1203       n_left -= n;
1204       if (n_left == 0)
1205         break;
1206
1207       d += n;
1208       if (1 != vlib_buffer_alloc_from_free_list (vm, &b->next_buffer, 1, free_list_index))
1209         goto out_of_buffers;
1210
1211       b->flags |= VLIB_BUFFER_NEXT_PRESENT;
1212
1213       b = vlib_get_buffer (vm, b->next_buffer);
1214     }
1215
1216   return bi;
1217
1218  out_of_buffers:
1219   clib_error ("out of buffers");
1220   return bi;
1221 }
1222
1223 u16
1224 vlib_buffer_chain_append_data_with_alloc(vlib_main_t *vm,
1225                              u32 free_list_index,
1226                              vlib_buffer_t *first,
1227                              vlib_buffer_t **last,
1228                              void * data, u16 data_len) {
1229   vlib_buffer_t *l = *last;
1230   u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
1231   u16 copied = 0;
1232   ASSERT(n_buffer_bytes >= l->current_length + l->current_data);
1233   while (data_len) {
1234     u16 max = n_buffer_bytes - l->current_length - l->current_data;
1235     if (max == 0) {
1236       if (1 != vlib_buffer_alloc_from_free_list (vm, &l->next_buffer, 1, free_list_index))
1237         return copied;
1238       *last = l = vlib_buffer_chain_buffer(vm, first, l, l->next_buffer);
1239       max = n_buffer_bytes - l->current_length - l->current_data;
1240     }
1241
1242     u16 len = (data_len > max)?max:data_len;
1243     memcpy(vlib_buffer_get_current (l) + l->current_length, data + copied, len);
1244     vlib_buffer_chain_increase_length(first, l, len);
1245     data_len -= len;
1246     copied += len;
1247   }
1248   return copied;
1249 }
1250
1251 static void vlib_serialize_tx (serialize_main_header_t * m, serialize_stream_t * s)
1252 {
1253   vlib_main_t * vm;
1254   vlib_serialize_buffer_main_t * sm;
1255   uword n, n_bytes_to_write;
1256   vlib_buffer_t * last;
1257
1258   n_bytes_to_write = s->current_buffer_index;
1259   sm = uword_to_pointer (s->data_function_opaque, vlib_serialize_buffer_main_t *);
1260   vm = sm->vlib_main;
1261
1262   ASSERT (sm->tx.max_n_data_bytes_per_chain > 0);
1263   if (serialize_stream_is_end_of_stream (s)
1264       || sm->tx.n_total_data_bytes + n_bytes_to_write > sm->tx.max_n_data_bytes_per_chain)
1265     {
1266       vlib_process_t * p = vlib_get_current_process (vm);
1267
1268       last = vlib_get_buffer (vm, sm->last_buffer);
1269       last->current_length = n_bytes_to_write;
1270
1271       vlib_set_next_frame_buffer (vm, &p->node_runtime, sm->tx.next_index, sm->first_buffer);
1272
1273       sm->first_buffer = sm->last_buffer = ~0;
1274       sm->tx.n_total_data_bytes = 0;
1275     }
1276
1277   else if (n_bytes_to_write == 0 && s->n_buffer_bytes == 0)
1278     {
1279       ASSERT (sm->first_buffer == ~0);
1280       ASSERT (sm->last_buffer == ~0);
1281       n = vlib_buffer_alloc_from_free_list (vm, &sm->first_buffer, 1, sm->tx.free_list_index);
1282       if (n != 1)
1283         serialize_error (m, clib_error_create ("vlib_buffer_alloc_from_free_list fails"));
1284       sm->last_buffer = sm->first_buffer;
1285       s->n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, sm->tx.free_list_index);
1286     }
1287
1288   if (n_bytes_to_write > 0)
1289     {
1290       vlib_buffer_t * prev = vlib_get_buffer (vm, sm->last_buffer);
1291       n = vlib_buffer_alloc_from_free_list (vm, &sm->last_buffer, 1, sm->tx.free_list_index);
1292       if (n != 1)
1293         serialize_error (m, clib_error_create ("vlib_buffer_alloc_from_free_list fails"));
1294       sm->tx.n_total_data_bytes += n_bytes_to_write;
1295       prev->current_length = n_bytes_to_write;
1296       prev->next_buffer = sm->last_buffer;
1297       prev->flags |= VLIB_BUFFER_NEXT_PRESENT;
1298     }
1299
1300   if (sm->last_buffer != ~0)
1301     {
1302       last = vlib_get_buffer (vm, sm->last_buffer);
1303       s->buffer = vlib_buffer_get_current (last);
1304       s->current_buffer_index = 0;
1305       ASSERT (last->current_data == s->current_buffer_index);
1306     }
1307 }
1308
1309 static void vlib_serialize_rx (serialize_main_header_t * m, serialize_stream_t * s)
1310 {
1311   vlib_main_t * vm;
1312   vlib_serialize_buffer_main_t * sm;
1313   vlib_buffer_t * last;
1314
1315   sm = uword_to_pointer (s->data_function_opaque, vlib_serialize_buffer_main_t *);
1316   vm = sm->vlib_main;
1317
1318   if (serialize_stream_is_end_of_stream (s))
1319     return;
1320
1321   if (sm->last_buffer != ~0)
1322     {
1323       last = vlib_get_buffer (vm, sm->last_buffer);
1324
1325       if (last->flags & VLIB_BUFFER_NEXT_PRESENT)
1326         sm->last_buffer = last->next_buffer;
1327       else
1328         {
1329           vlib_buffer_free (vm, &sm->first_buffer, /* count */ 1);
1330           sm->first_buffer = sm->last_buffer = ~0;
1331         }
1332     }
1333
1334   if (sm->last_buffer == ~0)
1335     {
1336       while (clib_fifo_elts (sm->rx.buffer_fifo) == 0)
1337         {
1338           sm->rx.ready_one_time_event = vlib_process_create_one_time_event (vm, vlib_current_process (vm), ~0);
1339           vlib_process_wait_for_one_time_event (vm, /* no event data */ 0, sm->rx.ready_one_time_event);
1340         }
1341
1342       clib_fifo_sub1 (sm->rx.buffer_fifo, sm->first_buffer);
1343       sm->last_buffer = sm->first_buffer;
1344     }
1345
1346   ASSERT (sm->last_buffer != ~0);
1347
1348   last = vlib_get_buffer (vm, sm->last_buffer);
1349   s->current_buffer_index = 0;
1350   s->buffer = vlib_buffer_get_current (last);
1351   s->n_buffer_bytes = last->current_length;
1352 }
1353
1354 static void
1355 serialize_open_vlib_helper (serialize_main_t * m,
1356                             vlib_main_t * vm,
1357                             vlib_serialize_buffer_main_t * sm,
1358                             uword is_read)
1359 {
1360   /* Initialize serialize main but save overflow buffer for re-use between calls. */
1361   {
1362     u8 * save = m->stream.overflow_buffer;
1363     memset (m, 0, sizeof (m[0]));
1364     m->stream.overflow_buffer = save;
1365     if (save)
1366       _vec_len (save) = 0;
1367   }
1368
1369   sm->first_buffer = sm->last_buffer = ~0;
1370   if (is_read)
1371     clib_fifo_reset (sm->rx.buffer_fifo);
1372   else
1373     sm->tx.n_total_data_bytes = 0;
1374   sm->vlib_main = vm;
1375   m->header.data_function = is_read ? vlib_serialize_rx : vlib_serialize_tx;
1376   m->stream.data_function_opaque = pointer_to_uword (sm);
1377 }
1378
1379 void serialize_open_vlib_buffer (serialize_main_t * m, vlib_main_t * vm, vlib_serialize_buffer_main_t * sm)
1380 { serialize_open_vlib_helper (m, vm, sm, /* is_read */ 0); }
1381
1382 void unserialize_open_vlib_buffer (serialize_main_t * m, vlib_main_t * vm, vlib_serialize_buffer_main_t * sm)
1383 { serialize_open_vlib_helper (m, vm, sm, /* is_read */ 1); }
1384
1385 u32 serialize_close_vlib_buffer (serialize_main_t * m)
1386 {
1387   vlib_serialize_buffer_main_t * sm
1388     = uword_to_pointer (m->stream.data_function_opaque, vlib_serialize_buffer_main_t *);
1389   vlib_buffer_t * last;
1390   serialize_stream_t * s = &m->stream;
1391
1392   last = vlib_get_buffer (sm->vlib_main, sm->last_buffer);
1393   last->current_length = s->current_buffer_index;
1394
1395   if (vec_len (s->overflow_buffer) > 0)
1396     {
1397       sm->last_buffer
1398         = vlib_buffer_add_data (sm->vlib_main, sm->tx.free_list_index,
1399                                 sm->last_buffer == ~0 ? 0 : sm->last_buffer,
1400                                 s->overflow_buffer,
1401                                 vec_len (s->overflow_buffer));
1402       _vec_len (s->overflow_buffer) = 0;
1403     }
1404
1405   return sm->first_buffer;
1406 }
1407
1408 void unserialize_close_vlib_buffer (serialize_main_t * m)
1409 {
1410   vlib_serialize_buffer_main_t * sm
1411     = uword_to_pointer (m->stream.data_function_opaque, vlib_serialize_buffer_main_t *);
1412   if (sm->first_buffer != ~0)
1413     vlib_buffer_free_one (sm->vlib_main, sm->first_buffer);
1414   clib_fifo_reset (sm->rx.buffer_fifo);
1415   if (m->stream.overflow_buffer)
1416     _vec_len (m->stream.overflow_buffer) = 0;
1417 }
1418
1419 static u8 * format_vlib_buffer_free_list (u8 * s, va_list * va)
1420 {
1421   vlib_buffer_free_list_t * f = va_arg (*va, vlib_buffer_free_list_t *);
1422   uword bytes_alloc, bytes_free, n_free, size;
1423
1424   if (! f)
1425     return format (s, "%=30s%=12s%=12s%=12s%=12s%=12s%=12s",
1426                    "Name", "Index", "Size", "Alloc", "Free", "#Alloc", "#Free");
1427
1428   size = sizeof (vlib_buffer_t) + f->n_data_bytes;
1429   n_free = vec_len (f->aligned_buffers) + vec_len (f->unaligned_buffers);
1430   bytes_alloc = size * f->n_alloc;
1431   bytes_free = size * n_free;
1432
1433   s = format (s, "%30s%12d%12d%=12U%=12U%=12d%=12d",
1434               f->name, f->index, f->n_data_bytes,
1435               format_memory_size, bytes_alloc,
1436               format_memory_size, bytes_free,
1437               f->n_alloc, n_free);
1438
1439   return s;
1440 }
1441
1442 static clib_error_t *
1443 show_buffers (vlib_main_t * vm,
1444               unformat_input_t * input,
1445               vlib_cli_command_t * cmd)
1446 {
1447   vlib_buffer_main_t * bm = vm->buffer_main;
1448   vlib_buffer_free_list_t * f;
1449
1450   vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, 0);
1451   pool_foreach (f, bm->buffer_free_list_pool, ({
1452     vlib_cli_output (vm, "%U", format_vlib_buffer_free_list, f);
1453   }));
1454
1455   return 0;
1456 }
1457
1458 VLIB_CLI_COMMAND (show_buffers_command, static) = {
1459   .path = "show buffers",
1460   .short_help = "Show packet buffer allocation",
1461   .function = show_buffers,
1462 };
1463