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