Remove duplicate code buffer_func.h
[vpp.git] / vlib / vlib / buffer_funcs.h
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_funcs.h: VLIB buffer related functions/inlines
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 #ifndef included_vlib_buffer_funcs_h
41 #define included_vlib_buffer_funcs_h
42
43 #include <vppinfra/hash.h>
44
45 #if DPDK == 1
46 #undef always_inline // dpdk and clib use conflicting always_inline macros.
47 #include <rte_config.h>
48 #include <rte_mbuf.h>
49
50 #if CLIB_DEBUG > 0
51 #define always_inline static inline
52 #else
53 #define always_inline static inline __attribute__ ((__always_inline__))
54 #endif
55 #endif
56
57 /** \file
58     vlib buffer access methods.
59 */
60
61
62 /** \brief Translate buffer index into buffer pointer
63
64     @param vm - (vlib_main_t *) vlib main data structure pointer
65     @param buffer_index - (u32) buffer index
66     @return - (vlib_buffer_t *) buffer pointer
67 */    
68 always_inline vlib_buffer_t *
69 vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
70 {
71   return vlib_physmem_at_offset (&vm->physmem_main, ((uword)buffer_index)
72                                  << CLIB_LOG2_CACHE_LINE_BYTES);
73 }
74
75 /** \brief Translate buffer pointer into buffer index
76
77     @param vm - (vlib_main_t *) vlib main data structure pointer
78     @param b - (void *) buffer pointer
79     @return - (u32) buffer index
80 */    
81 always_inline u32
82 vlib_get_buffer_index (vlib_main_t * vm, void * p)
83 {
84   uword offset = vlib_physmem_offset_of (&vm->physmem_main, p);
85   ASSERT((offset % (1<<CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
86   return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
87 }
88
89 /** \brief Get next buffer in buffer linklist, or zero for end of list.
90
91     @param vm - (vlib_main_t *) vlib main data structure pointer
92     @param b - (void *) buffer pointer
93     @return - (vlib_buffer_t *) next buffer, or NULL
94 */    
95 always_inline vlib_buffer_t *
96 vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
97 {
98   return (b->flags & VLIB_BUFFER_NEXT_PRESENT
99           ? vlib_get_buffer (vm, b->next_buffer)
100           : 0);
101 }
102
103 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm, vlib_buffer_t * b_first);
104
105 /** \brief Get length in bytes of the buffer chain
106
107     @param vm - (vlib_main_t *) vlib main data structure pointer
108     @param b - (void *) buffer pointer
109     @return - (uword) length of buffer chain
110 */    
111 always_inline uword
112 vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
113 {
114   uword l = b->current_length + b->total_length_not_including_first_buffer;
115   if (PREDICT_FALSE ((b->flags & (VLIB_BUFFER_NEXT_PRESENT
116                                   | VLIB_BUFFER_TOTAL_LENGTH_VALID))
117                      == VLIB_BUFFER_NEXT_PRESENT))
118     return vlib_buffer_length_in_chain_slow_path (vm, b);
119   return l;
120 }
121
122 /** \brief Get length in bytes of the buffer index buffer chain
123
124     @param vm - (vlib_main_t *) vlib main data structure pointer
125     @param bi - (u32) buffer index
126     @return - (uword) length of buffer chain
127 */    
128 always_inline uword
129 vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
130 {
131   vlib_buffer_t * b = vlib_get_buffer (vm, bi);
132   return vlib_buffer_length_in_chain (vm, b);
133 }
134
135 /** \brief Copy buffer contents to memory
136
137     @param vm - (vlib_main_t *) vlib main data structure pointer
138     @param bi - (u32) buffer index
139     @param contents - (u8 *) memory, <strong>must be large enough</strong>
140     @return - (uword) length of buffer chain
141 */    
142 always_inline uword
143 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
144 {
145   uword content_len = 0;
146   uword l;
147   vlib_buffer_t * b;
148
149   while (1)
150     {
151       b = vlib_get_buffer (vm, buffer_index);
152       l = b->current_length;
153       clib_memcpy (contents + content_len, b->data + b->current_data, l);
154       content_len += l;
155       if (! (b->flags & VLIB_BUFFER_NEXT_PRESENT))
156         break;
157       buffer_index = b->next_buffer;
158     }
159
160   return content_len;
161 }
162
163 /* Return physical address of buffer->data start. */
164 always_inline u64
165 vlib_get_buffer_data_physical_address (vlib_main_t * vm, u32 buffer_index)
166 {
167   return vlib_physmem_offset_to_physical (&vm->physmem_main,
168                                           (((uword)buffer_index) <<
169                                            CLIB_LOG2_CACHE_LINE_BYTES) +
170                                            STRUCT_OFFSET_OF (vlib_buffer_t, data));
171 }
172
173 /** \brief Prefetch buffer metadata by buffer index
174     The first 64 bytes of buffer contains most header information
175
176     @param vm - (vlib_main_t *) vlib main data structure pointer
177     @param bi - (u32) buffer index
178     @param type - LOAD, STORE. In most cases, STORE is the right answer
179 */
180 /* Prefetch buffer header given index. */
181 #define vlib_prefetch_buffer_with_index(vm,bi,type)     \
182   do {                                                  \
183     vlib_buffer_t * _b = vlib_get_buffer (vm, bi);      \
184     vlib_prefetch_buffer_header (_b, type);             \
185   } while (0)
186
187 #if 0
188 /* Iterate over known allocated vlib bufs. You probably do not want
189  * to do this!
190  @param vm      the vlib_main_t
191  @param bi      found allocated buffer index
192  @param body    operation to perform on buffer index
193  function executes body for each allocated buffer index
194  */
195 #define vlib_buffer_foreach_allocated(vm,bi,body)                \
196 do {                                                             \
197   vlib_main_t * _vmain = (vm);                                   \
198   vlib_buffer_main_t * _bmain = &_vmain->buffer_main;            \
199   hash_pair_t * _vbpair;                                         \
200   hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({       \
201     if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) {      \
202       (bi) = _vbpair->key;                                       \
203       body;                                                      \
204     }                                                            \
205   }));                                                           \
206 } while (0)
207 #endif
208
209 #if DPDK == 0
210
211 typedef enum {
212   /* Index is unknown. */
213   VLIB_BUFFER_UNKNOWN,
214
215   /* Index is known and free/allocated. */
216   VLIB_BUFFER_KNOWN_FREE,
217   VLIB_BUFFER_KNOWN_ALLOCATED,
218 } vlib_buffer_known_state_t;
219
220 always_inline vlib_buffer_known_state_t
221 vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
222 {
223   vlib_buffer_main_t * bm = vm->buffer_main;
224   ASSERT(os_get_cpu_number() == 0);
225
226   uword * p = hash_get (bm->buffer_known_hash, buffer_index);
227   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
228 }
229
230 always_inline void
231 vlib_buffer_set_known_state (vlib_main_t * vm,
232                              u32 buffer_index,
233                              vlib_buffer_known_state_t state)
234 {
235   vlib_buffer_main_t * bm = vm->buffer_main;
236   ASSERT(os_get_cpu_number() == 0);
237   hash_set (bm->buffer_known_hash, buffer_index, state);
238 }
239
240 /* Validates sanity of a single buffer.
241    Returns format'ed vector with error message if any. */
242 u8 * vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index, uword follow_chain);
243
244 /* Validate an array of buffers.  As above. */
245 u8 * vlib_validate_buffers (vlib_main_t * vm,
246                             u32 * buffers,
247                             uword next_buffer_stride,
248                             uword n_buffers,
249                             vlib_buffer_known_state_t known_state,
250                             uword follow_chain);
251
252 #endif /* DPDK == 0 */
253
254 clib_error_t *
255 vlib_buffer_pool_create(vlib_main_t * vm, unsigned num_mbufs,
256                         unsigned socket_id);
257
258 /** \brief Allocate buffers into supplied array
259
260     @param vm - (vlib_main_t *) vlib main data structure pointer
261     @param buffers - (u32 * ) buffer index array
262     @param n_buffers - (u32) number of buffers requested
263     @return - (u32) number of buffers actually allocated, may be 
264     less than the number requested or zero
265 */
266 u32 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers);
267
268 always_inline u32
269 vlib_buffer_round_size (u32 size)
270 { return round_pow2 (size, sizeof (vlib_buffer_t)); }
271
272 /** \brief Allocate buffers from specific freelist into supplied array
273
274     @param vm - (vlib_main_t *) vlib main data structure pointer
275     @param buffers - (u32 * ) buffer index array
276     @param n_buffers - (u32) number of buffers requested
277     @return - (u32) number of buffers actually allocated, may be 
278     less than the number requested or zero
279 */
280 u32 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
281                                       u32 * buffers,
282                                       u32 n_buffers,
283                                       u32 free_list_index);
284
285 /** \brief Free buffers
286     Frees the entire buffer chain for each buffer
287
288     @param vm - (vlib_main_t *) vlib main data structure pointer
289     @param buffers - (u32 * ) buffer index array
290     @param n_buffers - (u32) number of buffers to free
291
292 */
293 void vlib_buffer_free (vlib_main_t * vm,
294                        /* pointer to first buffer */
295                        u32 * buffers,
296                        /* number of buffers to free */
297                        u32 n_buffers);
298
299 /** \brief Free buffers, does not free the buffer chain for each buffer
300
301     @param vm - (vlib_main_t *) vlib main data structure pointer
302     @param buffers - (u32 * ) buffer index array
303     @param n_buffers - (u32) number of buffers to free
304
305 */
306 void vlib_buffer_free_no_next (vlib_main_t * vm,
307                                /* pointer to first buffer */
308                                u32 * buffers,
309                                /* number of buffers to free */
310                                u32 n_buffers);
311
312 /** \brief Free one buffer
313     Shorthand to free a single buffer chain. 
314
315     @param vm - (vlib_main_t *) vlib main data structure pointer
316     @param buffer_index - (u32) buffer index to free
317 */
318 always_inline void
319 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
320 {
321   vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
322 }
323
324 /* Add/delete buffer free lists. */
325 u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes, char * fmt, ...);
326 void vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index);
327
328 /* Find already existing public free list with given size or create one. */
329 u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes, char * fmt, ...);
330
331 always_inline vlib_buffer_free_list_t *
332 vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
333 {
334   vlib_buffer_main_t * bm = vm->buffer_main;
335   vlib_buffer_free_list_t * f;
336
337   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
338
339   /* Sanity: indices must match. */
340   ASSERT (f->index == free_list_index);
341
342   return f;
343 }
344
345 always_inline u32
346 vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
347 {
348   vlib_buffer_free_list_t * f = vlib_buffer_get_free_list (vm, free_list_index);
349   return f->n_data_bytes;
350 }
351
352 void
353 vlib_aligned_memcpy (void * _dst, void * _src, int n_bytes);
354
355 /* Reasonably fast buffer copy routine. */
356 always_inline void
357 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
358 {
359   while (n >= 4)
360     {
361       dst[0] = src[0];
362       dst[1] = src[1];
363       dst[2] = src[2];
364       dst[3] = src[3];
365       dst += 4;
366       src += 4;
367       n -= 4;
368     }
369   while (n > 0)
370     {
371       dst[0] = src[0];
372       dst += 1;
373       src += 1;
374       n -= 1;
375     }
376 }
377
378 always_inline void *
379 vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
380                             uword n_bytes, uword alignment)
381 {
382   void * r = vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
383   if (! r)
384     *error = clib_error_return (0, "failed to allocate %wd bytes of I/O memory", n_bytes);
385   else
386     *error = 0;
387   return r;
388 }
389
390 /* By default allocate I/O memory with cache line alignment. */
391 always_inline void *
392 vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
393 { return vlib_physmem_alloc_aligned (vm, error, n_bytes, CLIB_CACHE_LINE_BYTES); }
394
395 always_inline void
396 vlib_physmem_free (vlib_main_t * vm, void * mem)
397 { return vm->os_physmem_free (mem); }
398
399 always_inline u64
400 vlib_physmem_virtual_to_physical (vlib_main_t * vm, void * mem)
401 {
402   vlib_physmem_main_t * pm = &vm->physmem_main;
403   uword o = pointer_to_uword (mem) - pm->virtual.start;
404   return vlib_physmem_offset_to_physical (pm, o);
405 }
406
407 /* Append given data to end of buffer, possibly allocating new buffers. */
408 u32 vlib_buffer_add_data (vlib_main_t * vm,
409                           u32 free_list_index,
410                           u32 buffer_index,
411                           void * data, u32 n_data_bytes);
412
413 /*
414  * vlib_buffer_chain_* functions provide a way to create long buffers.
415  * When DPDK is enabled, the 'hidden' DPDK header is taken care of transparently.
416  */
417
418 /* Initializes the buffer as an empty packet with no chained buffers. */
419 always_inline void
420 vlib_buffer_chain_init(vlib_buffer_t *first)
421 {
422   first->total_length_not_including_first_buffer = 0;
423   first->current_length = 0;
424   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
425   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
426 #if DPDK == 1
427   struct rte_mbuf * mb = rte_mbuf_from_vlib_buffer(first);
428   rte_pktmbuf_reset(mb);
429   mb->data_off = VLIB_BUFFER_PRE_DATA_SIZE + first->current_data;
430 #endif
431 }
432
433 /* The provided next_bi buffer index is appended to the end of the packet. */
434 always_inline vlib_buffer_t *
435 vlib_buffer_chain_buffer(vlib_main_t *vm,
436                     vlib_buffer_t *first,
437                     vlib_buffer_t *last,
438                     u32 next_bi)
439 {
440   vlib_buffer_t *next_buffer = vlib_get_buffer(vm, next_bi);
441   last->next_buffer = next_bi;
442   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
443   next_buffer->current_length = 0;
444   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
445 #if DPDK == 1
446   struct rte_mbuf * mb;
447   mb = rte_mbuf_from_vlib_buffer(first);
448   mb->nb_segs++;
449
450   mb = rte_mbuf_from_vlib_buffer(last);
451   mb->next = rte_mbuf_from_vlib_buffer(next_buffer);
452
453   mb = rte_mbuf_from_vlib_buffer(next_buffer);
454   mb->data_len = 0;
455   mb->data_off = VLIB_BUFFER_PRE_DATA_SIZE + next_buffer->current_data;
456   mb->next = 0;
457 #endif
458   return next_buffer;
459 }
460
461 /* Increases or decreases the packet length.
462  * It does not allocate or deallocate new buffers.
463  * Therefore, the added length must be compatible
464  * with the last buffer. */
465 always_inline void
466 vlib_buffer_chain_increase_length(vlib_buffer_t *first,
467                              vlib_buffer_t *last,
468                              i32 len)
469 {
470   last->current_length += len;
471   if (first != last)
472     first->total_length_not_including_first_buffer += len;
473 #if DPDK == 1
474   struct rte_mbuf * mb_first = rte_mbuf_from_vlib_buffer(first);
475   struct rte_mbuf * mb_last = rte_mbuf_from_vlib_buffer(last);
476   mb_first->pkt_len += len;
477   mb_last->data_len += len;
478 #endif
479 }
480
481 /* Copy data to the end of the packet and increases its length.
482  * It does not allocate new buffers.
483  * Returns the number of copied bytes. */
484 always_inline u16
485 vlib_buffer_chain_append_data(vlib_main_t *vm,
486                              u32 free_list_index,
487                              vlib_buffer_t *first,
488                              vlib_buffer_t *last,
489                              void *data, u16 data_len)
490 {
491   u32 n_buffer_bytes = vlib_buffer_free_list_buffer_size (vm, free_list_index);
492   ASSERT(n_buffer_bytes >= last->current_length + last->current_data);
493   u16 len = clib_min(data_len, n_buffer_bytes - last->current_length - last->current_data);
494   clib_memcpy(vlib_buffer_get_current (last) + last->current_length, data, len);
495   vlib_buffer_chain_increase_length(first, last, len);
496   return len;
497 }
498
499 /* Copy data to the end of the packet and increases its length.
500  * Allocates additional buffers from the free list if necessary.
501  * Returns the number of copied bytes.
502  * 'last' value is modified whenever new buffers are allocated and
503  * chained and points to the last buffer in the chain. */
504 u16
505 vlib_buffer_chain_append_data_with_alloc(vlib_main_t *vm,
506                              u32 free_list_index,
507                              vlib_buffer_t *first,
508                              vlib_buffer_t **last,
509                              void * data, u16 data_len);
510 void vlib_buffer_chain_validate(vlib_main_t *vm, vlib_buffer_t *first);
511
512 format_function_t format_vlib_buffer, format_vlib_buffer_and_data, format_vlib_buffer_contents;
513
514 typedef struct {
515   /* Vector of packet data. */
516   u8 * packet_data;
517
518 #if DPDK == 0
519   /* Number of buffers to allocate in each call to physmem
520      allocator. */
521   u32 min_n_buffers_each_physmem_alloc;
522
523   /* Buffer free list for this template. */
524   u32 free_list_index;
525
526   u32 * free_buffers;
527 #endif
528 } vlib_packet_template_t;
529
530 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
531                                              vlib_packet_template_t * t);
532
533 void vlib_packet_template_init (vlib_main_t * vm,
534                                 vlib_packet_template_t * t,
535                                 void * packet_data,
536                                 uword n_packet_data_bytes,
537                                 uword min_n_buffers_each_physmem_alloc,
538                                 char * fmt, ...);
539
540 void *
541 vlib_packet_template_get_packet (vlib_main_t * vm, 
542                                  vlib_packet_template_t * t,
543                                  u32 * bi_result);
544
545 always_inline void
546 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
547 {
548   vec_free (t->packet_data);
549 }
550
551 always_inline u32
552 unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
553 {
554   serialize_stream_t * s = &m->stream;
555   vlib_serialize_buffer_main_t * sm
556     = uword_to_pointer (m->stream.data_function_opaque, vlib_serialize_buffer_main_t *);
557   vlib_main_t * vm = sm->vlib_main;
558   u32 n, * f;
559
560   n = s->n_buffer_bytes - s->current_buffer_index;
561   if (sm->last_buffer != ~0)
562     {
563       vlib_buffer_t * b = vlib_get_buffer (vm, sm->last_buffer);
564       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
565         {
566           b = vlib_get_buffer (vm, b->next_buffer);
567           n += b->current_length;
568         }
569     }
570
571   clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
572     n += vlib_buffer_index_length_in_chain (vm, f[0]);
573   }));
574
575   return n;
576 }
577
578 typedef union {
579   vlib_buffer_t b;
580   vlib_copy_unit_t i[sizeof (vlib_buffer_t) / sizeof (vlib_copy_unit_t)];
581 } vlib_buffer_union_t;
582
583 /* Set a buffer quickly into "uninitialized" state.  We want this to
584    be extremely cheap and arrange for all fields that need to be
585    initialized to be in the first 128 bits of the buffer. */
586 always_inline void
587 vlib_buffer_init_for_free_list (vlib_buffer_t * _dst,
588                                 vlib_buffer_free_list_t * fl)
589 {
590   vlib_buffer_union_t * dst = (vlib_buffer_union_t *) _dst;
591   vlib_buffer_union_t * src = (vlib_buffer_union_t *) &fl->buffer_init_template;
592
593   /* Make sure vlib_buffer_t is cacheline aligned and sized */
594   ASSERT(STRUCT_OFFSET_OF(vlib_buffer_t, cacheline0) == 0);
595   ASSERT(STRUCT_OFFSET_OF(vlib_buffer_t, cacheline1) == CLIB_CACHE_LINE_BYTES);
596   ASSERT(STRUCT_OFFSET_OF(vlib_buffer_t, cacheline2) == CLIB_CACHE_LINE_BYTES * 2);
597
598   /* Make sure buffer template is sane. */
599   ASSERT (fl->index == fl->buffer_init_template.free_list_index);
600
601   /* Copy template from src->current_data thru src->free_list_index */
602   dst->i[0] = src->i[0];
603   if (1 * sizeof (dst->i[0]) < 16)
604     dst->i[1] = src->i[1];
605   if (2 * sizeof (dst->i[0]) < 16)
606     dst->i[2] = src->i[2];
607
608   /* Make sure it really worked. */
609 #define _(f) ASSERT (dst->b.f == src->b.f)
610   _ (current_data);
611   _ (current_length);
612   _ (flags);
613   _ (free_list_index);
614 #undef _
615   ASSERT (dst->b.total_length_not_including_first_buffer == 0);
616 }
617
618 always_inline void
619 vlib_buffer_init_two_for_free_list (vlib_buffer_t * _dst0,
620                                     vlib_buffer_t * _dst1,
621                                     vlib_buffer_free_list_t * fl)
622 {
623   vlib_buffer_union_t * dst0 = (vlib_buffer_union_t *) _dst0;
624   vlib_buffer_union_t * dst1 = (vlib_buffer_union_t *) _dst1;
625   vlib_buffer_union_t * src = (vlib_buffer_union_t *) &fl->buffer_init_template;
626
627   /* Make sure buffer template is sane. */
628   ASSERT (fl->index == fl->buffer_init_template.free_list_index);
629
630   /* Copy template from src->current_data thru src->free_list_index */
631   dst0->i[0] = dst1->i[0] = src->i[0];
632   if (1 * sizeof (dst0->i[0]) < 16)
633     dst0->i[1] = dst1->i[1] = src->i[1];
634   if (2 * sizeof (dst0->i[0]) < 16)
635     dst0->i[2] = dst1->i[2] = src->i[2];
636
637   /* Make sure it really worked. */
638 #define _(f) ASSERT (dst0->b.f == src->b.f && dst1->b.f == src->b.f)
639   _ (current_data);
640   _ (current_length);
641   _ (flags);
642   _ (free_list_index);
643 #undef _
644   ASSERT (dst0->b.total_length_not_including_first_buffer == 0);
645   ASSERT (dst1->b.total_length_not_including_first_buffer == 0);
646 }
647
648 #if CLIB_DEBUG > 0
649 u32 * vlib_buffer_state_validation_lock;
650 uword * vlib_buffer_state_validation_hash;
651 void * vlib_buffer_state_heap;
652 #endif
653
654 static inline void 
655 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
656 {
657 #if CLIB_DEBUG > 0
658   uword * p;
659   void * oldheap;
660
661   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
662
663   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
664     ;
665
666   p = hash_get (vlib_buffer_state_validation_hash, b);
667
668   /* If we don't know about b, declare it to be in the expected state */
669   if (!p)
670     {
671       hash_set (vlib_buffer_state_validation_hash, b, expected);
672       goto out;
673     }
674   
675   if (p[0] != expected)
676     {
677       void cj_stop(void);
678       u32 bi;
679       vlib_main_t * vm = &vlib_global_main;
680       
681       cj_stop();
682       
683       bi = vlib_get_buffer_index (vm, b);
684
685       clib_mem_set_heap (oldheap);
686       clib_warning ("%.6f buffer %llx (%d): %s, not %s", 
687                     vlib_time_now(vm), bi,
688                     p[0] ? "busy" : "free",
689                     expected ? "busy" : "free");
690       os_panic();
691     }
692  out:
693   CLIB_MEMORY_BARRIER();
694   *vlib_buffer_state_validation_lock = 0;
695   clib_mem_set_heap (oldheap);
696 #endif
697 }
698
699 static inline void 
700 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
701 {
702 #if CLIB_DEBUG > 0
703   void * oldheap;
704
705   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
706
707   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
708     ;
709
710   hash_set (vlib_buffer_state_validation_hash, b, expected);
711
712   CLIB_MEMORY_BARRIER();
713   *vlib_buffer_state_validation_lock = 0;
714   clib_mem_set_heap (oldheap);
715 #endif  
716 }
717
718 #endif /* included_vlib_buffer_funcs_h */