blob: 97442e12239852beccd8bc22bfef60b32522547b [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{
109 uword l = b->current_length + b->total_length_not_including_first_buffer;
110 if (PREDICT_FALSE ((b->flags & (VLIB_BUFFER_NEXT_PRESENT
111 | VLIB_BUFFER_TOTAL_LENGTH_VALID))
112 == VLIB_BUFFER_NEXT_PRESENT))
113 return vlib_buffer_length_in_chain_slow_path (vm, b);
114 return l;
115}
116
117/** \brief Get length in bytes of the buffer index buffer chain
118
119 @param vm - (vlib_main_t *) vlib main data structure pointer
120 @param bi - (u32) buffer index
121 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400122*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123always_inline uword
124vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
125{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400126 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 return vlib_buffer_length_in_chain (vm, b);
128}
129
130/** \brief Copy buffer contents to memory
131
132 @param vm - (vlib_main_t *) vlib main data structure pointer
Chris Luked4024f52016-09-06 09:32:36 -0400133 @param buffer_index - (u32) buffer index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134 @param contents - (u8 *) memory, <strong>must be large enough</strong>
135 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400136*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137always_inline uword
138vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
139{
140 uword content_len = 0;
141 uword l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400142 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143
144 while (1)
145 {
146 b = vlib_get_buffer (vm, buffer_index);
147 l = b->current_length;
Damjan Marionf1213b82016-03-13 02:22:06 +0100148 clib_memcpy (contents + content_len, b->data + b->current_data, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149 content_len += l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400150 if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 break;
152 buffer_index = b->next_buffer;
153 }
154
155 return content_len;
156}
157
158/* Return physical address of buffer->data start. */
159always_inline u64
160vlib_get_buffer_data_physical_address (vlib_main_t * vm, u32 buffer_index)
161{
162 return vlib_physmem_offset_to_physical (&vm->physmem_main,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400163 (((uword) buffer_index) <<
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 CLIB_LOG2_CACHE_LINE_BYTES) +
Dave Barach9b8ffd92016-07-08 08:13:45 -0400165 STRUCT_OFFSET_OF (vlib_buffer_t,
166 data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167}
168
169/** \brief Prefetch buffer metadata by buffer index
170 The first 64 bytes of buffer contains most header information
171
172 @param vm - (vlib_main_t *) vlib main data structure pointer
173 @param bi - (u32) buffer index
174 @param type - LOAD, STORE. In most cases, STORE is the right answer
175*/
176/* Prefetch buffer header given index. */
177#define vlib_prefetch_buffer_with_index(vm,bi,type) \
178 do { \
179 vlib_buffer_t * _b = vlib_get_buffer (vm, bi); \
180 vlib_prefetch_buffer_header (_b, type); \
181 } while (0)
182
183#if 0
184/* Iterate over known allocated vlib bufs. You probably do not want
185 * to do this!
186 @param vm the vlib_main_t
187 @param bi found allocated buffer index
188 @param body operation to perform on buffer index
189 function executes body for each allocated buffer index
190 */
191#define vlib_buffer_foreach_allocated(vm,bi,body) \
192do { \
193 vlib_main_t * _vmain = (vm); \
194 vlib_buffer_main_t * _bmain = &_vmain->buffer_main; \
195 hash_pair_t * _vbpair; \
196 hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({ \
197 if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) { \
198 (bi) = _vbpair->key; \
199 body; \
200 } \
201 })); \
202} while (0)
203#endif
204
Dave Barach9b8ffd92016-07-08 08:13:45 -0400205typedef enum
206{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 /* Index is unknown. */
208 VLIB_BUFFER_UNKNOWN,
209
210 /* Index is known and free/allocated. */
211 VLIB_BUFFER_KNOWN_FREE,
212 VLIB_BUFFER_KNOWN_ALLOCATED,
213} vlib_buffer_known_state_t;
214
215always_inline vlib_buffer_known_state_t
216vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
217{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400218 vlib_buffer_main_t *bm = vm->buffer_main;
Damjan Marion586afd72017-04-05 19:18:20 +0200219 ASSERT (vlib_get_thread_index () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220
Dave Barach9b8ffd92016-07-08 08:13:45 -0400221 uword *p = hash_get (bm->buffer_known_hash, buffer_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222 return p ? p[0] : VLIB_BUFFER_UNKNOWN;
223}
224
225always_inline void
226vlib_buffer_set_known_state (vlib_main_t * vm,
227 u32 buffer_index,
228 vlib_buffer_known_state_t state)
229{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400230 vlib_buffer_main_t *bm = vm->buffer_main;
Damjan Marion586afd72017-04-05 19:18:20 +0200231 ASSERT (vlib_get_thread_index () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232 hash_set (bm->buffer_known_hash, buffer_index, state);
233}
234
235/* Validates sanity of a single buffer.
236 Returns format'ed vector with error message if any. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400237u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
238 uword follow_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240/** \brief Allocate buffers into supplied array
241
242 @param vm - (vlib_main_t *) vlib main data structure pointer
243 @param buffers - (u32 * ) buffer index array
244 @param n_buffers - (u32) number of buffers requested
Dave Barach9b8ffd92016-07-08 08:13:45 -0400245 @return - (u32) number of buffers actually allocated, may be
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 less than the number requested or zero
247*/
Damjan Marion878c6092017-01-04 13:19:27 +0100248always_inline u32
249vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
250{
251 vlib_buffer_main_t *bm = vm->buffer_main;
252
253 ASSERT (bm->cb.vlib_buffer_alloc_cb);
254
255 return bm->cb.vlib_buffer_alloc_cb (vm, buffers, n_buffers);
256}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257
258always_inline u32
259vlib_buffer_round_size (u32 size)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400260{
261 return round_pow2 (size, sizeof (vlib_buffer_t));
262}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263
264/** \brief Allocate buffers from specific freelist into supplied array
265
266 @param vm - (vlib_main_t *) vlib main data structure pointer
267 @param buffers - (u32 * ) buffer index array
268 @param n_buffers - (u32) number of buffers requested
Dave Barach9b8ffd92016-07-08 08:13:45 -0400269 @return - (u32) number of buffers actually allocated, may be
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270 less than the number requested or zero
271*/
Damjan Marion878c6092017-01-04 13:19:27 +0100272always_inline u32
273vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
274 u32 * buffers,
275 u32 n_buffers, u32 free_list_index)
276{
277 vlib_buffer_main_t *bm = vm->buffer_main;
278
279 ASSERT (bm->cb.vlib_buffer_alloc_from_free_list_cb);
280
281 return bm->cb.vlib_buffer_alloc_from_free_list_cb (vm, buffers, n_buffers,
282 free_list_index);
283}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284
285/** \brief Free buffers
286 Frees the entire buffer chain for each buffer
287
288 @param vm - (vlib_main_t *) vlib main data structure pointer
289 @param buffers - (u32 * ) buffer index array
290 @param n_buffers - (u32) number of buffers to free
291
292*/
Damjan Marion878c6092017-01-04 13:19:27 +0100293always_inline void
294vlib_buffer_free (vlib_main_t * vm,
295 /* pointer to first buffer */
296 u32 * buffers,
297 /* number of buffers to free */
298 u32 n_buffers)
299{
300 vlib_buffer_main_t *bm = vm->buffer_main;
301
302 ASSERT (bm->cb.vlib_buffer_free_cb);
303
304 return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
305}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
307/** \brief Free buffers, does not free the 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*/
Damjan Marion878c6092017-01-04 13:19:27 +0100314always_inline void
315vlib_buffer_free_no_next (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_no_next_cb);
324
325 return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
326}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327
328/** \brief Free one buffer
Dave Barach9b8ffd92016-07-08 08:13:45 -0400329 Shorthand to free a single buffer chain.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330
331 @param vm - (vlib_main_t *) vlib main data structure pointer
332 @param buffer_index - (u32) buffer index to free
333*/
334always_inline void
335vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
336{
337 vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
338}
339
340/* Add/delete buffer free lists. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400341u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
342 char *fmt, ...);
Damjan Marion878c6092017-01-04 13:19:27 +0100343always_inline void
344vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
345{
346 vlib_buffer_main_t *bm = vm->buffer_main;
347
348 ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
349
350 bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
351}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
353/* Find already existing public free list with given size or create one. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400354u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
355 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100357/* Merge two free lists */
358void vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
359 vlib_buffer_free_list_t * src);
360
361/* Make sure we have at least given number of unaligned buffers. */
362void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
363 vlib_buffer_free_list_t *
364 free_list,
365 uword n_unaligned_buffers);
366
367always_inline u32
368vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
369{
370 vlib_buffer_main_t *bm = vm->buffer_main;
371
372 size = vlib_buffer_round_size (size);
373 uword *p = hash_get (bm->free_list_by_size, size);
374 return p ? p[0] : ~0;
375}
376
377always_inline vlib_buffer_free_list_t *
378vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
379 u32 * index)
380{
381 vlib_buffer_main_t *bm = vm->buffer_main;
382 u32 i;
383
384 *index = i = b->free_list_index;
385 return pool_elt_at_index (bm->buffer_free_list_pool, i);
386}
387
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388always_inline vlib_buffer_free_list_t *
389vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
390{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400391 vlib_buffer_main_t *bm = vm->buffer_main;
392 vlib_buffer_free_list_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393
394 f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
395
396 /* Sanity: indices must match. */
397 ASSERT (f->index == free_list_index);
398
399 return f;
400}
401
402always_inline u32
403vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
404{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400405 vlib_buffer_free_list_t *f =
406 vlib_buffer_get_free_list (vm, free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407 return f->n_data_bytes;
408}
409
Dave Barach9b8ffd92016-07-08 08:13:45 -0400410void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700411
412/* Reasonably fast buffer copy routine. */
413always_inline void
414vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
415{
416 while (n >= 4)
417 {
418 dst[0] = src[0];
419 dst[1] = src[1];
420 dst[2] = src[2];
421 dst[3] = src[3];
422 dst += 4;
423 src += 4;
424 n -= 4;
425 }
426 while (n > 0)
427 {
428 dst[0] = src[0];
429 dst += 1;
430 src += 1;
431 n -= 1;
432 }
433}
434
435always_inline void *
436vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
437 uword n_bytes, uword alignment)
438{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400439 void *r =
440 vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
441 if (!r)
442 *error =
443 clib_error_return (0, "failed to allocate %wd bytes of I/O memory",
444 n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700445 else
446 *error = 0;
447 return r;
448}
449
450/* By default allocate I/O memory with cache line alignment. */
451always_inline void *
452vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400453{
454 return vlib_physmem_alloc_aligned (vm, error, n_bytes,
455 CLIB_CACHE_LINE_BYTES);
456}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457
458always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400459vlib_physmem_free (vlib_main_t * vm, void *mem)
460{
461 return vm->os_physmem_free (mem);
462}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700463
464always_inline u64
Dave Barach9b8ffd92016-07-08 08:13:45 -0400465vlib_physmem_virtual_to_physical (vlib_main_t * vm, void *mem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400467 vlib_physmem_main_t *pm = &vm->physmem_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468 uword o = pointer_to_uword (mem) - pm->virtual.start;
469 return vlib_physmem_offset_to_physical (pm, o);
470}
471
472/* Append given data to end of buffer, possibly allocating new buffers. */
473u32 vlib_buffer_add_data (vlib_main_t * vm,
474 u32 free_list_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400475 u32 buffer_index, void *data, u32 n_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100477/* duplicate all buffers in chain */
478always_inline vlib_buffer_t *
479vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
480{
481 vlib_buffer_t *s, *d, *fd;
482 uword n_alloc, n_buffers = 1;
Damjan Marion67655492016-11-15 12:50:28 +0100483 u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100484 int i;
485
486 s = b;
487 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
488 {
489 n_buffers++;
490 s = vlib_get_buffer (vm, s->next_buffer);
491 }
Neale Ranns9d676af2017-03-15 01:28:31 -0700492 u32 new_buffers[n_buffers];
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100493
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100494 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
Dave Barach26cd8c12017-02-23 17:11:26 -0500495
496 /* No guarantee that we'll get all the buffers we asked for */
497 if (PREDICT_FALSE (n_alloc < n_buffers))
498 {
499 if (n_alloc > 0)
500 vlib_buffer_free (vm, new_buffers, n_alloc);
Dave Barach26cd8c12017-02-23 17:11:26 -0500501 return 0;
502 }
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100503
504 /* 1st segment */
505 s = b;
506 fd = d = vlib_get_buffer (vm, new_buffers[0]);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100507 d->current_data = s->current_data;
508 d->current_length = s->current_length;
Damjan Marion67655492016-11-15 12:50:28 +0100509 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100510 d->total_length_not_including_first_buffer =
511 s->total_length_not_including_first_buffer;
512 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
Damjan Mariondce05452016-12-01 11:59:33 +0100513 clib_memcpy (vlib_buffer_get_current (d),
514 vlib_buffer_get_current (s), s->current_length);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100515
516 /* next segments */
517 for (i = 1; i < n_buffers; i++)
518 {
519 /* previous */
520 d->next_buffer = new_buffers[i];
521 /* current */
522 s = vlib_get_buffer (vm, s->next_buffer);
523 d = vlib_get_buffer (vm, new_buffers[i]);
524 d->current_data = s->current_data;
525 d->current_length = s->current_length;
526 clib_memcpy (vlib_buffer_get_current (d),
527 vlib_buffer_get_current (s), s->current_length);
Damjan Marion67655492016-11-15 12:50:28 +0100528 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100529 }
530
531 return fd;
532}
533
Damjan Marionc47ed032017-01-25 14:18:03 +0100534/** \brief Create multiple clones of buffer and store them in the supplied array
535
536 @param vm - (vlib_main_t *) vlib main data structure pointer
537 @param src_buffer - (u32) source buffer index
538 @param buffers - (u32 * ) buffer index array
539 @param n_buffers - (u8) number of buffer clones requested
540 @param head_end_offset - (u16) offset relative to current position
541 where packet head ends
542 @return - (u8) number of buffers actually cloned, may be
543 less than the number requested or zero
544*/
545
546always_inline u8
547vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
548 u8 n_buffers, u16 head_end_offset)
549{
550 u8 i;
551 vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
552
553 ASSERT (s->n_add_refs == 0);
554 ASSERT (n_buffers);
555
556 if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
557 {
558 buffers[0] = src_buffer;
559 for (i = 1; i < n_buffers; i++)
560 {
561 vlib_buffer_t *d;
562 d = vlib_buffer_copy (vm, s);
563 if (d == 0)
564 return i;
565 buffers[i] = vlib_get_buffer_index (vm, d);
566
567 }
568 return n_buffers;
569 }
570
571 n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
572 s->free_list_index);
573 if (PREDICT_FALSE (n_buffers == 0))
574 {
575 buffers[0] = src_buffer;
576 return 1;
577 }
578
579 for (i = 0; i < n_buffers; i++)
580 {
581 vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
582 d->current_data = s->current_data;
583 d->current_length = head_end_offset;
584 d->free_list_index = s->free_list_index;
585 d->total_length_not_including_first_buffer =
586 s->total_length_not_including_first_buffer + s->current_length -
587 head_end_offset;
588 d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
589 d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
590 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
591 clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
592 head_end_offset);
593 d->next_buffer = src_buffer;
594 }
595 vlib_buffer_advance (s, head_end_offset);
596 s->n_add_refs = n_buffers - 1;
597 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
598 {
599 s = vlib_get_buffer (vm, s->next_buffer);
600 s->n_add_refs = n_buffers - 1;
601 }
602
603 return n_buffers;
604}
605
606/** \brief Attach cloned tail to the buffer
607
608 @param vm - (vlib_main_t *) vlib main data structure pointer
609 @param head - (vlib_buffer_t *) head buffer
610 @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
611*/
612
613always_inline void
614vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
615 vlib_buffer_t * tail)
616{
617 ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
618 ASSERT (head->free_list_index == tail->free_list_index);
619
620 head->flags |= VLIB_BUFFER_NEXT_PRESENT;
621 head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
622 head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
623 head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
624 head->next_buffer = vlib_get_buffer_index (vm, tail);
625 head->total_length_not_including_first_buffer = tail->current_length +
626 tail->total_length_not_including_first_buffer;
627
628next_segment:
629 __sync_add_and_fetch (&tail->n_add_refs, 1);
630
631 if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
632 {
633 tail = vlib_get_buffer (vm, tail->next_buffer);
634 goto next_segment;
635 }
636}
637
Pierre Pfister328e99b2016-02-12 13:18:42 +0000638/* Initializes the buffer as an empty packet with no chained buffers. */
639always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400640vlib_buffer_chain_init (vlib_buffer_t * first)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000641{
642 first->total_length_not_including_first_buffer = 0;
643 first->current_length = 0;
644 first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
645 first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000646}
647
648/* The provided next_bi buffer index is appended to the end of the packet. */
649always_inline vlib_buffer_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400650vlib_buffer_chain_buffer (vlib_main_t * vm,
651 vlib_buffer_t * first,
652 vlib_buffer_t * last, u32 next_bi)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000653{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400654 vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000655 last->next_buffer = next_bi;
656 last->flags |= VLIB_BUFFER_NEXT_PRESENT;
657 next_buffer->current_length = 0;
658 next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000659 return next_buffer;
660}
661
662/* Increases or decreases the packet length.
663 * It does not allocate or deallocate new buffers.
664 * Therefore, the added length must be compatible
665 * with the last buffer. */
666always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400667vlib_buffer_chain_increase_length (vlib_buffer_t * first,
668 vlib_buffer_t * last, i32 len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000669{
670 last->current_length += len;
671 if (first != last)
672 first->total_length_not_including_first_buffer += len;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000673}
674
675/* Copy data to the end of the packet and increases its length.
676 * It does not allocate new buffers.
677 * Returns the number of copied bytes. */
678always_inline u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400679vlib_buffer_chain_append_data (vlib_main_t * vm,
680 u32 free_list_index,
681 vlib_buffer_t * first,
682 vlib_buffer_t * last, void *data, u16 data_len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000683{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400684 u32 n_buffer_bytes =
685 vlib_buffer_free_list_buffer_size (vm, free_list_index);
686 ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
687 u16 len = clib_min (data_len,
688 n_buffer_bytes - last->current_length -
689 last->current_data);
690 clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
691 len);
692 vlib_buffer_chain_increase_length (first, last, len);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000693 return len;
694}
695
696/* Copy data to the end of the packet and increases its length.
697 * Allocates additional buffers from the free list if necessary.
698 * Returns the number of copied bytes.
699 * 'last' value is modified whenever new buffers are allocated and
700 * chained and points to the last buffer in the chain. */
701u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400702vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
703 u32 free_list_index,
704 vlib_buffer_t * first,
705 vlib_buffer_t ** last,
706 void *data, u16 data_len);
707void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000708
Dave Barach9b8ffd92016-07-08 08:13:45 -0400709format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
710 format_vlib_buffer_contents;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711
Dave Barach9b8ffd92016-07-08 08:13:45 -0400712typedef struct
713{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714 /* Vector of packet data. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400715 u8 *packet_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717 /* Number of buffers to allocate in each call to physmem
718 allocator. */
719 u32 min_n_buffers_each_physmem_alloc;
720
721 /* Buffer free list for this template. */
722 u32 free_list_index;
723
Dave Barach9b8ffd92016-07-08 08:13:45 -0400724 u32 *free_buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725} vlib_packet_template_t;
726
727void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
728 vlib_packet_template_t * t);
729
730void vlib_packet_template_init (vlib_main_t * vm,
731 vlib_packet_template_t * t,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400732 void *packet_data,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733 uword n_packet_data_bytes,
734 uword min_n_buffers_each_physmem_alloc,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400735 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736
Dave Barach9b8ffd92016-07-08 08:13:45 -0400737void *vlib_packet_template_get_packet (vlib_main_t * vm,
738 vlib_packet_template_t * t,
739 u32 * bi_result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740
741always_inline void
742vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
743{
744 vec_free (t->packet_data);
745}
746
747always_inline u32
748unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
749{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400750 serialize_stream_t *s = &m->stream;
751 vlib_serialize_buffer_main_t *sm
752 = uword_to_pointer (m->stream.data_function_opaque,
753 vlib_serialize_buffer_main_t *);
754 vlib_main_t *vm = sm->vlib_main;
755 u32 n, *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756
757 n = s->n_buffer_bytes - s->current_buffer_index;
758 if (sm->last_buffer != ~0)
759 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400760 vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700761 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
762 {
763 b = vlib_get_buffer (vm, b->next_buffer);
764 n += b->current_length;
765 }
766 }
767
Dave Barach9b8ffd92016-07-08 08:13:45 -0400768 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700769 clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
770 n += vlib_buffer_index_length_in_chain (vm, f[0]);
771 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400772/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700773
774 return n;
775}
776
Ed Warnickecb9cada2015-12-08 15:45:58 -0700777/* Set a buffer quickly into "uninitialized" state. We want this to
778 be extremely cheap and arrange for all fields that need to be
779 initialized to be in the first 128 bits of the buffer. */
780always_inline void
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100781vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700782 vlib_buffer_free_list_t * fl)
783{
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100784 vlib_buffer_t *src = &fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700785
Damjan Marion19010202016-03-24 17:17:47 +0100786 /* Make sure vlib_buffer_t is cacheline aligned and sized */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400787 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
788 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
789 CLIB_CACHE_LINE_BYTES);
790 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
791 CLIB_CACHE_LINE_BYTES * 2);
Damjan Marion19010202016-03-24 17:17:47 +0100792
Ed Warnickecb9cada2015-12-08 15:45:58 -0700793 /* Make sure buffer template is sane. */
794 ASSERT (fl->index == fl->buffer_init_template.free_list_index);
795
Dave Barachf8690282017-03-01 11:38:02 -0500796 clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
797 STRUCT_MARK_PTR (src, template_start),
798 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
799 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
800
801 /* Not in the first 16 octets. */
802 dst->n_add_refs = src->n_add_refs;
803
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804 /* Make sure it really worked. */
Dave Barachf8690282017-03-01 11:38:02 -0500805#define _(f) ASSERT (dst->f == src->f);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400806 _(current_data);
807 _(current_length);
808 _(flags);
809 _(free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810#undef _
Dave Barachf8690282017-03-01 11:38:02 -0500811 ASSERT (dst->total_length_not_including_first_buffer == 0);
Damjan Marionc47ed032017-01-25 14:18:03 +0100812 ASSERT (dst->n_add_refs == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700813}
814
815always_inline void
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100816vlib_buffer_add_to_free_list (vlib_main_t * vm,
817 vlib_buffer_free_list_t * f,
818 u32 buffer_index, u8 do_init)
819{
820 vlib_buffer_t *b;
821 b = vlib_get_buffer (vm, buffer_index);
822 if (PREDICT_TRUE (do_init))
823 vlib_buffer_init_for_free_list (b, f);
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100824 vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100825}
826
827always_inline void
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100828vlib_buffer_init_two_for_free_list (vlib_buffer_t * dst0,
829 vlib_buffer_t * dst1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830 vlib_buffer_free_list_t * fl)
831{
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100832 vlib_buffer_t *src = &fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700833
834 /* Make sure buffer template is sane. */
835 ASSERT (fl->index == fl->buffer_init_template.free_list_index);
836
Dave Barachf8690282017-03-01 11:38:02 -0500837 clib_memcpy (STRUCT_MARK_PTR (dst0, template_start),
838 STRUCT_MARK_PTR (src, template_start),
839 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
840 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
841
842 clib_memcpy (STRUCT_MARK_PTR (dst1, template_start),
843 STRUCT_MARK_PTR (src, template_start),
844 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
845 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
846
847 /* Not in the first 16 octets. */
848 dst0->n_add_refs = src->n_add_refs;
849 dst1->n_add_refs = src->n_add_refs;
850
Ed Warnickecb9cada2015-12-08 15:45:58 -0700851 /* Make sure it really worked. */
Dave Barachf8690282017-03-01 11:38:02 -0500852#define _(f) ASSERT (dst0->f == src->f); ASSERT( dst1->f == src->f)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400853 _(current_data);
854 _(current_length);
855 _(flags);
856 _(free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857#undef _
Dave Barachf8690282017-03-01 11:38:02 -0500858
859 ASSERT (dst0->total_length_not_including_first_buffer == 0);
860 ASSERT (dst1->total_length_not_including_first_buffer == 0);
Damjan Marionc47ed032017-01-25 14:18:03 +0100861 ASSERT (dst0->n_add_refs == 0);
862 ASSERT (dst1->n_add_refs == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863}
864
865#if CLIB_DEBUG > 0
Damjan Marion6a7acc22016-12-19 16:28:36 +0100866extern u32 *vlib_buffer_state_validation_lock;
867extern uword *vlib_buffer_state_validation_hash;
868extern void *vlib_buffer_state_heap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869#endif
870
Dave Barach9b8ffd92016-07-08 08:13:45 -0400871static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
873{
874#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400875 uword *p;
876 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700877
878 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
879
880 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
881 ;
882
883 p = hash_get (vlib_buffer_state_validation_hash, b);
884
885 /* If we don't know about b, declare it to be in the expected state */
886 if (!p)
887 {
888 hash_set (vlib_buffer_state_validation_hash, b, expected);
889 goto out;
890 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400891
Ed Warnickecb9cada2015-12-08 15:45:58 -0700892 if (p[0] != expected)
893 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400894 void cj_stop (void);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700895 u32 bi;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400896 vlib_main_t *vm = &vlib_global_main;
897
898 cj_stop ();
899
Ed Warnickecb9cada2015-12-08 15:45:58 -0700900 bi = vlib_get_buffer_index (vm, b);
901
902 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400903 clib_warning ("%.6f buffer %llx (%d): %s, not %s",
904 vlib_time_now (vm), bi,
905 p[0] ? "busy" : "free", expected ? "busy" : "free");
906 os_panic ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400908out:
909 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910 *vlib_buffer_state_validation_lock = 0;
911 clib_mem_set_heap (oldheap);
912#endif
913}
914
Dave Barach9b8ffd92016-07-08 08:13:45 -0400915static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
917{
918#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400919 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700920
921 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
922
923 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
924 ;
925
926 hash_set (vlib_buffer_state_validation_hash, b, expected);
927
Dave Barach9b8ffd92016-07-08 08:13:45 -0400928 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700929 *vlib_buffer_state_validation_lock = 0;
930 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400931#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700932}
933
934#endif /* included_vlib_buffer_funcs_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400935
936/*
937 * fd.io coding-style-patch-verification: ON
938 *
939 * Local Variables:
940 * eval: (c-set-style "gnu")
941 * End:
942 */