blob: 75716eca7f66ce2d6dc115e6906239e4b25dcaf5 [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{
Dave Barach9b8ffd92016-07-08 08:13:45 -040059 return vlib_physmem_at_offset (&vm->physmem_main, ((uword) buffer_index)
60 << CLIB_LOG2_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -070061}
62
63/** \brief Translate buffer pointer into buffer index
64
65 @param vm - (vlib_main_t *) vlib main data structure pointer
Chris Luked4024f52016-09-06 09:32:36 -040066 @param p - (void *) buffer pointer
Ed Warnickecb9cada2015-12-08 15:45:58 -070067 @return - (u32) buffer index
Dave Barach9b8ffd92016-07-08 08:13:45 -040068*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070069always_inline u32
Dave Barach9b8ffd92016-07-08 08:13:45 -040070vlib_get_buffer_index (vlib_main_t * vm, void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -070071{
72 uword offset = vlib_physmem_offset_of (&vm->physmem_main, p);
Dave Barach9b8ffd92016-07-08 08:13:45 -040073 ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070074 return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
75}
76
77/** \brief Get next buffer in buffer linklist, or zero for end of list.
78
79 @param vm - (vlib_main_t *) vlib main data structure pointer
80 @param b - (void *) buffer pointer
81 @return - (vlib_buffer_t *) next buffer, or NULL
Dave Barach9b8ffd92016-07-08 08:13:45 -040082*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070083always_inline vlib_buffer_t *
84vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
85{
86 return (b->flags & VLIB_BUFFER_NEXT_PRESENT
Dave Barach9b8ffd92016-07-08 08:13:45 -040087 ? vlib_get_buffer (vm, b->next_buffer) : 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070088}
89
Dave Barach9b8ffd92016-07-08 08:13:45 -040090uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
91 vlib_buffer_t * b_first);
Ed Warnickecb9cada2015-12-08 15:45:58 -070092
93/** \brief Get length in bytes of the buffer chain
94
95 @param vm - (vlib_main_t *) vlib main data structure pointer
96 @param b - (void *) buffer pointer
97 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -040098*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070099always_inline uword
100vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
101{
102 uword l = b->current_length + b->total_length_not_including_first_buffer;
103 if (PREDICT_FALSE ((b->flags & (VLIB_BUFFER_NEXT_PRESENT
104 | VLIB_BUFFER_TOTAL_LENGTH_VALID))
105 == VLIB_BUFFER_NEXT_PRESENT))
106 return vlib_buffer_length_in_chain_slow_path (vm, b);
107 return l;
108}
109
110/** \brief Get length in bytes of the buffer index buffer chain
111
112 @param vm - (vlib_main_t *) vlib main data structure pointer
113 @param bi - (u32) buffer index
114 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400115*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116always_inline uword
117vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
118{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400119 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120 return vlib_buffer_length_in_chain (vm, b);
121}
122
123/** \brief Copy buffer contents to memory
124
125 @param vm - (vlib_main_t *) vlib main data structure pointer
Chris Luked4024f52016-09-06 09:32:36 -0400126 @param buffer_index - (u32) buffer index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 @param contents - (u8 *) memory, <strong>must be large enough</strong>
128 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400129*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130always_inline uword
131vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
132{
133 uword content_len = 0;
134 uword l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400135 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
137 while (1)
138 {
139 b = vlib_get_buffer (vm, buffer_index);
140 l = b->current_length;
Damjan Marionf1213b82016-03-13 02:22:06 +0100141 clib_memcpy (contents + content_len, b->data + b->current_data, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142 content_len += l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400143 if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144 break;
145 buffer_index = b->next_buffer;
146 }
147
148 return content_len;
149}
150
151/* Return physical address of buffer->data start. */
152always_inline u64
153vlib_get_buffer_data_physical_address (vlib_main_t * vm, u32 buffer_index)
154{
155 return vlib_physmem_offset_to_physical (&vm->physmem_main,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400156 (((uword) buffer_index) <<
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157 CLIB_LOG2_CACHE_LINE_BYTES) +
Dave Barach9b8ffd92016-07-08 08:13:45 -0400158 STRUCT_OFFSET_OF (vlib_buffer_t,
159 data));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160}
161
162/** \brief Prefetch buffer metadata by buffer index
163 The first 64 bytes of buffer contains most header information
164
165 @param vm - (vlib_main_t *) vlib main data structure pointer
166 @param bi - (u32) buffer index
167 @param type - LOAD, STORE. In most cases, STORE is the right answer
168*/
169/* Prefetch buffer header given index. */
170#define vlib_prefetch_buffer_with_index(vm,bi,type) \
171 do { \
172 vlib_buffer_t * _b = vlib_get_buffer (vm, bi); \
173 vlib_prefetch_buffer_header (_b, type); \
174 } while (0)
175
176#if 0
177/* Iterate over known allocated vlib bufs. You probably do not want
178 * to do this!
179 @param vm the vlib_main_t
180 @param bi found allocated buffer index
181 @param body operation to perform on buffer index
182 function executes body for each allocated buffer index
183 */
184#define vlib_buffer_foreach_allocated(vm,bi,body) \
185do { \
186 vlib_main_t * _vmain = (vm); \
187 vlib_buffer_main_t * _bmain = &_vmain->buffer_main; \
188 hash_pair_t * _vbpair; \
189 hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({ \
190 if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) { \
191 (bi) = _vbpair->key; \
192 body; \
193 } \
194 })); \
195} while (0)
196#endif
197
198#if DPDK == 0
199
Dave Barach9b8ffd92016-07-08 08:13:45 -0400200typedef enum
201{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 /* Index is unknown. */
203 VLIB_BUFFER_UNKNOWN,
204
205 /* Index is known and free/allocated. */
206 VLIB_BUFFER_KNOWN_FREE,
207 VLIB_BUFFER_KNOWN_ALLOCATED,
208} vlib_buffer_known_state_t;
209
210always_inline vlib_buffer_known_state_t
211vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
212{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400213 vlib_buffer_main_t *bm = vm->buffer_main;
214 ASSERT (os_get_cpu_number () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215
Dave Barach9b8ffd92016-07-08 08:13:45 -0400216 uword *p = hash_get (bm->buffer_known_hash, buffer_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217 return p ? p[0] : VLIB_BUFFER_UNKNOWN;
218}
219
220always_inline void
221vlib_buffer_set_known_state (vlib_main_t * vm,
222 u32 buffer_index,
223 vlib_buffer_known_state_t state)
224{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400225 vlib_buffer_main_t *bm = vm->buffer_main;
226 ASSERT (os_get_cpu_number () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227 hash_set (bm->buffer_known_hash, buffer_index, state);
228}
229
230/* Validates sanity of a single buffer.
231 Returns format'ed vector with error message if any. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400232u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
233 uword follow_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235#endif /* DPDK == 0 */
236
Dave Barach9b8ffd92016-07-08 08:13:45 -0400237clib_error_t *vlib_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
238 unsigned socket_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239
240/** \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*/
248u32 vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers);
249
250always_inline u32
251vlib_buffer_round_size (u32 size)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400252{
253 return round_pow2 (size, sizeof (vlib_buffer_t));
254}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255
256/** \brief Allocate buffers from specific freelist into supplied array
257
258 @param vm - (vlib_main_t *) vlib main data structure pointer
259 @param buffers - (u32 * ) buffer index array
260 @param n_buffers - (u32) number of buffers requested
Dave Barach9b8ffd92016-07-08 08:13:45 -0400261 @return - (u32) number of buffers actually allocated, may be
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262 less than the number requested or zero
263*/
264u32 vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
265 u32 * buffers,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400266 u32 n_buffers, u32 free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
268/** \brief Free buffers
269 Frees the entire buffer chain for each buffer
270
271 @param vm - (vlib_main_t *) vlib main data structure pointer
272 @param buffers - (u32 * ) buffer index array
273 @param n_buffers - (u32) number of buffers to free
274
275*/
276void vlib_buffer_free (vlib_main_t * vm,
277 /* pointer to first buffer */
278 u32 * buffers,
279 /* number of buffers to free */
280 u32 n_buffers);
281
282/** \brief Free buffers, does not free the buffer chain for each buffer
283
284 @param vm - (vlib_main_t *) vlib main data structure pointer
285 @param buffers - (u32 * ) buffer index array
286 @param n_buffers - (u32) number of buffers to free
287
288*/
289void vlib_buffer_free_no_next (vlib_main_t * vm,
290 /* pointer to first buffer */
291 u32 * buffers,
292 /* number of buffers to free */
293 u32 n_buffers);
294
295/** \brief Free one buffer
Dave Barach9b8ffd92016-07-08 08:13:45 -0400296 Shorthand to free a single buffer chain.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297
298 @param vm - (vlib_main_t *) vlib main data structure pointer
299 @param buffer_index - (u32) buffer index to free
300*/
301always_inline void
302vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
303{
304 vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
305}
306
307/* Add/delete buffer free lists. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400308u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
309 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700310void vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index);
311
312/* Find already existing public free list with given size or create one. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400313u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
314 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315
316always_inline vlib_buffer_free_list_t *
317vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
318{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400319 vlib_buffer_main_t *bm = vm->buffer_main;
320 vlib_buffer_free_list_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700321
322 f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
323
324 /* Sanity: indices must match. */
325 ASSERT (f->index == free_list_index);
326
327 return f;
328}
329
330always_inline u32
331vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
332{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400333 vlib_buffer_free_list_t *f =
334 vlib_buffer_get_free_list (vm, free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335 return f->n_data_bytes;
336}
337
Dave Barach9b8ffd92016-07-08 08:13:45 -0400338void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
340/* Reasonably fast buffer copy routine. */
341always_inline void
342vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
343{
344 while (n >= 4)
345 {
346 dst[0] = src[0];
347 dst[1] = src[1];
348 dst[2] = src[2];
349 dst[3] = src[3];
350 dst += 4;
351 src += 4;
352 n -= 4;
353 }
354 while (n > 0)
355 {
356 dst[0] = src[0];
357 dst += 1;
358 src += 1;
359 n -= 1;
360 }
361}
362
363always_inline void *
364vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
365 uword n_bytes, uword alignment)
366{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400367 void *r =
368 vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
369 if (!r)
370 *error =
371 clib_error_return (0, "failed to allocate %wd bytes of I/O memory",
372 n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373 else
374 *error = 0;
375 return r;
376}
377
378/* By default allocate I/O memory with cache line alignment. */
379always_inline void *
380vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400381{
382 return vlib_physmem_alloc_aligned (vm, error, n_bytes,
383 CLIB_CACHE_LINE_BYTES);
384}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385
386always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400387vlib_physmem_free (vlib_main_t * vm, void *mem)
388{
389 return vm->os_physmem_free (mem);
390}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391
392always_inline u64
Dave Barach9b8ffd92016-07-08 08:13:45 -0400393vlib_physmem_virtual_to_physical (vlib_main_t * vm, void *mem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400395 vlib_physmem_main_t *pm = &vm->physmem_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 uword o = pointer_to_uword (mem) - pm->virtual.start;
397 return vlib_physmem_offset_to_physical (pm, o);
398}
399
400/* Append given data to end of buffer, possibly allocating new buffers. */
401u32 vlib_buffer_add_data (vlib_main_t * vm,
402 u32 free_list_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400403 u32 buffer_index, void *data, u32 n_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100405/* duplicate all buffers in chain */
406always_inline vlib_buffer_t *
407vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
408{
409 vlib_buffer_t *s, *d, *fd;
410 uword n_alloc, n_buffers = 1;
411 u32 *new_buffers = 0;
Damjan Marion67655492016-11-15 12:50:28 +0100412 u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100413 int i;
414
415 s = b;
416 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
417 {
418 n_buffers++;
419 s = vlib_get_buffer (vm, s->next_buffer);
420 }
421
422 vec_validate (new_buffers, n_buffers - 1);
423 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
424 ASSERT (n_alloc == n_buffers);
425
426 /* 1st segment */
427 s = b;
428 fd = d = vlib_get_buffer (vm, new_buffers[0]);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100429 d->current_data = s->current_data;
430 d->current_length = s->current_length;
Damjan Marion67655492016-11-15 12:50:28 +0100431 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100432 d->total_length_not_including_first_buffer =
433 s->total_length_not_including_first_buffer;
434 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
Damjan Mariondce05452016-12-01 11:59:33 +0100435 clib_memcpy (vlib_buffer_get_current (d),
436 vlib_buffer_get_current (s), s->current_length);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100437
438 /* next segments */
439 for (i = 1; i < n_buffers; i++)
440 {
441 /* previous */
442 d->next_buffer = new_buffers[i];
443 /* current */
444 s = vlib_get_buffer (vm, s->next_buffer);
445 d = vlib_get_buffer (vm, new_buffers[i]);
446 d->current_data = s->current_data;
447 d->current_length = s->current_length;
448 clib_memcpy (vlib_buffer_get_current (d),
449 vlib_buffer_get_current (s), s->current_length);
Damjan Marion67655492016-11-15 12:50:28 +0100450 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100451 }
452
453 return fd;
454}
455
Pierre Pfister328e99b2016-02-12 13:18:42 +0000456/*
457 * vlib_buffer_chain_* functions provide a way to create long buffers.
458 * When DPDK is enabled, the 'hidden' DPDK header is taken care of transparently.
459 */
460
461/* Initializes the buffer as an empty packet with no chained buffers. */
462always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400463vlib_buffer_chain_init (vlib_buffer_t * first)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000464{
465 first->total_length_not_including_first_buffer = 0;
466 first->current_length = 0;
467 first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
468 first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000469}
470
471/* The provided next_bi buffer index is appended to the end of the packet. */
472always_inline vlib_buffer_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400473vlib_buffer_chain_buffer (vlib_main_t * vm,
474 vlib_buffer_t * first,
475 vlib_buffer_t * last, u32 next_bi)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000476{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400477 vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000478 last->next_buffer = next_bi;
479 last->flags |= VLIB_BUFFER_NEXT_PRESENT;
480 next_buffer->current_length = 0;
481 next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000482 return next_buffer;
483}
484
485/* Increases or decreases the packet length.
486 * It does not allocate or deallocate new buffers.
487 * Therefore, the added length must be compatible
488 * with the last buffer. */
489always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400490vlib_buffer_chain_increase_length (vlib_buffer_t * first,
491 vlib_buffer_t * last, i32 len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000492{
493 last->current_length += len;
494 if (first != last)
495 first->total_length_not_including_first_buffer += len;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000496}
497
498/* Copy data to the end of the packet and increases its length.
499 * It does not allocate new buffers.
500 * Returns the number of copied bytes. */
501always_inline u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400502vlib_buffer_chain_append_data (vlib_main_t * vm,
503 u32 free_list_index,
504 vlib_buffer_t * first,
505 vlib_buffer_t * last, void *data, u16 data_len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000506{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400507 u32 n_buffer_bytes =
508 vlib_buffer_free_list_buffer_size (vm, free_list_index);
509 ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
510 u16 len = clib_min (data_len,
511 n_buffer_bytes - last->current_length -
512 last->current_data);
513 clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
514 len);
515 vlib_buffer_chain_increase_length (first, last, len);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000516 return len;
517}
518
519/* Copy data to the end of the packet and increases its length.
520 * Allocates additional buffers from the free list if necessary.
521 * Returns the number of copied bytes.
522 * 'last' value is modified whenever new buffers are allocated and
523 * chained and points to the last buffer in the chain. */
524u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400525vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
526 u32 free_list_index,
527 vlib_buffer_t * first,
528 vlib_buffer_t ** last,
529 void *data, u16 data_len);
530void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000531
Dave Barach9b8ffd92016-07-08 08:13:45 -0400532format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
533 format_vlib_buffer_contents;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534
Dave Barach9b8ffd92016-07-08 08:13:45 -0400535typedef struct
536{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537 /* Vector of packet data. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400538 u8 *packet_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539
Dave Barach70835742016-07-07 10:35:56 -0400540 /* Note: the next three fields are unused if DPDK == 1 */
541
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542 /* Number of buffers to allocate in each call to physmem
543 allocator. */
544 u32 min_n_buffers_each_physmem_alloc;
545
546 /* Buffer free list for this template. */
547 u32 free_list_index;
548
Dave Barach9b8ffd92016-07-08 08:13:45 -0400549 u32 *free_buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550} vlib_packet_template_t;
551
552void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
553 vlib_packet_template_t * t);
554
555void vlib_packet_template_init (vlib_main_t * vm,
556 vlib_packet_template_t * t,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400557 void *packet_data,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558 uword n_packet_data_bytes,
559 uword min_n_buffers_each_physmem_alloc,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400560 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561
Dave Barach9b8ffd92016-07-08 08:13:45 -0400562void *vlib_packet_template_get_packet (vlib_main_t * vm,
563 vlib_packet_template_t * t,
564 u32 * bi_result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565
566always_inline void
567vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
568{
569 vec_free (t->packet_data);
570}
571
572always_inline u32
573unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
574{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400575 serialize_stream_t *s = &m->stream;
576 vlib_serialize_buffer_main_t *sm
577 = uword_to_pointer (m->stream.data_function_opaque,
578 vlib_serialize_buffer_main_t *);
579 vlib_main_t *vm = sm->vlib_main;
580 u32 n, *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581
582 n = s->n_buffer_bytes - s->current_buffer_index;
583 if (sm->last_buffer != ~0)
584 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400585 vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700586 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
587 {
588 b = vlib_get_buffer (vm, b->next_buffer);
589 n += b->current_length;
590 }
591 }
592
Dave Barach9b8ffd92016-07-08 08:13:45 -0400593 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700594 clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
595 n += vlib_buffer_index_length_in_chain (vm, f[0]);
596 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400597/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700598
599 return n;
600}
601
Dave Barach9b8ffd92016-07-08 08:13:45 -0400602typedef union
603{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604 vlib_buffer_t b;
605 vlib_copy_unit_t i[sizeof (vlib_buffer_t) / sizeof (vlib_copy_unit_t)];
Dave Barach9b8ffd92016-07-08 08:13:45 -0400606}
607vlib_buffer_union_t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608
609/* Set a buffer quickly into "uninitialized" state. We want this to
610 be extremely cheap and arrange for all fields that need to be
611 initialized to be in the first 128 bits of the buffer. */
612always_inline void
613vlib_buffer_init_for_free_list (vlib_buffer_t * _dst,
614 vlib_buffer_free_list_t * fl)
615{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400616 vlib_buffer_union_t *dst = (vlib_buffer_union_t *) _dst;
617 vlib_buffer_union_t *src =
618 (vlib_buffer_union_t *) & fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619
Damjan Marion19010202016-03-24 17:17:47 +0100620 /* Make sure vlib_buffer_t is cacheline aligned and sized */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400621 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
622 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
623 CLIB_CACHE_LINE_BYTES);
624 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
625 CLIB_CACHE_LINE_BYTES * 2);
Damjan Marion19010202016-03-24 17:17:47 +0100626
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627 /* Make sure buffer template is sane. */
628 ASSERT (fl->index == fl->buffer_init_template.free_list_index);
629
630 /* Copy template from src->current_data thru src->free_list_index */
631 dst->i[0] = src->i[0];
632 if (1 * sizeof (dst->i[0]) < 16)
633 dst->i[1] = src->i[1];
634 if (2 * sizeof (dst->i[0]) < 16)
635 dst->i[2] = src->i[2];
636
637 /* Make sure it really worked. */
638#define _(f) ASSERT (dst->b.f == src->b.f)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400639 _(current_data);
640 _(current_length);
641 _(flags);
642 _(free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643#undef _
644 ASSERT (dst->b.total_length_not_including_first_buffer == 0);
645}
646
647always_inline void
648vlib_buffer_init_two_for_free_list (vlib_buffer_t * _dst0,
649 vlib_buffer_t * _dst1,
650 vlib_buffer_free_list_t * fl)
651{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400652 vlib_buffer_union_t *dst0 = (vlib_buffer_union_t *) _dst0;
653 vlib_buffer_union_t *dst1 = (vlib_buffer_union_t *) _dst1;
654 vlib_buffer_union_t *src =
655 (vlib_buffer_union_t *) & fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656
657 /* Make sure buffer template is sane. */
658 ASSERT (fl->index == fl->buffer_init_template.free_list_index);
659
660 /* Copy template from src->current_data thru src->free_list_index */
661 dst0->i[0] = dst1->i[0] = src->i[0];
662 if (1 * sizeof (dst0->i[0]) < 16)
663 dst0->i[1] = dst1->i[1] = src->i[1];
664 if (2 * sizeof (dst0->i[0]) < 16)
665 dst0->i[2] = dst1->i[2] = src->i[2];
666
667 /* Make sure it really worked. */
668#define _(f) ASSERT (dst0->b.f == src->b.f && dst1->b.f == src->b.f)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400669 _(current_data);
670 _(current_length);
671 _(flags);
672 _(free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673#undef _
674 ASSERT (dst0->b.total_length_not_including_first_buffer == 0);
675 ASSERT (dst1->b.total_length_not_including_first_buffer == 0);
676}
677
678#if CLIB_DEBUG > 0
Damjan Marion6a7acc22016-12-19 16:28:36 +0100679extern u32 *vlib_buffer_state_validation_lock;
680extern uword *vlib_buffer_state_validation_hash;
681extern void *vlib_buffer_state_heap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700682#endif
683
Dave Barach9b8ffd92016-07-08 08:13:45 -0400684static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
686{
687#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400688 uword *p;
689 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700690
691 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
692
693 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
694 ;
695
696 p = hash_get (vlib_buffer_state_validation_hash, b);
697
698 /* If we don't know about b, declare it to be in the expected state */
699 if (!p)
700 {
701 hash_set (vlib_buffer_state_validation_hash, b, expected);
702 goto out;
703 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400704
Ed Warnickecb9cada2015-12-08 15:45:58 -0700705 if (p[0] != expected)
706 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400707 void cj_stop (void);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708 u32 bi;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400709 vlib_main_t *vm = &vlib_global_main;
710
711 cj_stop ();
712
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713 bi = vlib_get_buffer_index (vm, b);
714
715 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400716 clib_warning ("%.6f buffer %llx (%d): %s, not %s",
717 vlib_time_now (vm), bi,
718 p[0] ? "busy" : "free", expected ? "busy" : "free");
719 os_panic ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700720 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400721out:
722 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723 *vlib_buffer_state_validation_lock = 0;
724 clib_mem_set_heap (oldheap);
725#endif
726}
727
Dave Barach9b8ffd92016-07-08 08:13:45 -0400728static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700729vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
730{
731#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400732 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700733
734 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
735
736 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
737 ;
738
739 hash_set (vlib_buffer_state_validation_hash, b, expected);
740
Dave Barach9b8ffd92016-07-08 08:13:45 -0400741 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 *vlib_buffer_state_validation_lock = 0;
743 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400744#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745}
746
747#endif /* included_vlib_buffer_funcs_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400748
749/*
750 * fd.io coding-style-patch-verification: ON
751 *
752 * Local Variables:
753 * eval: (c-set-style "gnu")
754 * End:
755 */