buffers: fix vector types
[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
46 /** \file
47     vlib buffer access methods.
48 */
49
50
51 /** \brief Translate buffer index into buffer pointer
52
53     @param vm - (vlib_main_t *) vlib main data structure pointer
54     @param buffer_index - (u32) buffer index
55     @return - (vlib_buffer_t *) buffer pointer
56 */
57 always_inline vlib_buffer_t *
58 vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
59 {
60   vlib_buffer_main_t *bm = vm->buffer_main;
61   uword offset = ((uword) buffer_index) << CLIB_LOG2_CACHE_LINE_BYTES;
62   ASSERT (offset < bm->buffer_mem_size);
63
64   return uword_to_pointer (bm->buffer_mem_start + offset, void *);
65 }
66
67 static_always_inline void
68 vlib_buffer_copy_indices (u32 * dst, u32 * src, u32 n_indices)
69 {
70   clib_memcpy_fast (dst, src, n_indices * sizeof (u32));
71 }
72
73 STATIC_ASSERT_OFFSET_OF (vlib_buffer_t, template_end, 64);
74 static_always_inline void
75 vlib_buffer_copy_template (vlib_buffer_t * b, vlib_buffer_t * bt)
76 {
77 #if defined CLIB_HAVE_VEC512
78   b->as_u8x64[0] = bt->as_u8x64[0];
79 #elif defined (CLIB_HAVE_VEC256)
80   b->as_u8x32[0] = bt->as_u8x32[0];
81   b->as_u8x32[1] = bt->as_u8x32[1];
82 #elif defined (CLIB_HAVE_VEC128)
83   b->as_u8x16[0] = bt->as_u8x16[0];
84   b->as_u8x16[1] = bt->as_u8x16[1];
85   b->as_u8x16[2] = bt->as_u8x16[2];
86   b->as_u8x16[3] = bt->as_u8x16[3];
87 #else
88   clib_memcpy_fast (b, bt, 64);
89 #endif
90 }
91
92 /** \brief Translate array of buffer indices into buffer pointers with offset
93
94     @param vm - (vlib_main_t *) vlib main data structure pointer
95     @param bi - (u32 *) array of buffer indices
96     @param b - (void **) array to store buffer pointers
97     @param count - (uword) number of elements
98     @param offset - (i32) offset applied to each pointer
99 */
100 static_always_inline void
101 vlib_get_buffers_with_offset (vlib_main_t * vm, u32 * bi, void **b, int count,
102                               i32 offset)
103 {
104   uword buffer_mem_start = vm->buffer_main->buffer_mem_start;
105 #ifdef CLIB_HAVE_VEC256
106   u64x4 off = u64x4_splat (buffer_mem_start + offset);
107   /* if count is not const, compiler will not unroll while loop
108      se we maintain two-in-parallel variant */
109   while (count >= 8)
110     {
111       u64x4 b0 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi));
112       u64x4 b1 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi + 4));
113       /* shift and add to get vlib_buffer_t pointer */
114       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
115       u64x4_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 4);
116       b += 8;
117       bi += 8;
118       count -= 8;
119     }
120 #endif
121   while (count >= 4)
122     {
123 #ifdef CLIB_HAVE_VEC256
124       u64x4 b0 = u32x4_extend_to_u64x4 (u32x4_load_unaligned (bi));
125       /* shift and add to get vlib_buffer_t pointer */
126       u64x4_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
127 #elif defined (CLIB_HAVE_VEC128)
128       u64x2 off = u64x2_splat (buffer_mem_start + offset);
129       u32x4 bi4 = u32x4_load_unaligned (bi);
130       u64x2 b0 = u32x4_extend_to_u64x2 ((u32x4) bi4);
131 #if defined (__aarch64__)
132       u64x2 b1 = u32x4_extend_to_u64x2_high ((u32x4) bi4);
133 #else
134       bi4 = u32x4_shuffle (bi4, 2, 3, 0, 1);
135       u64x2 b1 = u32x4_extend_to_u64x2 ((u32x4) bi4);
136 #endif
137       u64x2_store_unaligned ((b0 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b);
138       u64x2_store_unaligned ((b1 << CLIB_LOG2_CACHE_LINE_BYTES) + off, b + 2);
139 #else
140       b[0] = ((u8 *) vlib_get_buffer (vm, bi[0])) + offset;
141       b[1] = ((u8 *) vlib_get_buffer (vm, bi[1])) + offset;
142       b[2] = ((u8 *) vlib_get_buffer (vm, bi[2])) + offset;
143       b[3] = ((u8 *) vlib_get_buffer (vm, bi[3])) + offset;
144 #endif
145       b += 4;
146       bi += 4;
147       count -= 4;
148     }
149   while (count)
150     {
151       b[0] = ((u8 *) vlib_get_buffer (vm, bi[0])) + offset;
152       b += 1;
153       bi += 1;
154       count -= 1;
155     }
156 }
157
158 /** \brief Translate array of buffer indices into buffer pointers
159
160     @param vm - (vlib_main_t *) vlib main data structure pointer
161     @param bi - (u32 *) array of buffer indices
162     @param b - (vlib_buffer_t **) array to store buffer pointers
163     @param count - (uword) number of elements
164 */
165
166 static_always_inline void
167 vlib_get_buffers (vlib_main_t * vm, u32 * bi, vlib_buffer_t ** b, int count)
168 {
169   vlib_get_buffers_with_offset (vm, bi, (void **) b, count, 0);
170 }
171
172 /** \brief Translate buffer pointer into buffer index
173
174     @param vm - (vlib_main_t *) vlib main data structure pointer
175     @param p - (void *) buffer pointer
176     @return - (u32) buffer index
177 */
178
179 always_inline u32
180 vlib_get_buffer_index (vlib_main_t * vm, void *p)
181 {
182   vlib_buffer_main_t *bm = vm->buffer_main;
183   uword offset = pointer_to_uword (p) - bm->buffer_mem_start;
184   ASSERT (pointer_to_uword (p) >= bm->buffer_mem_start);
185   ASSERT (offset < bm->buffer_mem_size);
186   ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
187   return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
188 }
189
190 /** \brief Translate array of buffer pointers into buffer indices with offset
191
192     @param vm - (vlib_main_t *) vlib main data structure pointer
193     @param b - (void **) array of buffer pointers
194     @param bi - (u32 *) array to store buffer indices
195     @param count - (uword) number of elements
196     @param offset - (i32) offset applied to each pointer
197 */
198 static_always_inline void
199 vlib_get_buffer_indices_with_offset (vlib_main_t * vm, void **b, u32 * bi,
200                                      uword count, i32 offset)
201 {
202 #ifdef CLIB_HAVE_VEC256
203   u32x8 mask = { 0, 2, 4, 6, 1, 3, 5, 7 };
204   u64x4 off4 = u64x4_splat (vm->buffer_main->buffer_mem_start - offset);
205
206   while (count >= 8)
207     {
208       /* load 4 pointers into 256-bit register */
209       u64x4 v0 = u64x4_load_unaligned (b);
210       u64x4 v1 = u64x4_load_unaligned (b + 4);
211       u32x8 v2, v3;
212
213       v0 -= off4;
214       v1 -= off4;
215
216       v0 >>= CLIB_LOG2_CACHE_LINE_BYTES;
217       v1 >>= CLIB_LOG2_CACHE_LINE_BYTES;
218
219       /* permute 256-bit register so lower u32s of each buffer index are
220        * placed into lower 128-bits */
221       v2 = u32x8_permute ((u32x8) v0, mask);
222       v3 = u32x8_permute ((u32x8) v1, mask);
223
224       /* extract lower 128-bits and save them to the array of buffer indices */
225       u32x4_store_unaligned (u32x8_extract_lo (v2), bi);
226       u32x4_store_unaligned (u32x8_extract_lo (v3), bi + 4);
227       bi += 8;
228       b += 8;
229       count -= 8;
230     }
231 #endif
232   while (count >= 4)
233     {
234       /* equivalent non-nector implementation */
235       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
236       bi[1] = vlib_get_buffer_index (vm, ((u8 *) b[1]) + offset);
237       bi[2] = vlib_get_buffer_index (vm, ((u8 *) b[2]) + offset);
238       bi[3] = vlib_get_buffer_index (vm, ((u8 *) b[3]) + offset);
239       bi += 4;
240       b += 4;
241       count -= 4;
242     }
243   while (count)
244     {
245       bi[0] = vlib_get_buffer_index (vm, ((u8 *) b[0]) + offset);
246       bi += 1;
247       b += 1;
248       count -= 1;
249     }
250 }
251
252 /** \brief Translate array of buffer pointers into buffer indices
253
254     @param vm - (vlib_main_t *) vlib main data structure pointer
255     @param b - (vlib_buffer_t **) array of buffer pointers
256     @param bi - (u32 *) array to store buffer indices
257     @param count - (uword) number of elements
258 */
259 static_always_inline void
260 vlib_get_buffer_indices (vlib_main_t * vm, vlib_buffer_t ** b, u32 * bi,
261                          uword count)
262 {
263   vlib_get_buffer_indices_with_offset (vm, (void **) b, bi, count, 0);
264 }
265
266 /** \brief Get next buffer in buffer linklist, or zero for end of list.
267
268     @param vm - (vlib_main_t *) vlib main data structure pointer
269     @param b - (void *) buffer pointer
270     @return - (vlib_buffer_t *) next buffer, or NULL
271 */
272 always_inline vlib_buffer_t *
273 vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
274 {
275   return (b->flags & VLIB_BUFFER_NEXT_PRESENT
276           ? vlib_get_buffer (vm, b->next_buffer) : 0);
277 }
278
279 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
280                                              vlib_buffer_t * b_first);
281
282 /** \brief Get length in bytes of the buffer chain
283
284     @param vm - (vlib_main_t *) vlib main data structure pointer
285     @param b - (void *) buffer pointer
286     @return - (uword) length of buffer chain
287 */
288 always_inline uword
289 vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
290 {
291   uword len = b->current_length;
292
293   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
294     return len;
295
296   if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
297     return len + b->total_length_not_including_first_buffer;
298
299   return vlib_buffer_length_in_chain_slow_path (vm, b);
300 }
301
302 /** \brief Get length in bytes of the buffer index buffer chain
303
304     @param vm - (vlib_main_t *) vlib main data structure pointer
305     @param bi - (u32) buffer index
306     @return - (uword) length of buffer chain
307 */
308 always_inline uword
309 vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
310 {
311   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
312   return vlib_buffer_length_in_chain (vm, b);
313 }
314
315 /** \brief Copy buffer contents to memory
316
317     @param vm - (vlib_main_t *) vlib main data structure pointer
318     @param buffer_index - (u32) buffer index
319     @param contents - (u8 *) memory, <strong>must be large enough</strong>
320     @return - (uword) length of buffer chain
321 */
322 always_inline uword
323 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
324 {
325   uword content_len = 0;
326   uword l;
327   vlib_buffer_t *b;
328
329   while (1)
330     {
331       b = vlib_get_buffer (vm, buffer_index);
332       l = b->current_length;
333       clib_memcpy_fast (contents + content_len, b->data + b->current_data, l);
334       content_len += l;
335       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
336         break;
337       buffer_index = b->next_buffer;
338     }
339
340   return content_len;
341 }
342
343 always_inline uword
344 vlib_buffer_get_pa (vlib_main_t * vm, vlib_buffer_t * b)
345 {
346   return vlib_physmem_get_pa (vm, b->data);
347 }
348
349 always_inline uword
350 vlib_buffer_get_current_pa (vlib_main_t * vm, vlib_buffer_t * b)
351 {
352   return vlib_buffer_get_pa (vm, b) + b->current_data;
353 }
354
355 /** \brief Prefetch buffer metadata by buffer index
356     The first 64 bytes of buffer contains most header information
357
358     @param vm - (vlib_main_t *) vlib main data structure pointer
359     @param bi - (u32) buffer index
360     @param type - LOAD, STORE. In most cases, STORE is the right answer
361 */
362 /* Prefetch buffer header given index. */
363 #define vlib_prefetch_buffer_with_index(vm,bi,type)     \
364   do {                                                  \
365     vlib_buffer_t * _b = vlib_get_buffer (vm, bi);      \
366     vlib_prefetch_buffer_header (_b, type);             \
367   } while (0)
368
369 typedef enum
370 {
371   /* Index is unknown. */
372   VLIB_BUFFER_UNKNOWN,
373
374   /* Index is known and free/allocated. */
375   VLIB_BUFFER_KNOWN_FREE,
376   VLIB_BUFFER_KNOWN_ALLOCATED,
377 } vlib_buffer_known_state_t;
378
379 void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
380                                       uword n_buffers,
381                                       vlib_buffer_known_state_t
382                                       expected_state);
383
384 always_inline vlib_buffer_known_state_t
385 vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
386 {
387   vlib_buffer_main_t *bm = vm->buffer_main;
388
389   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
390   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
391   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
392   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
393 }
394
395 always_inline void
396 vlib_buffer_set_known_state (vlib_main_t * vm, u32 buffer_index,
397                              vlib_buffer_known_state_t state)
398 {
399   vlib_buffer_main_t *bm = vm->buffer_main;
400
401   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
402   hash_set (bm->buffer_known_hash, buffer_index, state);
403   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
404 }
405
406 /* Validates sanity of a single buffer.
407    Returns format'ed vector with error message if any. */
408 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
409                           uword follow_chain);
410
411 always_inline u32
412 vlib_buffer_round_size (u32 size)
413 {
414   return round_pow2 (size, sizeof (vlib_buffer_t));
415 }
416
417 /** \brief Allocate buffers from specific freelist into supplied array
418
419     @param vm - (vlib_main_t *) vlib main data structure pointer
420     @param buffers - (u32 * ) buffer index array
421     @param n_buffers - (u32) number of buffers requested
422     @return - (u32) number of buffers actually allocated, may be
423     less than the number requested or zero
424 */
425 always_inline u32
426 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
427                                   u32 * buffers,
428                                   u32 n_buffers,
429                                   vlib_buffer_free_list_index_t index)
430 {
431   vlib_buffer_free_list_t *fl;
432   vlib_buffer_main_t *bm = vm->buffer_main;
433   u32 *src;
434   uword len;
435
436   ASSERT (bm->cb.vlib_buffer_fill_free_list_cb);
437
438   fl = pool_elt_at_index (vm->buffer_free_list_pool, index);
439
440   len = vec_len (fl->buffers);
441
442   if (PREDICT_FALSE (len < n_buffers))
443     {
444       bm->cb.vlib_buffer_fill_free_list_cb (vm, fl, n_buffers);
445       if (PREDICT_FALSE ((len = vec_len (fl->buffers)) == 0))
446         return 0;
447
448       /* even if fill free list didn't manage to refill free list
449          we should give what we have */
450       n_buffers = clib_min (len, n_buffers);
451
452       /* following code is intentionaly duplicated to allow compiler
453          to optimize fast path when n_buffers is constant value */
454       src = fl->buffers + len - n_buffers;
455       vlib_buffer_copy_indices (buffers, src, n_buffers);
456       _vec_len (fl->buffers) -= n_buffers;
457
458       /* Verify that buffers are known free. */
459       vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
460                                        VLIB_BUFFER_KNOWN_FREE);
461
462       return n_buffers;
463     }
464
465   src = fl->buffers + len - n_buffers;
466   vlib_buffer_copy_indices (buffers, src, n_buffers);
467   _vec_len (fl->buffers) -= n_buffers;
468
469   /* Verify that buffers are known free. */
470   vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
471                                    VLIB_BUFFER_KNOWN_FREE);
472
473   return n_buffers;
474 }
475
476 /** \brief Allocate buffers into supplied array
477
478     @param vm - (vlib_main_t *) vlib main data structure pointer
479     @param buffers - (u32 * ) buffer index array
480     @param n_buffers - (u32) number of buffers requested
481     @return - (u32) number of buffers actually allocated, may be
482     less than the number requested or zero
483 */
484 always_inline u32
485 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
486 {
487   return vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
488                                            VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
489 }
490
491 /** \brief Allocate buffers into ring
492
493     @param vm - (vlib_main_t *) vlib main data structure pointer
494     @param buffers - (u32 * ) buffer index ring
495     @param start - (u32) first slot in the ring
496     @param ring_size - (u32) ring size
497     @param n_buffers - (u32) number of buffers requested
498     @return - (u32) number of buffers actually allocated, may be
499     less than the number requested or zero
500 */
501 always_inline u32
502 vlib_buffer_alloc_to_ring (vlib_main_t * vm, u32 * ring, u32 start,
503                            u32 ring_size, u32 n_buffers)
504 {
505   u32 n_alloc;
506
507   ASSERT (n_buffers <= ring_size);
508
509   if (PREDICT_TRUE (start + n_buffers <= ring_size))
510     return vlib_buffer_alloc (vm, ring + start, n_buffers);
511
512   n_alloc = vlib_buffer_alloc (vm, ring + start, ring_size - start);
513
514   if (PREDICT_TRUE (n_alloc == ring_size - start))
515     n_alloc += vlib_buffer_alloc (vm, ring, n_buffers - n_alloc);
516
517   return n_alloc;
518 }
519
520 /** \brief Free buffers
521     Frees the entire buffer chain for each buffer
522
523     @param vm - (vlib_main_t *) vlib main data structure pointer
524     @param buffers - (u32 * ) buffer index array
525     @param n_buffers - (u32) number of buffers to free
526
527 */
528 always_inline void
529 vlib_buffer_free (vlib_main_t * vm,
530                   /* pointer to first buffer */
531                   u32 * buffers,
532                   /* number of buffers to free */
533                   u32 n_buffers)
534 {
535   vlib_buffer_main_t *bm = vm->buffer_main;
536
537   ASSERT (bm->cb.vlib_buffer_free_cb);
538
539   return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
540 }
541
542 /** \brief Free buffers, does not free the buffer chain for each buffer
543
544     @param vm - (vlib_main_t *) vlib main data structure pointer
545     @param buffers - (u32 * ) buffer index array
546     @param n_buffers - (u32) number of buffers to free
547
548 */
549 always_inline void
550 vlib_buffer_free_no_next (vlib_main_t * vm,
551                           /* pointer to first buffer */
552                           u32 * buffers,
553                           /* number of buffers to free */
554                           u32 n_buffers)
555 {
556   vlib_buffer_main_t *bm = vm->buffer_main;
557
558   ASSERT (bm->cb.vlib_buffer_free_no_next_cb);
559
560   return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
561 }
562
563 /** \brief Free one buffer
564     Shorthand to free a single buffer chain.
565
566     @param vm - (vlib_main_t *) vlib main data structure pointer
567     @param buffer_index - (u32) buffer index to free
568 */
569 always_inline void
570 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
571 {
572   vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
573 }
574
575 /** \brief Free buffers from ring
576
577     @param vm - (vlib_main_t *) vlib main data structure pointer
578     @param buffers - (u32 * ) buffer index ring
579     @param start - (u32) first slot in the ring
580     @param ring_size - (u32) ring size
581     @param n_buffers - (u32) number of buffers
582 */
583 always_inline void
584 vlib_buffer_free_from_ring (vlib_main_t * vm, u32 * ring, u32 start,
585                             u32 ring_size, u32 n_buffers)
586 {
587   ASSERT (n_buffers <= ring_size);
588
589   if (PREDICT_TRUE (start + n_buffers <= ring_size))
590     {
591       vlib_buffer_free (vm, ring + start, n_buffers);
592     }
593   else
594     {
595       vlib_buffer_free (vm, ring + start, ring_size - start);
596       vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
597     }
598 }
599
600 /** \brief Free buffers from ring without freeing tail buffers
601
602     @param vm - (vlib_main_t *) vlib main data structure pointer
603     @param buffers - (u32 * ) buffer index ring
604     @param start - (u32) first slot in the ring
605     @param ring_size - (u32) ring size
606     @param n_buffers - (u32) number of buffers
607 */
608 always_inline void
609 vlib_buffer_free_from_ring_no_next (vlib_main_t * vm, u32 * ring, u32 start,
610                                     u32 ring_size, u32 n_buffers)
611 {
612   ASSERT (n_buffers <= ring_size);
613
614   if (PREDICT_TRUE (start + n_buffers <= ring_size))
615     {
616       vlib_buffer_free_no_next (vm, ring + start, n_buffers);
617     }
618   else
619     {
620       vlib_buffer_free_no_next (vm, ring + start, ring_size - start);
621       vlib_buffer_free_no_next (vm, ring, n_buffers - (ring_size - start));
622     }
623 }
624
625 /* Add/delete buffer free lists. */
626 vlib_buffer_free_list_index_t vlib_buffer_create_free_list (vlib_main_t * vm,
627                                                             u32 n_data_bytes,
628                                                             char *fmt, ...);
629
630 /* Append given data to end of buffer, possibly allocating new buffers. */
631 int vlib_buffer_add_data (vlib_main_t * vm, u32 * buffer_index, void *data,
632                           u32 n_data_bytes);
633
634 /* duplicate all buffers in chain */
635 always_inline vlib_buffer_t *
636 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
637 {
638   vlib_buffer_t *s, *d, *fd;
639   uword n_alloc, n_buffers = 1;
640   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
641   int i;
642
643   s = b;
644   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
645     {
646       n_buffers++;
647       s = vlib_get_buffer (vm, s->next_buffer);
648     }
649   u32 new_buffers[n_buffers];
650
651   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
652
653   /* No guarantee that we'll get all the buffers we asked for */
654   if (PREDICT_FALSE (n_alloc < n_buffers))
655     {
656       if (n_alloc > 0)
657         vlib_buffer_free (vm, new_buffers, n_alloc);
658       return 0;
659     }
660
661   /* 1st segment */
662   s = b;
663   fd = d = vlib_get_buffer (vm, new_buffers[0]);
664   d->current_data = s->current_data;
665   d->current_length = s->current_length;
666   d->flags = s->flags & flag_mask;
667   d->total_length_not_including_first_buffer =
668     s->total_length_not_including_first_buffer;
669   clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
670   clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
671   clib_memcpy_fast (vlib_buffer_get_current (d),
672                     vlib_buffer_get_current (s), s->current_length);
673
674   /* next segments */
675   for (i = 1; i < n_buffers; i++)
676     {
677       /* previous */
678       d->next_buffer = new_buffers[i];
679       /* current */
680       s = vlib_get_buffer (vm, s->next_buffer);
681       d = vlib_get_buffer (vm, new_buffers[i]);
682       d->current_data = s->current_data;
683       d->current_length = s->current_length;
684       clib_memcpy_fast (vlib_buffer_get_current (d),
685                         vlib_buffer_get_current (s), s->current_length);
686       d->flags = s->flags & flag_mask;
687     }
688
689   return fd;
690 }
691
692 /** \brief Create a maximum of 256 clones of buffer and store them
693     in the supplied array
694
695     @param vm - (vlib_main_t *) vlib main data structure pointer
696     @param src_buffer - (u32) source buffer index
697     @param buffers - (u32 * ) buffer index array
698     @param n_buffers - (u16) number of buffer clones requested (<=256)
699     @param head_end_offset - (u16) offset relative to current position
700            where packet head ends
701     @return - (u16) number of buffers actually cloned, may be
702     less than the number requested or zero
703 */
704 always_inline u16
705 vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
706                        u16 n_buffers, u16 head_end_offset)
707 {
708   u16 i;
709   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
710
711   ASSERT (s->n_add_refs == 0);
712   ASSERT (n_buffers);
713   ASSERT (n_buffers <= 256);
714
715   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
716     {
717       buffers[0] = src_buffer;
718       for (i = 1; i < n_buffers; i++)
719         {
720           vlib_buffer_t *d;
721           d = vlib_buffer_copy (vm, s);
722           if (d == 0)
723             return i;
724           buffers[i] = vlib_get_buffer_index (vm, d);
725
726         }
727       return n_buffers;
728     }
729
730   if (PREDICT_FALSE (n_buffers == 1))
731     {
732       buffers[0] = src_buffer;
733       return 1;
734     }
735
736   n_buffers = vlib_buffer_alloc (vm, buffers, n_buffers);
737
738   for (i = 0; i < n_buffers; i++)
739     {
740       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
741       d->current_data = s->current_data;
742       d->current_length = head_end_offset;
743       d->total_length_not_including_first_buffer = s->current_length -
744         head_end_offset;
745       if (PREDICT_FALSE (s->flags & VLIB_BUFFER_NEXT_PRESENT))
746         {
747           d->total_length_not_including_first_buffer +=
748             s->total_length_not_including_first_buffer;
749         }
750       d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
751       d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
752       clib_memcpy_fast (d->opaque, s->opaque, sizeof (s->opaque));
753       clib_memcpy_fast (d->opaque2, s->opaque2, sizeof (s->opaque2));
754       clib_memcpy_fast (vlib_buffer_get_current (d),
755                         vlib_buffer_get_current (s), head_end_offset);
756       d->next_buffer = src_buffer;
757     }
758   vlib_buffer_advance (s, head_end_offset);
759   s->n_add_refs = n_buffers - 1;
760   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
761     {
762       s = vlib_get_buffer (vm, s->next_buffer);
763       s->n_add_refs = n_buffers - 1;
764     }
765
766   return n_buffers;
767 }
768
769 /** \brief Create multiple clones of buffer and store them
770     in the supplied array
771
772     @param vm - (vlib_main_t *) vlib main data structure pointer
773     @param src_buffer - (u32) source buffer index
774     @param buffers - (u32 * ) buffer index array
775     @param n_buffers - (u16) number of buffer clones requested (<=256)
776     @param head_end_offset - (u16) offset relative to current position
777            where packet head ends
778     @return - (u16) number of buffers actually cloned, may be
779     less than the number requested or zero
780 */
781 always_inline u16
782 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
783                    u16 n_buffers, u16 head_end_offset)
784 {
785   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
786   u16 n_cloned = 0;
787
788   while (n_buffers > 256)
789     {
790       vlib_buffer_t *copy;
791       copy = vlib_buffer_copy (vm, s);
792       n_cloned += vlib_buffer_clone_256 (vm,
793                                          vlib_get_buffer_index (vm, copy),
794                                          (buffers + n_cloned),
795                                          256, head_end_offset);
796       n_buffers -= 256;
797     }
798   n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
799                                      buffers + n_cloned,
800                                      n_buffers, head_end_offset);
801
802   return n_cloned;
803 }
804
805 /** \brief Attach cloned tail to the buffer
806
807     @param vm - (vlib_main_t *) vlib main data structure pointer
808     @param head - (vlib_buffer_t *) head buffer
809     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
810 */
811
812 always_inline void
813 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
814                           vlib_buffer_t * tail)
815 {
816   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
817
818   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
819   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
820   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
821   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
822   head->next_buffer = vlib_get_buffer_index (vm, tail);
823   head->total_length_not_including_first_buffer = tail->current_length +
824     tail->total_length_not_including_first_buffer;
825
826 next_segment:
827   clib_atomic_add_fetch (&tail->n_add_refs, 1);
828
829   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
830     {
831       tail = vlib_get_buffer (vm, tail->next_buffer);
832       goto next_segment;
833     }
834 }
835
836 /* Initializes the buffer as an empty packet with no chained buffers. */
837 always_inline void
838 vlib_buffer_chain_init (vlib_buffer_t * first)
839 {
840   first->total_length_not_including_first_buffer = 0;
841   first->current_length = 0;
842   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
843   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
844 }
845
846 /* The provided next_bi buffer index is appended to the end of the packet. */
847 always_inline vlib_buffer_t *
848 vlib_buffer_chain_buffer (vlib_main_t * vm, vlib_buffer_t * last, u32 next_bi)
849 {
850   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
851   last->next_buffer = next_bi;
852   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
853   next_buffer->current_length = 0;
854   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
855   return next_buffer;
856 }
857
858 /* Increases or decreases the packet length.
859  * It does not allocate or deallocate new buffers.
860  * Therefore, the added length must be compatible
861  * with the last buffer. */
862 always_inline void
863 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
864                                    vlib_buffer_t * last, i32 len)
865 {
866   last->current_length += len;
867   if (first != last)
868     first->total_length_not_including_first_buffer += len;
869 }
870
871 /* Copy data to the end of the packet and increases its length.
872  * It does not allocate new buffers.
873  * Returns the number of copied bytes. */
874 always_inline u16
875 vlib_buffer_chain_append_data (vlib_main_t * vm,
876                                vlib_buffer_free_list_index_t free_list_index,
877                                vlib_buffer_t * first,
878                                vlib_buffer_t * last, void *data, u16 data_len)
879 {
880   u32 n_buffer_bytes = VLIB_BUFFER_DATA_SIZE;
881   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
882   u16 len = clib_min (data_len,
883                       n_buffer_bytes - last->current_length -
884                       last->current_data);
885   clib_memcpy_fast (vlib_buffer_get_current (last) + last->current_length,
886                     data, len);
887   vlib_buffer_chain_increase_length (first, last, len);
888   return len;
889 }
890
891 /* Copy data to the end of the packet and increases its length.
892  * Allocates additional buffers from the free list if necessary.
893  * Returns the number of copied bytes.
894  * 'last' value is modified whenever new buffers are allocated and
895  * chained and points to the last buffer in the chain. */
896 u16
897 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
898                                           vlib_buffer_free_list_index_t
899                                           free_list_index,
900                                           vlib_buffer_t * first,
901                                           vlib_buffer_t ** last, void *data,
902                                           u16 data_len);
903 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
904
905 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
906   format_vlib_buffer_contents;
907
908 typedef struct
909 {
910   /* Vector of packet data. */
911   u8 *packet_data;
912
913   /* Number of buffers to allocate in each call to allocator. */
914   u32 min_n_buffers_each_alloc;
915
916   /* Buffer free list for this template. */
917   vlib_buffer_free_list_index_t free_list_index;
918
919   u32 *free_buffers;
920
921   u8 *name;
922 } vlib_packet_template_t;
923
924 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
925                                              vlib_packet_template_t * t);
926
927 void vlib_packet_template_init (vlib_main_t * vm,
928                                 vlib_packet_template_t * t,
929                                 void *packet_data,
930                                 uword n_packet_data_bytes,
931                                 uword min_n_buffers_each_alloc,
932                                 char *fmt, ...);
933
934 void *vlib_packet_template_get_packet (vlib_main_t * vm,
935                                        vlib_packet_template_t * t,
936                                        u32 * bi_result);
937
938 always_inline void
939 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
940 {
941   vec_free (t->packet_data);
942 }
943
944 static_always_inline vlib_buffer_pool_t *
945 vlib_buffer_pool_get (vlib_main_t * vm, u8 buffer_pool_index)
946 {
947   vlib_buffer_main_t *bm = vm->buffer_main;
948   return vec_elt_at_index (bm->buffer_pools, buffer_pool_index);
949 }
950
951 always_inline void
952 vlib_buffer_add_to_free_list (vlib_main_t * vm,
953                               vlib_buffer_free_list_t * f,
954                               u32 buffer_index, u8 do_init)
955 {
956   vlib_buffer_pool_t *bp = vlib_buffer_pool_get (vm, f->buffer_pool_index);
957   vlib_buffer_t *b;
958   b = vlib_get_buffer (vm, buffer_index);
959   if (PREDICT_TRUE (do_init))
960     clib_memset (b, 0, STRUCT_OFFSET_OF (vlib_buffer_t, template_end));
961   vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
962
963   if (vec_len (f->buffers) > 4 * VLIB_FRAME_SIZE)
964     {
965       clib_spinlock_lock (&bp->lock);
966       /* keep last stored buffers, as they are more likely hot in the cache */
967       vec_add_aligned (bp->buffers, f->buffers, VLIB_FRAME_SIZE,
968                        CLIB_CACHE_LINE_BYTES);
969       vec_delete (f->buffers, VLIB_FRAME_SIZE, 0);
970       f->n_alloc -= VLIB_FRAME_SIZE;
971       clib_spinlock_unlock (&bp->lock);
972     }
973 }
974
975 #if CLIB_DEBUG > 0
976 extern u32 *vlib_buffer_state_validation_lock;
977 extern uword *vlib_buffer_state_validation_hash;
978 extern void *vlib_buffer_state_heap;
979 #endif
980
981 static inline void
982 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
983 {
984 #if CLIB_DEBUG > 0
985   uword *p;
986   void *oldheap;
987
988   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
989
990   while (clib_atomic_test_and_set (vlib_buffer_state_validation_lock))
991     ;
992
993   p = hash_get (vlib_buffer_state_validation_hash, b);
994
995   /* If we don't know about b, declare it to be in the expected state */
996   if (!p)
997     {
998       hash_set (vlib_buffer_state_validation_hash, b, expected);
999       goto out;
1000     }
1001
1002   if (p[0] != expected)
1003     {
1004       void cj_stop (void);
1005       u32 bi;
1006       vlib_main_t *vm = &vlib_global_main;
1007
1008       cj_stop ();
1009
1010       bi = vlib_get_buffer_index (vm, b);
1011
1012       clib_mem_set_heap (oldheap);
1013       clib_warning ("%.6f buffer %llx (%d): %s, not %s",
1014                     vlib_time_now (vm), bi,
1015                     p[0] ? "busy" : "free", expected ? "busy" : "free");
1016       os_panic ();
1017     }
1018 out:
1019   CLIB_MEMORY_BARRIER ();
1020   *vlib_buffer_state_validation_lock = 0;
1021   clib_mem_set_heap (oldheap);
1022 #endif
1023 }
1024
1025 static inline void
1026 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
1027 {
1028 #if CLIB_DEBUG > 0
1029   void *oldheap;
1030
1031   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
1032
1033   while (clib_atomic_test_and_set (vlib_buffer_state_validation_lock))
1034     ;
1035
1036   hash_set (vlib_buffer_state_validation_hash, b, expected);
1037
1038   CLIB_MEMORY_BARRIER ();
1039   *vlib_buffer_state_validation_lock = 0;
1040   clib_mem_set_heap (oldheap);
1041 #endif
1042 }
1043
1044 /** minimum data size of first buffer in a buffer chain */
1045 #define VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE (256)
1046
1047 /**
1048  * @brief compress buffer chain in a way where the first buffer is at least
1049  * VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE long
1050  *
1051  * @param[in] vm - vlib_main
1052  * @param[in,out] first - first buffer in chain
1053  * @param[in,out] discard_vector - vector of buffer indexes which were removed
1054  * from the chain
1055  */
1056 always_inline void
1057 vlib_buffer_chain_compress (vlib_main_t * vm,
1058                             vlib_buffer_t * first, u32 ** discard_vector)
1059 {
1060   if (first->current_length >= VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE ||
1061       !(first->flags & VLIB_BUFFER_NEXT_PRESENT))
1062     {
1063       /* this is already big enough or not a chain */
1064       return;
1065     }
1066
1067   u32 want_first_size = clib_min (VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE,
1068                                   VLIB_BUFFER_DATA_SIZE -
1069                                   first->current_data);
1070   do
1071     {
1072       vlib_buffer_t *second = vlib_get_buffer (vm, first->next_buffer);
1073       u32 need = want_first_size - first->current_length;
1074       u32 amount_to_copy = clib_min (need, second->current_length);
1075       clib_memcpy_fast (((u8 *) vlib_buffer_get_current (first)) +
1076                         first->current_length,
1077                         vlib_buffer_get_current (second), amount_to_copy);
1078       first->current_length += amount_to_copy;
1079       second->current_data += amount_to_copy;
1080       second->current_length -= amount_to_copy;
1081       if (first->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1082         {
1083           first->total_length_not_including_first_buffer -= amount_to_copy;
1084         }
1085       if (!second->current_length)
1086         {
1087           vec_add1 (*discard_vector, first->next_buffer);
1088           if (second->flags & VLIB_BUFFER_NEXT_PRESENT)
1089             {
1090               first->next_buffer = second->next_buffer;
1091             }
1092           else
1093             {
1094               first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1095             }
1096           second->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1097         }
1098     }
1099   while ((first->current_length < want_first_size) &&
1100          (first->flags & VLIB_BUFFER_NEXT_PRESENT));
1101 }
1102
1103 /**
1104  * @brief linearize buffer chain - the first buffer is filled, if needed,
1105  * buffers are allocated and filled, returns free space in last buffer or
1106  * negative on failure
1107  *
1108  * @param[in] vm - vlib_main
1109  * @param[in,out] first - first buffer in chain
1110  */
1111 always_inline int
1112 vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * first)
1113 {
1114   vlib_buffer_t *b = first;
1115   u32 buf_len = VLIB_BUFFER_DATA_SIZE;
1116   // free buffer chain starting from the second buffer
1117   int free_count = (b->flags & VLIB_BUFFER_NEXT_PRESENT) != 0;
1118   u32 chain_to_free = b->next_buffer;
1119
1120   u32 len = vlib_buffer_length_in_chain (vm, b);
1121   u32 free_len = buf_len - b->current_data - b->current_length;
1122   int alloc_len = clib_max (len - free_len, 0); //use the free len in the first buffer
1123   int n_buffers = (alloc_len + buf_len - 1) / buf_len;
1124   u32 new_buffers[n_buffers];
1125
1126   u32 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
1127   if (n_alloc != n_buffers)
1128     {
1129       vlib_buffer_free_no_next (vm, new_buffers, n_alloc);
1130       return -1;
1131     }
1132
1133   vlib_buffer_t *s = b;
1134   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
1135     {
1136       s = vlib_get_buffer (vm, s->next_buffer);
1137       int d_free_len = buf_len - b->current_data - b->current_length;
1138       ASSERT (d_free_len >= 0);
1139       // chain buf and split write
1140       u32 copy_len = clib_min (d_free_len, s->current_length);
1141       u8 *d = vlib_buffer_put_uninit (b, copy_len);
1142       clib_memcpy (d, vlib_buffer_get_current (s), copy_len);
1143       int rest = s->current_length - copy_len;
1144       if (rest > 0)
1145         {
1146           //prev buf is full
1147           ASSERT (vlib_buffer_get_tail (b) == b->data + buf_len);
1148           ASSERT (n_buffers > 0);
1149           b = vlib_buffer_chain_buffer (vm, b, new_buffers[--n_buffers]);
1150           //make full use of the new buffers
1151           b->current_data = 0;
1152           d = vlib_buffer_put_uninit (b, rest);
1153           clib_memcpy (d, vlib_buffer_get_current (s) + copy_len, rest);
1154         }
1155     }
1156   vlib_buffer_free (vm, &chain_to_free, free_count);
1157   b->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
1158   if (b == first)               /* no buffers addeed */
1159     b->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1160   ASSERT (len == vlib_buffer_length_in_chain (vm, first));
1161   ASSERT (n_buffers == 0);
1162   return buf_len - b->current_data - b->current_length;
1163 }
1164
1165 #endif /* included_vlib_buffer_funcs_h */
1166
1167 /*
1168  * fd.io coding-style-patch-verification: ON
1169  *
1170  * Local Variables:
1171  * eval: (c-set-style "gnu")
1172  * End:
1173  */