vlib: add vlib_buffer_free_from_ring
[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 len = b->current_length;
110
111   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
112     return len;
113
114   if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
115     return len + b->total_length_not_including_first_buffer;
116
117   return vlib_buffer_length_in_chain_slow_path (vm, b);
118 }
119
120 /** \brief Get length in bytes of the buffer index buffer chain
121
122     @param vm - (vlib_main_t *) vlib main data structure pointer
123     @param bi - (u32) buffer index
124     @return - (uword) length of buffer chain
125 */
126 always_inline uword
127 vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
128 {
129   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
130   return vlib_buffer_length_in_chain (vm, b);
131 }
132
133 /** \brief Copy buffer contents to memory
134
135     @param vm - (vlib_main_t *) vlib main data structure pointer
136     @param buffer_index - (u32) buffer index
137     @param contents - (u8 *) memory, <strong>must be large enough</strong>
138     @return - (uword) length of buffer chain
139 */
140 always_inline uword
141 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
142 {
143   uword content_len = 0;
144   uword l;
145   vlib_buffer_t *b;
146
147   while (1)
148     {
149       b = vlib_get_buffer (vm, buffer_index);
150       l = b->current_length;
151       clib_memcpy (contents + content_len, b->data + b->current_data, l);
152       content_len += l;
153       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
154         break;
155       buffer_index = b->next_buffer;
156     }
157
158   return content_len;
159 }
160
161 /* Return physical address of buffer->data start. */
162 always_inline u64
163 vlib_get_buffer_data_physical_address (vlib_main_t * vm, u32 buffer_index)
164 {
165   vlib_buffer_main_t *bm = vm->buffer_main;
166   vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
167   vlib_buffer_pool_t *pool = vec_elt_at_index (bm->buffer_pools,
168                                                b->buffer_pool_index);
169
170   return vlib_physmem_virtual_to_physical (vm, pool->physmem_region, b->data);
171 }
172
173 /** \brief Prefetch buffer metadata by buffer index
174     The first 64 bytes of buffer contains most header information
175
176     @param vm - (vlib_main_t *) vlib main data structure pointer
177     @param bi - (u32) buffer index
178     @param type - LOAD, STORE. In most cases, STORE is the right answer
179 */
180 /* Prefetch buffer header given index. */
181 #define vlib_prefetch_buffer_with_index(vm,bi,type)     \
182   do {                                                  \
183     vlib_buffer_t * _b = vlib_get_buffer (vm, bi);      \
184     vlib_prefetch_buffer_header (_b, type);             \
185   } while (0)
186
187 #if 0
188 /* Iterate over known allocated vlib bufs. You probably do not want
189  * to do this!
190  @param vm      the vlib_main_t
191  @param bi      found allocated buffer index
192  @param body    operation to perform on buffer index
193  function executes body for each allocated buffer index
194  */
195 #define vlib_buffer_foreach_allocated(vm,bi,body)                \
196 do {                                                             \
197   vlib_main_t * _vmain = (vm);                                   \
198   vlib_buffer_main_t * _bmain = &_vmain->buffer_main;            \
199   hash_pair_t * _vbpair;                                         \
200   hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({       \
201     if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) {      \
202       (bi) = _vbpair->key;                                       \
203       body;                                                      \
204     }                                                            \
205   }));                                                           \
206 } while (0)
207 #endif
208
209 typedef enum
210 {
211   /* Index is unknown. */
212   VLIB_BUFFER_UNKNOWN,
213
214   /* Index is known and free/allocated. */
215   VLIB_BUFFER_KNOWN_FREE,
216   VLIB_BUFFER_KNOWN_ALLOCATED,
217 } vlib_buffer_known_state_t;
218
219 void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
220                                       uword n_buffers,
221                                       vlib_buffer_known_state_t
222                                       expected_state);
223
224 always_inline vlib_buffer_known_state_t
225 vlib_buffer_is_known (u32 buffer_index)
226 {
227   vlib_buffer_main_t *bm = vlib_global_main.buffer_main;
228
229   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
230   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
231   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
232   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
233 }
234
235 always_inline void
236 vlib_buffer_set_known_state (u32 buffer_index,
237                              vlib_buffer_known_state_t state)
238 {
239   vlib_buffer_main_t *bm = vlib_global_main.buffer_main;
240
241   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
242   hash_set (bm->buffer_known_hash, buffer_index, state);
243   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
244 }
245
246 /* Validates sanity of a single buffer.
247    Returns format'ed vector with error message if any. */
248 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
249                           uword follow_chain);
250
251 always_inline u32
252 vlib_buffer_round_size (u32 size)
253 {
254   return round_pow2 (size, sizeof (vlib_buffer_t));
255 }
256
257 always_inline vlib_buffer_free_list_index_t
258 vlib_buffer_get_free_list_index (vlib_buffer_t * b)
259 {
260   if (PREDICT_FALSE (b->flags & VLIB_BUFFER_NON_DEFAULT_FREELIST))
261     return b->free_list_index;
262
263   return 0;
264 }
265
266 always_inline void
267 vlib_buffer_set_free_list_index (vlib_buffer_t * b,
268                                  vlib_buffer_free_list_index_t index)
269 {
270   if (PREDICT_FALSE (index))
271     {
272       b->flags |= VLIB_BUFFER_NON_DEFAULT_FREELIST;
273       b->free_list_index = index;
274     }
275   else
276     b->flags &= ~VLIB_BUFFER_NON_DEFAULT_FREELIST;
277 }
278
279 /** \brief Allocate buffers from specific freelist into supplied array
280
281     @param vm - (vlib_main_t *) vlib main data structure pointer
282     @param buffers - (u32 * ) buffer index array
283     @param n_buffers - (u32) number of buffers requested
284     @return - (u32) number of buffers actually allocated, may be
285     less than the number requested or zero
286 */
287 always_inline u32
288 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
289                                   u32 * buffers,
290                                   u32 n_buffers,
291                                   vlib_buffer_free_list_index_t index)
292 {
293   vlib_buffer_main_t *bm = vm->buffer_main;
294   vlib_buffer_free_list_t *fl;
295   u32 *src;
296   uword len;
297
298   ASSERT (bm->cb.vlib_buffer_fill_free_list_cb);
299
300   fl = pool_elt_at_index (bm->buffer_free_list_pool, index);
301
302   len = vec_len (fl->buffers);
303
304   if (PREDICT_FALSE (len < n_buffers))
305     {
306       bm->cb.vlib_buffer_fill_free_list_cb (vm, fl, n_buffers);
307       len = vec_len (fl->buffers);
308
309       /* even if fill free list didn't manage to refill free list
310          we should give what we have */
311       n_buffers = clib_min (len, n_buffers);
312
313       /* following code is intentionaly duplicated to allow compiler
314          to optimize fast path when n_buffers is constant value */
315       src = fl->buffers + len - n_buffers;
316       clib_memcpy (buffers, src, n_buffers * sizeof (u32));
317       _vec_len (fl->buffers) -= n_buffers;
318
319       /* Verify that buffers are known free. */
320       vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
321                                        VLIB_BUFFER_KNOWN_FREE);
322
323       return n_buffers;
324     }
325
326   src = fl->buffers + len - n_buffers;
327   clib_memcpy (buffers, src, n_buffers * sizeof (u32));
328   _vec_len (fl->buffers) -= n_buffers;
329
330   /* Verify that buffers are known free. */
331   vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
332                                    VLIB_BUFFER_KNOWN_FREE);
333
334   return n_buffers;
335 }
336
337 /** \brief Allocate buffers into supplied array
338
339     @param vm - (vlib_main_t *) vlib main data structure pointer
340     @param buffers - (u32 * ) buffer index array
341     @param n_buffers - (u32) number of buffers requested
342     @return - (u32) number of buffers actually allocated, may be
343     less than the number requested or zero
344 */
345 always_inline u32
346 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
347 {
348   return vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
349                                            VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
350 }
351
352 /** \brief Allocate buffers into ring
353
354     @param vm - (vlib_main_t *) vlib main data structure pointer
355     @param buffers - (u32 * ) buffer index ring
356     @param start - (u32) first slot in the ring
357     @param ring_size - (u32) ring size
358     @param n_buffers - (u32) number of buffers requested
359     @return - (u32) number of buffers actually allocated, may be
360     less than the number requested or zero
361 */
362 always_inline u32
363 vlib_buffer_alloc_to_ring (vlib_main_t * vm, u32 * ring, u32 start,
364                            u32 ring_size, u32 n_buffers)
365 {
366   u32 n_alloc;
367
368   ASSERT (n_buffers <= ring_size);
369
370   if (PREDICT_TRUE (start + n_buffers <= ring_size))
371     return vlib_buffer_alloc (vm, ring + start, n_buffers);
372
373   n_alloc = vlib_buffer_alloc (vm, ring + start, ring_size - start);
374
375   if (PREDICT_TRUE (n_alloc == ring_size - start))
376     n_alloc += vlib_buffer_alloc (vm, ring, n_buffers - n_alloc);
377
378   return n_alloc;
379 }
380
381 /** \brief Free buffers
382     Frees the entire buffer chain for each buffer
383
384     @param vm - (vlib_main_t *) vlib main data structure pointer
385     @param buffers - (u32 * ) buffer index array
386     @param n_buffers - (u32) number of buffers to free
387
388 */
389 always_inline void
390 vlib_buffer_free (vlib_main_t * vm,
391                   /* pointer to first buffer */
392                   u32 * buffers,
393                   /* number of buffers to free */
394                   u32 n_buffers)
395 {
396   vlib_buffer_main_t *bm = vm->buffer_main;
397
398   ASSERT (bm->cb.vlib_buffer_free_cb);
399
400   return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
401 }
402
403 /** \brief Free buffers, does not free the buffer chain for each buffer
404
405     @param vm - (vlib_main_t *) vlib main data structure pointer
406     @param buffers - (u32 * ) buffer index array
407     @param n_buffers - (u32) number of buffers to free
408
409 */
410 always_inline void
411 vlib_buffer_free_no_next (vlib_main_t * vm,
412                           /* pointer to first buffer */
413                           u32 * buffers,
414                           /* number of buffers to free */
415                           u32 n_buffers)
416 {
417   vlib_buffer_main_t *bm = vm->buffer_main;
418
419   ASSERT (bm->cb.vlib_buffer_free_no_next_cb);
420
421   return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
422 }
423
424 /** \brief Free one buffer
425     Shorthand to free a single buffer chain.
426
427     @param vm - (vlib_main_t *) vlib main data structure pointer
428     @param buffer_index - (u32) buffer index to free
429 */
430 always_inline void
431 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
432 {
433   vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
434 }
435
436 /** \brief Free buffers from ring
437
438     @param vm - (vlib_main_t *) vlib main data structure pointer
439     @param buffers - (u32 * ) buffer index ring
440     @param start - (u32) first slot in the ring
441     @param ring_size - (u32) ring size
442     @param n_buffers - (u32) number of buffers
443 */
444 always_inline void
445 vlib_buffer_free_from_ring (vlib_main_t * vm, u32 * ring, u32 start,
446                             u32 ring_size, u32 n_buffers)
447 {
448   ASSERT (n_buffers <= ring_size);
449
450   if (PREDICT_TRUE (start + n_buffers <= ring_size))
451     {
452       vlib_buffer_free (vm, ring + start, n_buffers);
453     }
454   else
455     {
456       vlib_buffer_free (vm, ring + start, ring_size - start);
457       vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
458     }
459 }
460
461
462 /* Add/delete buffer free lists. */
463 vlib_buffer_free_list_index_t vlib_buffer_create_free_list (vlib_main_t * vm,
464                                                             u32 n_data_bytes,
465                                                             char *fmt, ...);
466 always_inline void
467 vlib_buffer_delete_free_list (vlib_main_t * vm,
468                               vlib_buffer_free_list_index_t free_list_index)
469 {
470   vlib_buffer_main_t *bm = vm->buffer_main;
471
472   ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
473
474   bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
475 }
476
477 /* Find already existing public free list with given size or create one. */
478 vlib_buffer_free_list_index_t vlib_buffer_get_or_create_free_list (vlib_main_t
479                                                                    * vm,
480                                                                    u32
481                                                                    n_data_bytes,
482                                                                    char *fmt,
483                                                                    ...);
484
485 /* Merge two free lists */
486 void vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
487                                    vlib_buffer_free_list_t * src);
488
489 /* Make sure we have at least given number of unaligned buffers. */
490 void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
491                                            vlib_buffer_free_list_t *
492                                            free_list,
493                                            uword n_unaligned_buffers);
494
495 always_inline vlib_buffer_free_list_index_t
496 vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
497 {
498   vlib_buffer_main_t *bm = vm->buffer_main;
499
500   size = vlib_buffer_round_size (size);
501   uword *p = hash_get (bm->free_list_by_size, size);
502   return p ? p[0] : ~0;
503 }
504
505 always_inline vlib_buffer_free_list_t *
506 vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
507                                   vlib_buffer_free_list_index_t * index)
508 {
509   vlib_buffer_main_t *bm = vm->buffer_main;
510   vlib_buffer_free_list_index_t i;
511
512   *index = i = vlib_buffer_get_free_list_index (b);
513   return pool_elt_at_index (bm->buffer_free_list_pool, i);
514 }
515
516 always_inline vlib_buffer_free_list_t *
517 vlib_buffer_get_free_list (vlib_main_t * vm,
518                            vlib_buffer_free_list_index_t free_list_index)
519 {
520   vlib_buffer_main_t *bm = vm->buffer_main;
521   vlib_buffer_free_list_t *f;
522
523   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
524
525   /* Sanity: indices must match. */
526   ASSERT (f->index == free_list_index);
527
528   return f;
529 }
530
531 always_inline u32
532 vlib_buffer_free_list_buffer_size (vlib_main_t * vm,
533                                    vlib_buffer_free_list_index_t index)
534 {
535   vlib_buffer_free_list_t *f = vlib_buffer_get_free_list (vm, index);
536   return f->n_data_bytes;
537 }
538
539 void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
540
541 /* Reasonably fast buffer copy routine. */
542 always_inline void
543 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
544 {
545   while (n >= 4)
546     {
547       dst[0] = src[0];
548       dst[1] = src[1];
549       dst[2] = src[2];
550       dst[3] = src[3];
551       dst += 4;
552       src += 4;
553       n -= 4;
554     }
555   while (n > 0)
556     {
557       dst[0] = src[0];
558       dst += 1;
559       src += 1;
560       n -= 1;
561     }
562 }
563
564 /* Append given data to end of buffer, possibly allocating new buffers. */
565 u32 vlib_buffer_add_data (vlib_main_t * vm,
566                           vlib_buffer_free_list_index_t free_list_index,
567                           u32 buffer_index, void *data, u32 n_data_bytes);
568
569 /* duplicate all buffers in chain */
570 always_inline vlib_buffer_t *
571 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
572 {
573   vlib_buffer_t *s, *d, *fd;
574   uword n_alloc, n_buffers = 1;
575   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
576   int i;
577
578   s = b;
579   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
580     {
581       n_buffers++;
582       s = vlib_get_buffer (vm, s->next_buffer);
583     }
584   u32 new_buffers[n_buffers];
585
586   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
587
588   /* No guarantee that we'll get all the buffers we asked for */
589   if (PREDICT_FALSE (n_alloc < n_buffers))
590     {
591       if (n_alloc > 0)
592         vlib_buffer_free (vm, new_buffers, n_alloc);
593       return 0;
594     }
595
596   /* 1st segment */
597   s = b;
598   fd = d = vlib_get_buffer (vm, new_buffers[0]);
599   d->current_data = s->current_data;
600   d->current_length = s->current_length;
601   d->flags = s->flags & flag_mask;
602   d->total_length_not_including_first_buffer =
603     s->total_length_not_including_first_buffer;
604   clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
605   clib_memcpy (vlib_buffer_get_current (d),
606                vlib_buffer_get_current (s), s->current_length);
607
608   /* next segments */
609   for (i = 1; i < n_buffers; i++)
610     {
611       /* previous */
612       d->next_buffer = new_buffers[i];
613       /* current */
614       s = vlib_get_buffer (vm, s->next_buffer);
615       d = vlib_get_buffer (vm, new_buffers[i]);
616       d->current_data = s->current_data;
617       d->current_length = s->current_length;
618       clib_memcpy (vlib_buffer_get_current (d),
619                    vlib_buffer_get_current (s), s->current_length);
620       d->flags = s->flags & flag_mask;
621     }
622
623   return fd;
624 }
625
626 /** \brief Create a maximum of 256 clones of buffer and store them
627     in the supplied array
628
629     @param vm - (vlib_main_t *) vlib main data structure pointer
630     @param src_buffer - (u32) source buffer index
631     @param buffers - (u32 * ) buffer index array
632     @param n_buffers - (u16) number of buffer clones requested (<=256)
633     @param head_end_offset - (u16) offset relative to current position
634            where packet head ends
635     @return - (u16) number of buffers actually cloned, may be
636     less than the number requested or zero
637 */
638 always_inline u16
639 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
640                        u16 n_buffers, u16 head_end_offset)
641 {
642   u16 i;
643   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
644
645   ASSERT (s->n_add_refs == 0);
646   ASSERT (n_buffers);
647   ASSERT (n_buffers <= 256);
648
649   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
650     {
651       buffers[0] = src_buffer;
652       for (i = 1; i < n_buffers; i++)
653         {
654           vlib_buffer_t *d;
655           d = vlib_buffer_copy (vm, s);
656           if (d == 0)
657             return i;
658           buffers[i] = vlib_get_buffer_index (vm, d);
659
660         }
661       return n_buffers;
662     }
663
664   if (PREDICT_FALSE (n_buffers == 1))
665     {
666       buffers[0] = src_buffer;
667       return 1;
668     }
669
670   n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
671                                                 vlib_buffer_get_free_list_index
672                                                 (s));
673
674   for (i = 0; i < n_buffers; i++)
675     {
676       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
677       d->current_data = s->current_data;
678       d->current_length = head_end_offset;
679       vlib_buffer_set_free_list_index (d,
680                                        vlib_buffer_get_free_list_index (s));
681       d->total_length_not_including_first_buffer =
682         s->total_length_not_including_first_buffer + s->current_length -
683         head_end_offset;
684       d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
685       d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
686       clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
687       clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
688                    head_end_offset);
689       d->next_buffer = src_buffer;
690     }
691   vlib_buffer_advance (s, head_end_offset);
692   s->n_add_refs = n_buffers - 1;
693   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
694     {
695       s = vlib_get_buffer (vm, s->next_buffer);
696       s->n_add_refs = n_buffers - 1;
697     }
698
699   return n_buffers;
700 }
701
702 /** \brief Create multiple clones of buffer and store them
703     in the supplied array
704
705     @param vm - (vlib_main_t *) vlib main data structure pointer
706     @param src_buffer - (u32) source buffer index
707     @param buffers - (u32 * ) buffer index array
708     @param n_buffers - (u16) number of buffer clones requested (<=256)
709     @param head_end_offset - (u16) offset relative to current position
710            where packet head ends
711     @return - (u16) number of buffers actually cloned, may be
712     less than the number requested or zero
713 */
714 always_inline u16
715 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
716                    u16 n_buffers, u16 head_end_offset)
717 {
718   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
719   u16 n_cloned = 0;
720
721   while (n_buffers > 256)
722     {
723       vlib_buffer_t *copy;
724       copy = vlib_buffer_copy (vm, s);
725       n_cloned += vlib_buffer_clone_256 (vm,
726                                          vlib_get_buffer_index (vm, copy),
727                                          (buffers + n_cloned),
728                                          256, head_end_offset);
729       n_buffers -= 256;
730     }
731   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
732                                      buffers + n_cloned,
733                                      n_buffers, head_end_offset);
734
735   return n_cloned;
736 }
737
738 /** \brief Attach cloned tail to the buffer
739
740     @param vm - (vlib_main_t *) vlib main data structure pointer
741     @param head - (vlib_buffer_t *) head buffer
742     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
743 */
744
745 always_inline void
746 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
747                           vlib_buffer_t * tail)
748 {
749   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
750   ASSERT (vlib_buffer_get_free_list_index (head) ==
751           vlib_buffer_get_free_list_index (tail));
752
753   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
754   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
755   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
756   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
757   head->next_buffer = vlib_get_buffer_index (vm, tail);
758   head->total_length_not_including_first_buffer = tail->current_length +
759     tail->total_length_not_including_first_buffer;
760
761 next_segment:
762   __sync_add_and_fetch (&tail->n_add_refs, 1);
763
764   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
765     {
766       tail = vlib_get_buffer (vm, tail->next_buffer);
767       goto next_segment;
768     }
769 }
770
771 /* Initializes the buffer as an empty packet with no chained buffers. */
772 always_inline void
773 vlib_buffer_chain_init (vlib_buffer_t * first)
774 {
775   first->total_length_not_including_first_buffer = 0;
776   first->current_length = 0;
777   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
778   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
779 }
780
781 /* The provided next_bi buffer index is appended to the end of the packet. */
782 always_inline vlib_buffer_t *
783 vlib_buffer_chain_buffer (vlib_main_t * vm,
784                           vlib_buffer_t * first,
785                           vlib_buffer_t * last, u32 next_bi)
786 {
787   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
788   last->next_buffer = next_bi;
789   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
790   next_buffer->current_length = 0;
791   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
792   return next_buffer;
793 }
794
795 /* Increases or decreases the packet length.
796  * It does not allocate or deallocate new buffers.
797  * Therefore, the added length must be compatible
798  * with the last buffer. */
799 always_inline void
800 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
801                                    vlib_buffer_t * last, i32 len)
802 {
803   last->current_length += len;
804   if (first != last)
805     first->total_length_not_including_first_buffer += len;
806 }
807
808 /* Copy data to the end of the packet and increases its length.
809  * It does not allocate new buffers.
810  * Returns the number of copied bytes. */
811 always_inline u16
812 vlib_buffer_chain_append_data (vlib_main_t * vm,
813                                vlib_buffer_free_list_index_t free_list_index,
814                                vlib_buffer_t * first,
815                                vlib_buffer_t * last, void *data, u16 data_len)
816 {
817   u32 n_buffer_bytes =
818     vlib_buffer_free_list_buffer_size (vm, free_list_index);
819   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
820   u16 len = clib_min (data_len,
821                       n_buffer_bytes - last->current_length -
822                       last->current_data);
823   clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
824                len);
825   vlib_buffer_chain_increase_length (first, last, len);
826   return len;
827 }
828
829 /* Copy data to the end of the packet and increases its length.
830  * Allocates additional buffers from the free list if necessary.
831  * Returns the number of copied bytes.
832  * 'last' value is modified whenever new buffers are allocated and
833  * chained and points to the last buffer in the chain. */
834 u16
835 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
836                                           vlib_buffer_free_list_index_t
837                                           free_list_index,
838                                           vlib_buffer_t * first,
839                                           vlib_buffer_t ** last, void *data,
840                                           u16 data_len);
841 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
842
843 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
844   format_vlib_buffer_contents;
845
846 typedef struct
847 {
848   /* Vector of packet data. */
849   u8 *packet_data;
850
851   /* Number of buffers to allocate in each call to physmem
852      allocator. */
853   u32 min_n_buffers_each_physmem_alloc;
854
855   /* Buffer free list for this template. */
856   vlib_buffer_free_list_index_t free_list_index;
857
858   u32 *free_buffers;
859 } vlib_packet_template_t;
860
861 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
862                                              vlib_packet_template_t * t);
863
864 void vlib_packet_template_init (vlib_main_t * vm,
865                                 vlib_packet_template_t * t,
866                                 void *packet_data,
867                                 uword n_packet_data_bytes,
868                                 uword min_n_buffers_each_physmem_alloc,
869                                 char *fmt, ...);
870
871 void *vlib_packet_template_get_packet (vlib_main_t * vm,
872                                        vlib_packet_template_t * t,
873                                        u32 * bi_result);
874
875 always_inline void
876 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
877 {
878   vec_free (t->packet_data);
879 }
880
881 always_inline u32
882 unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
883 {
884   serialize_stream_t *s = &m->stream;
885   vlib_serialize_buffer_main_t *sm
886     = uword_to_pointer (m->stream.data_function_opaque,
887                         vlib_serialize_buffer_main_t *);
888   vlib_main_t *vm = sm->vlib_main;
889   u32 n, *f;
890
891   n = s->n_buffer_bytes - s->current_buffer_index;
892   if (sm->last_buffer != ~0)
893     {
894       vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
895       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
896         {
897           b = vlib_get_buffer (vm, b->next_buffer);
898           n += b->current_length;
899         }
900     }
901
902   /* *INDENT-OFF* */
903   clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
904     n += vlib_buffer_index_length_in_chain (vm, f[0]);
905   }));
906 /* *INDENT-ON* */
907
908   return n;
909 }
910
911 /* Set a buffer quickly into "uninitialized" state.  We want this to
912    be extremely cheap and arrange for all fields that need to be
913    initialized to be in the first 128 bits of the buffer. */
914 always_inline void
915 vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
916                                 vlib_buffer_free_list_t * fl)
917 {
918   vlib_buffer_t *src = &fl->buffer_init_template;
919
920   /* Make sure vlib_buffer_t is cacheline aligned and sized */
921   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
922   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
923           CLIB_CACHE_LINE_BYTES);
924   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
925           CLIB_CACHE_LINE_BYTES * 2);
926
927   /* Make sure buffer template is sane. */
928   ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
929
930   clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
931                STRUCT_MARK_PTR (src, template_start),
932                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
933                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
934
935   /* Not in the first 16 octets. */
936   dst->n_add_refs = src->n_add_refs;
937   vlib_buffer_set_free_list_index (dst, fl->index);
938
939   /* Make sure it really worked. */
940 #define _(f) ASSERT (dst->f == src->f);
941   _(current_data);
942   _(current_length);
943   _(flags);
944 #undef _
945   /* ASSERT (dst->total_length_not_including_first_buffer == 0); */
946   /* total_length_not_including_first_buffer is not in the template anymore
947    * so it may actually not zeroed for some buffers. One option is to
948    * uncomment the line lower (comes at a cost), the other, is to just  not
949    * care */
950   /* dst->total_length_not_including_first_buffer = 0; */
951   ASSERT (dst->n_add_refs == 0);
952 }
953
954 always_inline void
955 vlib_buffer_add_to_free_list (vlib_main_t * vm,
956                               vlib_buffer_free_list_t * f,
957                               u32 buffer_index, u8 do_init)
958 {
959   vlib_buffer_t *b;
960   b = vlib_get_buffer (vm, buffer_index);
961   if (PREDICT_TRUE (do_init))
962     vlib_buffer_init_for_free_list (b, f);
963   vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
964
965   if (vec_len (f->buffers) > 4 * VLIB_FRAME_SIZE)
966     {
967       vlib_buffer_free_list_t *mf;
968       mf = vlib_buffer_get_free_list (vlib_mains[0], f->index);
969       clib_spinlock_lock (&mf->global_buffers_lock);
970       /* keep last stored buffers, as they are more likely hot in the cache */
971       vec_add_aligned (mf->global_buffers, f->buffers, VLIB_FRAME_SIZE,
972                        CLIB_CACHE_LINE_BYTES);
973       vec_delete (f->buffers, VLIB_FRAME_SIZE, 0);
974       f->n_alloc -= VLIB_FRAME_SIZE;
975       clib_spinlock_unlock (&mf->global_buffers_lock);
976     }
977 }
978
979 #if CLIB_DEBUG > 0
980 extern u32 *vlib_buffer_state_validation_lock;
981 extern uword *vlib_buffer_state_validation_hash;
982 extern void *vlib_buffer_state_heap;
983 #endif
984
985 static inline void
986 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
987 {
988 #if CLIB_DEBUG > 0
989   uword *p;
990   void *oldheap;
991
992   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
993
994   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
995     ;
996
997   p = hash_get (vlib_buffer_state_validation_hash, b);
998
999   /* If we don't know about b, declare it to be in the expected state */
1000   if (!p)
1001     {
1002       hash_set (vlib_buffer_state_validation_hash, b, expected);
1003       goto out;
1004     }
1005
1006   if (p[0] != expected)
1007     {
1008       void cj_stop (void);
1009       u32 bi;
1010       vlib_main_t *vm = &vlib_global_main;
1011
1012       cj_stop ();
1013
1014       bi = vlib_get_buffer_index (vm, b);
1015
1016       clib_mem_set_heap (oldheap);
1017       clib_warning ("%.6f buffer %llx (%d): %s, not %s",
1018                     vlib_time_now (vm), bi,
1019                     p[0] ? "busy" : "free", expected ? "busy" : "free");
1020       os_panic ();
1021     }
1022 out:
1023   CLIB_MEMORY_BARRIER ();
1024   *vlib_buffer_state_validation_lock = 0;
1025   clib_mem_set_heap (oldheap);
1026 #endif
1027 }
1028
1029 static inline void
1030 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
1031 {
1032 #if CLIB_DEBUG > 0
1033   void *oldheap;
1034
1035   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
1036
1037   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
1038     ;
1039
1040   hash_set (vlib_buffer_state_validation_hash, b, expected);
1041
1042   CLIB_MEMORY_BARRIER ();
1043   *vlib_buffer_state_validation_lock = 0;
1044   clib_mem_set_heap (oldheap);
1045 #endif
1046 }
1047
1048 /** minimum data size of first buffer in a buffer chain */
1049 #define VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE (256)
1050
1051 /**
1052  * @brief compress buffer chain in a way where the first buffer is at least
1053  * VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE long
1054  *
1055  * @param[in] vm - vlib_main
1056  * @param[in,out] first - first buffer in chain
1057  * @param[in,out] discard_vector - vector of buffer indexes which were removed
1058  * from the chain
1059  */
1060 always_inline void
1061 vlib_buffer_chain_compress (vlib_main_t * vm,
1062                             vlib_buffer_t * first, u32 ** discard_vector)
1063 {
1064   if (first->current_length >= VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE ||
1065       !(first->flags & VLIB_BUFFER_NEXT_PRESENT))
1066     {
1067       /* this is already big enough or not a chain */
1068       return;
1069     }
1070   /* probe free list to find allocated buffer size to avoid overfill */
1071   vlib_buffer_free_list_index_t index;
1072   vlib_buffer_free_list_t *free_list =
1073     vlib_buffer_get_buffer_free_list (vm, first, &index);
1074
1075   u32 want_first_size = clib_min (VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE,
1076                                   free_list->n_data_bytes -
1077                                   first->current_data);
1078   do
1079     {
1080       vlib_buffer_t *second = vlib_get_buffer (vm, first->next_buffer);
1081       u32 need = want_first_size - first->current_length;
1082       u32 amount_to_copy = clib_min (need, second->current_length);
1083       clib_memcpy (((u8 *) vlib_buffer_get_current (first)) +
1084                    first->current_length,
1085                    vlib_buffer_get_current (second), amount_to_copy);
1086       first->current_length += amount_to_copy;
1087       vlib_buffer_advance (second, amount_to_copy);
1088       if (first->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1089         {
1090           first->total_length_not_including_first_buffer -= amount_to_copy;
1091         }
1092       if (!second->current_length)
1093         {
1094           vec_add1 (*discard_vector, first->next_buffer);
1095           if (second->flags & VLIB_BUFFER_NEXT_PRESENT)
1096             {
1097               first->next_buffer = second->next_buffer;
1098             }
1099           else
1100             {
1101               first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1102             }
1103           second->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1104         }
1105     }
1106   while ((first->current_length < want_first_size) &&
1107          (first->flags & VLIB_BUFFER_NEXT_PRESENT));
1108 }
1109
1110 #endif /* included_vlib_buffer_funcs_h */
1111
1112 /*
1113  * fd.io coding-style-patch-verification: ON
1114  *
1115  * Local Variables:
1116  * eval: (c-set-style "gnu")
1117  * End:
1118  */