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