Fix issues reported by coverity
[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 p - (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) : 0);
100 }
101
102 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
103                                              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 buffer_index - (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,
171                                                             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 {
214   /* Index is unknown. */
215   VLIB_BUFFER_UNKNOWN,
216
217   /* Index is known and free/allocated. */
218   VLIB_BUFFER_KNOWN_FREE,
219   VLIB_BUFFER_KNOWN_ALLOCATED,
220 } vlib_buffer_known_state_t;
221
222 always_inline vlib_buffer_known_state_t
223 vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
224 {
225   vlib_buffer_main_t *bm = vm->buffer_main;
226   ASSERT (os_get_cpu_number () == 0);
227
228   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
229   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
230 }
231
232 always_inline void
233 vlib_buffer_set_known_state (vlib_main_t * vm,
234                              u32 buffer_index,
235                              vlib_buffer_known_state_t state)
236 {
237   vlib_buffer_main_t *bm = vm->buffer_main;
238   ASSERT (os_get_cpu_number () == 0);
239   hash_set (bm->buffer_known_hash, buffer_index, state);
240 }
241
242 /* Validates sanity of a single buffer.
243    Returns format'ed vector with error message if any. */
244 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
245                           uword follow_chain);
246
247 /* Validate an array of buffers.  As above. */
248 u8 *vlib_validate_buffers (vlib_main_t * vm,
249                            u32 * buffers,
250                            uword next_buffer_stride,
251                            uword n_buffers,
252                            vlib_buffer_known_state_t known_state,
253                            uword follow_chain);
254
255 #endif /* DPDK == 0 */
256
257 clib_error_t *vlib_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
258                                        unsigned socket_id);
259
260 /** \brief Allocate buffers 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 u32 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers);
269
270 always_inline u32
271 vlib_buffer_round_size (u32 size)
272 {
273   return round_pow2 (size, sizeof (vlib_buffer_t));
274 }
275
276 /** \brief Allocate buffers from specific freelist into supplied array
277
278     @param vm - (vlib_main_t *) vlib main data structure pointer
279     @param buffers - (u32 * ) buffer index array
280     @param n_buffers - (u32) number of buffers requested
281     @return - (u32) number of buffers actually allocated, may be
282     less than the number requested or zero
283 */
284 u32 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
285                                       u32 * buffers,
286                                       u32 n_buffers, u32 free_list_index);
287
288 /** \brief Free buffers
289     Frees the entire buffer chain for each buffer
290
291     @param vm - (vlib_main_t *) vlib main data structure pointer
292     @param buffers - (u32 * ) buffer index array
293     @param n_buffers - (u32) number of buffers to free
294
295 */
296 void vlib_buffer_free (vlib_main_t * vm,
297                        /* pointer to first buffer */
298                        u32 * buffers,
299                        /* number of buffers to free */
300                        u32 n_buffers);
301
302 /** \brief Free buffers, does not free the buffer chain for each buffer
303
304     @param vm - (vlib_main_t *) vlib main data structure pointer
305     @param buffers - (u32 * ) buffer index array
306     @param n_buffers - (u32) number of buffers to free
307
308 */
309 void vlib_buffer_free_no_next (vlib_main_t * vm,
310                                /* pointer to first buffer */
311                                u32 * buffers,
312                                /* number of buffers to free */
313                                u32 n_buffers);
314
315 /** \brief Free one buffer
316     Shorthand to free a single buffer chain.
317
318     @param vm - (vlib_main_t *) vlib main data structure pointer
319     @param buffer_index - (u32) buffer index to free
320 */
321 always_inline void
322 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
323 {
324   vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
325 }
326
327 /* Add/delete buffer free lists. */
328 u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
329                                   char *fmt, ...);
330 void vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index);
331
332 /* Find already existing public free list with given size or create one. */
333 u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
334                                          char *fmt, ...);
335
336 always_inline vlib_buffer_free_list_t *
337 vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
338 {
339   vlib_buffer_main_t *bm = vm->buffer_main;
340   vlib_buffer_free_list_t *f;
341
342   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
343
344   /* Sanity: indices must match. */
345   ASSERT (f->index == free_list_index);
346
347   return f;
348 }
349
350 always_inline u32
351 vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
352 {
353   vlib_buffer_free_list_t *f =
354     vlib_buffer_get_free_list (vm, free_list_index);
355   return f->n_data_bytes;
356 }
357
358 void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
359
360 /* Reasonably fast buffer copy routine. */
361 always_inline void
362 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
363 {
364   while (n >= 4)
365     {
366       dst[0] = src[0];
367       dst[1] = src[1];
368       dst[2] = src[2];
369       dst[3] = src[3];
370       dst += 4;
371       src += 4;
372       n -= 4;
373     }
374   while (n > 0)
375     {
376       dst[0] = src[0];
377       dst += 1;
378       src += 1;
379       n -= 1;
380     }
381 }
382
383 always_inline void *
384 vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
385                             uword n_bytes, uword alignment)
386 {
387   void *r =
388     vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
389   if (!r)
390     *error =
391       clib_error_return (0, "failed to allocate %wd bytes of I/O memory",
392                          n_bytes);
393   else
394     *error = 0;
395   return r;
396 }
397
398 /* By default allocate I/O memory with cache line alignment. */
399 always_inline void *
400 vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
401 {
402   return vlib_physmem_alloc_aligned (vm, error, n_bytes,
403                                      CLIB_CACHE_LINE_BYTES);
404 }
405
406 always_inline void
407 vlib_physmem_free (vlib_main_t * vm, void *mem)
408 {
409   return vm->os_physmem_free (mem);
410 }
411
412 always_inline u64
413 vlib_physmem_virtual_to_physical (vlib_main_t * vm, void *mem)
414 {
415   vlib_physmem_main_t *pm = &vm->physmem_main;
416   uword o = pointer_to_uword (mem) - pm->virtual.start;
417   return vlib_physmem_offset_to_physical (pm, o);
418 }
419
420 /* Append given data to end of buffer, possibly allocating new buffers. */
421 u32 vlib_buffer_add_data (vlib_main_t * vm,
422                           u32 free_list_index,
423                           u32 buffer_index, void *data, u32 n_data_bytes);
424
425 /* duplicate all buffers in chain */
426 always_inline vlib_buffer_t *
427 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
428 {
429   vlib_buffer_t *s, *d, *fd;
430   uword n_alloc, n_buffers = 1;
431   u32 *new_buffers = 0;
432   int i;
433
434   s = b;
435   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
436     {
437       n_buffers++;
438       s = vlib_get_buffer (vm, s->next_buffer);
439     }
440
441   vec_validate (new_buffers, n_buffers - 1);
442   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
443   ASSERT (n_alloc == n_buffers);
444
445   /* 1st segment */
446   s = b;
447   fd = d = vlib_get_buffer (vm, new_buffers[0]);
448   clib_memcpy (vlib_buffer_get_current (d),
449                vlib_buffer_get_current (s), s->current_length);
450   d->current_data = s->current_data;
451   d->current_length = s->current_length;
452   d->flags = s->flags;
453   d->total_length_not_including_first_buffer =
454     s->total_length_not_including_first_buffer;
455   clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
456 #if DPDK > 0
457   struct rte_mbuf *ms, *md;
458   ms = rte_mbuf_from_vlib_buffer (s);
459   md = rte_mbuf_from_vlib_buffer (d);
460   rte_pktmbuf_reset (md);
461   md->nb_segs = ms->nb_segs;
462   md->data_len = ms->data_len;
463   md->pkt_len = ms->pkt_len;
464   md->data_off = ms->data_off;
465 #endif
466
467   /* next segments */
468   for (i = 1; i < n_buffers; i++)
469     {
470       /* previous */
471       d->next_buffer = new_buffers[i];
472       /* current */
473       s = vlib_get_buffer (vm, s->next_buffer);
474       d = vlib_get_buffer (vm, new_buffers[i]);
475       d->current_data = s->current_data;
476       d->current_length = s->current_length;
477       clib_memcpy (vlib_buffer_get_current (d),
478                    vlib_buffer_get_current (s), s->current_length);
479       d->flags = s->flags;
480 #if DPDK > 0
481       /* previous */
482       md->next = rte_mbuf_from_vlib_buffer (d);
483       /* current */
484       md = rte_mbuf_from_vlib_buffer (d);
485       ms = rte_mbuf_from_vlib_buffer (s);
486       rte_pktmbuf_reset (md);
487       md->data_len = ms->data_len;
488       md->pkt_len = ms->pkt_len;
489       md->data_off = ms->data_off;
490       md->next = 0;
491 #endif
492     }
493
494   return fd;
495 }
496
497 /*
498  * vlib_buffer_chain_* functions provide a way to create long buffers.
499  * When DPDK is enabled, the 'hidden' DPDK header is taken care of transparently.
500  */
501
502 /* Initializes the buffer as an empty packet with no chained buffers. */
503 always_inline void
504 vlib_buffer_chain_init (vlib_buffer_t * first)
505 {
506   first->total_length_not_including_first_buffer = 0;
507   first->current_length = 0;
508   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
509   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
510 #if DPDK == 1
511   struct rte_mbuf *mb = rte_mbuf_from_vlib_buffer (first);
512   rte_pktmbuf_reset (mb);
513   mb->data_off = VLIB_BUFFER_PRE_DATA_SIZE + first->current_data;
514 #endif
515 }
516
517 /* The provided next_bi buffer index is appended to the end of the packet. */
518 always_inline vlib_buffer_t *
519 vlib_buffer_chain_buffer (vlib_main_t * vm,
520                           vlib_buffer_t * first,
521                           vlib_buffer_t * last, u32 next_bi)
522 {
523   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
524   last->next_buffer = next_bi;
525   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
526   next_buffer->current_length = 0;
527   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
528 #if DPDK == 1
529   struct rte_mbuf *mb;
530   mb = rte_mbuf_from_vlib_buffer (first);
531   mb->nb_segs++;
532
533   mb = rte_mbuf_from_vlib_buffer (last);
534   mb->next = rte_mbuf_from_vlib_buffer (next_buffer);
535
536   mb = rte_mbuf_from_vlib_buffer (next_buffer);
537   mb->data_len = 0;
538   mb->data_off = VLIB_BUFFER_PRE_DATA_SIZE + next_buffer->current_data;
539   mb->next = 0;
540 #endif
541   return next_buffer;
542 }
543
544 /* Increases or decreases the packet length.
545  * It does not allocate or deallocate new buffers.
546  * Therefore, the added length must be compatible
547  * with the last buffer. */
548 always_inline void
549 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
550                                    vlib_buffer_t * last, i32 len)
551 {
552   last->current_length += len;
553   if (first != last)
554     first->total_length_not_including_first_buffer += len;
555 #if DPDK == 1
556   struct rte_mbuf *mb_first = rte_mbuf_from_vlib_buffer (first);
557   struct rte_mbuf *mb_last = rte_mbuf_from_vlib_buffer (last);
558   mb_first->pkt_len += len;
559   mb_last->data_len += len;
560 #endif
561 }
562
563 /* Copy data to the end of the packet and increases its length.
564  * It does not allocate new buffers.
565  * Returns the number of copied bytes. */
566 always_inline u16
567 vlib_buffer_chain_append_data (vlib_main_t * vm,
568                                u32 free_list_index,
569                                vlib_buffer_t * first,
570                                vlib_buffer_t * last, void *data, u16 data_len)
571 {
572   u32 n_buffer_bytes =
573     vlib_buffer_free_list_buffer_size (vm, free_list_index);
574   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
575   u16 len = clib_min (data_len,
576                       n_buffer_bytes - last->current_length -
577                       last->current_data);
578   clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
579                len);
580   vlib_buffer_chain_increase_length (first, last, len);
581   return len;
582 }
583
584 /* Copy data to the end of the packet and increases its length.
585  * Allocates additional buffers from the free list if necessary.
586  * Returns the number of copied bytes.
587  * 'last' value is modified whenever new buffers are allocated and
588  * chained and points to the last buffer in the chain. */
589 u16
590 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
591                                           u32 free_list_index,
592                                           vlib_buffer_t * first,
593                                           vlib_buffer_t ** last,
594                                           void *data, u16 data_len);
595 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
596
597 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
598   format_vlib_buffer_contents;
599
600 typedef struct
601 {
602   /* Vector of packet data. */
603   u8 *packet_data;
604
605   /* Note: the next three fields are unused if DPDK == 1 */
606
607   /* Number of buffers to allocate in each call to physmem
608      allocator. */
609   u32 min_n_buffers_each_physmem_alloc;
610
611   /* Buffer free list for this template. */
612   u32 free_list_index;
613
614   u32 *free_buffers;
615 } vlib_packet_template_t;
616
617 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
618                                              vlib_packet_template_t * t);
619
620 void vlib_packet_template_init (vlib_main_t * vm,
621                                 vlib_packet_template_t * t,
622                                 void *packet_data,
623                                 uword n_packet_data_bytes,
624                                 uword min_n_buffers_each_physmem_alloc,
625                                 char *fmt, ...);
626
627 void *vlib_packet_template_get_packet (vlib_main_t * vm,
628                                        vlib_packet_template_t * t,
629                                        u32 * bi_result);
630
631 always_inline void
632 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
633 {
634   vec_free (t->packet_data);
635 }
636
637 always_inline u32
638 unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
639 {
640   serialize_stream_t *s = &m->stream;
641   vlib_serialize_buffer_main_t *sm
642     = uword_to_pointer (m->stream.data_function_opaque,
643                         vlib_serialize_buffer_main_t *);
644   vlib_main_t *vm = sm->vlib_main;
645   u32 n, *f;
646
647   n = s->n_buffer_bytes - s->current_buffer_index;
648   if (sm->last_buffer != ~0)
649     {
650       vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
651       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
652         {
653           b = vlib_get_buffer (vm, b->next_buffer);
654           n += b->current_length;
655         }
656     }
657
658   /* *INDENT-OFF* */
659   clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
660     n += vlib_buffer_index_length_in_chain (vm, f[0]);
661   }));
662 /* *INDENT-ON* */
663
664   return n;
665 }
666
667 typedef union
668 {
669   vlib_buffer_t b;
670   vlib_copy_unit_t i[sizeof (vlib_buffer_t) / sizeof (vlib_copy_unit_t)];
671 }
672 vlib_buffer_union_t;
673
674 /* Set a buffer quickly into "uninitialized" state.  We want this to
675    be extremely cheap and arrange for all fields that need to be
676    initialized to be in the first 128 bits of the buffer. */
677 always_inline void
678 vlib_buffer_init_for_free_list (vlib_buffer_t * _dst,
679                                 vlib_buffer_free_list_t * fl)
680 {
681   vlib_buffer_union_t *dst = (vlib_buffer_union_t *) _dst;
682   vlib_buffer_union_t *src =
683     (vlib_buffer_union_t *) & fl->buffer_init_template;
684
685   /* Make sure vlib_buffer_t is cacheline aligned and sized */
686   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
687   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
688           CLIB_CACHE_LINE_BYTES);
689   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
690           CLIB_CACHE_LINE_BYTES * 2);
691
692   /* Make sure buffer template is sane. */
693   ASSERT (fl->index == fl->buffer_init_template.free_list_index);
694
695   /* Copy template from src->current_data thru src->free_list_index */
696   dst->i[0] = src->i[0];
697   if (1 * sizeof (dst->i[0]) < 16)
698     dst->i[1] = src->i[1];
699   if (2 * sizeof (dst->i[0]) < 16)
700     dst->i[2] = src->i[2];
701
702   /* Make sure it really worked. */
703 #define _(f) ASSERT (dst->b.f == src->b.f)
704   _(current_data);
705   _(current_length);
706   _(flags);
707   _(free_list_index);
708 #undef _
709   ASSERT (dst->b.total_length_not_including_first_buffer == 0);
710 }
711
712 always_inline void
713 vlib_buffer_init_two_for_free_list (vlib_buffer_t * _dst0,
714                                     vlib_buffer_t * _dst1,
715                                     vlib_buffer_free_list_t * fl)
716 {
717   vlib_buffer_union_t *dst0 = (vlib_buffer_union_t *) _dst0;
718   vlib_buffer_union_t *dst1 = (vlib_buffer_union_t *) _dst1;
719   vlib_buffer_union_t *src =
720     (vlib_buffer_union_t *) & fl->buffer_init_template;
721
722   /* Make sure buffer template is sane. */
723   ASSERT (fl->index == fl->buffer_init_template.free_list_index);
724
725   /* Copy template from src->current_data thru src->free_list_index */
726   dst0->i[0] = dst1->i[0] = src->i[0];
727   if (1 * sizeof (dst0->i[0]) < 16)
728     dst0->i[1] = dst1->i[1] = src->i[1];
729   if (2 * sizeof (dst0->i[0]) < 16)
730     dst0->i[2] = dst1->i[2] = src->i[2];
731
732   /* Make sure it really worked. */
733 #define _(f) ASSERT (dst0->b.f == src->b.f && dst1->b.f == src->b.f)
734   _(current_data);
735   _(current_length);
736   _(flags);
737   _(free_list_index);
738 #undef _
739   ASSERT (dst0->b.total_length_not_including_first_buffer == 0);
740   ASSERT (dst1->b.total_length_not_including_first_buffer == 0);
741 }
742
743 #if CLIB_DEBUG > 0
744 u32 *vlib_buffer_state_validation_lock;
745 uword *vlib_buffer_state_validation_hash;
746 void *vlib_buffer_state_heap;
747 #endif
748
749 static inline void
750 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
751 {
752 #if CLIB_DEBUG > 0
753   uword *p;
754   void *oldheap;
755
756   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
757
758   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
759     ;
760
761   p = hash_get (vlib_buffer_state_validation_hash, b);
762
763   /* If we don't know about b, declare it to be in the expected state */
764   if (!p)
765     {
766       hash_set (vlib_buffer_state_validation_hash, b, expected);
767       goto out;
768     }
769
770   if (p[0] != expected)
771     {
772       void cj_stop (void);
773       u32 bi;
774       vlib_main_t *vm = &vlib_global_main;
775
776       cj_stop ();
777
778       bi = vlib_get_buffer_index (vm, b);
779
780       clib_mem_set_heap (oldheap);
781       clib_warning ("%.6f buffer %llx (%d): %s, not %s",
782                     vlib_time_now (vm), bi,
783                     p[0] ? "busy" : "free", expected ? "busy" : "free");
784       os_panic ();
785     }
786 out:
787   CLIB_MEMORY_BARRIER ();
788   *vlib_buffer_state_validation_lock = 0;
789   clib_mem_set_heap (oldheap);
790 #endif
791 }
792
793 static inline void
794 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
795 {
796 #if CLIB_DEBUG > 0
797   void *oldheap;
798
799   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
800
801   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
802     ;
803
804   hash_set (vlib_buffer_state_validation_hash, b, expected);
805
806   CLIB_MEMORY_BARRIER ();
807   *vlib_buffer_state_validation_lock = 0;
808   clib_mem_set_heap (oldheap);
809 #endif
810 }
811
812 #endif /* included_vlib_buffer_funcs_h */
813
814 /*
815  * fd.io coding-style-patch-verification: ON
816  *
817  * Local Variables:
818  * eval: (c-set-style "gnu")
819  * End:
820  */