Thread safe internal buffer manager
[vpp.git] / src / vlib / buffer_funcs.h
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * buffer_funcs.h: VLIB buffer related functions/inlines
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #ifndef included_vlib_buffer_funcs_h
41 #define included_vlib_buffer_funcs_h
42
43 #include <vppinfra/hash.h>
44
45 /** \file
46     vlib buffer access methods.
47 */
48
49
50 /** \brief Translate buffer index into buffer pointer
51
52     @param vm - (vlib_main_t *) vlib main data structure pointer
53     @param buffer_index - (u32) buffer index
54     @return - (vlib_buffer_t *) buffer pointer
55 */
56 always_inline vlib_buffer_t *
57 vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
58 {
59   vlib_buffer_main_t *bm = vm->buffer_main;
60   uword offset = ((uword) buffer_index) << CLIB_LOG2_CACHE_LINE_BYTES;
61   ASSERT (offset < bm->buffer_mem_size);
62
63   return uword_to_pointer (bm->buffer_mem_start + offset, void *);
64 }
65
66 /** \brief Translate buffer pointer into buffer index
67
68     @param vm - (vlib_main_t *) vlib main data structure pointer
69     @param p - (void *) buffer pointer
70     @return - (u32) buffer index
71 */
72
73 always_inline u32
74 vlib_get_buffer_index (vlib_main_t * vm, void *p)
75 {
76   vlib_buffer_main_t *bm = vm->buffer_main;
77   uword offset = pointer_to_uword (p) - bm->buffer_mem_start;
78   ASSERT (pointer_to_uword (p) >= bm->buffer_mem_start);
79   ASSERT (offset < bm->buffer_mem_size);
80   ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
81   return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
82 }
83
84 /** \brief Get next buffer in buffer linklist, or zero for end of list.
85
86     @param vm - (vlib_main_t *) vlib main data structure pointer
87     @param b - (void *) buffer pointer
88     @return - (vlib_buffer_t *) next buffer, or NULL
89 */
90 always_inline vlib_buffer_t *
91 vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
92 {
93   return (b->flags & VLIB_BUFFER_NEXT_PRESENT
94           ? vlib_get_buffer (vm, b->next_buffer) : 0);
95 }
96
97 uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
98                                              vlib_buffer_t * b_first);
99
100 /** \brief Get length in bytes of the buffer chain
101
102     @param vm - (vlib_main_t *) vlib main data structure pointer
103     @param b - (void *) buffer pointer
104     @return - (uword) length of buffer chain
105 */
106 always_inline uword
107 vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
108 {
109   uword len = b->current_length;
110
111   if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
112     return len;
113
114   if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
115     return len + b->total_length_not_including_first_buffer;
116
117   return vlib_buffer_length_in_chain_slow_path (vm, b);
118 }
119
120 /** \brief Get length in bytes of the buffer index buffer chain
121
122     @param vm - (vlib_main_t *) vlib main data structure pointer
123     @param bi - (u32) buffer index
124     @return - (uword) length of buffer chain
125 */
126 always_inline uword
127 vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
128 {
129   vlib_buffer_t *b = vlib_get_buffer (vm, bi);
130   return vlib_buffer_length_in_chain (vm, b);
131 }
132
133 /** \brief Copy buffer contents to memory
134
135     @param vm - (vlib_main_t *) vlib main data structure pointer
136     @param buffer_index - (u32) buffer index
137     @param contents - (u8 *) memory, <strong>must be large enough</strong>
138     @return - (uword) length of buffer chain
139 */
140 always_inline uword
141 vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
142 {
143   uword content_len = 0;
144   uword l;
145   vlib_buffer_t *b;
146
147   while (1)
148     {
149       b = vlib_get_buffer (vm, buffer_index);
150       l = b->current_length;
151       clib_memcpy (contents + content_len, b->data + b->current_data, l);
152       content_len += l;
153       if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
154         break;
155       buffer_index = b->next_buffer;
156     }
157
158   return content_len;
159 }
160
161 /* Return physical address of buffer->data start. */
162 always_inline u64
163 vlib_get_buffer_data_physical_address (vlib_main_t * vm, u32 buffer_index)
164 {
165   return vlib_physmem_offset_to_physical (&vm->physmem_main,
166                                           (((uword) buffer_index) <<
167                                            CLIB_LOG2_CACHE_LINE_BYTES) +
168                                           STRUCT_OFFSET_OF (vlib_buffer_t,
169                                                             data));
170 }
171
172 /** \brief Prefetch buffer metadata by buffer index
173     The first 64 bytes of buffer contains most header information
174
175     @param vm - (vlib_main_t *) vlib main data structure pointer
176     @param bi - (u32) buffer index
177     @param type - LOAD, STORE. In most cases, STORE is the right answer
178 */
179 /* Prefetch buffer header given index. */
180 #define vlib_prefetch_buffer_with_index(vm,bi,type)     \
181   do {                                                  \
182     vlib_buffer_t * _b = vlib_get_buffer (vm, bi);      \
183     vlib_prefetch_buffer_header (_b, type);             \
184   } while (0)
185
186 #if 0
187 /* Iterate over known allocated vlib bufs. You probably do not want
188  * to do this!
189  @param vm      the vlib_main_t
190  @param bi      found allocated buffer index
191  @param body    operation to perform on buffer index
192  function executes body for each allocated buffer index
193  */
194 #define vlib_buffer_foreach_allocated(vm,bi,body)                \
195 do {                                                             \
196   vlib_main_t * _vmain = (vm);                                   \
197   vlib_buffer_main_t * _bmain = &_vmain->buffer_main;            \
198   hash_pair_t * _vbpair;                                         \
199   hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({       \
200     if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) {      \
201       (bi) = _vbpair->key;                                       \
202       body;                                                      \
203     }                                                            \
204   }));                                                           \
205 } while (0)
206 #endif
207
208 typedef enum
209 {
210   /* Index is unknown. */
211   VLIB_BUFFER_UNKNOWN,
212
213   /* Index is known and free/allocated. */
214   VLIB_BUFFER_KNOWN_FREE,
215   VLIB_BUFFER_KNOWN_ALLOCATED,
216 } vlib_buffer_known_state_t;
217
218 always_inline vlib_buffer_known_state_t
219 vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
220 {
221   vlib_buffer_main_t *bm = vm->buffer_main;
222
223   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
224   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
225   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
226   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
227 }
228
229 always_inline void
230 vlib_buffer_set_known_state (vlib_main_t * vm,
231                              u32 buffer_index,
232                              vlib_buffer_known_state_t state)
233 {
234   vlib_buffer_main_t *bm = vm->buffer_main;
235   clib_spinlock_lock (&bm->buffer_known_hash_lockp);
236   hash_set (bm->buffer_known_hash, buffer_index, state);
237   clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
238 }
239
240 /* Validates sanity of a single buffer.
241    Returns format'ed vector with error message if any. */
242 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
243                           uword follow_chain);
244
245 /** \brief Allocate buffers into supplied array
246
247     @param vm - (vlib_main_t *) vlib main data structure pointer
248     @param buffers - (u32 * ) buffer index array
249     @param n_buffers - (u32) number of buffers requested
250     @return - (u32) number of buffers actually allocated, may be
251     less than the number requested or zero
252 */
253 always_inline u32
254 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
255 {
256   vlib_buffer_main_t *bm = vm->buffer_main;
257
258   ASSERT (bm->cb.vlib_buffer_alloc_cb);
259
260   return bm->cb.vlib_buffer_alloc_cb (vm, buffers, n_buffers);
261 }
262
263 always_inline u32
264 vlib_buffer_round_size (u32 size)
265 {
266   return round_pow2 (size, sizeof (vlib_buffer_t));
267 }
268
269 always_inline u32
270 vlib_buffer_get_free_list_index (vlib_buffer_t * b)
271 {
272   return b->flags & VLIB_BUFFER_FREE_LIST_INDEX_MASK;
273 }
274
275 always_inline void
276 vlib_buffer_set_free_list_index (vlib_buffer_t * b, u32 index)
277 {
278   /* if there is an need for more free lists we should consider
279      storig data in the 2nd cacheline */
280   ASSERT (VLIB_BUFFER_FREE_LIST_INDEX_MASK & 1);
281   ASSERT (index <= VLIB_BUFFER_FREE_LIST_INDEX_MASK);
282
283   b->flags &= ~VLIB_BUFFER_FREE_LIST_INDEX_MASK;
284   b->flags |= index & VLIB_BUFFER_FREE_LIST_INDEX_MASK;
285 }
286
287 /** \brief Allocate buffers from specific freelist into supplied array
288
289     @param vm - (vlib_main_t *) vlib main data structure pointer
290     @param buffers - (u32 * ) buffer index array
291     @param n_buffers - (u32) number of buffers requested
292     @return - (u32) number of buffers actually allocated, may be
293     less than the number requested or zero
294 */
295 always_inline u32
296 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
297                                   u32 * buffers,
298                                   u32 n_buffers, u32 free_list_index)
299 {
300   vlib_buffer_main_t *bm = vm->buffer_main;
301
302   ASSERT (bm->cb.vlib_buffer_alloc_from_free_list_cb);
303
304   return bm->cb.vlib_buffer_alloc_from_free_list_cb (vm, buffers, n_buffers,
305                                                      free_list_index);
306 }
307
308 /** \brief Free buffers
309     Frees the entire buffer chain for each buffer
310
311     @param vm - (vlib_main_t *) vlib main data structure pointer
312     @param buffers - (u32 * ) buffer index array
313     @param n_buffers - (u32) number of buffers to free
314
315 */
316 always_inline void
317 vlib_buffer_free (vlib_main_t * vm,
318                   /* pointer to first buffer */
319                   u32 * buffers,
320                   /* number of buffers to free */
321                   u32 n_buffers)
322 {
323   vlib_buffer_main_t *bm = vm->buffer_main;
324
325   ASSERT (bm->cb.vlib_buffer_free_cb);
326
327   return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
328 }
329
330 /** \brief Free buffers, does not free the buffer chain for each buffer
331
332     @param vm - (vlib_main_t *) vlib main data structure pointer
333     @param buffers - (u32 * ) buffer index array
334     @param n_buffers - (u32) number of buffers to free
335
336 */
337 always_inline void
338 vlib_buffer_free_no_next (vlib_main_t * vm,
339                           /* pointer to first buffer */
340                           u32 * buffers,
341                           /* number of buffers to free */
342                           u32 n_buffers)
343 {
344   vlib_buffer_main_t *bm = vm->buffer_main;
345
346   ASSERT (bm->cb.vlib_buffer_free_no_next_cb);
347
348   return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
349 }
350
351 /** \brief Free one buffer
352     Shorthand to free a single buffer chain.
353
354     @param vm - (vlib_main_t *) vlib main data structure pointer
355     @param buffer_index - (u32) buffer index to free
356 */
357 always_inline void
358 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
359 {
360   vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
361 }
362
363 /* Add/delete buffer free lists. */
364 u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
365                                   char *fmt, ...);
366 always_inline void
367 vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
368 {
369   vlib_buffer_main_t *bm = vm->buffer_main;
370
371   ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
372
373   bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
374 }
375
376 /* Find already existing public free list with given size or create one. */
377 u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
378                                          char *fmt, ...);
379
380 /* Merge two free lists */
381 void vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
382                                    vlib_buffer_free_list_t * src);
383
384 /* Make sure we have at least given number of unaligned buffers. */
385 void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
386                                            vlib_buffer_free_list_t *
387                                            free_list,
388                                            uword n_unaligned_buffers);
389
390 always_inline u32
391 vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
392 {
393   vlib_buffer_main_t *bm = vm->buffer_main;
394
395   size = vlib_buffer_round_size (size);
396   uword *p = hash_get (bm->free_list_by_size, size);
397   return p ? p[0] : ~0;
398 }
399
400 always_inline vlib_buffer_free_list_t *
401 vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
402                                   u32 * index)
403 {
404   vlib_buffer_main_t *bm = vm->buffer_main;
405   u32 i;
406
407   *index = i = vlib_buffer_get_free_list_index (b);
408   return pool_elt_at_index (bm->buffer_free_list_pool, i);
409 }
410
411 always_inline vlib_buffer_free_list_t *
412 vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
413 {
414   vlib_buffer_main_t *bm = vm->buffer_main;
415   vlib_buffer_free_list_t *f;
416
417   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
418
419   /* Sanity: indices must match. */
420   ASSERT (f->index == free_list_index);
421
422   return f;
423 }
424
425 always_inline u32
426 vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
427 {
428   vlib_buffer_free_list_t *f =
429     vlib_buffer_get_free_list (vm, free_list_index);
430   return f->n_data_bytes;
431 }
432
433 void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
434
435 /* Reasonably fast buffer copy routine. */
436 always_inline void
437 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
438 {
439   while (n >= 4)
440     {
441       dst[0] = src[0];
442       dst[1] = src[1];
443       dst[2] = src[2];
444       dst[3] = src[3];
445       dst += 4;
446       src += 4;
447       n -= 4;
448     }
449   while (n > 0)
450     {
451       dst[0] = src[0];
452       dst += 1;
453       src += 1;
454       n -= 1;
455     }
456 }
457
458 always_inline void *
459 vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
460                             uword n_bytes, uword alignment)
461 {
462   void *r =
463     vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
464   if (!r)
465     *error =
466       clib_error_return (0, "failed to allocate %wd bytes of I/O memory",
467                          n_bytes);
468   else
469     *error = 0;
470   return r;
471 }
472
473 /* By default allocate I/O memory with cache line alignment. */
474 always_inline void *
475 vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
476 {
477   return vlib_physmem_alloc_aligned (vm, error, n_bytes,
478                                      CLIB_CACHE_LINE_BYTES);
479 }
480
481 always_inline void
482 vlib_physmem_free (vlib_main_t * vm, void *mem)
483 {
484   return vm->os_physmem_free (mem);
485 }
486
487 always_inline u64
488 vlib_physmem_virtual_to_physical (vlib_main_t * vm, void *mem)
489 {
490   vlib_physmem_main_t *pm = &vm->physmem_main;
491   uword o = pointer_to_uword (mem) - pm->virtual.start;
492   return vlib_physmem_offset_to_physical (pm, o);
493 }
494
495 /* Append given data to end of buffer, possibly allocating new buffers. */
496 u32 vlib_buffer_add_data (vlib_main_t * vm,
497                           u32 free_list_index,
498                           u32 buffer_index, void *data, u32 n_data_bytes);
499
500 /* duplicate all buffers in chain */
501 always_inline vlib_buffer_t *
502 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
503 {
504   vlib_buffer_t *s, *d, *fd;
505   uword n_alloc, n_buffers = 1;
506   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
507   int i;
508
509   s = b;
510   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
511     {
512       n_buffers++;
513       s = vlib_get_buffer (vm, s->next_buffer);
514     }
515   u32 new_buffers[n_buffers];
516
517   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
518
519   /* No guarantee that we'll get all the buffers we asked for */
520   if (PREDICT_FALSE (n_alloc < n_buffers))
521     {
522       if (n_alloc > 0)
523         vlib_buffer_free (vm, new_buffers, n_alloc);
524       return 0;
525     }
526
527   /* 1st segment */
528   s = b;
529   fd = d = vlib_get_buffer (vm, new_buffers[0]);
530   d->current_data = s->current_data;
531   d->current_length = s->current_length;
532   d->flags = s->flags & flag_mask;
533   d->total_length_not_including_first_buffer =
534     s->total_length_not_including_first_buffer;
535   clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
536   clib_memcpy (vlib_buffer_get_current (d),
537                vlib_buffer_get_current (s), s->current_length);
538
539   /* next segments */
540   for (i = 1; i < n_buffers; i++)
541     {
542       /* previous */
543       d->next_buffer = new_buffers[i];
544       /* current */
545       s = vlib_get_buffer (vm, s->next_buffer);
546       d = vlib_get_buffer (vm, new_buffers[i]);
547       d->current_data = s->current_data;
548       d->current_length = s->current_length;
549       clib_memcpy (vlib_buffer_get_current (d),
550                    vlib_buffer_get_current (s), s->current_length);
551       d->flags = s->flags & flag_mask;
552     }
553
554   return fd;
555 }
556
557 /** \brief Create multiple clones of buffer and store them in the supplied array
558
559     @param vm - (vlib_main_t *) vlib main data structure pointer
560     @param src_buffer - (u32) source buffer index
561     @param buffers - (u32 * ) buffer index array
562     @param n_buffers - (u8) number of buffer clones requested
563     @param head_end_offset - (u16) offset relative to current position
564            where packet head ends
565     @return - (u8) number of buffers actually cloned, may be
566     less than the number requested or zero
567 */
568
569 always_inline u8
570 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
571                    u8 n_buffers, u16 head_end_offset)
572 {
573   u8 i;
574   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
575
576   ASSERT (s->n_add_refs == 0);
577   ASSERT (n_buffers);
578
579   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
580     {
581       buffers[0] = src_buffer;
582       for (i = 1; i < n_buffers; i++)
583         {
584           vlib_buffer_t *d;
585           d = vlib_buffer_copy (vm, s);
586           if (d == 0)
587             return i;
588           buffers[i] = vlib_get_buffer_index (vm, d);
589
590         }
591       return n_buffers;
592     }
593
594   n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
595                                                 vlib_buffer_get_free_list_index
596                                                 (s));
597   if (PREDICT_FALSE (n_buffers == 0))
598     {
599       buffers[0] = src_buffer;
600       return 1;
601     }
602
603   for (i = 0; i < n_buffers; i++)
604     {
605       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
606       d->current_data = s->current_data;
607       d->current_length = head_end_offset;
608       vlib_buffer_set_free_list_index (d,
609                                        vlib_buffer_get_free_list_index (s));
610       d->total_length_not_including_first_buffer =
611         s->total_length_not_including_first_buffer + s->current_length -
612         head_end_offset;
613       d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
614       d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
615       clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
616       clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
617                    head_end_offset);
618       d->next_buffer = src_buffer;
619     }
620   vlib_buffer_advance (s, head_end_offset);
621   s->n_add_refs = n_buffers - 1;
622   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
623     {
624       s = vlib_get_buffer (vm, s->next_buffer);
625       s->n_add_refs = n_buffers - 1;
626     }
627
628   return n_buffers;
629 }
630
631 /** \brief Attach cloned tail to the buffer
632
633     @param vm - (vlib_main_t *) vlib main data structure pointer
634     @param head - (vlib_buffer_t *) head buffer
635     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
636 */
637
638 always_inline void
639 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
640                           vlib_buffer_t * tail)
641 {
642   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
643   ASSERT (vlib_buffer_get_free_list_index (head) ==
644           vlib_buffer_get_free_list_index (tail));
645
646   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
647   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
648   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
649   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
650   head->next_buffer = vlib_get_buffer_index (vm, tail);
651   head->total_length_not_including_first_buffer = tail->current_length +
652     tail->total_length_not_including_first_buffer;
653
654 next_segment:
655   __sync_add_and_fetch (&tail->n_add_refs, 1);
656
657   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
658     {
659       tail = vlib_get_buffer (vm, tail->next_buffer);
660       goto next_segment;
661     }
662 }
663
664 /* Initializes the buffer as an empty packet with no chained buffers. */
665 always_inline void
666 vlib_buffer_chain_init (vlib_buffer_t * first)
667 {
668   first->total_length_not_including_first_buffer = 0;
669   first->current_length = 0;
670   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
671   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
672 }
673
674 /* The provided next_bi buffer index is appended to the end of the packet. */
675 always_inline vlib_buffer_t *
676 vlib_buffer_chain_buffer (vlib_main_t * vm,
677                           vlib_buffer_t * first,
678                           vlib_buffer_t * last, u32 next_bi)
679 {
680   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
681   last->next_buffer = next_bi;
682   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
683   next_buffer->current_length = 0;
684   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
685   return next_buffer;
686 }
687
688 /* Increases or decreases the packet length.
689  * It does not allocate or deallocate new buffers.
690  * Therefore, the added length must be compatible
691  * with the last buffer. */
692 always_inline void
693 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
694                                    vlib_buffer_t * last, i32 len)
695 {
696   last->current_length += len;
697   if (first != last)
698     first->total_length_not_including_first_buffer += len;
699 }
700
701 /* Copy data to the end of the packet and increases its length.
702  * It does not allocate new buffers.
703  * Returns the number of copied bytes. */
704 always_inline u16
705 vlib_buffer_chain_append_data (vlib_main_t * vm,
706                                u32 free_list_index,
707                                vlib_buffer_t * first,
708                                vlib_buffer_t * last, void *data, u16 data_len)
709 {
710   u32 n_buffer_bytes =
711     vlib_buffer_free_list_buffer_size (vm, free_list_index);
712   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
713   u16 len = clib_min (data_len,
714                       n_buffer_bytes - last->current_length -
715                       last->current_data);
716   clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
717                len);
718   vlib_buffer_chain_increase_length (first, last, len);
719   return len;
720 }
721
722 /* Copy data to the end of the packet and increases its length.
723  * Allocates additional buffers from the free list if necessary.
724  * Returns the number of copied bytes.
725  * 'last' value is modified whenever new buffers are allocated and
726  * chained and points to the last buffer in the chain. */
727 u16
728 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
729                                           u32 free_list_index,
730                                           vlib_buffer_t * first,
731                                           vlib_buffer_t ** last,
732                                           void *data, u16 data_len);
733 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
734
735 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
736   format_vlib_buffer_contents;
737
738 typedef struct
739 {
740   /* Vector of packet data. */
741   u8 *packet_data;
742
743   /* Number of buffers to allocate in each call to physmem
744      allocator. */
745   u32 min_n_buffers_each_physmem_alloc;
746
747   /* Buffer free list for this template. */
748   u32 free_list_index;
749
750   u32 *free_buffers;
751 } vlib_packet_template_t;
752
753 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
754                                              vlib_packet_template_t * t);
755
756 void vlib_packet_template_init (vlib_main_t * vm,
757                                 vlib_packet_template_t * t,
758                                 void *packet_data,
759                                 uword n_packet_data_bytes,
760                                 uword min_n_buffers_each_physmem_alloc,
761                                 char *fmt, ...);
762
763 void *vlib_packet_template_get_packet (vlib_main_t * vm,
764                                        vlib_packet_template_t * t,
765                                        u32 * bi_result);
766
767 always_inline void
768 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
769 {
770   vec_free (t->packet_data);
771 }
772
773 always_inline u32
774 unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
775 {
776   serialize_stream_t *s = &m->stream;
777   vlib_serialize_buffer_main_t *sm
778     = uword_to_pointer (m->stream.data_function_opaque,
779                         vlib_serialize_buffer_main_t *);
780   vlib_main_t *vm = sm->vlib_main;
781   u32 n, *f;
782
783   n = s->n_buffer_bytes - s->current_buffer_index;
784   if (sm->last_buffer != ~0)
785     {
786       vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
787       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
788         {
789           b = vlib_get_buffer (vm, b->next_buffer);
790           n += b->current_length;
791         }
792     }
793
794   /* *INDENT-OFF* */
795   clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
796     n += vlib_buffer_index_length_in_chain (vm, f[0]);
797   }));
798 /* *INDENT-ON* */
799
800   return n;
801 }
802
803 /* Set a buffer quickly into "uninitialized" state.  We want this to
804    be extremely cheap and arrange for all fields that need to be
805    initialized to be in the first 128 bits of the buffer. */
806 always_inline void
807 vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
808                                 vlib_buffer_free_list_t * fl)
809 {
810   vlib_buffer_t *src = &fl->buffer_init_template;
811
812   /* Make sure vlib_buffer_t is cacheline aligned and sized */
813   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
814   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
815           CLIB_CACHE_LINE_BYTES);
816   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
817           CLIB_CACHE_LINE_BYTES * 2);
818
819   /* Make sure buffer template is sane. */
820   ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
821
822   clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
823                STRUCT_MARK_PTR (src, template_start),
824                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
825                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
826
827   /* Not in the first 16 octets. */
828   dst->n_add_refs = src->n_add_refs;
829
830   /* Make sure it really worked. */
831 #define _(f) ASSERT (dst->f == src->f);
832   _(current_data);
833   _(current_length);
834   _(flags);
835 #undef _
836   ASSERT (dst->total_length_not_including_first_buffer == 0);
837   ASSERT (dst->n_add_refs == 0);
838 }
839
840 always_inline void
841 vlib_buffer_add_to_free_list (vlib_main_t * vm,
842                               vlib_buffer_free_list_t * f,
843                               u32 buffer_index, u8 do_init)
844 {
845   vlib_buffer_t *b;
846   u32 i;
847   b = vlib_get_buffer (vm, buffer_index);
848   if (PREDICT_TRUE (do_init))
849     vlib_buffer_init_for_free_list (b, f);
850   vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
851
852   if (vec_len (f->buffers) > 3 * VLIB_FRAME_SIZE)
853     {
854       /* keep last stored buffers, as they are more likely hot in the cache */
855       for (i = 0; i < VLIB_FRAME_SIZE; i++)
856         vm->os_physmem_free (vlib_get_buffer (vm, i));
857       vec_delete (f->buffers, VLIB_FRAME_SIZE, 0);
858     }
859 }
860
861 always_inline void
862 vlib_buffer_init_two_for_free_list (vlib_buffer_t * dst0,
863                                     vlib_buffer_t * dst1,
864                                     vlib_buffer_free_list_t * fl)
865 {
866   vlib_buffer_t *src = &fl->buffer_init_template;
867
868   /* Make sure buffer template is sane. */
869   ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
870
871   clib_memcpy (STRUCT_MARK_PTR (dst0, template_start),
872                STRUCT_MARK_PTR (src, template_start),
873                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
874                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
875
876   clib_memcpy (STRUCT_MARK_PTR (dst1, template_start),
877                STRUCT_MARK_PTR (src, template_start),
878                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
879                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
880
881   /* Not in the first 16 octets. */
882   dst0->n_add_refs = src->n_add_refs;
883   dst1->n_add_refs = src->n_add_refs;
884
885   /* Make sure it really worked. */
886 #define _(f) ASSERT (dst0->f == src->f);  ASSERT( dst1->f == src->f)
887   _(current_data);
888   _(current_length);
889   _(flags);
890 #undef _
891
892   ASSERT (dst0->total_length_not_including_first_buffer == 0);
893   ASSERT (dst1->total_length_not_including_first_buffer == 0);
894   ASSERT (dst0->n_add_refs == 0);
895   ASSERT (dst1->n_add_refs == 0);
896 }
897
898 #if CLIB_DEBUG > 0
899 extern u32 *vlib_buffer_state_validation_lock;
900 extern uword *vlib_buffer_state_validation_hash;
901 extern void *vlib_buffer_state_heap;
902 #endif
903
904 static inline void
905 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
906 {
907 #if CLIB_DEBUG > 0
908   uword *p;
909   void *oldheap;
910
911   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
912
913   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
914     ;
915
916   p = hash_get (vlib_buffer_state_validation_hash, b);
917
918   /* If we don't know about b, declare it to be in the expected state */
919   if (!p)
920     {
921       hash_set (vlib_buffer_state_validation_hash, b, expected);
922       goto out;
923     }
924
925   if (p[0] != expected)
926     {
927       void cj_stop (void);
928       u32 bi;
929       vlib_main_t *vm = &vlib_global_main;
930
931       cj_stop ();
932
933       bi = vlib_get_buffer_index (vm, b);
934
935       clib_mem_set_heap (oldheap);
936       clib_warning ("%.6f buffer %llx (%d): %s, not %s",
937                     vlib_time_now (vm), bi,
938                     p[0] ? "busy" : "free", expected ? "busy" : "free");
939       os_panic ();
940     }
941 out:
942   CLIB_MEMORY_BARRIER ();
943   *vlib_buffer_state_validation_lock = 0;
944   clib_mem_set_heap (oldheap);
945 #endif
946 }
947
948 static inline void
949 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
950 {
951 #if CLIB_DEBUG > 0
952   void *oldheap;
953
954   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
955
956   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
957     ;
958
959   hash_set (vlib_buffer_state_validation_hash, b, expected);
960
961   CLIB_MEMORY_BARRIER ();
962   *vlib_buffer_state_validation_lock = 0;
963   clib_mem_set_heap (oldheap);
964 #endif
965 }
966
967 #endif /* included_vlib_buffer_funcs_h */
968
969 /*
970  * fd.io coding-style-patch-verification: ON
971  *
972  * Local Variables:
973  * eval: (c-set-style "gnu")
974  * End:
975  */