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