07f270c8c2329845722759eda9b321467a03b082
[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 #include <vppinfra/fifo.h>
45 #include <vlib/buffer.h>
46 #include <vlib/physmem_funcs.h>
47 #include <vlib/main.h>
48 #include <vlib/node.h>
49
50 /** \file
51     vlib buffer access methods.
52 */
53
54 always_inline void
55 vlib_buffer_validate (vlib_main_t * vm, vlib_buffer_t * b)
56 {
57   vlib_buffer_main_t *bm = vm->buffer_main;
58   vlib_buffer_pool_t *bp;
59
60   /* reference count in allocated buffer always must be 1 or higher */
61   ASSERT (b->ref_count > 0);
62
63   /* verify that buffer pool index is valid */
64   bp = vec_elt_at_index (bm->buffer_pools, b->buffer_pool_index);
65   ASSERT (pointer_to_uword (b) >= bp->start);
66   ASSERT (pointer_to_uword (b) < bp->start + bp->size -
67           (bp->data_size + sizeof (vlib_buffer_t)));
68 }
69
70 always_inline void *
71 vlib_buffer_ptr_from_index (uword buffer_mem_start, u32 buffer_index,
72                             uword offset)
73 {
74   offset += ((uword) buffer_index) << CLIB_LOG2_CACHE_LINE_BYTES;
75   return uword_to_pointer (buffer_mem_start + offset, vlib_buffer_t *);
76 }
77
78 /** \brief Translate buffer index into buffer pointer
79
80     @param vm - (vlib_main_t *) vlib main data structure pointer
81     @param buffer_index - (u32) buffer index
82     @return - (vlib_buffer_t *) buffer pointer
83 */
84 always_inline vlib_buffer_t *
85 vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
86 {
87   vlib_buffer_main_t *bm = vm->buffer_main;
88   vlib_buffer_t *b;
89
90   b = vlib_buffer_ptr_from_index (bm->buffer_mem_start, buffer_index, 0);
91   vlib_buffer_validate (vm, b);
92   return b;
93 }
94
95 static_always_inline u32
96 vlib_buffer_get_default_data_size (vlib_main_t * vm)
97 {
98   return vm->buffer_main->default_data_size;
99 }
100
101 static_always_inline void
102 vlib_buffer_copy_indices (u32 * dst, u32 * src, u32 n_indices)
103 {
104 #if defined(CLIB_HAVE_VEC512)
105   while (n_indices >= 16)
106     {
107       u32x16_store_unaligned (u32x16_load_unaligned (src), dst);
108       dst += 16;
109       src += 16;
110       n_indices -= 16;
111     }
112 #endif
113
114 #if defined(CLIB_HAVE_VEC256)
115   while (n_indices >= 8)
116     {
117       u32x8_store_unaligned (u32x8_load_unaligned (src), dst);
118       dst += 8;
119       src += 8;
120       n_indices -= 8;
121     }
122 #endif
123
124 #if defined(CLIB_HAVE_VEC128)
125   while (n_indices >= 4)
126     {
127       u32x4_store_unaligned (u32x4_load_unaligned (src), dst);
128       dst += 4;
129       src += 4;
130       n_indices -= 4;
131     }
132 #endif
133
134   while (n_indices)
135     {
136       dst[0] = src[0];
137       dst += 1;
138       src += 1;
139       n_indices -= 1;
140     }
141 }
142
143 always_inline void
144 vlib_buffer_copy_indices_from_ring (u32 * dst, u32 * ring, u32 start,
145                                     u32 ring_size, u32 n_buffers)
146 {
147   ASSERT (n_buffers <= ring_size);
148
149   if (PREDICT_TRUE (start + n_buffers <= ring_size))
150     {
151       vlib_buffer_copy_indices (dst, ring + start, n_buffers);
152     }
153   else
154     {
155       u32 n = ring_size - start;
156       vlib_buffer_copy_indices (dst, ring + start, n);
157       vlib_buffer_copy_indices (dst + n, ring, n_buffers - n);
158     }
159 }
160
161 STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, template_end, 64);
162 static_always_inline void
163 vlib_buffer_copy_template (vlib_buffer_t * b, vlib_buffer_t * bt)
164 {
165 #if defined CLIB_HAVE_VEC512
166   b->as_u8x64[0] = bt->as_u8x64[0];
167 #elif defined (CLIB_HAVE_VEC256)
168   b->as_u8x32[0] = bt->as_u8x32[0];
169   b->as_u8x32[1] = bt->as_u8x32[1];
170 #elif defined (CLIB_HAVE_VEC128)
171   b->as_u8x16[0] = bt->as_u8x16[0];
172   b->as_u8x16[1] = bt->as_u8x16[1];
173   b->as_u8x16[2] = bt->as_u8x16[2];
174   b->as_u8x16[3] = bt->as_u8x16[3];
175 #else
176   clib_memcpy_fast (b, bt, 64);
177 #endif
178 }
179
180 always_inline u8
181 vlib_buffer_pool_get_default_for_numa (vlib_main_t * vm, u32 numa_node)
182 {
183   ASSERT (numa_node < VLIB_BUFFER_MAX_NUMA_NODES);
184   return vm->buffer_main->default_buffer_pool_index_for_numa[numa_node];
185 }
186
187 /** \brief Translate array of buffer indices into buffer pointers with offset
188
189     @param vm - (vlib_main_t *) vlib main data structure pointer
190     @param bi - (u32 *) array of buffer indices
191     @param b - (void **) array to store buffer pointers
192     @param count - (uword) number of elements
193     @param offset - (i32) offset applied to each pointer
194 */
195 static_always_inline void
196 vlib_get_buffers_with_offset (vlib_main_t * vm, u32 * bi, void **b, int count,
197                               i32 offset)
198 {
199   uword buffer_mem_start = vm->buffer_main->buffer_mem_start;
200 #ifdef CLIB_HAVE_VEC256
201   u64x4 off = u64x4_splat (buffer_mem_start + offset);
202   /* if count is not const, compiler will not unroll while loop
203      se we maintain two-in-parallel variant */
204   while (count >= 8)
205     {
206       u64x4 b0 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi));
207       u64x4 b1 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi + 4));
208       /* shift and add to get vlib_buffer_t pointer */
209       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
210       u64x4_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 4);
211       b += 8;
212       bi += 8;
213       count -= 8;
214     }
215 #endif
216   while (count >= 4)
217     {
218 #ifdef CLIB_HAVE_VEC256
219       u64x4 b0 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi));
220       /* shift and add to get vlib_buffer_t pointer */
221       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
222 #elif defined (CLIB_HAVE_VEC128)
223       u64x2 off = u64x2_splat (buffer_mem_start + offset);
224       u32x4 bi4 = u32x4_load_unaligned (bi);
225       u64x2 b0 = u32x4_extend_to_u64x2 ((u32x4) bi4);
226 #if defined (__aarch64__)
227       u64x2 b1 = u32x4_extend_to_u64x2_high ((u32x4) bi4);
228 #else
229       bi4 = u32x4_shuffle (bi4, 2, 3, 0, 1);
230       u64x2 b1 = u32x4_extend_to_u64x2 ((u32x4) bi4);
231 #endif
232       u64x2_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
233       u64x2_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 2);
234 #else
235       b[0] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[0], offset);
236       b[1] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[1], offset);
237       b[2] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[2], offset);
238       b[3] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[3], offset);
239 #endif
240       b += 4;
241       bi += 4;
242       count -= 4;
243     }
244   while (count)
245     {
246       b[0] = vlib_buffer_ptr_from_index (buffer_mem_start, bi[0], offset);
247       b += 1;
248       bi += 1;
249       count -= 1;
250     }
251 }
252
253 /** \brief Translate array of buffer indices into buffer pointers
254
255     @param vm - (vlib_main_t *) vlib main data structure pointer
256     @param bi - (u32 *) array of buffer indices
257     @param b - (vlib_buffer_t **) array to store buffer pointers
258     @param count - (uword) number of elements
259 */
260
261 static_always_inline void
262 vlib_get_buffers (vlib_main_t * vm, u32 * bi, vlib_buffer_t ** b, int count)
263 {
264   vlib_get_buffers_with_offset (vm, bi, (void **) b, count, 0);
265 }
266
267 /** \brief Translate buffer pointer into buffer index
268
269     @param vm - (vlib_main_t *) vlib main data structure pointer
270     @param p - (void *) buffer pointer
271     @return - (u32) buffer index
272 */
273
274 always_inline u32
275 vlib_get_buffer_index (vlib_main_t * vm, void *p)
276 {
277   vlib_buffer_main_t *bm = vm->buffer_main;
278   uword offset = pointer_to_uword (p) - bm->buffer_mem_start;
279   ASSERT (pointer_to_uword (p) >= bm->buffer_mem_start);
280   ASSERT (offset < bm->buffer_mem_size);
281   ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
282   return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
283 }
284
285 /** \brief Translate array of buffer pointers into buffer indices with offset
286
287     @param vm - (vlib_main_t *) vlib main data structure pointer
288     @param b - (void **) array of buffer pointers
289     @param bi - (u32 *) array to store buffer indices
290     @param count - (uword) number of elements
291     @param offset - (i32) offset applied to each pointer
292 */
293 static_always_inline void
294 vlib_get_buffer_indices_with_offset (vlib_main_t * vm, void **b, u32 * bi,
295                                      uword count, i32 offset)
296 {
297 #ifdef CLIB_HAVE_VEC256
298   u32x8 mask = { 0, 2, 4, 6, 1, 3, 5, 7 };
299   u64x4 off4 = u64x4_splat (vm->buffer_main->buffer_mem_start - offset);
300
301   while (count >= 8)
302     {
303       /* load 4 pointers into 256-bit register */
304       u64x4 v0 = u64x4_load_unaligned (b);
305       u64x4 v1 = u64x4_load_unaligned (b + 4);
306       u32x8 v2, v3;
307
308       v0 -= off4;
309       v1 -= off4;
310
311       v0 >>= CLIB_LOG2_CACHE_LINE_BYTES;
312       v1 >>= CLIB_LOG2_CACHE_LINE_BYTES;
313
314       /* permute 256-bit register so lower u32s of each buffer index are
315        * placed into lower 128-bits */
316       v2 = u32x8_permute ((u32x8) v0, mask);
317       v3 = u32x8_permute ((u32x8) v1, mask);
318
319       /* extract lower 128-bits and save them to the array of buffer indices */
320       u32x4_store_unaligned (u32x8_extract_lo (v2), bi);
321       u32x4_store_unaligned (u32x8_extract_lo (v3), bi + 4);
322       bi += 8;
323       b += 8;
324       count -= 8;
325     }
326 #endif
327   while (count >= 4)
328     {
329       /* equivalent non-nector implementation */
330       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
331       bi[1] = vlib_get_buffer_index (vm, ((u8 *) b[1]) + offset);
332       bi[2] = vlib_get_buffer_index (vm, ((u8 *) b[2]) + offset);
333       bi[3] = vlib_get_buffer_index (vm, ((u8 *) b[3]) + offset);
334       bi += 4;
335       b += 4;
336       count -= 4;
337     }
338   while (count)
339     {
340       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
341       bi += 1;
342       b += 1;
343       count -= 1;
344     }
345 }
346
347 /** \brief Translate array of buffer pointers into buffer indices
348
349     @param vm - (vlib_main_t *) vlib main data structure pointer
350     @param b - (vlib_buffer_t **) array of buffer pointers
351     @param bi - (u32 *) array to store buffer indices
352     @param count - (uword) number of elements
353 */
354 static_always_inline void
355 vlib_get_buffer_indices (vlib_main_t * vm, vlib_buffer_t ** b, u32 * bi,
356                          uword count)
357 {
358   vlib_get_buffer_indices_with_offset (vm, (void **) b, bi, count, 0);
359 }
360
361 /** \brief Get next buffer in buffer linklist, or zero for end of list.
362
363     @param vm - (vlib_main_t *) vlib main data structure pointer
364     @param b - (void *) buffer pointer
365     @return - (vlib_buffer_t *) next buffer, or NULL
366 */
367 always_inline vlib_buffer_t *
368 vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
369 {
370   return (b->flags & VLIB_BUFFER_NEXT_PRESENT
371           ? vlib_get_buffer (vm, b->next_buffer) : 0);
372 }
373
374 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
375                                              vlib_buffer_t * b_first);
376
377 /** \brief Get length in bytes of the buffer chain
378
379     @param vm - (vlib_main_t *) vlib main data structure pointer
380     @param b - (void *) buffer pointer
381     @return - (uword) length of buffer chain
382 */
383 always_inline uword
384 vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
385 {
386   uword len = b->current_length;
387
388   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
389     return len;
390
391   if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
392     return len + b->total_length_not_including_first_buffer;
393
394   return vlib_buffer_length_in_chain_slow_path (vm, b);
395 }
396
397 /** \brief Get length in bytes of the buffer index buffer chain
398
399     @param vm - (vlib_main_t *) vlib main data structure pointer
400     @param bi - (u32) buffer index
401     @return - (uword) length of buffer chain
402 */
403 always_inline uword
404 vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
405 {
406   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
407   return vlib_buffer_length_in_chain (vm, b);
408 }
409
410 /** \brief Copy buffer contents to memory
411
412     @param vm - (vlib_main_t *) vlib main data structure pointer
413     @param buffer_index - (u32) buffer index
414     @param contents - (u8 *) memory, <strong>must be large enough</strong>
415     @return - (uword) length of buffer chain
416 */
417 always_inline uword
418 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
419 {
420   uword content_len = 0;
421   uword l;
422   vlib_buffer_t *b;
423
424   while (1)
425     {
426       b = vlib_get_buffer (vm, buffer_index);
427       l = b->current_length;
428       clib_memcpy_fast (contents + content_len, b->data + b->current_data, l);
429       content_len += l;
430       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
431         break;
432       buffer_index = b->next_buffer;
433     }
434
435   return content_len;
436 }
437
438 always_inline uword
439 vlib_buffer_get_pa (vlib_main_t * vm, vlib_buffer_t * b)
440 {
441   return vlib_physmem_get_pa (vm, b->data);
442 }
443
444 always_inline uword
445 vlib_buffer_get_current_pa (vlib_main_t * vm, vlib_buffer_t * b)
446 {
447   return vlib_buffer_get_pa (vm, b) + b->current_data;
448 }
449
450 /** \brief Prefetch buffer metadata by buffer index
451     The first 64 bytes of buffer contains most header information
452
453     @param vm - (vlib_main_t *) vlib main data structure pointer
454     @param bi - (u32) buffer index
455     @param type - LOAD, STORE. In most cases, STORE is the right answer
456 */
457 /* Prefetch buffer header given index. */
458 #define vlib_prefetch_buffer_with_index(vm,bi,type)     \
459   do {                                                  \
460     vlib_buffer_t * _b = vlib_get_buffer (vm, bi);      \
461     vlib_prefetch_buffer_header (_b, type);             \
462   } while (0)
463
464 typedef enum
465 {
466   /* Index is unknown. */
467   VLIB_BUFFER_UNKNOWN,
468
469   /* Index is known and free/allocated. */
470   VLIB_BUFFER_KNOWN_FREE,
471   VLIB_BUFFER_KNOWN_ALLOCATED,
472 } vlib_buffer_known_state_t;
473
474 void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
475                                       uword n_buffers,
476                                       vlib_buffer_known_state_t
477                                       expected_state);
478
479 always_inline vlib_buffer_known_state_t
480 vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
481 {
482   vlib_buffer_main_t *bm = vm->buffer_main;
483
484   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
485   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
486   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
487   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
488 }
489
490 /* Validates sanity of a single buffer.
491    Returns format'ed vector with error message if any. */
492 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
493                           uword follow_chain);
494
495 u8 *vlib_validate_buffers (vlib_main_t * vm,
496                            u32 * buffers,
497                            uword next_buffer_stride,
498                            uword n_buffers,
499                            vlib_buffer_known_state_t known_state,
500                            uword follow_buffer_next);
501
502 static_always_inline vlib_buffer_pool_t *
503 vlib_get_buffer_pool (vlib_main_t * vm, u8 buffer_pool_index)
504 {
505   vlib_buffer_main_t *bm = vm->buffer_main;
506   return vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
507 }
508
509 static_always_inline uword
510 vlib_buffer_pool_get (vlib_main_t * vm, u8 buffer_pool_index, u32 * buffers,
511                       u32 n_buffers)
512 {
513   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
514   u32 len;
515
516   ASSERT (bp->buffers);
517
518   clib_spinlock_lock (&bp->lock);
519   len = bp->n_avail;
520   if (PREDICT_TRUE (n_buffers < len))
521     {
522       len -= n_buffers;
523       vlib_buffer_copy_indices (buffers, bp->buffers + len, n_buffers);
524       bp->n_avail = len;
525       clib_spinlock_unlock (&bp->lock);
526       return n_buffers;
527     }
528   else
529     {
530       vlib_buffer_copy_indices (buffers, bp->buffers, len);
531       bp->n_avail = 0;
532       clib_spinlock_unlock (&bp->lock);
533       return len;
534     }
535 }
536
537
538 /** \brief Allocate buffers from specific pool into supplied array
539
540     @param vm - (vlib_main_t *) vlib main data structure pointer
541     @param buffers - (u32 * ) buffer index array
542     @param n_buffers - (u32) number of buffers requested
543     @return - (u32) number of buffers actually allocated, may be
544     less than the number requested or zero
545 */
546
547 always_inline u32
548 vlib_buffer_alloc_from_pool (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
549                              u8 buffer_pool_index)
550 {
551   vlib_buffer_main_t *bm = vm->buffer_main;
552   vlib_buffer_pool_t *bp;
553   vlib_buffer_pool_thread_t *bpt;
554   u32 *src, *dst, len, n_left;
555
556   bp = vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
557   bpt = vec_elt_at_index (bp->threads, vm->thread_index);
558
559   dst = buffers;
560   n_left = n_buffers;
561   len = bpt->n_cached;
562
563   /* per-thread cache contains enough buffers */
564   if (len >= n_buffers)
565     {
566       src = bpt->cached_buffers + len - n_buffers;
567       vlib_buffer_copy_indices (dst, src, n_buffers);
568       bpt->n_cached -= n_buffers;
569
570       if (CLIB_DEBUG > 0)
571         vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
572                                          VLIB_BUFFER_KNOWN_FREE);
573       return n_buffers;
574     }
575
576   /* alloc bigger than cache - take buffers directly from main pool */
577   if (n_buffers >= VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ)
578     {
579       n_buffers = vlib_buffer_pool_get (vm, buffer_pool_index, buffers,
580                                         n_buffers);
581
582       if (CLIB_DEBUG > 0)
583         vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
584                                          VLIB_BUFFER_KNOWN_FREE);
585       return n_buffers;
586     }
587
588   /* take everything available in the cache */
589   if (len)
590     {
591       vlib_buffer_copy_indices (dst, bpt->cached_buffers, len);
592       bpt->n_cached = 0;
593       dst += len;
594       n_left -= len;
595     }
596
597   len = round_pow2 (n_left, 32);
598   len = vlib_buffer_pool_get (vm, buffer_pool_index, bpt->cached_buffers,
599                               len);
600   bpt->n_cached = len;
601
602   if (len)
603     {
604       u32 n_copy = clib_min (len, n_left);
605       src = bpt->cached_buffers + len - n_copy;
606       vlib_buffer_copy_indices (dst, src, n_copy);
607       bpt->n_cached -= n_copy;
608       n_left -= n_copy;
609     }
610
611   n_buffers -= n_left;
612
613   /* Verify that buffers are known free. */
614   if (CLIB_DEBUG > 0)
615     vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
616                                      VLIB_BUFFER_KNOWN_FREE);
617
618   return n_buffers;
619 }
620
621 /** \brief Allocate buffers from specific numa node into supplied array
622
623     @param vm - (vlib_main_t *) vlib main data structure pointer
624     @param buffers - (u32 * ) buffer index array
625     @param n_buffers - (u32) number of buffers requested
626     @param numa_node - (u32) numa node
627     @return - (u32) number of buffers actually allocated, may be
628     less than the number requested or zero
629 */
630 always_inline u32
631 vlib_buffer_alloc_on_numa (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
632                            u32 numa_node)
633 {
634   u8 index = vlib_buffer_pool_get_default_for_numa (vm, numa_node);
635   return vlib_buffer_alloc_from_pool (vm, buffers, n_buffers, index);
636 }
637
638 /** \brief Allocate buffers into supplied array
639
640     @param vm - (vlib_main_t *) vlib main data structure pointer
641     @param buffers - (u32 * ) buffer index array
642     @param n_buffers - (u32) number of buffers requested
643     @return - (u32) number of buffers actually allocated, may be
644     less than the number requested or zero
645 */
646
647 always_inline u32
648 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
649 {
650   return vlib_buffer_alloc_on_numa (vm, buffers, n_buffers, vm->numa_node);
651 }
652
653 /** \brief Allocate buffers into ring
654
655     @param vm - (vlib_main_t *) vlib main data structure pointer
656     @param buffers - (u32 * ) buffer index ring
657     @param start - (u32) first slot in the ring
658     @param ring_size - (u32) ring size
659     @param n_buffers - (u32) number of buffers requested
660     @return - (u32) number of buffers actually allocated, may be
661     less than the number requested or zero
662 */
663 always_inline u32
664 vlib_buffer_alloc_to_ring (vlib_main_t * vm, u32 * ring, u32 start,
665                            u32 ring_size, u32 n_buffers)
666 {
667   u32 n_alloc;
668
669   ASSERT (n_buffers <= ring_size);
670
671   if (PREDICT_TRUE (start + n_buffers <= ring_size))
672     return vlib_buffer_alloc (vm, ring + start, n_buffers);
673
674   n_alloc = vlib_buffer_alloc (vm, ring + start, ring_size - start);
675
676   if (PREDICT_TRUE (n_alloc == ring_size - start))
677     n_alloc += vlib_buffer_alloc (vm, ring, n_buffers - n_alloc);
678
679   return n_alloc;
680 }
681
682 /** \brief Allocate buffers into ring from specific buffer pool
683
684     @param vm - (vlib_main_t *) vlib main data structure pointer
685     @param buffers - (u32 * ) buffer index ring
686     @param start - (u32) first slot in the ring
687     @param ring_size - (u32) ring size
688     @param n_buffers - (u32) number of buffers requested
689     @return - (u32) number of buffers actually allocated, may be
690     less than the number requested or zero
691 */
692 always_inline u32
693 vlib_buffer_alloc_to_ring_from_pool (vlib_main_t * vm, u32 * ring, u32 start,
694                                      u32 ring_size, u32 n_buffers,
695                                      u8 buffer_pool_index)
696 {
697   u32 n_alloc;
698
699   ASSERT (n_buffers <= ring_size);
700
701   if (PREDICT_TRUE (start + n_buffers <= ring_size))
702     return vlib_buffer_alloc_from_pool (vm, ring + start, n_buffers,
703                                         buffer_pool_index);
704
705   n_alloc = vlib_buffer_alloc_from_pool (vm, ring + start, ring_size - start,
706                                          buffer_pool_index);
707
708   if (PREDICT_TRUE (n_alloc == ring_size - start))
709     n_alloc += vlib_buffer_alloc_from_pool (vm, ring, n_buffers - n_alloc,
710                                             buffer_pool_index);
711
712   return n_alloc;
713 }
714
715 static_always_inline void
716 vlib_buffer_pool_put (vlib_main_t * vm, u8 buffer_pool_index,
717                       u32 * buffers, u32 n_buffers)
718 {
719   vlib_buffer_pool_t *bp = vlib_get_buffer_pool (vm, buffer_pool_index);
720   vlib_buffer_pool_thread_t *bpt = vec_elt_at_index (bp->threads,
721                                                      vm->thread_index);
722   u32 n_cached, n_empty;
723
724   if (CLIB_DEBUG > 0)
725     vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
726                                      VLIB_BUFFER_KNOWN_ALLOCATED);
727
728   n_cached = bpt->n_cached;
729   n_empty = VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ - n_cached;
730   if (n_buffers <= n_empty)
731     {
732       vlib_buffer_copy_indices (bpt->cached_buffers + n_cached,
733                                 buffers, n_buffers);
734       bpt->n_cached = n_cached + n_buffers;
735       return;
736     }
737
738   vlib_buffer_copy_indices (bpt->cached_buffers + n_cached,
739                             buffers + n_buffers - n_empty, n_empty);
740   bpt->n_cached = VLIB_BUFFER_POOL_PER_THREAD_CACHE_SZ;
741
742   clib_spinlock_lock (&bp->lock);
743   vlib_buffer_copy_indices (bp->buffers + bp->n_avail, buffers,
744                             n_buffers - n_empty);
745   bp->n_avail += n_buffers - n_empty;
746   clib_spinlock_unlock (&bp->lock);
747 }
748
749 static_always_inline void
750 vlib_buffer_free_inline (vlib_main_t * vm, u32 * buffers, u32 n_buffers,
751                          int maybe_next)
752 {
753   const int queue_size = 128;
754   vlib_buffer_pool_t *bp = 0;
755   u8 buffer_pool_index = ~0;
756   u32 n_queue = 0, queue[queue_size + 4];
757   vlib_buffer_t bt = { };
758 #if defined(CLIB_HAVE_VEC128)
759   vlib_buffer_t bpi_mask = {.buffer_pool_index = ~0 };
760   vlib_buffer_t bpi_vec = {.buffer_pool_index = ~0 };
761   vlib_buffer_t flags_refs_mask = {
762     .flags = VLIB_BUFFER_NEXT_PRESENT,
763     .ref_count = ~1
764   };
765 #endif
766
767   while (n_buffers)
768     {
769       vlib_buffer_t *b[8];
770       u32 bi, sum = 0, flags, next;
771
772       if (n_buffers < 12)
773         goto one_by_one;
774
775       vlib_get_buffers (vm, buffers, b, 4);
776       vlib_get_buffers (vm, buffers + 8, b + 4, 4);
777
778       vlib_prefetch_buffer_header (b[4], LOAD);
779       vlib_prefetch_buffer_header (b[5], LOAD);
780       vlib_prefetch_buffer_header (b[6], LOAD);
781       vlib_prefetch_buffer_header (b[7], LOAD);
782
783 #if defined(CLIB_HAVE_VEC128)
784       u8x16 p0, p1, p2, p3, r;
785       p0 = u8x16_load_unaligned (b[0]);
786       p1 = u8x16_load_unaligned (b[1]);
787       p2 = u8x16_load_unaligned (b[2]);
788       p3 = u8x16_load_unaligned (b[3]);
789
790       r = p0 ^ bpi_vec.as_u8x16[0];
791       r |= p1 ^ bpi_vec.as_u8x16[0];
792       r |= p2 ^ bpi_vec.as_u8x16[0];
793       r |= p3 ^ bpi_vec.as_u8x16[0];
794       r &= bpi_mask.as_u8x16[0];
795       r |= (p0 | p1 | p2 | p3) & flags_refs_mask.as_u8x16[0];
796
797       sum = !u8x16_is_all_zero (r);
798 #else
799       sum |= b[0]->flags;
800       sum |= b[1]->flags;
801       sum |= b[2]->flags;
802       sum |= b[3]->flags;
803       sum &= VLIB_BUFFER_NEXT_PRESENT;
804       sum += b[0]->ref_count - 1;
805       sum += b[1]->ref_count - 1;
806       sum += b[2]->ref_count - 1;
807       sum += b[3]->ref_count - 1;
808       sum |= b[0]->buffer_pool_index ^ buffer_pool_index;
809       sum |= b[1]->buffer_pool_index ^ buffer_pool_index;
810       sum |= b[2]->buffer_pool_index ^ buffer_pool_index;
811       sum |= b[3]->buffer_pool_index ^ buffer_pool_index;
812 #endif
813
814       if (sum)
815         goto one_by_one;
816
817       vlib_buffer_copy_indices (queue + n_queue, buffers, 4);
818       vlib_buffer_copy_template (b[0], &bt);
819       vlib_buffer_copy_template (b[1], &bt);
820       vlib_buffer_copy_template (b[2], &bt);
821       vlib_buffer_copy_template (b[3], &bt);
822       n_queue += 4;
823
824       vlib_buffer_validate (vm, b[0]);
825       vlib_buffer_validate (vm, b[1]);
826       vlib_buffer_validate (vm, b[2]);
827       vlib_buffer_validate (vm, b[3]);
828
829       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
830       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
831       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
832       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
833
834       if (n_queue >= queue_size)
835         {
836           vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
837           n_queue = 0;
838         }
839       buffers += 4;
840       n_buffers -= 4;
841       continue;
842
843     one_by_one:
844       bi = buffers[0];
845
846     next_in_chain:
847       b[0] = vlib_get_buffer (vm, bi);
848       flags = b[0]->flags;
849       next = b[0]->next_buffer;
850
851       if (PREDICT_FALSE (buffer_pool_index != b[0]->buffer_pool_index))
852         {
853
854           if (n_queue)
855             {
856               vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
857               n_queue = 0;
858             }
859
860           buffer_pool_index = b[0]->buffer_pool_index;
861 #if defined(CLIB_HAVE_VEC128)
862           bpi_vec.buffer_pool_index = buffer_pool_index;
863 #endif
864           bp = vlib_get_buffer_pool (vm, buffer_pool_index);
865           vlib_buffer_copy_template (&bt, &bp->buffer_template);
866         }
867
868       vlib_buffer_validate (vm, b[0]);
869
870       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
871
872       if (clib_atomic_sub_fetch (&b[0]->ref_count, 1) == 0)
873         {
874           vlib_buffer_copy_template (b[0], &bt);
875           queue[n_queue++] = bi;
876         }
877
878       if (n_queue == queue_size)
879         {
880           vlib_buffer_pool_put (vm, buffer_pool_index, queue, queue_size);
881           n_queue = 0;
882         }
883
884       if (maybe_next && (flags & VLIB_BUFFER_NEXT_PRESENT))
885         {
886           bi = next;
887           goto next_in_chain;
888         }
889
890       buffers++;
891       n_buffers--;
892     }
893
894   if (n_queue)
895     vlib_buffer_pool_put (vm, buffer_pool_index, queue, n_queue);
896 }
897
898
899 /** \brief Free buffers
900     Frees the entire buffer chain for each buffer
901
902     @param vm - (vlib_main_t *) vlib main data structure pointer
903     @param buffers - (u32 * ) buffer index array
904     @param n_buffers - (u32) number of buffers to free
905
906 */
907 always_inline void
908 vlib_buffer_free (vlib_main_t * vm,
909                   /* pointer to first buffer */
910                   u32 * buffers,
911                   /* number of buffers to free */
912                   u32 n_buffers)
913 {
914   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 1);
915 }
916
917 /** \brief Free buffers, does not free the buffer chain for each buffer
918
919     @param vm - (vlib_main_t *) vlib main data structure pointer
920     @param buffers - (u32 * ) buffer index array
921     @param n_buffers - (u32) number of buffers to free
922
923 */
924 always_inline void
925 vlib_buffer_free_no_next (vlib_main_t * vm,
926                           /* pointer to first buffer */
927                           u32 * buffers,
928                           /* number of buffers to free */
929                           u32 n_buffers)
930 {
931   vlib_buffer_free_inline (vm, buffers, n_buffers, /* maybe next */ 0);
932 }
933
934 /** \brief Free one buffer
935     Shorthand to free a single buffer chain.
936
937     @param vm - (vlib_main_t *) vlib main data structure pointer
938     @param buffer_index - (u32) buffer index to free
939 */
940 always_inline void
941 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
942 {
943   vlib_buffer_free_inline (vm, &buffer_index, 1, /* maybe next */ 1);
944 }
945
946 /** \brief Free buffers from ring
947
948     @param vm - (vlib_main_t *) vlib main data structure pointer
949     @param buffers - (u32 * ) buffer index ring
950     @param start - (u32) first slot in the ring
951     @param ring_size - (u32) ring size
952     @param n_buffers - (u32) number of buffers
953 */
954 always_inline void
955 vlib_buffer_free_from_ring (vlib_main_t * vm, u32 * ring, u32 start,
956                             u32 ring_size, u32 n_buffers)
957 {
958   ASSERT (n_buffers <= ring_size);
959
960   if (PREDICT_TRUE (start + n_buffers <= ring_size))
961     {
962       vlib_buffer_free (vm, ring + start, n_buffers);
963     }
964   else
965     {
966       vlib_buffer_free (vm, ring + start, ring_size - start);
967       vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
968     }
969 }
970
971 /** \brief Free buffers from ring without freeing tail buffers
972
973     @param vm - (vlib_main_t *) vlib main data structure pointer
974     @param buffers - (u32 * ) buffer index ring
975     @param start - (u32) first slot in the ring
976     @param ring_size - (u32) ring size
977     @param n_buffers - (u32) number of buffers
978 */
979 always_inline void
980 vlib_buffer_free_from_ring_no_next (vlib_main_t * vm, u32 * ring, u32 start,
981                                     u32 ring_size, u32 n_buffers)
982 {
983   ASSERT (n_buffers <= ring_size);
984
985   if (PREDICT_TRUE (start + n_buffers <= ring_size))
986     {
987       vlib_buffer_free_no_next (vm, ring + start, n_buffers);
988     }
989   else
990     {
991       vlib_buffer_free_no_next (vm, ring + start, ring_size - start);
992       vlib_buffer_free_no_next (vm, ring, n_buffers - (ring_size - start));
993     }
994 }
995
996 /* Append given data to end of buffer, possibly allocating new buffers. */
997 int vlib_buffer_add_data (vlib_main_t * vm, u32 * buffer_index, void *data,
998                           u32 n_data_bytes);
999
1000 /* Define vlib_buffer and vnet_buffer flags bits preserved for copy/clone */
1001 #define VLIB_BUFFER_COPY_CLONE_FLAGS_MASK                       \
1002   (VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID |  \
1003    VLIB_BUFFER_IS_TRACED | ~VLIB_BUFFER_FLAGS_ALL)
1004
1005 /* duplicate all buffers in chain */
1006 always_inline vlib_buffer_t *
1007 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
1008 {
1009   vlib_buffer_t *s, *d, *fd;
1010   uword n_alloc, n_buffers = 1;
1011   u32 flag_mask = VLIB_BUFFER_COPY_CLONE_FLAGS_MASK;
1012   int i;
1013
1014   s = b;
1015   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1016     {
1017       n_buffers++;
1018       s = vlib_get_buffer (vm, s->next_buffer);
1019     }
1020   u32 new_buffers[n_buffers];
1021
1022   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
1023
1024   /* No guarantee that we'll get all the buffers we asked for */
1025   if (PREDICT_FALSE (n_alloc < n_buffers))
1026     {
1027       if (n_alloc > 0)
1028         vlib_buffer_free (vm, new_buffers, n_alloc);
1029       return 0;
1030     }
1031
1032   /* 1st segment */
1033   s = b;
1034   fd = d = vlib_get_buffer (vm, new_buffers[0]);
1035   d->current_data = s->current_data;
1036   d->current_length = s->current_length;
1037   d->flags = s->flags & flag_mask;
1038   d->trace_handle = s->trace_handle;
1039   d->total_length_not_including_first_buffer =
1040     s->total_length_not_including_first_buffer;
1041   clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
1042   clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
1043   clib_memcpy_fast (vlib_buffer_get_current (d),
1044                     vlib_buffer_get_current (s), s->current_length);
1045
1046   /* next segments */
1047   for (i = 1; i < n_buffers; i++)
1048     {
1049       /* previous */
1050       d->next_buffer = new_buffers[i];
1051       /* current */
1052       s = vlib_get_buffer (vm, s->next_buffer);
1053       d = vlib_get_buffer (vm, new_buffers[i]);
1054       d->current_data = s->current_data;
1055       d->current_length = s->current_length;
1056       clib_memcpy_fast (vlib_buffer_get_current (d),
1057                         vlib_buffer_get_current (s), s->current_length);
1058       d->flags = s->flags & flag_mask;
1059     }
1060
1061   return fd;
1062 }
1063
1064 /* duplicate first buffer in chain */
1065 always_inline vlib_buffer_t *
1066 vlib_buffer_copy_no_chain (vlib_main_t * vm, vlib_buffer_t * b, u32 * di)
1067 {
1068   vlib_buffer_t *d;
1069
1070   if ((vlib_buffer_alloc (vm, di, 1)) != 1)
1071     return 0;
1072
1073   d = vlib_get_buffer (vm, *di);
1074   /* 1st segment */
1075   d->current_data = b->current_data;
1076   d->current_length = b->current_length;
1077   clib_memcpy_fast (d->opaque, b->opaque, sizeof (b->opaque));
1078   clib_memcpy_fast (d->opaque2, b->opaque2, sizeof (b->opaque2));
1079   clib_memcpy_fast (vlib_buffer_get_current (d),
1080                     vlib_buffer_get_current (b), b->current_length);
1081
1082   return d;
1083 }
1084
1085 /*  \brief Move packet from current position to offset position in buffer.
1086     Only work for small packet using one buffer with room to fit the move
1087     @param vm - (vlib_main_t *) vlib main data structure pointer
1088     @param b -  (vlib_buffer_t *) pointer to buffer
1089     @param offset - (i16) position to move the packet in buffer
1090  */
1091 always_inline void
1092 vlib_buffer_move (vlib_main_t * vm, vlib_buffer_t * b, i16 offset)
1093 {
1094   ASSERT ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
1095   ASSERT (offset + VLIB_BUFFER_PRE_DATA_SIZE >= 0);
1096   ASSERT (offset + b->current_length <
1097           vlib_buffer_get_default_data_size (vm));
1098
1099   u8 *source = vlib_buffer_get_current (b);
1100   b->current_data = offset;
1101   u8 *destination = vlib_buffer_get_current (b);
1102   u16 length = b->current_length;
1103
1104   if (source + length <= destination)   /* no overlap */
1105     clib_memcpy_fast (destination, source, length);
1106   else
1107     memmove (destination, source, length);
1108 }
1109
1110 /** \brief Create a maximum of 256 clones of buffer and store them
1111     in the supplied array
1112
1113     @param vm - (vlib_main_t *) vlib main data structure pointer
1114     @param src_buffer - (u32) source buffer index
1115     @param buffers - (u32 * ) buffer index array
1116     @param n_buffers - (u16) number of buffer clones requested (<=256)
1117     @param head_end_offset - (u16) offset relative to current position
1118            where packet head ends
1119     @param offset - (i16) copy packet head at current position if 0,
1120            else at offset position to change headroom space as specified
1121     @return - (u16) number of buffers actually cloned, may be
1122     less than the number requested or zero
1123 */
1124 always_inline u16
1125 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1126                        u16 n_buffers, u16 head_end_offset, i16 offset)
1127 {
1128   u16 i;
1129   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
1130
1131   ASSERT (s->ref_count == 1);
1132   ASSERT (n_buffers);
1133   ASSERT (n_buffers <= 256);
1134   ASSERT (offset + VLIB_BUFFER_PRE_DATA_SIZE >= 0);
1135   ASSERT ((offset + head_end_offset) <
1136           vlib_buffer_get_default_data_size (vm));
1137
1138   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
1139     {
1140       buffers[0] = src_buffer;
1141       if (offset)
1142         vlib_buffer_move (vm, s, offset);
1143
1144       for (i = 1; i < n_buffers; i++)
1145         {
1146           vlib_buffer_t *d;
1147           d = vlib_buffer_copy (vm, s);
1148           if (d == 0)
1149             return i;
1150           buffers[i] = vlib_get_buffer_index (vm, d);
1151
1152         }
1153       return n_buffers;
1154     }
1155
1156   if (PREDICT_FALSE ((n_buffers == 1) && (offset == 0)))
1157     {
1158       buffers[0] = src_buffer;
1159       return 1;
1160     }
1161
1162   n_buffers = vlib_buffer_alloc_from_pool (vm, buffers, n_buffers,
1163                                            s->buffer_pool_index);
1164
1165   for (i = 0; i < n_buffers; i++)
1166     {
1167       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
1168       if (offset)
1169         d->current_data = offset;
1170       else
1171         d->current_data = s->current_data;
1172
1173       d->current_length = head_end_offset;
1174       ASSERT (d->buffer_pool_index == s->buffer_pool_index);
1175
1176       d->total_length_not_including_first_buffer = s->current_length -
1177         head_end_offset;
1178       if (PREDICT_FALSE (s->flags & VLIB_BUFFER_NEXT_PRESENT))
1179         {
1180           d->total_length_not_including_first_buffer +=
1181             s->total_length_not_including_first_buffer;
1182         }
1183       d->flags = (s->flags & VLIB_BUFFER_COPY_CLONE_FLAGS_MASK) |
1184         VLIB_BUFFER_NEXT_PRESENT;
1185       d->trace_handle = s->trace_handle;
1186       clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
1187       clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
1188       clib_memcpy_fast (vlib_buffer_get_current (d),
1189                         vlib_buffer_get_current (s), head_end_offset);
1190       d->next_buffer = src_buffer;
1191     }
1192   vlib_buffer_advance (s, head_end_offset);
1193   s->ref_count = n_buffers;
1194   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1195     {
1196       s = vlib_get_buffer (vm, s->next_buffer);
1197       s->ref_count = n_buffers;
1198     }
1199
1200   return n_buffers;
1201 }
1202
1203 /** \brief Create multiple clones of buffer and store them
1204     in the supplied array
1205
1206     @param vm - (vlib_main_t *) vlib main data structure pointer
1207     @param src_buffer - (u32) source buffer index
1208     @param buffers - (u32 * ) buffer index array
1209     @param n_buffers - (u16) number of buffer clones requested (<=256)
1210     @param head_end_offset - (u16) offset relative to current position
1211            where packet head ends
1212     @param offset - (i16) copy packet head at current position if 0,
1213            else at offset position to change headroom space as specified
1214     @return - (u16) number of buffers actually cloned, may be
1215     less than the number requested or zero
1216 */
1217 always_inline u16
1218 vlib_buffer_clone_at_offset (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1219                              u16 n_buffers, u16 head_end_offset, i16 offset)
1220 {
1221   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
1222   u16 n_cloned = 0;
1223
1224   while (n_buffers > 256)
1225     {
1226       vlib_buffer_t *copy;
1227       copy = vlib_buffer_copy (vm, s);
1228       n_cloned += vlib_buffer_clone_256 (vm,
1229                                          vlib_get_buffer_index (vm, copy),
1230                                          (buffers + n_cloned),
1231                                          256, head_end_offset, offset);
1232       n_buffers -= 256;
1233     }
1234   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
1235                                      buffers + n_cloned,
1236                                      n_buffers, head_end_offset, offset);
1237
1238   return n_cloned;
1239 }
1240
1241 /** \brief Create multiple clones of buffer and store them
1242     in the supplied array
1243
1244     @param vm - (vlib_main_t *) vlib main data structure pointer
1245     @param src_buffer - (u32) source buffer index
1246     @param buffers - (u32 * ) buffer index array
1247     @param n_buffers - (u16) number of buffer clones requested (<=256)
1248     @param head_end_offset - (u16) offset relative to current position
1249            where packet head ends
1250     @return - (u16) number of buffers actually cloned, may be
1251     less than the number requested or zero
1252 */
1253 always_inline u16
1254 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
1255                    u16 n_buffers, u16 head_end_offset)
1256 {
1257   return vlib_buffer_clone_at_offset (vm, src_buffer, buffers, n_buffers,
1258                                       head_end_offset, 0);
1259 }
1260
1261 /** \brief Attach cloned tail to the buffer
1262
1263     @param vm - (vlib_main_t *) vlib main data structure pointer
1264     @param head - (vlib_buffer_t *) head buffer
1265     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
1266 */
1267
1268 always_inline void
1269 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
1270                           vlib_buffer_t * tail)
1271 {
1272   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
1273   ASSERT (head->buffer_pool_index == tail->buffer_pool_index);
1274
1275   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
1276   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1277   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
1278   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
1279   head->next_buffer = vlib_get_buffer_index (vm, tail);
1280   head->total_length_not_including_first_buffer = tail->current_length +
1281     tail->total_length_not_including_first_buffer;
1282
1283 next_segment:
1284   clib_atomic_add_fetch (&tail->ref_count, 1);
1285
1286   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
1287     {
1288       tail = vlib_get_buffer (vm, tail->next_buffer);
1289       goto next_segment;
1290     }
1291 }
1292
1293 /* Initializes the buffer as an empty packet with no chained buffers. */
1294 always_inline void
1295 vlib_buffer_chain_init (vlib_buffer_t * first)
1296 {
1297   first->total_length_not_including_first_buffer = 0;
1298   first->current_length = 0;
1299   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1300   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
1301 }
1302
1303 /* The provided next_bi buffer index is appended to the end of the packet. */
1304 always_inline vlib_buffer_t *
1305 vlib_buffer_chain_buffer (vlib_main_t * vm, vlib_buffer_t * last, u32 next_bi)
1306 {
1307   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
1308   last->next_buffer = next_bi;
1309   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
1310   next_buffer->current_length = 0;
1311   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1312   return next_buffer;
1313 }
1314
1315 /* Increases or decreases the packet length.
1316  * It does not allocate or deallocate new buffers.
1317  * Therefore, the added length must be compatible
1318  * with the last buffer. */
1319 always_inline void
1320 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
1321                                    vlib_buffer_t * last, i32 len)
1322 {
1323   last->current_length += len;
1324   if (first != last)
1325     first->total_length_not_including_first_buffer += len;
1326 }
1327
1328 /* Copy data to the end of the packet and increases its length.
1329  * It does not allocate new buffers.
1330  * Returns the number of copied bytes. */
1331 always_inline u16
1332 vlib_buffer_chain_append_data (vlib_main_t * vm,
1333                                vlib_buffer_t * first,
1334                                vlib_buffer_t * last, void *data, u16 data_len)
1335 {
1336   u32 n_buffer_bytes = vlib_buffer_get_default_data_size (vm);
1337   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
1338   u16 len = clib_min (data_len,
1339                       n_buffer_bytes - last->current_length -
1340                       last->current_data);
1341   clib_memcpy_fast (vlib_buffer_get_current (last) + last->current_length,
1342                     data, len);
1343   vlib_buffer_chain_increase_length (first, last, len);
1344   return len;
1345 }
1346
1347 /* Copy data to the end of the packet and increases its length.
1348  * Allocates additional buffers from the free list if necessary.
1349  * Returns the number of copied bytes.
1350  * 'last' value is modified whenever new buffers are allocated and
1351  * chained and points to the last buffer in the chain. */
1352 u16
1353 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
1354                                           vlib_buffer_t * first,
1355                                           vlib_buffer_t ** last, void *data,
1356                                           u16 data_len);
1357 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
1358
1359 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
1360   format_vlib_buffer_contents, format_vlib_buffer_no_chain;
1361
1362 typedef struct
1363 {
1364   /* Vector of packet data. */
1365   u8 *packet_data;
1366
1367   /* Number of buffers to allocate in each call to allocator. */
1368   u32 min_n_buffers_each_alloc;
1369
1370   u8 *name;
1371 } vlib_packet_template_t;
1372
1373 void vlib_packet_template_init (vlib_main_t * vm,
1374                                 vlib_packet_template_t * t,
1375                                 void *packet_data,
1376                                 uword n_packet_data_bytes,
1377                                 uword min_n_buffers_each_alloc,
1378                                 char *fmt, ...);
1379
1380 void *vlib_packet_template_get_packet (vlib_main_t * vm,
1381                                        vlib_packet_template_t * t,
1382                                        u32 * bi_result);
1383
1384 always_inline void
1385 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
1386 {
1387   vec_free (t->packet_data);
1388 }
1389
1390 always_inline u32
1391 vlib_buffer_space_left_at_end (vlib_main_t * vm, vlib_buffer_t * b)
1392 {
1393   return b->data + vlib_buffer_get_default_data_size (vm) -
1394     ((u8 *) vlib_buffer_get_current (b) + b->current_length);
1395 }
1396
1397 always_inline u32
1398 vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * b)
1399 {
1400   vlib_buffer_t *db = b, *sb, *first = b;
1401   int is_cloned = 0;
1402   u32 bytes_left = 0, data_size;
1403   u16 src_left, dst_left, n_buffers = 1;
1404   u8 *dp, *sp;
1405   u32 to_free = 0;
1406
1407   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
1408     return 1;
1409
1410   data_size = vlib_buffer_get_default_data_size (vm);
1411
1412   dst_left = vlib_buffer_space_left_at_end (vm, b);
1413
1414   while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1415     {
1416       b = vlib_get_buffer (vm, b->next_buffer);
1417       if (b->ref_count > 1)
1418         is_cloned = 1;
1419       bytes_left += b->current_length;
1420       n_buffers++;
1421     }
1422
1423   /* if buffer is cloned, create completely new chain - unless everything fits
1424    * into one buffer */
1425   if (is_cloned && bytes_left >= dst_left)
1426     {
1427       u32 len = 0;
1428       u32 space_needed = bytes_left - dst_left;
1429       u32 tail;
1430
1431       if (vlib_buffer_alloc (vm, &tail, 1) == 0)
1432         return 0;
1433
1434       ++n_buffers;
1435       len += data_size;
1436       b = vlib_get_buffer (vm, tail);
1437
1438       while (len < space_needed)
1439         {
1440           u32 bi;
1441           if (vlib_buffer_alloc (vm, &bi, 1) == 0)
1442             {
1443               vlib_buffer_free_one (vm, tail);
1444               return 0;
1445             }
1446           b->flags = VLIB_BUFFER_NEXT_PRESENT;
1447           b->next_buffer = bi;
1448           b = vlib_get_buffer (vm, bi);
1449           len += data_size;
1450           n_buffers++;
1451         }
1452       sb = vlib_get_buffer (vm, first->next_buffer);
1453       to_free = first->next_buffer;
1454       first->next_buffer = tail;
1455     }
1456   else
1457     sb = vlib_get_buffer (vm, first->next_buffer);
1458
1459   src_left = sb->current_length;
1460   sp = vlib_buffer_get_current (sb);
1461   dp = vlib_buffer_get_tail (db);
1462
1463   while (bytes_left)
1464     {
1465       u16 bytes_to_copy;
1466
1467       if (dst_left == 0)
1468         {
1469           db->current_length = dp - (u8 *) vlib_buffer_get_current (db);
1470           ASSERT (db->flags & VLIB_BUFFER_NEXT_PRESENT);
1471           db = vlib_get_buffer (vm, db->next_buffer);
1472           dst_left = data_size;
1473           if (db->current_data > 0)
1474             {
1475               db->current_data = 0;
1476             }
1477           else
1478             {
1479               dst_left += -db->current_data;
1480             }
1481           dp = vlib_buffer_get_current (db);
1482         }
1483
1484       while (src_left == 0)
1485         {
1486           ASSERT (sb->flags & VLIB_BUFFER_NEXT_PRESENT);
1487           sb = vlib_get_buffer (vm, sb->next_buffer);
1488           src_left = sb->current_length;
1489           sp = vlib_buffer_get_current (sb);
1490         }
1491
1492       bytes_to_copy = clib_min (dst_left, src_left);
1493
1494       if (dp != sp)
1495         {
1496           if (sb == db)
1497             bytes_to_copy = clib_min (bytes_to_copy, sp - dp);
1498
1499           clib_memcpy_fast (dp, sp, bytes_to_copy);
1500         }
1501
1502       src_left -= bytes_to_copy;
1503       dst_left -= bytes_to_copy;
1504       dp += bytes_to_copy;
1505       sp += bytes_to_copy;
1506       bytes_left -= bytes_to_copy;
1507     }
1508   if (db != first)
1509     db->current_data = 0;
1510   db->current_length = dp - (u8 *) vlib_buffer_get_current (db);
1511
1512   if (is_cloned && to_free)
1513     vlib_buffer_free_one (vm, to_free);
1514   else
1515     {
1516       if (db->flags & VLIB_BUFFER_NEXT_PRESENT)
1517         vlib_buffer_free_one (vm, db->next_buffer);
1518       db->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1519       b = first;
1520       n_buffers = 1;
1521       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
1522         {
1523           b = vlib_get_buffer (vm, b->next_buffer);
1524           ++n_buffers;
1525         }
1526     }
1527
1528   first->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1529
1530   return n_buffers;
1531 }
1532
1533 #endif /* included_vlib_buffer_funcs_h */
1534
1535 /*
1536  * fd.io coding-style-patch-verification: ON
1537  *
1538  * Local Variables:
1539  * eval: (c-set-style "gnu")
1540  * End:
1541  */