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