blob: 08f5b3e901044ab92e8a6ea4f945253680480904 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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
Dave Barach9b8ffd92016-07-08 08:13:45 -040055*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070056always_inline vlib_buffer_t *
57vlib_get_buffer (vlib_main_t * vm, u32 buffer_index)
58{
Damjan Marion04a7f052017-07-10 15:06:17 +020059 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 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -070064}
65
66/** \brief Translate buffer pointer into buffer index
67
68 @param vm - (vlib_main_t *) vlib main data structure pointer
Chris Luked4024f52016-09-06 09:32:36 -040069 @param p - (void *) buffer pointer
Ed Warnickecb9cada2015-12-08 15:45:58 -070070 @return - (u32) buffer index
Dave Barach9b8ffd92016-07-08 08:13:45 -040071*/
Damjan Marion04a7f052017-07-10 15:06:17 +020072
Ed Warnickecb9cada2015-12-08 15:45:58 -070073always_inline u32
Dave Barach9b8ffd92016-07-08 08:13:45 -040074vlib_get_buffer_index (vlib_main_t * vm, void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -070075{
Damjan Marion04a7f052017-07-10 15:06:17 +020076 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);
Dave Barach9b8ffd92016-07-08 08:13:45 -040080 ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070081 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
Dave Barach9b8ffd92016-07-08 08:13:45 -040089*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070090always_inline vlib_buffer_t *
91vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
92{
93 return (b->flags & VLIB_BUFFER_NEXT_PRESENT
Dave Barach9b8ffd92016-07-08 08:13:45 -040094 ? vlib_get_buffer (vm, b->next_buffer) : 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070095}
96
Dave Barach9b8ffd92016-07-08 08:13:45 -040097uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
98 vlib_buffer_t * b_first);
Ed Warnickecb9cada2015-12-08 15:45:58 -070099
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
Dave Barach9b8ffd92016-07-08 08:13:45 -0400105*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106always_inline uword
107vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
108{
Damjan Marion072401e2017-07-13 18:53:27 +0200109 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);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118}
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
Dave Barach9b8ffd92016-07-08 08:13:45 -0400125*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126always_inline uword
127vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
128{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400129 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130 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
Chris Luked4024f52016-09-06 09:32:36 -0400136 @param buffer_index - (u32) buffer index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137 @param contents - (u8 *) memory, <strong>must be large enough</strong>
138 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400139*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140always_inline uword
141vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
142{
143 uword content_len = 0;
144 uword l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400145 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
147 while (1)
148 {
149 b = vlib_get_buffer (vm, buffer_index);
150 l = b->current_length;
Damjan Marionf1213b82016-03-13 02:22:06 +0100151 clib_memcpy (contents + content_len, b->data + b->current_data, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152 content_len += l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400153 if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 break;
155 buffer_index = b->next_buffer;
156 }
157
158 return content_len;
159}
160
161/* Return physical address of buffer->data start. */
162always_inline u64
163vlib_get_buffer_data_physical_address (vlib_main_t * vm, u32 buffer_index)
164{
Damjan Marion149ba772017-10-12 13:09:26 +0200165 vlib_physmem_region_index_t pri;
166 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
167 pri = vm->buffer_main->buffer_pools[b->buffer_pool_index].physmem_region;
168 return vlib_physmem_offset_to_physical (vm, pri,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400169 (((uword) buffer_index) <<
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170 CLIB_LOG2_CACHE_LINE_BYTES) +
Dave Barach9b8ffd92016-07-08 08:13:45 -0400171 STRUCT_OFFSET_OF (vlib_buffer_t,
172 data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173}
174
175/** \brief Prefetch buffer metadata by buffer index
176 The first 64 bytes of buffer contains most header information
177
178 @param vm - (vlib_main_t *) vlib main data structure pointer
179 @param bi - (u32) buffer index
180 @param type - LOAD, STORE. In most cases, STORE is the right answer
181*/
182/* Prefetch buffer header given index. */
183#define vlib_prefetch_buffer_with_index(vm,bi,type) \
184 do { \
185 vlib_buffer_t * _b = vlib_get_buffer (vm, bi); \
186 vlib_prefetch_buffer_header (_b, type); \
187 } while (0)
188
189#if 0
190/* Iterate over known allocated vlib bufs. You probably do not want
191 * to do this!
192 @param vm the vlib_main_t
193 @param bi found allocated buffer index
194 @param body operation to perform on buffer index
195 function executes body for each allocated buffer index
196 */
197#define vlib_buffer_foreach_allocated(vm,bi,body) \
198do { \
199 vlib_main_t * _vmain = (vm); \
200 vlib_buffer_main_t * _bmain = &_vmain->buffer_main; \
201 hash_pair_t * _vbpair; \
202 hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({ \
203 if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) { \
204 (bi) = _vbpair->key; \
205 body; \
206 } \
207 })); \
208} while (0)
209#endif
210
Dave Barach9b8ffd92016-07-08 08:13:45 -0400211typedef enum
212{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213 /* Index is unknown. */
214 VLIB_BUFFER_UNKNOWN,
215
216 /* Index is known and free/allocated. */
217 VLIB_BUFFER_KNOWN_FREE,
218 VLIB_BUFFER_KNOWN_ALLOCATED,
219} vlib_buffer_known_state_t;
220
Damjan Marionc8a26c62017-11-24 20:15:23 +0100221void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
222 uword n_buffers,
223 vlib_buffer_known_state_t
224 expected_state);
225
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226always_inline vlib_buffer_known_state_t
227vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
228{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400229 vlib_buffer_main_t *bm = vm->buffer_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230
Damjan Marion6b0f5892017-07-27 04:01:24 -0400231 clib_spinlock_lock (&bm->buffer_known_hash_lockp);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400232 uword *p = hash_get (bm->buffer_known_hash, buffer_index);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400233 clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 return p ? p[0] : VLIB_BUFFER_UNKNOWN;
235}
236
237always_inline void
238vlib_buffer_set_known_state (vlib_main_t * vm,
239 u32 buffer_index,
240 vlib_buffer_known_state_t state)
241{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400242 vlib_buffer_main_t *bm = vm->buffer_main;
Damjan Marion6b0f5892017-07-27 04:01:24 -0400243 clib_spinlock_lock (&bm->buffer_known_hash_lockp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 hash_set (bm->buffer_known_hash, buffer_index, state);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400245 clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246}
247
248/* Validates sanity of a single buffer.
249 Returns format'ed vector with error message if any. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400250u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
251 uword follow_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253always_inline u32
254vlib_buffer_round_size (u32 size)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400255{
256 return round_pow2 (size, sizeof (vlib_buffer_t));
257}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258
Damjan Marion072401e2017-07-13 18:53:27 +0200259always_inline u32
260vlib_buffer_get_free_list_index (vlib_buffer_t * b)
261{
262 return b->flags & VLIB_BUFFER_FREE_LIST_INDEX_MASK;
263}
264
265always_inline void
266vlib_buffer_set_free_list_index (vlib_buffer_t * b, u32 index)
267{
268 /* if there is an need for more free lists we should consider
269 storig data in the 2nd cacheline */
270 ASSERT (VLIB_BUFFER_FREE_LIST_INDEX_MASK & 1);
271 ASSERT (index <= VLIB_BUFFER_FREE_LIST_INDEX_MASK);
272
273 b->flags &= ~VLIB_BUFFER_FREE_LIST_INDEX_MASK;
274 b->flags |= index & VLIB_BUFFER_FREE_LIST_INDEX_MASK;
275}
276
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277/** \brief Allocate buffers from specific freelist into supplied array
278
279 @param vm - (vlib_main_t *) vlib main data structure pointer
280 @param buffers - (u32 * ) buffer index array
281 @param n_buffers - (u32) number of buffers requested
Dave Barach9b8ffd92016-07-08 08:13:45 -0400282 @return - (u32) number of buffers actually allocated, may be
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283 less than the number requested or zero
284*/
Damjan Marion878c6092017-01-04 13:19:27 +0100285always_inline u32
286vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
287 u32 * buffers,
288 u32 n_buffers, u32 free_list_index)
289{
290 vlib_buffer_main_t *bm = vm->buffer_main;
Damjan Marionc8a26c62017-11-24 20:15:23 +0100291 vlib_buffer_free_list_t *fl;
292 u32 *src;
293 uword len;
Damjan Marion878c6092017-01-04 13:19:27 +0100294
Damjan Marionc8a26c62017-11-24 20:15:23 +0100295 ASSERT (bm->cb.vlib_buffer_fill_free_list_cb);
Damjan Marion878c6092017-01-04 13:19:27 +0100296
Damjan Marionc8a26c62017-11-24 20:15:23 +0100297 fl = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
298
299 len = vec_len (fl->buffers);
300
301 if (PREDICT_FALSE (len < n_buffers))
302 {
303 bm->cb.vlib_buffer_fill_free_list_cb (vm, fl, n_buffers);
304 len = vec_len (fl->buffers);
305
306 /* even if fill free list didn't manage to refill free list
307 we should give what we have */
308 n_buffers = clib_min (len, n_buffers);
309
310 /* following code is intentionaly duplicated to allow compiler
311 to optimize fast path when n_buffers is constant value */
312 src = fl->buffers + len - n_buffers;
313 clib_memcpy (buffers, src, n_buffers * sizeof (u32));
314 _vec_len (fl->buffers) -= n_buffers;
315
316 /* Verify that buffers are known free. */
317 vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
318 VLIB_BUFFER_KNOWN_FREE);
319
320 return n_buffers;
321 }
322
323 src = fl->buffers + len - n_buffers;
324 clib_memcpy (buffers, src, n_buffers * sizeof (u32));
325 _vec_len (fl->buffers) -= n_buffers;
326
327 /* Verify that buffers are known free. */
328 vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
329 VLIB_BUFFER_KNOWN_FREE);
330
331 return n_buffers;
332}
333
334/** \brief Allocate buffers into supplied array
335
336 @param vm - (vlib_main_t *) vlib main data structure pointer
337 @param buffers - (u32 * ) buffer index array
338 @param n_buffers - (u32) number of buffers requested
339 @return - (u32) number of buffers actually allocated, may be
340 less than the number requested or zero
341*/
342always_inline u32
343vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
344{
345 return vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
346 VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
Damjan Marion878c6092017-01-04 13:19:27 +0100347}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700348
349/** \brief Free buffers
350 Frees the entire buffer chain for each buffer
351
352 @param vm - (vlib_main_t *) vlib main data structure pointer
353 @param buffers - (u32 * ) buffer index array
354 @param n_buffers - (u32) number of buffers to free
355
356*/
Damjan Marion878c6092017-01-04 13:19:27 +0100357always_inline void
358vlib_buffer_free (vlib_main_t * vm,
359 /* pointer to first buffer */
360 u32 * buffers,
361 /* number of buffers to free */
362 u32 n_buffers)
363{
364 vlib_buffer_main_t *bm = vm->buffer_main;
365
366 ASSERT (bm->cb.vlib_buffer_free_cb);
367
368 return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
369}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370
371/** \brief Free buffers, does not free the buffer chain for each buffer
372
373 @param vm - (vlib_main_t *) vlib main data structure pointer
374 @param buffers - (u32 * ) buffer index array
375 @param n_buffers - (u32) number of buffers to free
376
377*/
Damjan Marion878c6092017-01-04 13:19:27 +0100378always_inline void
379vlib_buffer_free_no_next (vlib_main_t * vm,
380 /* pointer to first buffer */
381 u32 * buffers,
382 /* number of buffers to free */
383 u32 n_buffers)
384{
385 vlib_buffer_main_t *bm = vm->buffer_main;
386
387 ASSERT (bm->cb.vlib_buffer_free_no_next_cb);
388
389 return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
390}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391
392/** \brief Free one buffer
Dave Barach9b8ffd92016-07-08 08:13:45 -0400393 Shorthand to free a single buffer chain.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394
395 @param vm - (vlib_main_t *) vlib main data structure pointer
396 @param buffer_index - (u32) buffer index to free
397*/
398always_inline void
399vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
400{
401 vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
402}
403
404/* Add/delete buffer free lists. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400405u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
406 char *fmt, ...);
Damjan Marion878c6092017-01-04 13:19:27 +0100407always_inline void
408vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
409{
410 vlib_buffer_main_t *bm = vm->buffer_main;
411
412 ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
413
414 bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
415}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416
417/* Find already existing public free list with given size or create one. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400418u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
419 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100421/* Merge two free lists */
422void vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
423 vlib_buffer_free_list_t * src);
424
425/* Make sure we have at least given number of unaligned buffers. */
426void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
427 vlib_buffer_free_list_t *
428 free_list,
429 uword n_unaligned_buffers);
430
431always_inline u32
432vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
433{
434 vlib_buffer_main_t *bm = vm->buffer_main;
435
436 size = vlib_buffer_round_size (size);
437 uword *p = hash_get (bm->free_list_by_size, size);
438 return p ? p[0] : ~0;
439}
440
441always_inline vlib_buffer_free_list_t *
442vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
443 u32 * index)
444{
445 vlib_buffer_main_t *bm = vm->buffer_main;
446 u32 i;
447
Damjan Marion072401e2017-07-13 18:53:27 +0200448 *index = i = vlib_buffer_get_free_list_index (b);
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100449 return pool_elt_at_index (bm->buffer_free_list_pool, i);
450}
451
Ed Warnickecb9cada2015-12-08 15:45:58 -0700452always_inline vlib_buffer_free_list_t *
453vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
454{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400455 vlib_buffer_main_t *bm = vm->buffer_main;
456 vlib_buffer_free_list_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457
458 f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
459
460 /* Sanity: indices must match. */
461 ASSERT (f->index == free_list_index);
462
463 return f;
464}
465
466always_inline u32
467vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
468{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400469 vlib_buffer_free_list_t *f =
470 vlib_buffer_get_free_list (vm, free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 return f->n_data_bytes;
472}
473
Dave Barach9b8ffd92016-07-08 08:13:45 -0400474void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475
476/* Reasonably fast buffer copy routine. */
477always_inline void
478vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
479{
480 while (n >= 4)
481 {
482 dst[0] = src[0];
483 dst[1] = src[1];
484 dst[2] = src[2];
485 dst[3] = src[3];
486 dst += 4;
487 src += 4;
488 n -= 4;
489 }
490 while (n > 0)
491 {
492 dst[0] = src[0];
493 dst += 1;
494 src += 1;
495 n -= 1;
496 }
497}
498
Ed Warnickecb9cada2015-12-08 15:45:58 -0700499/* Append given data to end of buffer, possibly allocating new buffers. */
500u32 vlib_buffer_add_data (vlib_main_t * vm,
501 u32 free_list_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400502 u32 buffer_index, void *data, u32 n_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100504/* duplicate all buffers in chain */
505always_inline vlib_buffer_t *
506vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
507{
508 vlib_buffer_t *s, *d, *fd;
509 uword n_alloc, n_buffers = 1;
Damjan Marion67655492016-11-15 12:50:28 +0100510 u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100511 int i;
512
513 s = b;
514 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
515 {
516 n_buffers++;
517 s = vlib_get_buffer (vm, s->next_buffer);
518 }
Neale Ranns9d676af2017-03-15 01:28:31 -0700519 u32 new_buffers[n_buffers];
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100520
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100521 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
Dave Barach26cd8c12017-02-23 17:11:26 -0500522
523 /* No guarantee that we'll get all the buffers we asked for */
524 if (PREDICT_FALSE (n_alloc < n_buffers))
525 {
526 if (n_alloc > 0)
527 vlib_buffer_free (vm, new_buffers, n_alloc);
Dave Barach26cd8c12017-02-23 17:11:26 -0500528 return 0;
529 }
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100530
531 /* 1st segment */
532 s = b;
533 fd = d = vlib_get_buffer (vm, new_buffers[0]);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100534 d->current_data = s->current_data;
535 d->current_length = s->current_length;
Damjan Marion67655492016-11-15 12:50:28 +0100536 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100537 d->total_length_not_including_first_buffer =
538 s->total_length_not_including_first_buffer;
539 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
Damjan Mariondce05452016-12-01 11:59:33 +0100540 clib_memcpy (vlib_buffer_get_current (d),
541 vlib_buffer_get_current (s), s->current_length);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100542
543 /* next segments */
544 for (i = 1; i < n_buffers; i++)
545 {
546 /* previous */
547 d->next_buffer = new_buffers[i];
548 /* current */
549 s = vlib_get_buffer (vm, s->next_buffer);
550 d = vlib_get_buffer (vm, new_buffers[i]);
551 d->current_data = s->current_data;
552 d->current_length = s->current_length;
553 clib_memcpy (vlib_buffer_get_current (d),
554 vlib_buffer_get_current (s), s->current_length);
Damjan Marion67655492016-11-15 12:50:28 +0100555 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100556 }
557
558 return fd;
559}
560
Damjan Marionc47ed032017-01-25 14:18:03 +0100561/** \brief Create multiple clones of buffer and store them in the supplied array
562
563 @param vm - (vlib_main_t *) vlib main data structure pointer
564 @param src_buffer - (u32) source buffer index
565 @param buffers - (u32 * ) buffer index array
566 @param n_buffers - (u8) number of buffer clones requested
567 @param head_end_offset - (u16) offset relative to current position
568 where packet head ends
569 @return - (u8) number of buffers actually cloned, may be
570 less than the number requested or zero
571*/
572
573always_inline u8
574vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
575 u8 n_buffers, u16 head_end_offset)
576{
577 u8 i;
578 vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
579
580 ASSERT (s->n_add_refs == 0);
581 ASSERT (n_buffers);
582
583 if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
584 {
585 buffers[0] = src_buffer;
586 for (i = 1; i < n_buffers; i++)
587 {
588 vlib_buffer_t *d;
589 d = vlib_buffer_copy (vm, s);
590 if (d == 0)
591 return i;
592 buffers[i] = vlib_get_buffer_index (vm, d);
593
594 }
595 return n_buffers;
596 }
597
598 n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
Damjan Marion072401e2017-07-13 18:53:27 +0200599 vlib_buffer_get_free_list_index
600 (s));
Damjan Marionc47ed032017-01-25 14:18:03 +0100601 if (PREDICT_FALSE (n_buffers == 0))
602 {
603 buffers[0] = src_buffer;
604 return 1;
605 }
606
607 for (i = 0; i < n_buffers; i++)
608 {
609 vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
610 d->current_data = s->current_data;
611 d->current_length = head_end_offset;
Damjan Marion072401e2017-07-13 18:53:27 +0200612 vlib_buffer_set_free_list_index (d,
613 vlib_buffer_get_free_list_index (s));
Damjan Marionc47ed032017-01-25 14:18:03 +0100614 d->total_length_not_including_first_buffer =
615 s->total_length_not_including_first_buffer + s->current_length -
616 head_end_offset;
617 d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
618 d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
619 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
620 clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
621 head_end_offset);
622 d->next_buffer = src_buffer;
623 }
624 vlib_buffer_advance (s, head_end_offset);
625 s->n_add_refs = n_buffers - 1;
626 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
627 {
628 s = vlib_get_buffer (vm, s->next_buffer);
629 s->n_add_refs = n_buffers - 1;
630 }
631
632 return n_buffers;
633}
634
635/** \brief Attach cloned tail to the buffer
636
637 @param vm - (vlib_main_t *) vlib main data structure pointer
638 @param head - (vlib_buffer_t *) head buffer
639 @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
640*/
641
642always_inline void
643vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
644 vlib_buffer_t * tail)
645{
646 ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
Damjan Marion072401e2017-07-13 18:53:27 +0200647 ASSERT (vlib_buffer_get_free_list_index (head) ==
648 vlib_buffer_get_free_list_index (tail));
Damjan Marionc47ed032017-01-25 14:18:03 +0100649
650 head->flags |= VLIB_BUFFER_NEXT_PRESENT;
651 head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
652 head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
653 head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
654 head->next_buffer = vlib_get_buffer_index (vm, tail);
655 head->total_length_not_including_first_buffer = tail->current_length +
656 tail->total_length_not_including_first_buffer;
657
658next_segment:
659 __sync_add_and_fetch (&tail->n_add_refs, 1);
660
661 if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
662 {
663 tail = vlib_get_buffer (vm, tail->next_buffer);
664 goto next_segment;
665 }
666}
667
Pierre Pfister328e99b2016-02-12 13:18:42 +0000668/* Initializes the buffer as an empty packet with no chained buffers. */
669always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400670vlib_buffer_chain_init (vlib_buffer_t * first)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000671{
672 first->total_length_not_including_first_buffer = 0;
673 first->current_length = 0;
674 first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
675 first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000676}
677
678/* The provided next_bi buffer index is appended to the end of the packet. */
679always_inline vlib_buffer_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400680vlib_buffer_chain_buffer (vlib_main_t * vm,
681 vlib_buffer_t * first,
682 vlib_buffer_t * last, u32 next_bi)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000683{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400684 vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000685 last->next_buffer = next_bi;
686 last->flags |= VLIB_BUFFER_NEXT_PRESENT;
687 next_buffer->current_length = 0;
688 next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000689 return next_buffer;
690}
691
692/* Increases or decreases the packet length.
693 * It does not allocate or deallocate new buffers.
694 * Therefore, the added length must be compatible
695 * with the last buffer. */
696always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400697vlib_buffer_chain_increase_length (vlib_buffer_t * first,
698 vlib_buffer_t * last, i32 len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000699{
700 last->current_length += len;
701 if (first != last)
702 first->total_length_not_including_first_buffer += len;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000703}
704
705/* Copy data to the end of the packet and increases its length.
706 * It does not allocate new buffers.
707 * Returns the number of copied bytes. */
708always_inline u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400709vlib_buffer_chain_append_data (vlib_main_t * vm,
710 u32 free_list_index,
711 vlib_buffer_t * first,
712 vlib_buffer_t * last, void *data, u16 data_len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000713{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400714 u32 n_buffer_bytes =
715 vlib_buffer_free_list_buffer_size (vm, free_list_index);
716 ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
717 u16 len = clib_min (data_len,
718 n_buffer_bytes - last->current_length -
719 last->current_data);
720 clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
721 len);
722 vlib_buffer_chain_increase_length (first, last, len);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000723 return len;
724}
725
726/* Copy data to the end of the packet and increases its length.
727 * Allocates additional buffers from the free list if necessary.
728 * Returns the number of copied bytes.
729 * 'last' value is modified whenever new buffers are allocated and
730 * chained and points to the last buffer in the chain. */
731u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400732vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
733 u32 free_list_index,
734 vlib_buffer_t * first,
735 vlib_buffer_t ** last,
736 void *data, u16 data_len);
737void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000738
Dave Barach9b8ffd92016-07-08 08:13:45 -0400739format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
740 format_vlib_buffer_contents;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700741
Dave Barach9b8ffd92016-07-08 08:13:45 -0400742typedef struct
743{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744 /* Vector of packet data. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400745 u8 *packet_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747 /* Number of buffers to allocate in each call to physmem
748 allocator. */
749 u32 min_n_buffers_each_physmem_alloc;
750
751 /* Buffer free list for this template. */
752 u32 free_list_index;
753
Dave Barach9b8ffd92016-07-08 08:13:45 -0400754 u32 *free_buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755} vlib_packet_template_t;
756
757void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
758 vlib_packet_template_t * t);
759
760void vlib_packet_template_init (vlib_main_t * vm,
761 vlib_packet_template_t * t,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400762 void *packet_data,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700763 uword n_packet_data_bytes,
764 uword min_n_buffers_each_physmem_alloc,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400765 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700766
Dave Barach9b8ffd92016-07-08 08:13:45 -0400767void *vlib_packet_template_get_packet (vlib_main_t * vm,
768 vlib_packet_template_t * t,
769 u32 * bi_result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700770
771always_inline void
772vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
773{
774 vec_free (t->packet_data);
775}
776
777always_inline u32
778unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
779{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400780 serialize_stream_t *s = &m->stream;
781 vlib_serialize_buffer_main_t *sm
782 = uword_to_pointer (m->stream.data_function_opaque,
783 vlib_serialize_buffer_main_t *);
784 vlib_main_t *vm = sm->vlib_main;
785 u32 n, *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700786
787 n = s->n_buffer_bytes - s->current_buffer_index;
788 if (sm->last_buffer != ~0)
789 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400790 vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
792 {
793 b = vlib_get_buffer (vm, b->next_buffer);
794 n += b->current_length;
795 }
796 }
797
Dave Barach9b8ffd92016-07-08 08:13:45 -0400798 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799 clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
800 n += vlib_buffer_index_length_in_chain (vm, f[0]);
801 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400802/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803
804 return n;
805}
806
Ed Warnickecb9cada2015-12-08 15:45:58 -0700807/* Set a buffer quickly into "uninitialized" state. We want this to
808 be extremely cheap and arrange for all fields that need to be
809 initialized to be in the first 128 bits of the buffer. */
810always_inline void
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100811vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812 vlib_buffer_free_list_t * fl)
813{
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100814 vlib_buffer_t *src = &fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815
Damjan Marion19010202016-03-24 17:17:47 +0100816 /* Make sure vlib_buffer_t is cacheline aligned and sized */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400817 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
818 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
819 CLIB_CACHE_LINE_BYTES);
820 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
821 CLIB_CACHE_LINE_BYTES * 2);
Damjan Marion19010202016-03-24 17:17:47 +0100822
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823 /* Make sure buffer template is sane. */
Damjan Marion072401e2017-07-13 18:53:27 +0200824 ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825
Dave Barachf8690282017-03-01 11:38:02 -0500826 clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
827 STRUCT_MARK_PTR (src, template_start),
828 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
829 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
830
831 /* Not in the first 16 octets. */
832 dst->n_add_refs = src->n_add_refs;
833
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834 /* Make sure it really worked. */
Dave Barachf8690282017-03-01 11:38:02 -0500835#define _(f) ASSERT (dst->f == src->f);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400836 _(current_data);
837 _(current_length);
838 _(flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839#undef _
Florin Corasb2215d62017-08-01 16:56:58 -0700840 /* ASSERT (dst->total_length_not_including_first_buffer == 0); */
841 /* total_length_not_including_first_buffer is not in the template anymore
842 * so it may actually not zeroed for some buffers. One option is to
843 * uncomment the line lower (comes at a cost), the other, is to just not
844 * care */
845 /* dst->total_length_not_including_first_buffer = 0; */
Damjan Marionc47ed032017-01-25 14:18:03 +0100846 ASSERT (dst->n_add_refs == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847}
848
849always_inline void
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100850vlib_buffer_add_to_free_list (vlib_main_t * vm,
851 vlib_buffer_free_list_t * f,
852 u32 buffer_index, u8 do_init)
853{
854 vlib_buffer_t *b;
855 b = vlib_get_buffer (vm, buffer_index);
856 if (PREDICT_TRUE (do_init))
857 vlib_buffer_init_for_free_list (b, f);
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100858 vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400859
Damjan Marionb6a8ed72017-08-29 00:15:35 +0200860 if (vec_len (f->buffers) > 4 * VLIB_FRAME_SIZE)
Damjan Marion6b0f5892017-07-27 04:01:24 -0400861 {
Damjan Marionb6a8ed72017-08-29 00:15:35 +0200862 vlib_buffer_free_list_t *mf;
863 mf = vlib_buffer_get_free_list (vlib_mains[0], f->index);
864 clib_spinlock_lock (&mf->global_buffers_lock);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400865 /* keep last stored buffers, as they are more likely hot in the cache */
Damjan Marionb6a8ed72017-08-29 00:15:35 +0200866 vec_add_aligned (mf->global_buffers, f->buffers, VLIB_FRAME_SIZE,
867 CLIB_CACHE_LINE_BYTES);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400868 vec_delete (f->buffers, VLIB_FRAME_SIZE, 0);
Klement Sekera75e974b2017-11-09 09:12:12 +0100869 f->n_alloc -= VLIB_FRAME_SIZE;
Damjan Marionb6a8ed72017-08-29 00:15:35 +0200870 clib_spinlock_unlock (&mf->global_buffers_lock);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400871 }
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100872}
873
874always_inline void
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100875vlib_buffer_init_two_for_free_list (vlib_buffer_t * dst0,
876 vlib_buffer_t * dst1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700877 vlib_buffer_free_list_t * fl)
878{
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100879 vlib_buffer_t *src = &fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880
881 /* Make sure buffer template is sane. */
Damjan Marion072401e2017-07-13 18:53:27 +0200882 ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700883
Dave Barachf8690282017-03-01 11:38:02 -0500884 clib_memcpy (STRUCT_MARK_PTR (dst0, template_start),
885 STRUCT_MARK_PTR (src, template_start),
886 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
887 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
888
889 clib_memcpy (STRUCT_MARK_PTR (dst1, template_start),
890 STRUCT_MARK_PTR (src, template_start),
891 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
892 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
893
894 /* Not in the first 16 octets. */
895 dst0->n_add_refs = src->n_add_refs;
896 dst1->n_add_refs = src->n_add_refs;
897
Ed Warnickecb9cada2015-12-08 15:45:58 -0700898 /* Make sure it really worked. */
Dave Barachf8690282017-03-01 11:38:02 -0500899#define _(f) ASSERT (dst0->f == src->f); ASSERT( dst1->f == src->f)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400900 _(current_data);
901 _(current_length);
902 _(flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903#undef _
Dave Barachf8690282017-03-01 11:38:02 -0500904
905 ASSERT (dst0->total_length_not_including_first_buffer == 0);
906 ASSERT (dst1->total_length_not_including_first_buffer == 0);
Damjan Marionc47ed032017-01-25 14:18:03 +0100907 ASSERT (dst0->n_add_refs == 0);
908 ASSERT (dst1->n_add_refs == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700909}
910
911#if CLIB_DEBUG > 0
Damjan Marion6a7acc22016-12-19 16:28:36 +0100912extern u32 *vlib_buffer_state_validation_lock;
913extern uword *vlib_buffer_state_validation_hash;
914extern void *vlib_buffer_state_heap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915#endif
916
Dave Barach9b8ffd92016-07-08 08:13:45 -0400917static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
919{
920#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400921 uword *p;
922 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700923
924 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
925
926 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
927 ;
928
929 p = hash_get (vlib_buffer_state_validation_hash, b);
930
931 /* If we don't know about b, declare it to be in the expected state */
932 if (!p)
933 {
934 hash_set (vlib_buffer_state_validation_hash, b, expected);
935 goto out;
936 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400937
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938 if (p[0] != expected)
939 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400940 void cj_stop (void);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941 u32 bi;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400942 vlib_main_t *vm = &vlib_global_main;
943
944 cj_stop ();
945
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946 bi = vlib_get_buffer_index (vm, b);
947
948 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400949 clib_warning ("%.6f buffer %llx (%d): %s, not %s",
950 vlib_time_now (vm), bi,
951 p[0] ? "busy" : "free", expected ? "busy" : "free");
952 os_panic ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400954out:
955 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956 *vlib_buffer_state_validation_lock = 0;
957 clib_mem_set_heap (oldheap);
958#endif
959}
960
Dave Barach9b8ffd92016-07-08 08:13:45 -0400961static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700962vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
963{
964#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400965 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700966
967 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
968
969 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
970 ;
971
972 hash_set (vlib_buffer_state_validation_hash, b, expected);
973
Dave Barach9b8ffd92016-07-08 08:13:45 -0400974 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975 *vlib_buffer_state_validation_lock = 0;
976 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400977#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978}
979
980#endif /* included_vlib_buffer_funcs_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400981
982/*
983 * fd.io coding-style-patch-verification: ON
984 *
985 * Local Variables:
986 * eval: (c-set-style "gnu")
987 * End:
988 */