Introduce l{2,3,4}_hdr_offset fields in the buffer metadata
[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   ASSERT (vlib_get_thread_index () == 0);
223
224   uword *p = hash_get (bm->buffer_known_hash, buffer_index);
225   return p ? p[0] : VLIB_BUFFER_UNKNOWN;
226 }
227
228 always_inline void
229 vlib_buffer_set_known_state (vlib_main_t * vm,
230                              u32 buffer_index,
231                              vlib_buffer_known_state_t state)
232 {
233   vlib_buffer_main_t *bm = vm->buffer_main;
234   ASSERT (vlib_get_thread_index () == 0);
235   hash_set (bm->buffer_known_hash, buffer_index, state);
236 }
237
238 /* Validates sanity of a single buffer.
239    Returns format'ed vector with error message if any. */
240 u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
241                           uword follow_chain);
242
243 /** \brief Allocate buffers into supplied array
244
245     @param vm - (vlib_main_t *) vlib main data structure pointer
246     @param buffers - (u32 * ) buffer index array
247     @param n_buffers - (u32) number of buffers requested
248     @return - (u32) number of buffers actually allocated, may be
249     less than the number requested or zero
250 */
251 always_inline u32
252 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
253 {
254   vlib_buffer_main_t *bm = vm->buffer_main;
255
256   ASSERT (bm->cb.vlib_buffer_alloc_cb);
257
258   return bm->cb.vlib_buffer_alloc_cb (vm, buffers, n_buffers);
259 }
260
261 always_inline u32
262 vlib_buffer_round_size (u32 size)
263 {
264   return round_pow2 (size, sizeof (vlib_buffer_t));
265 }
266
267 always_inline u32
268 vlib_buffer_get_free_list_index (vlib_buffer_t * b)
269 {
270   return b->flags & VLIB_BUFFER_FREE_LIST_INDEX_MASK;
271 }
272
273 always_inline void
274 vlib_buffer_set_free_list_index (vlib_buffer_t * b, u32 index)
275 {
276   /* if there is an need for more free lists we should consider
277      storig data in the 2nd cacheline */
278   ASSERT (VLIB_BUFFER_FREE_LIST_INDEX_MASK & 1);
279   ASSERT (index <= VLIB_BUFFER_FREE_LIST_INDEX_MASK);
280
281   b->flags &= ~VLIB_BUFFER_FREE_LIST_INDEX_MASK;
282   b->flags |= index & VLIB_BUFFER_FREE_LIST_INDEX_MASK;
283 }
284
285 /** \brief Allocate buffers from specific freelist into supplied array
286
287     @param vm - (vlib_main_t *) vlib main data structure pointer
288     @param buffers - (u32 * ) buffer index array
289     @param n_buffers - (u32) number of buffers requested
290     @return - (u32) number of buffers actually allocated, may be
291     less than the number requested or zero
292 */
293 always_inline u32
294 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
295                                   u32 * buffers,
296                                   u32 n_buffers, u32 free_list_index)
297 {
298   vlib_buffer_main_t *bm = vm->buffer_main;
299
300   ASSERT (bm->cb.vlib_buffer_alloc_from_free_list_cb);
301
302   return bm->cb.vlib_buffer_alloc_from_free_list_cb (vm, buffers, n_buffers,
303                                                      free_list_index);
304 }
305
306 /** \brief Free buffers
307     Frees the entire buffer chain for each buffer
308
309     @param vm - (vlib_main_t *) vlib main data structure pointer
310     @param buffers - (u32 * ) buffer index array
311     @param n_buffers - (u32) number of buffers to free
312
313 */
314 always_inline void
315 vlib_buffer_free (vlib_main_t * vm,
316                   /* pointer to first buffer */
317                   u32 * buffers,
318                   /* number of buffers to free */
319                   u32 n_buffers)
320 {
321   vlib_buffer_main_t *bm = vm->buffer_main;
322
323   ASSERT (bm->cb.vlib_buffer_free_cb);
324
325   return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
326 }
327
328 /** \brief Free buffers, does not free the buffer chain for each buffer
329
330     @param vm - (vlib_main_t *) vlib main data structure pointer
331     @param buffers - (u32 * ) buffer index array
332     @param n_buffers - (u32) number of buffers to free
333
334 */
335 always_inline void
336 vlib_buffer_free_no_next (vlib_main_t * vm,
337                           /* pointer to first buffer */
338                           u32 * buffers,
339                           /* number of buffers to free */
340                           u32 n_buffers)
341 {
342   vlib_buffer_main_t *bm = vm->buffer_main;
343
344   ASSERT (bm->cb.vlib_buffer_free_no_next_cb);
345
346   return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
347 }
348
349 /** \brief Free one buffer
350     Shorthand to free a single buffer chain.
351
352     @param vm - (vlib_main_t *) vlib main data structure pointer
353     @param buffer_index - (u32) buffer index to free
354 */
355 always_inline void
356 vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
357 {
358   vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
359 }
360
361 /* Add/delete buffer free lists. */
362 u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
363                                   char *fmt, ...);
364 always_inline void
365 vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
366 {
367   vlib_buffer_main_t *bm = vm->buffer_main;
368
369   ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
370
371   bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
372 }
373
374 /* Find already existing public free list with given size or create one. */
375 u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
376                                          char *fmt, ...);
377
378 /* Merge two free lists */
379 void vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
380                                    vlib_buffer_free_list_t * src);
381
382 /* Make sure we have at least given number of unaligned buffers. */
383 void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
384                                            vlib_buffer_free_list_t *
385                                            free_list,
386                                            uword n_unaligned_buffers);
387
388 always_inline u32
389 vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
390 {
391   vlib_buffer_main_t *bm = vm->buffer_main;
392
393   size = vlib_buffer_round_size (size);
394   uword *p = hash_get (bm->free_list_by_size, size);
395   return p ? p[0] : ~0;
396 }
397
398 always_inline vlib_buffer_free_list_t *
399 vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
400                                   u32 * index)
401 {
402   vlib_buffer_main_t *bm = vm->buffer_main;
403   u32 i;
404
405   *index = i = vlib_buffer_get_free_list_index (b);
406   return pool_elt_at_index (bm->buffer_free_list_pool, i);
407 }
408
409 always_inline vlib_buffer_free_list_t *
410 vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
411 {
412   vlib_buffer_main_t *bm = vm->buffer_main;
413   vlib_buffer_free_list_t *f;
414
415   f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
416
417   /* Sanity: indices must match. */
418   ASSERT (f->index == free_list_index);
419
420   return f;
421 }
422
423 always_inline u32
424 vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
425 {
426   vlib_buffer_free_list_t *f =
427     vlib_buffer_get_free_list (vm, free_list_index);
428   return f->n_data_bytes;
429 }
430
431 void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
432
433 /* Reasonably fast buffer copy routine. */
434 always_inline void
435 vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
436 {
437   while (n >= 4)
438     {
439       dst[0] = src[0];
440       dst[1] = src[1];
441       dst[2] = src[2];
442       dst[3] = src[3];
443       dst += 4;
444       src += 4;
445       n -= 4;
446     }
447   while (n > 0)
448     {
449       dst[0] = src[0];
450       dst += 1;
451       src += 1;
452       n -= 1;
453     }
454 }
455
456 always_inline void *
457 vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
458                             uword n_bytes, uword alignment)
459 {
460   void *r =
461     vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
462   if (!r)
463     *error =
464       clib_error_return (0, "failed to allocate %wd bytes of I/O memory",
465                          n_bytes);
466   else
467     *error = 0;
468   return r;
469 }
470
471 /* By default allocate I/O memory with cache line alignment. */
472 always_inline void *
473 vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
474 {
475   return vlib_physmem_alloc_aligned (vm, error, n_bytes,
476                                      CLIB_CACHE_LINE_BYTES);
477 }
478
479 always_inline void
480 vlib_physmem_free (vlib_main_t * vm, void *mem)
481 {
482   return vm->os_physmem_free (mem);
483 }
484
485 always_inline u64
486 vlib_physmem_virtual_to_physical (vlib_main_t * vm, void *mem)
487 {
488   vlib_physmem_main_t *pm = &vm->physmem_main;
489   uword o = pointer_to_uword (mem) - pm->virtual.start;
490   return vlib_physmem_offset_to_physical (pm, o);
491 }
492
493 /* Append given data to end of buffer, possibly allocating new buffers. */
494 u32 vlib_buffer_add_data (vlib_main_t * vm,
495                           u32 free_list_index,
496                           u32 buffer_index, void *data, u32 n_data_bytes);
497
498 /* duplicate all buffers in chain */
499 always_inline vlib_buffer_t *
500 vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
501 {
502   vlib_buffer_t *s, *d, *fd;
503   uword n_alloc, n_buffers = 1;
504   u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
505   int i;
506
507   s = b;
508   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
509     {
510       n_buffers++;
511       s = vlib_get_buffer (vm, s->next_buffer);
512     }
513   u32 new_buffers[n_buffers];
514
515   n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
516
517   /* No guarantee that we'll get all the buffers we asked for */
518   if (PREDICT_FALSE (n_alloc < n_buffers))
519     {
520       if (n_alloc > 0)
521         vlib_buffer_free (vm, new_buffers, n_alloc);
522       return 0;
523     }
524
525   /* 1st segment */
526   s = b;
527   fd = d = vlib_get_buffer (vm, new_buffers[0]);
528   d->current_data = s->current_data;
529   d->current_length = s->current_length;
530   d->flags = s->flags & flag_mask;
531   d->total_length_not_including_first_buffer =
532     s->total_length_not_including_first_buffer;
533   clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
534   clib_memcpy (vlib_buffer_get_current (d),
535                vlib_buffer_get_current (s), s->current_length);
536
537   /* next segments */
538   for (i = 1; i < n_buffers; i++)
539     {
540       /* previous */
541       d->next_buffer = new_buffers[i];
542       /* current */
543       s = vlib_get_buffer (vm, s->next_buffer);
544       d = vlib_get_buffer (vm, new_buffers[i]);
545       d->current_data = s->current_data;
546       d->current_length = s->current_length;
547       clib_memcpy (vlib_buffer_get_current (d),
548                    vlib_buffer_get_current (s), s->current_length);
549       d->flags = s->flags & flag_mask;
550     }
551
552   return fd;
553 }
554
555 /** \brief Create multiple clones of buffer and store them in the supplied array
556
557     @param vm - (vlib_main_t *) vlib main data structure pointer
558     @param src_buffer - (u32) source buffer index
559     @param buffers - (u32 * ) buffer index array
560     @param n_buffers - (u8) number of buffer clones requested
561     @param head_end_offset - (u16) offset relative to current position
562            where packet head ends
563     @return - (u8) number of buffers actually cloned, may be
564     less than the number requested or zero
565 */
566
567 always_inline u8
568 vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
569                    u8 n_buffers, u16 head_end_offset)
570 {
571   u8 i;
572   vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
573
574   ASSERT (s->n_add_refs == 0);
575   ASSERT (n_buffers);
576
577   if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
578     {
579       buffers[0] = src_buffer;
580       for (i = 1; i < n_buffers; i++)
581         {
582           vlib_buffer_t *d;
583           d = vlib_buffer_copy (vm, s);
584           if (d == 0)
585             return i;
586           buffers[i] = vlib_get_buffer_index (vm, d);
587
588         }
589       return n_buffers;
590     }
591
592   n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
593                                                 vlib_buffer_get_free_list_index
594                                                 (s));
595   if (PREDICT_FALSE (n_buffers == 0))
596     {
597       buffers[0] = src_buffer;
598       return 1;
599     }
600
601   for (i = 0; i < n_buffers; i++)
602     {
603       vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
604       d->current_data = s->current_data;
605       d->current_length = head_end_offset;
606       vlib_buffer_set_free_list_index (d,
607                                        vlib_buffer_get_free_list_index (s));
608       d->total_length_not_including_first_buffer =
609         s->total_length_not_including_first_buffer + s->current_length -
610         head_end_offset;
611       d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
612       d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
613       clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
614       clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
615                    head_end_offset);
616       d->next_buffer = src_buffer;
617     }
618   vlib_buffer_advance (s, head_end_offset);
619   s->n_add_refs = n_buffers - 1;
620   while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
621     {
622       s = vlib_get_buffer (vm, s->next_buffer);
623       s->n_add_refs = n_buffers - 1;
624     }
625
626   return n_buffers;
627 }
628
629 /** \brief Attach cloned tail to the buffer
630
631     @param vm - (vlib_main_t *) vlib main data structure pointer
632     @param head - (vlib_buffer_t *) head buffer
633     @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
634 */
635
636 always_inline void
637 vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
638                           vlib_buffer_t * tail)
639 {
640   ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
641   ASSERT (vlib_buffer_get_free_list_index (head) ==
642           vlib_buffer_get_free_list_index (tail));
643
644   head->flags |= VLIB_BUFFER_NEXT_PRESENT;
645   head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
646   head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
647   head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
648   head->next_buffer = vlib_get_buffer_index (vm, tail);
649   head->total_length_not_including_first_buffer = tail->current_length +
650     tail->total_length_not_including_first_buffer;
651
652 next_segment:
653   __sync_add_and_fetch (&tail->n_add_refs, 1);
654
655   if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
656     {
657       tail = vlib_get_buffer (vm, tail->next_buffer);
658       goto next_segment;
659     }
660 }
661
662 /* Initializes the buffer as an empty packet with no chained buffers. */
663 always_inline void
664 vlib_buffer_chain_init (vlib_buffer_t * first)
665 {
666   first->total_length_not_including_first_buffer = 0;
667   first->current_length = 0;
668   first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
669   first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
670 }
671
672 /* The provided next_bi buffer index is appended to the end of the packet. */
673 always_inline vlib_buffer_t *
674 vlib_buffer_chain_buffer (vlib_main_t * vm,
675                           vlib_buffer_t * first,
676                           vlib_buffer_t * last, u32 next_bi)
677 {
678   vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
679   last->next_buffer = next_bi;
680   last->flags |= VLIB_BUFFER_NEXT_PRESENT;
681   next_buffer->current_length = 0;
682   next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
683   return next_buffer;
684 }
685
686 /* Increases or decreases the packet length.
687  * It does not allocate or deallocate new buffers.
688  * Therefore, the added length must be compatible
689  * with the last buffer. */
690 always_inline void
691 vlib_buffer_chain_increase_length (vlib_buffer_t * first,
692                                    vlib_buffer_t * last, i32 len)
693 {
694   last->current_length += len;
695   if (first != last)
696     first->total_length_not_including_first_buffer += len;
697 }
698
699 /* Copy data to the end of the packet and increases its length.
700  * It does not allocate new buffers.
701  * Returns the number of copied bytes. */
702 always_inline u16
703 vlib_buffer_chain_append_data (vlib_main_t * vm,
704                                u32 free_list_index,
705                                vlib_buffer_t * first,
706                                vlib_buffer_t * last, void *data, u16 data_len)
707 {
708   u32 n_buffer_bytes =
709     vlib_buffer_free_list_buffer_size (vm, free_list_index);
710   ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
711   u16 len = clib_min (data_len,
712                       n_buffer_bytes - last->current_length -
713                       last->current_data);
714   clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
715                len);
716   vlib_buffer_chain_increase_length (first, last, len);
717   return len;
718 }
719
720 /* Copy data to the end of the packet and increases its length.
721  * Allocates additional buffers from the free list if necessary.
722  * Returns the number of copied bytes.
723  * 'last' value is modified whenever new buffers are allocated and
724  * chained and points to the last buffer in the chain. */
725 u16
726 vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
727                                           u32 free_list_index,
728                                           vlib_buffer_t * first,
729                                           vlib_buffer_t ** last,
730                                           void *data, u16 data_len);
731 void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
732
733 format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
734   format_vlib_buffer_contents;
735
736 typedef struct
737 {
738   /* Vector of packet data. */
739   u8 *packet_data;
740
741   /* Number of buffers to allocate in each call to physmem
742      allocator. */
743   u32 min_n_buffers_each_physmem_alloc;
744
745   /* Buffer free list for this template. */
746   u32 free_list_index;
747
748   u32 *free_buffers;
749 } vlib_packet_template_t;
750
751 void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
752                                              vlib_packet_template_t * t);
753
754 void vlib_packet_template_init (vlib_main_t * vm,
755                                 vlib_packet_template_t * t,
756                                 void *packet_data,
757                                 uword n_packet_data_bytes,
758                                 uword min_n_buffers_each_physmem_alloc,
759                                 char *fmt, ...);
760
761 void *vlib_packet_template_get_packet (vlib_main_t * vm,
762                                        vlib_packet_template_t * t,
763                                        u32 * bi_result);
764
765 always_inline void
766 vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
767 {
768   vec_free (t->packet_data);
769 }
770
771 always_inline u32
772 unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
773 {
774   serialize_stream_t *s = &m->stream;
775   vlib_serialize_buffer_main_t *sm
776     = uword_to_pointer (m->stream.data_function_opaque,
777                         vlib_serialize_buffer_main_t *);
778   vlib_main_t *vm = sm->vlib_main;
779   u32 n, *f;
780
781   n = s->n_buffer_bytes - s->current_buffer_index;
782   if (sm->last_buffer != ~0)
783     {
784       vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
785       while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
786         {
787           b = vlib_get_buffer (vm, b->next_buffer);
788           n += b->current_length;
789         }
790     }
791
792   /* *INDENT-OFF* */
793   clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
794     n += vlib_buffer_index_length_in_chain (vm, f[0]);
795   }));
796 /* *INDENT-ON* */
797
798   return n;
799 }
800
801 /* Set a buffer quickly into "uninitialized" state.  We want this to
802    be extremely cheap and arrange for all fields that need to be
803    initialized to be in the first 128 bits of the buffer. */
804 always_inline void
805 vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
806                                 vlib_buffer_free_list_t * fl)
807 {
808   vlib_buffer_t *src = &fl->buffer_init_template;
809
810   /* Make sure vlib_buffer_t is cacheline aligned and sized */
811   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
812   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
813           CLIB_CACHE_LINE_BYTES);
814   ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
815           CLIB_CACHE_LINE_BYTES * 2);
816
817   /* Make sure buffer template is sane. */
818   ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
819
820   clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
821                STRUCT_MARK_PTR (src, template_start),
822                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
823                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
824
825   /* Not in the first 16 octets. */
826   dst->n_add_refs = src->n_add_refs;
827
828   /* Make sure it really worked. */
829 #define _(f) ASSERT (dst->f == src->f);
830   _(current_data);
831   _(current_length);
832   _(flags);
833 #undef _
834   ASSERT (dst->total_length_not_including_first_buffer == 0);
835   ASSERT (dst->n_add_refs == 0);
836 }
837
838 always_inline void
839 vlib_buffer_add_to_free_list (vlib_main_t * vm,
840                               vlib_buffer_free_list_t * f,
841                               u32 buffer_index, u8 do_init)
842 {
843   vlib_buffer_t *b;
844   b = vlib_get_buffer (vm, buffer_index);
845   if (PREDICT_TRUE (do_init))
846     vlib_buffer_init_for_free_list (b, f);
847   vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
848 }
849
850 always_inline void
851 vlib_buffer_init_two_for_free_list (vlib_buffer_t * dst0,
852                                     vlib_buffer_t * dst1,
853                                     vlib_buffer_free_list_t * fl)
854 {
855   vlib_buffer_t *src = &fl->buffer_init_template;
856
857   /* Make sure buffer template is sane. */
858   ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
859
860   clib_memcpy (STRUCT_MARK_PTR (dst0, template_start),
861                STRUCT_MARK_PTR (src, template_start),
862                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
863                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
864
865   clib_memcpy (STRUCT_MARK_PTR (dst1, template_start),
866                STRUCT_MARK_PTR (src, template_start),
867                STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
868                STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
869
870   /* Not in the first 16 octets. */
871   dst0->n_add_refs = src->n_add_refs;
872   dst1->n_add_refs = src->n_add_refs;
873
874   /* Make sure it really worked. */
875 #define _(f) ASSERT (dst0->f == src->f);  ASSERT( dst1->f == src->f)
876   _(current_data);
877   _(current_length);
878   _(flags);
879 #undef _
880
881   ASSERT (dst0->total_length_not_including_first_buffer == 0);
882   ASSERT (dst1->total_length_not_including_first_buffer == 0);
883   ASSERT (dst0->n_add_refs == 0);
884   ASSERT (dst1->n_add_refs == 0);
885 }
886
887 #if CLIB_DEBUG > 0
888 extern u32 *vlib_buffer_state_validation_lock;
889 extern uword *vlib_buffer_state_validation_hash;
890 extern void *vlib_buffer_state_heap;
891 #endif
892
893 static inline void
894 vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
895 {
896 #if CLIB_DEBUG > 0
897   uword *p;
898   void *oldheap;
899
900   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
901
902   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
903     ;
904
905   p = hash_get (vlib_buffer_state_validation_hash, b);
906
907   /* If we don't know about b, declare it to be in the expected state */
908   if (!p)
909     {
910       hash_set (vlib_buffer_state_validation_hash, b, expected);
911       goto out;
912     }
913
914   if (p[0] != expected)
915     {
916       void cj_stop (void);
917       u32 bi;
918       vlib_main_t *vm = &vlib_global_main;
919
920       cj_stop ();
921
922       bi = vlib_get_buffer_index (vm, b);
923
924       clib_mem_set_heap (oldheap);
925       clib_warning ("%.6f buffer %llx (%d): %s, not %s",
926                     vlib_time_now (vm), bi,
927                     p[0] ? "busy" : "free", expected ? "busy" : "free");
928       os_panic ();
929     }
930 out:
931   CLIB_MEMORY_BARRIER ();
932   *vlib_buffer_state_validation_lock = 0;
933   clib_mem_set_heap (oldheap);
934 #endif
935 }
936
937 static inline void
938 vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
939 {
940 #if CLIB_DEBUG > 0
941   void *oldheap;
942
943   oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
944
945   while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
946     ;
947
948   hash_set (vlib_buffer_state_validation_hash, b, expected);
949
950   CLIB_MEMORY_BARRIER ();
951   *vlib_buffer_state_validation_lock = 0;
952   clib_mem_set_heap (oldheap);
953 #endif
954 }
955
956 #endif /* included_vlib_buffer_funcs_h */
957
958 /*
959  * fd.io coding-style-patch-verification: ON
960  *
961  * Local Variables:
962  * eval: (c-set-style "gnu")
963  * End:
964  */