Refactor vlib_buffer flags
[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 /* Add/delete buffer free lists. */
437 vlib_buffer_free_list_index_t vlib_buffer_create_free_list (vlib_main_t * vm,
438                                                             u32 n_data_bytes,
439                                                             char *fmt, ...);
440 always_inline void
441 vlib_buffer_delete_free_list (vlib_main_t * vm,
442                               vlib_buffer_free_list_index_t free_list_index)
443 {
444   vlib_buffer_main_t *bm = vm->buffer_main;
445
446   ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
447
448   bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
449 }
450
451 /* Find already existing public free list with given size or create one. */
452 vlib_buffer_free_list_index_t vlib_buffer_get_or_create_free_list (vlib_main_t
453                                                                    * vm,
454                                                                    u32
455                                                                    n_data_bytes,
456                                                                    char *fmt,
457                                                                    ...);
458
459 /* Merge two free lists */
460 void vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
461                                    vlib_buffer_free_list_t * src);
462
463 /* Make sure we have at least given number of unaligned buffers. */
464 void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
465                                            vlib_buffer_free_list_t *
466                                            free_list,
467                                            uword n_unaligned_buffers);
468
469 always_inline vlib_buffer_free_list_index_t
470 vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
471 {
472   vlib_buffer_main_t *bm = vm->buffer_main;
473
474   size = vlib_buffer_round_size (size);
475   uword *p = hash_get (bm->free_list_by_size, size);
476   return p ? p[0] : ~0;
477 }
478
479 always_inline vlib_buffer_free_list_t *
480 vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
481                                   vlib_buffer_free_list_index_t * index)
482 {
483   vlib_buffer_main_t *bm = vm->buffer_main;
484   vlib_buffer_free_list_index_t i;
485
486   *index = i = vlib_buffer_get_free_list_index (b);
487   return pool_elt_at_index (bm->buffer_free_list_pool, i);
488 }
489
490 always_inline vlib_buffer_free_list_t *
491 vlib_buffer_get_free_list (vlib_main_t * vm,
492                            vlib_buffer_free_list_index_t free_list_index)
493 {
494   vlib_buffer_main_t *bm = vm->buffer_main;
495   vlib_buffer_free_list_t *f;
496
497   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
498
499   /* Sanity: indices must match. */
500   ASSERT (f->index == free_list_index);
501
502   return f;
503 }
504
505 always_inline u32
506 vlib_buffer_free_list_buffer_size (vlib_main_t * vm,
507                                    vlib_buffer_free_list_index_t index)
508 {
509   vlib_buffer_free_list_t *f = vlib_buffer_get_free_list (vm, index);
510   return f->n_data_bytes;
511 }
512
513 void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
514
515 /* Reasonably fast buffer copy routine. */
516 always_inline void
517 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
518 {
519   while (n >= 4)
520     {
521       dst[0] = src[0];
522       dst[1] = src[1];
523       dst[2] = src[2];
524       dst[3] = src[3];
525       dst += 4;
526       src += 4;
527       n -= 4;
528     }
529   while (n > 0)
530     {
531       dst[0] = src[0];
532       dst += 1;
533       src += 1;
534       n -= 1;
535     }
536 }
537
538 /* Append given data to end of buffer, possibly allocating new buffers. */
539 u32 vlib_buffer_add_data (vlib_main_t * vm,
540                           vlib_buffer_free_list_index_t free_list_index,
541                           u32 buffer_index, void *data, u32 n_data_bytes);
542
543 /* duplicate all buffers in chain */
544 always_inline vlib_buffer_t *
545 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
546 {
547   vlib_buffer_t *s, *d, *fd;
548   uword n_alloc, n_buffers = 1;
549   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
550   int i;
551
552   s = b;
553   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
554     {
555       n_buffers++;
556       s = vlib_get_buffer (vm, s->next_buffer);
557     }
558   u32 new_buffers[n_buffers];
559
560   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
561
562   /* No guarantee that we'll get all the buffers we asked for */
563   if (PREDICT_FALSE (n_alloc < n_buffers))
564     {
565       if (n_alloc > 0)
566         vlib_buffer_free (vm, new_buffers, n_alloc);
567       return 0;
568     }
569
570   /* 1st segment */
571   s = b;
572   fd = d = vlib_get_buffer (vm, new_buffers[0]);
573   d->current_data = s->current_data;
574   d->current_length = s->current_length;
575   d->flags = s->flags & flag_mask;
576   d->total_length_not_including_first_buffer =
577     s->total_length_not_including_first_buffer;
578   clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
579   clib_memcpy (vlib_buffer_get_current (d),
580                vlib_buffer_get_current (s), s->current_length);
581
582   /* next segments */
583   for (i = 1; i < n_buffers; i++)
584     {
585       /* previous */
586       d->next_buffer = new_buffers[i];
587       /* current */
588       s = vlib_get_buffer (vm, s->next_buffer);
589       d = vlib_get_buffer (vm, new_buffers[i]);
590       d->current_data = s->current_data;
591       d->current_length = s->current_length;
592       clib_memcpy (vlib_buffer_get_current (d),
593                    vlib_buffer_get_current (s), s->current_length);
594       d->flags = s->flags & flag_mask;
595     }
596
597   return fd;
598 }
599
600 /** \brief Create a maximum of 256 clones of buffer and store them
601     in the supplied array
602
603     @param vm - (vlib_main_t *) vlib main data structure pointer
604     @param src_buffer - (u32) source buffer index
605     @param buffers - (u32 * ) buffer index array
606     @param n_buffers - (u16) number of buffer clones requested (<=256)
607     @param head_end_offset - (u16) offset relative to current position
608            where packet head ends
609     @return - (u16) number of buffers actually cloned, may be
610     less than the number requested or zero
611 */
612 always_inline u16
613 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
614                        u16 n_buffers, u16 head_end_offset)
615 {
616   u16 i;
617   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
618
619   ASSERT (s->n_add_refs == 0);
620   ASSERT (n_buffers);
621   ASSERT (n_buffers <= 256);
622
623   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
624     {
625       buffers[0] = src_buffer;
626       for (i = 1; i < n_buffers; i++)
627         {
628           vlib_buffer_t *d;
629           d = vlib_buffer_copy (vm, s);
630           if (d == 0)
631             return i;
632           buffers[i] = vlib_get_buffer_index (vm, d);
633
634         }
635       return n_buffers;
636     }
637
638   if (PREDICT_FALSE (n_buffers == 1))
639     {
640       buffers[0] = src_buffer;
641       return 1;
642     }
643
644   n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
645                                                 vlib_buffer_get_free_list_index
646                                                 (s));
647
648   for (i = 0; i < n_buffers; i++)
649     {
650       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
651       d->current_data = s->current_data;
652       d->current_length = head_end_offset;
653       vlib_buffer_set_free_list_index (d,
654                                        vlib_buffer_get_free_list_index (s));
655       d->total_length_not_including_first_buffer =
656         s->total_length_not_including_first_buffer + s->current_length -
657         head_end_offset;
658       d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
659       d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
660       clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
661       clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
662                    head_end_offset);
663       d->next_buffer = src_buffer;
664     }
665   vlib_buffer_advance (s, head_end_offset);
666   s->n_add_refs = n_buffers - 1;
667   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
668     {
669       s = vlib_get_buffer (vm, s->next_buffer);
670       s->n_add_refs = n_buffers - 1;
671     }
672
673   return n_buffers;
674 }
675
676 /** \brief Create multiple clones of buffer and store them
677     in the supplied array
678
679     @param vm - (vlib_main_t *) vlib main data structure pointer
680     @param src_buffer - (u32) source buffer index
681     @param buffers - (u32 * ) buffer index array
682     @param n_buffers - (u16) number of buffer clones requested (<=256)
683     @param head_end_offset - (u16) offset relative to current position
684            where packet head ends
685     @return - (u16) number of buffers actually cloned, may be
686     less than the number requested or zero
687 */
688 always_inline u16
689 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
690                    u16 n_buffers, u16 head_end_offset)
691 {
692   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
693   u16 n_cloned = 0;
694
695   while (n_buffers > 256)
696     {
697       vlib_buffer_t *copy;
698       copy = vlib_buffer_copy (vm, s);
699       n_cloned += vlib_buffer_clone_256 (vm,
700                                          vlib_get_buffer_index (vm, copy),
701                                          (buffers + n_cloned),
702                                          256, head_end_offset);
703       n_buffers -= 256;
704     }
705   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
706                                      buffers + n_cloned,
707                                      n_buffers, head_end_offset);
708
709   return n_cloned;
710 }
711
712 /** \brief Attach cloned tail to the buffer
713
714     @param vm - (vlib_main_t *) vlib main data structure pointer
715     @param head - (vlib_buffer_t *) head buffer
716     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
717 */
718
719 always_inline void
720 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
721                           vlib_buffer_t * tail)
722 {
723   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
724   ASSERT (vlib_buffer_get_free_list_index (head) ==
725           vlib_buffer_get_free_list_index (tail));
726
727   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
728   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
729   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
730   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
731   head->next_buffer = vlib_get_buffer_index (vm, tail);
732   head->total_length_not_including_first_buffer = tail->current_length +
733     tail->total_length_not_including_first_buffer;
734
735 next_segment:
736   __sync_add_and_fetch (&tail->n_add_refs, 1);
737
738   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
739     {
740       tail = vlib_get_buffer (vm, tail->next_buffer);
741       goto next_segment;
742     }
743 }
744
745 /* Initializes the buffer as an empty packet with no chained buffers. */
746 always_inline void
747 vlib_buffer_chain_init (vlib_buffer_t * first)
748 {
749   first->total_length_not_including_first_buffer = 0;
750   first->current_length = 0;
751   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
752   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
753 }
754
755 /* The provided next_bi buffer index is appended to the end of the packet. */
756 always_inline vlib_buffer_t *
757 vlib_buffer_chain_buffer (vlib_main_t * vm,
758                           vlib_buffer_t * first,
759                           vlib_buffer_t * last, u32 next_bi)
760 {
761   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
762   last->next_buffer = next_bi;
763   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
764   next_buffer->current_length = 0;
765   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
766   return next_buffer;
767 }
768
769 /* Increases or decreases the packet length.
770  * It does not allocate or deallocate new buffers.
771  * Therefore, the added length must be compatible
772  * with the last buffer. */
773 always_inline void
774 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
775                                    vlib_buffer_t * last, i32 len)
776 {
777   last->current_length += len;
778   if (first != last)
779     first->total_length_not_including_first_buffer += len;
780 }
781
782 /* Copy data to the end of the packet and increases its length.
783  * It does not allocate new buffers.
784  * Returns the number of copied bytes. */
785 always_inline u16
786 vlib_buffer_chain_append_data (vlib_main_t * vm,
787                                vlib_buffer_free_list_index_t free_list_index,
788                                vlib_buffer_t * first,
789                                vlib_buffer_t * last, void *data, u16 data_len)
790 {
791   u32 n_buffer_bytes =
792     vlib_buffer_free_list_buffer_size (vm, free_list_index);
793   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
794   u16 len = clib_min (data_len,
795                       n_buffer_bytes - last->current_length -
796                       last->current_data);
797   clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
798                len);
799   vlib_buffer_chain_increase_length (first, last, len);
800   return len;
801 }
802
803 /* Copy data to the end of the packet and increases its length.
804  * Allocates additional buffers from the free list if necessary.
805  * Returns the number of copied bytes.
806  * 'last' value is modified whenever new buffers are allocated and
807  * chained and points to the last buffer in the chain. */
808 u16
809 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
810                                           vlib_buffer_free_list_index_t
811                                           free_list_index,
812                                           vlib_buffer_t * first,
813                                           vlib_buffer_t ** last, void *data,
814                                           u16 data_len);
815 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
816
817 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
818   format_vlib_buffer_contents;
819
820 typedef struct
821 {
822   /* Vector of packet data. */
823   u8 *packet_data;
824
825   /* Number of buffers to allocate in each call to physmem
826      allocator. */
827   u32 min_n_buffers_each_physmem_alloc;
828
829   /* Buffer free list for this template. */
830   vlib_buffer_free_list_index_t free_list_index;
831
832   u32 *free_buffers;
833 } vlib_packet_template_t;
834
835 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
836                                              vlib_packet_template_t * t);
837
838 void vlib_packet_template_init (vlib_main_t * vm,
839                                 vlib_packet_template_t * t,
840                                 void *packet_data,
841                                 uword n_packet_data_bytes,
842                                 uword min_n_buffers_each_physmem_alloc,
843                                 char *fmt, ...);
844
845 void *vlib_packet_template_get_packet (vlib_main_t * vm,
846                                        vlib_packet_template_t * t,
847                                        u32 * bi_result);
848
849 always_inline void
850 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
851 {
852   vec_free (t->packet_data);
853 }
854
855 always_inline u32
856 unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
857 {
858   serialize_stream_t *s = &m->stream;
859   vlib_serialize_buffer_main_t *sm
860     = uword_to_pointer (m->stream.data_function_opaque,
861                         vlib_serialize_buffer_main_t *);
862   vlib_main_t *vm = sm->vlib_main;
863   u32 n, *f;
864
865   n = s->n_buffer_bytes - s->current_buffer_index;
866   if (sm->last_buffer != ~0)
867     {
868       vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
869       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
870         {
871           b = vlib_get_buffer (vm, b->next_buffer);
872           n += b->current_length;
873         }
874     }
875
876   /* *INDENT-OFF* */
877   clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
878     n += vlib_buffer_index_length_in_chain (vm, f[0]);
879   }));
880 /* *INDENT-ON* */
881
882   return n;
883 }
884
885 /* Set a buffer quickly into "uninitialized" state.  We want this to
886    be extremely cheap and arrange for all fields that need to be
887    initialized to be in the first 128 bits of the buffer. */
888 always_inline void
889 vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
890                                 vlib_buffer_free_list_t * fl)
891 {
892   vlib_buffer_t *src = &fl->buffer_init_template;
893
894   /* Make sure vlib_buffer_t is cacheline aligned and sized */
895   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
896   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
897           CLIB_CACHE_LINE_BYTES);
898   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
899           CLIB_CACHE_LINE_BYTES * 2);
900
901   /* Make sure buffer template is sane. */
902   ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
903
904   clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
905                STRUCT_MARK_PTR (src, template_start),
906                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
907                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
908
909   /* Not in the first 16 octets. */
910   dst->n_add_refs = src->n_add_refs;
911   vlib_buffer_set_free_list_index (dst, fl->index);
912
913   /* Make sure it really worked. */
914 #define _(f) ASSERT (dst->f == src->f);
915   _(current_data);
916   _(current_length);
917   _(flags);
918 #undef _
919   /* ASSERT (dst->total_length_not_including_first_buffer == 0); */
920   /* total_length_not_including_first_buffer is not in the template anymore
921    * so it may actually not zeroed for some buffers. One option is to
922    * uncomment the line lower (comes at a cost), the other, is to just  not
923    * care */
924   /* dst->total_length_not_including_first_buffer = 0; */
925   ASSERT (dst->n_add_refs == 0);
926 }
927
928 always_inline void
929 vlib_buffer_add_to_free_list (vlib_main_t * vm,
930                               vlib_buffer_free_list_t * f,
931                               u32 buffer_index, u8 do_init)
932 {
933   vlib_buffer_t *b;
934   b = vlib_get_buffer (vm, buffer_index);
935   if (PREDICT_TRUE (do_init))
936     vlib_buffer_init_for_free_list (b, f);
937   vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
938
939   if (vec_len (f->buffers) > 4 * VLIB_FRAME_SIZE)
940     {
941       vlib_buffer_free_list_t *mf;
942       mf = vlib_buffer_get_free_list (vlib_mains[0], f->index);
943       clib_spinlock_lock (&mf->global_buffers_lock);
944       /* keep last stored buffers, as they are more likely hot in the cache */
945       vec_add_aligned (mf->global_buffers, f->buffers, VLIB_FRAME_SIZE,
946                        CLIB_CACHE_LINE_BYTES);
947       vec_delete (f->buffers, VLIB_FRAME_SIZE, 0);
948       f->n_alloc -= VLIB_FRAME_SIZE;
949       clib_spinlock_unlock (&mf->global_buffers_lock);
950     }
951 }
952
953 #if CLIB_DEBUG > 0
954 extern u32 *vlib_buffer_state_validation_lock;
955 extern uword *vlib_buffer_state_validation_hash;
956 extern void *vlib_buffer_state_heap;
957 #endif
958
959 static inline void
960 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
961 {
962 #if CLIB_DEBUG > 0
963   uword *p;
964   void *oldheap;
965
966   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
967
968   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
969     ;
970
971   p = hash_get (vlib_buffer_state_validation_hash, b);
972
973   /* If we don't know about b, declare it to be in the expected state */
974   if (!p)
975     {
976       hash_set (vlib_buffer_state_validation_hash, b, expected);
977       goto out;
978     }
979
980   if (p[0] != expected)
981     {
982       void cj_stop (void);
983       u32 bi;
984       vlib_main_t *vm = &vlib_global_main;
985
986       cj_stop ();
987
988       bi = vlib_get_buffer_index (vm, b);
989
990       clib_mem_set_heap (oldheap);
991       clib_warning ("%.6f buffer %llx (%d): %s, not %s",
992                     vlib_time_now (vm), bi,
993                     p[0] ? "busy" : "free", expected ? "busy" : "free");
994       os_panic ();
995     }
996 out:
997   CLIB_MEMORY_BARRIER ();
998   *vlib_buffer_state_validation_lock = 0;
999   clib_mem_set_heap (oldheap);
1000 #endif
1001 }
1002
1003 static inline void
1004 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
1005 {
1006 #if CLIB_DEBUG > 0
1007   void *oldheap;
1008
1009   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
1010
1011   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
1012     ;
1013
1014   hash_set (vlib_buffer_state_validation_hash, b, expected);
1015
1016   CLIB_MEMORY_BARRIER ();
1017   *vlib_buffer_state_validation_lock = 0;
1018   clib_mem_set_heap (oldheap);
1019 #endif
1020 }
1021
1022 /** minimum data size of first buffer in a buffer chain */
1023 #define VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE (256)
1024
1025 /**
1026  * @brief compress buffer chain in a way where the first buffer is at least
1027  * VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE long
1028  *
1029  * @param[in] vm - vlib_main
1030  * @param[in,out] first - first buffer in chain
1031  * @param[in,out] discard_vector - vector of buffer indexes which were removed
1032  * from the chain
1033  */
1034 always_inline void
1035 vlib_buffer_chain_compress (vlib_main_t * vm,
1036                             vlib_buffer_t * first, u32 ** discard_vector)
1037 {
1038   if (first->current_length >= VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE ||
1039       !(first->flags & VLIB_BUFFER_NEXT_PRESENT))
1040     {
1041       /* this is already big enough or not a chain */
1042       return;
1043     }
1044   /* probe free list to find allocated buffer size to avoid overfill */
1045   vlib_buffer_free_list_index_t index;
1046   vlib_buffer_free_list_t *free_list =
1047     vlib_buffer_get_buffer_free_list (vm, first, &index);
1048
1049   u32 want_first_size = clib_min (VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE,
1050                                   free_list->n_data_bytes -
1051                                   first->current_data);
1052   do
1053     {
1054       vlib_buffer_t *second = vlib_get_buffer (vm, first->next_buffer);
1055       u32 need = want_first_size - first->current_length;
1056       u32 amount_to_copy = clib_min (need, second->current_length);
1057       clib_memcpy (((u8 *) vlib_buffer_get_current (first)) +
1058                    first->current_length,
1059                    vlib_buffer_get_current (second), amount_to_copy);
1060       first->current_length += amount_to_copy;
1061       vlib_buffer_advance (second, amount_to_copy);
1062       if (first->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1063         {
1064           first->total_length_not_including_first_buffer -= amount_to_copy;
1065         }
1066       if (!second->current_length)
1067         {
1068           vec_add1 (*discard_vector, first->next_buffer);
1069           if (second->flags & VLIB_BUFFER_NEXT_PRESENT)
1070             {
1071               first->next_buffer = second->next_buffer;
1072             }
1073           else
1074             {
1075               first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1076             }
1077           second->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1078         }
1079     }
1080   while ((first->current_length < want_first_size) &&
1081          (first->flags & VLIB_BUFFER_NEXT_PRESENT));
1082 }
1083
1084 #endif /* included_vlib_buffer_funcs_h */
1085
1086 /*
1087  * fd.io coding-style-patch-verification: ON
1088  *
1089  * Local Variables:
1090  * eval: (c-set-style "gnu")
1091  * End:
1092  */