vlib: add buffer and thread callbacks
[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 always_inline vlib_buffer_free_list_t *
354 vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
355 {
356   vlib_buffer_main_t *bm = vm->buffer_main;
357   vlib_buffer_free_list_t *f;
358
359   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
360
361   /* Sanity: indices must match. */
362   ASSERT (f->index == free_list_index);
363
364   return f;
365 }
366
367 always_inline u32
368 vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
369 {
370   vlib_buffer_free_list_t *f =
371     vlib_buffer_get_free_list (vm, free_list_index);
372   return f->n_data_bytes;
373 }
374
375 void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
376
377 /* Reasonably fast buffer copy routine. */
378 always_inline void
379 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
380 {
381   while (n >= 4)
382     {
383       dst[0] = src[0];
384       dst[1] = src[1];
385       dst[2] = src[2];
386       dst[3] = src[3];
387       dst += 4;
388       src += 4;
389       n -= 4;
390     }
391   while (n > 0)
392     {
393       dst[0] = src[0];
394       dst += 1;
395       src += 1;
396       n -= 1;
397     }
398 }
399
400 always_inline void *
401 vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
402                             uword n_bytes, uword alignment)
403 {
404   void *r =
405     vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
406   if (!r)
407     *error =
408       clib_error_return (0, "failed to allocate %wd bytes of I/O memory",
409                          n_bytes);
410   else
411     *error = 0;
412   return r;
413 }
414
415 /* By default allocate I/O memory with cache line alignment. */
416 always_inline void *
417 vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
418 {
419   return vlib_physmem_alloc_aligned (vm, error, n_bytes,
420                                      CLIB_CACHE_LINE_BYTES);
421 }
422
423 always_inline void
424 vlib_physmem_free (vlib_main_t * vm, void *mem)
425 {
426   return vm->os_physmem_free (mem);
427 }
428
429 always_inline u64
430 vlib_physmem_virtual_to_physical (vlib_main_t * vm, void *mem)
431 {
432   vlib_physmem_main_t *pm = &vm->physmem_main;
433   uword o = pointer_to_uword (mem) - pm->virtual.start;
434   return vlib_physmem_offset_to_physical (pm, o);
435 }
436
437 /* Append given data to end of buffer, possibly allocating new buffers. */
438 u32 vlib_buffer_add_data (vlib_main_t * vm,
439                           u32 free_list_index,
440                           u32 buffer_index, void *data, u32 n_data_bytes);
441
442 /* duplicate all buffers in chain */
443 always_inline vlib_buffer_t *
444 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
445 {
446   vlib_buffer_t *s, *d, *fd;
447   uword n_alloc, n_buffers = 1;
448   u32 *new_buffers = 0;
449   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
450   int i;
451
452   s = b;
453   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
454     {
455       n_buffers++;
456       s = vlib_get_buffer (vm, s->next_buffer);
457     }
458
459   vec_validate (new_buffers, n_buffers - 1);
460   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
461   ASSERT (n_alloc == n_buffers);
462
463   /* 1st segment */
464   s = b;
465   fd = d = vlib_get_buffer (vm, new_buffers[0]);
466   d->current_data = s->current_data;
467   d->current_length = s->current_length;
468   d->flags = s->flags & flag_mask;
469   d->total_length_not_including_first_buffer =
470     s->total_length_not_including_first_buffer;
471   clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
472   clib_memcpy (vlib_buffer_get_current (d),
473                vlib_buffer_get_current (s), s->current_length);
474
475   /* next segments */
476   for (i = 1; i < n_buffers; i++)
477     {
478       /* previous */
479       d->next_buffer = new_buffers[i];
480       /* current */
481       s = vlib_get_buffer (vm, s->next_buffer);
482       d = vlib_get_buffer (vm, new_buffers[i]);
483       d->current_data = s->current_data;
484       d->current_length = s->current_length;
485       clib_memcpy (vlib_buffer_get_current (d),
486                    vlib_buffer_get_current (s), s->current_length);
487       d->flags = s->flags & flag_mask;
488     }
489
490   return fd;
491 }
492
493 /* Initializes the buffer as an empty packet with no chained buffers. */
494 always_inline void
495 vlib_buffer_chain_init (vlib_buffer_t * first)
496 {
497   first->total_length_not_including_first_buffer = 0;
498   first->current_length = 0;
499   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
500   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
501 }
502
503 /* The provided next_bi buffer index is appended to the end of the packet. */
504 always_inline vlib_buffer_t *
505 vlib_buffer_chain_buffer (vlib_main_t * vm,
506                           vlib_buffer_t * first,
507                           vlib_buffer_t * last, u32 next_bi)
508 {
509   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
510   last->next_buffer = next_bi;
511   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
512   next_buffer->current_length = 0;
513   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
514   return next_buffer;
515 }
516
517 /* Increases or decreases the packet length.
518  * It does not allocate or deallocate new buffers.
519  * Therefore, the added length must be compatible
520  * with the last buffer. */
521 always_inline void
522 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
523                                    vlib_buffer_t * last, i32 len)
524 {
525   last->current_length += len;
526   if (first != last)
527     first->total_length_not_including_first_buffer += len;
528 }
529
530 /* Copy data to the end of the packet and increases its length.
531  * It does not allocate new buffers.
532  * Returns the number of copied bytes. */
533 always_inline u16
534 vlib_buffer_chain_append_data (vlib_main_t * vm,
535                                u32 free_list_index,
536                                vlib_buffer_t * first,
537                                vlib_buffer_t * last, void *data, u16 data_len)
538 {
539   u32 n_buffer_bytes =
540     vlib_buffer_free_list_buffer_size (vm, free_list_index);
541   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
542   u16 len = clib_min (data_len,
543                       n_buffer_bytes - last->current_length -
544                       last->current_data);
545   clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
546                len);
547   vlib_buffer_chain_increase_length (first, last, len);
548   return len;
549 }
550
551 /* Copy data to the end of the packet and increases its length.
552  * Allocates additional buffers from the free list if necessary.
553  * Returns the number of copied bytes.
554  * 'last' value is modified whenever new buffers are allocated and
555  * chained and points to the last buffer in the chain. */
556 u16
557 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
558                                           u32 free_list_index,
559                                           vlib_buffer_t * first,
560                                           vlib_buffer_t ** last,
561                                           void *data, u16 data_len);
562 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
563
564 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
565   format_vlib_buffer_contents;
566
567 typedef struct
568 {
569   /* Vector of packet data. */
570   u8 *packet_data;
571
572   /* Number of buffers to allocate in each call to physmem
573      allocator. */
574   u32 min_n_buffers_each_physmem_alloc;
575
576   /* Buffer free list for this template. */
577   u32 free_list_index;
578
579   u32 *free_buffers;
580 } vlib_packet_template_t;
581
582 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
583                                              vlib_packet_template_t * t);
584
585 void vlib_packet_template_init (vlib_main_t * vm,
586                                 vlib_packet_template_t * t,
587                                 void *packet_data,
588                                 uword n_packet_data_bytes,
589                                 uword min_n_buffers_each_physmem_alloc,
590                                 char *fmt, ...);
591
592 void *vlib_packet_template_get_packet (vlib_main_t * vm,
593                                        vlib_packet_template_t * t,
594                                        u32 * bi_result);
595
596 always_inline void
597 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
598 {
599   vec_free (t->packet_data);
600 }
601
602 always_inline u32
603 unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
604 {
605   serialize_stream_t *s = &m->stream;
606   vlib_serialize_buffer_main_t *sm
607     = uword_to_pointer (m->stream.data_function_opaque,
608                         vlib_serialize_buffer_main_t *);
609   vlib_main_t *vm = sm->vlib_main;
610   u32 n, *f;
611
612   n = s->n_buffer_bytes - s->current_buffer_index;
613   if (sm->last_buffer != ~0)
614     {
615       vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
616       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
617         {
618           b = vlib_get_buffer (vm, b->next_buffer);
619           n += b->current_length;
620         }
621     }
622
623   /* *INDENT-OFF* */
624   clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
625     n += vlib_buffer_index_length_in_chain (vm, f[0]);
626   }));
627 /* *INDENT-ON* */
628
629   return n;
630 }
631
632 typedef union
633 {
634   vlib_buffer_t b;
635   vlib_copy_unit_t i[sizeof (vlib_buffer_t) / sizeof (vlib_copy_unit_t)];
636 }
637 vlib_buffer_union_t;
638
639 /* Set a buffer quickly into "uninitialized" state.  We want this to
640    be extremely cheap and arrange for all fields that need to be
641    initialized to be in the first 128 bits of the buffer. */
642 always_inline void
643 vlib_buffer_init_for_free_list (vlib_buffer_t * _dst,
644                                 vlib_buffer_free_list_t * fl)
645 {
646   vlib_buffer_union_t *dst = (vlib_buffer_union_t *) _dst;
647   vlib_buffer_union_t *src =
648     (vlib_buffer_union_t *) & fl->buffer_init_template;
649
650   /* Make sure vlib_buffer_t is cacheline aligned and sized */
651   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
652   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
653           CLIB_CACHE_LINE_BYTES);
654   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
655           CLIB_CACHE_LINE_BYTES * 2);
656
657   /* Make sure buffer template is sane. */
658   ASSERT (fl->index == fl->buffer_init_template.free_list_index);
659
660   /* Copy template from src->current_data thru src->free_list_index */
661   dst->i[0] = src->i[0];
662   if (1 * sizeof (dst->i[0]) < 16)
663     dst->i[1] = src->i[1];
664   if (2 * sizeof (dst->i[0]) < 16)
665     dst->i[2] = src->i[2];
666
667   /* Make sure it really worked. */
668 #define _(f) ASSERT (dst->b.f == src->b.f)
669   _(current_data);
670   _(current_length);
671   _(flags);
672   _(free_list_index);
673 #undef _
674   ASSERT (dst->b.total_length_not_including_first_buffer == 0);
675 }
676
677 always_inline void
678 vlib_buffer_init_two_for_free_list (vlib_buffer_t * _dst0,
679                                     vlib_buffer_t * _dst1,
680                                     vlib_buffer_free_list_t * fl)
681 {
682   vlib_buffer_union_t *dst0 = (vlib_buffer_union_t *) _dst0;
683   vlib_buffer_union_t *dst1 = (vlib_buffer_union_t *) _dst1;
684   vlib_buffer_union_t *src =
685     (vlib_buffer_union_t *) & fl->buffer_init_template;
686
687   /* Make sure buffer template is sane. */
688   ASSERT (fl->index == fl->buffer_init_template.free_list_index);
689
690   /* Copy template from src->current_data thru src->free_list_index */
691   dst0->i[0] = dst1->i[0] = src->i[0];
692   if (1 * sizeof (dst0->i[0]) < 16)
693     dst0->i[1] = dst1->i[1] = src->i[1];
694   if (2 * sizeof (dst0->i[0]) < 16)
695     dst0->i[2] = dst1->i[2] = src->i[2];
696
697   /* Make sure it really worked. */
698 #define _(f) ASSERT (dst0->b.f == src->b.f && dst1->b.f == src->b.f)
699   _(current_data);
700   _(current_length);
701   _(flags);
702   _(free_list_index);
703 #undef _
704   ASSERT (dst0->b.total_length_not_including_first_buffer == 0);
705   ASSERT (dst1->b.total_length_not_including_first_buffer == 0);
706 }
707
708 #if CLIB_DEBUG > 0
709 extern u32 *vlib_buffer_state_validation_lock;
710 extern uword *vlib_buffer_state_validation_hash;
711 extern void *vlib_buffer_state_heap;
712 #endif
713
714 static inline void
715 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
716 {
717 #if CLIB_DEBUG > 0
718   uword *p;
719   void *oldheap;
720
721   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
722
723   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
724     ;
725
726   p = hash_get (vlib_buffer_state_validation_hash, b);
727
728   /* If we don't know about b, declare it to be in the expected state */
729   if (!p)
730     {
731       hash_set (vlib_buffer_state_validation_hash, b, expected);
732       goto out;
733     }
734
735   if (p[0] != expected)
736     {
737       void cj_stop (void);
738       u32 bi;
739       vlib_main_t *vm = &vlib_global_main;
740
741       cj_stop ();
742
743       bi = vlib_get_buffer_index (vm, b);
744
745       clib_mem_set_heap (oldheap);
746       clib_warning ("%.6f buffer %llx (%d): %s, not %s",
747                     vlib_time_now (vm), bi,
748                     p[0] ? "busy" : "free", expected ? "busy" : "free");
749       os_panic ();
750     }
751 out:
752   CLIB_MEMORY_BARRIER ();
753   *vlib_buffer_state_validation_lock = 0;
754   clib_mem_set_heap (oldheap);
755 #endif
756 }
757
758 static inline void
759 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
760 {
761 #if CLIB_DEBUG > 0
762   void *oldheap;
763
764   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
765
766   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
767     ;
768
769   hash_set (vlib_buffer_state_validation_hash, b, expected);
770
771   CLIB_MEMORY_BARRIER ();
772   *vlib_buffer_state_validation_lock = 0;
773   clib_mem_set_heap (oldheap);
774 #endif
775 }
776
777 #endif /* included_vlib_buffer_funcs_h */
778
779 /*
780  * fd.io coding-style-patch-verification: ON
781  *
782  * Local Variables:
783  * eval: (c-set-style "gnu")
784  * End:
785  */