blob: 394c336ac49e08756be4d62d4e05d7e5d599333b [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
Dave Barach9b8ffd92016-07-08 08:13:45 -0400198typedef enum
199{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 /* Index is unknown. */
201 VLIB_BUFFER_UNKNOWN,
202
203 /* Index is known and free/allocated. */
204 VLIB_BUFFER_KNOWN_FREE,
205 VLIB_BUFFER_KNOWN_ALLOCATED,
206} vlib_buffer_known_state_t;
207
208always_inline vlib_buffer_known_state_t
209vlib_buffer_is_known (vlib_main_t * vm, u32 buffer_index)
210{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400211 vlib_buffer_main_t *bm = vm->buffer_main;
212 ASSERT (os_get_cpu_number () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213
Dave Barach9b8ffd92016-07-08 08:13:45 -0400214 uword *p = hash_get (bm->buffer_known_hash, buffer_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 return p ? p[0] : VLIB_BUFFER_UNKNOWN;
216}
217
218always_inline void
219vlib_buffer_set_known_state (vlib_main_t * vm,
220 u32 buffer_index,
221 vlib_buffer_known_state_t state)
222{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400223 vlib_buffer_main_t *bm = vm->buffer_main;
224 ASSERT (os_get_cpu_number () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225 hash_set (bm->buffer_known_hash, buffer_index, state);
226}
227
228/* Validates sanity of a single buffer.
229 Returns format'ed vector with error message if any. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400230u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
231 uword follow_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232
Dave Barach9b8ffd92016-07-08 08:13:45 -0400233clib_error_t *vlib_buffer_pool_create (vlib_main_t * vm, unsigned num_mbufs,
234 unsigned socket_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235
236/** \brief Allocate buffers into supplied array
237
238 @param vm - (vlib_main_t *) vlib main data structure pointer
239 @param buffers - (u32 * ) buffer index array
240 @param n_buffers - (u32) number of buffers requested
Dave Barach9b8ffd92016-07-08 08:13:45 -0400241 @return - (u32) number of buffers actually allocated, may be
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 less than the number requested or zero
243*/
Damjan Marion878c6092017-01-04 13:19:27 +0100244always_inline u32
245vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
246{
247 vlib_buffer_main_t *bm = vm->buffer_main;
248
249 ASSERT (bm->cb.vlib_buffer_alloc_cb);
250
251 return bm->cb.vlib_buffer_alloc_cb (vm, buffers, n_buffers);
252}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253
254always_inline u32
255vlib_buffer_round_size (u32 size)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400256{
257 return round_pow2 (size, sizeof (vlib_buffer_t));
258}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259
260/** \brief Allocate buffers from specific freelist into supplied array
261
262 @param vm - (vlib_main_t *) vlib main data structure pointer
263 @param buffers - (u32 * ) buffer index array
264 @param n_buffers - (u32) number of buffers requested
Dave Barach9b8ffd92016-07-08 08:13:45 -0400265 @return - (u32) number of buffers actually allocated, may be
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266 less than the number requested or zero
267*/
Damjan Marion878c6092017-01-04 13:19:27 +0100268always_inline u32
269vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
270 u32 * buffers,
271 u32 n_buffers, u32 free_list_index)
272{
273 vlib_buffer_main_t *bm = vm->buffer_main;
274
275 ASSERT (bm->cb.vlib_buffer_alloc_from_free_list_cb);
276
277 return bm->cb.vlib_buffer_alloc_from_free_list_cb (vm, buffers, n_buffers,
278 free_list_index);
279}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280
281/** \brief Free buffers
282 Frees the entire 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*/
Damjan Marion878c6092017-01-04 13:19:27 +0100289always_inline void
290vlib_buffer_free (vlib_main_t * vm,
291 /* pointer to first buffer */
292 u32 * buffers,
293 /* number of buffers to free */
294 u32 n_buffers)
295{
296 vlib_buffer_main_t *bm = vm->buffer_main;
297
298 ASSERT (bm->cb.vlib_buffer_free_cb);
299
300 return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
301}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302
303/** \brief Free buffers, does not free the buffer chain for each buffer
304
305 @param vm - (vlib_main_t *) vlib main data structure pointer
306 @param buffers - (u32 * ) buffer index array
307 @param n_buffers - (u32) number of buffers to free
308
309*/
Damjan Marion878c6092017-01-04 13:19:27 +0100310always_inline void
311vlib_buffer_free_no_next (vlib_main_t * vm,
312 /* pointer to first buffer */
313 u32 * buffers,
314 /* number of buffers to free */
315 u32 n_buffers)
316{
317 vlib_buffer_main_t *bm = vm->buffer_main;
318
319 ASSERT (bm->cb.vlib_buffer_free_no_next_cb);
320
321 return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
322}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700323
324/** \brief Free one buffer
Dave Barach9b8ffd92016-07-08 08:13:45 -0400325 Shorthand to free a single buffer chain.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326
327 @param vm - (vlib_main_t *) vlib main data structure pointer
328 @param buffer_index - (u32) buffer index to free
329*/
330always_inline void
331vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
332{
333 vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
334}
335
336/* Add/delete buffer free lists. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400337u32 vlib_buffer_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
338 char *fmt, ...);
Damjan Marion878c6092017-01-04 13:19:27 +0100339always_inline void
340vlib_buffer_delete_free_list (vlib_main_t * vm, u32 free_list_index)
341{
342 vlib_buffer_main_t *bm = vm->buffer_main;
343
344 ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
345
346 bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
347}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700348
349/* Find already existing public free list with given size or create one. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400350u32 vlib_buffer_get_or_create_free_list (vlib_main_t * vm, u32 n_data_bytes,
351 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100353/* Merge two free lists */
354void vlib_buffer_merge_free_lists (vlib_buffer_free_list_t * dst,
355 vlib_buffer_free_list_t * src);
356
357/* Make sure we have at least given number of unaligned buffers. */
358void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
359 vlib_buffer_free_list_t *
360 free_list,
361 uword n_unaligned_buffers);
362
363always_inline u32
364vlib_buffer_get_free_list_with_size (vlib_main_t * vm, u32 size)
365{
366 vlib_buffer_main_t *bm = vm->buffer_main;
367
368 size = vlib_buffer_round_size (size);
369 uword *p = hash_get (bm->free_list_by_size, size);
370 return p ? p[0] : ~0;
371}
372
373always_inline vlib_buffer_free_list_t *
374vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
375 u32 * index)
376{
377 vlib_buffer_main_t *bm = vm->buffer_main;
378 u32 i;
379
380 *index = i = b->free_list_index;
381 return pool_elt_at_index (bm->buffer_free_list_pool, i);
382}
383
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384always_inline vlib_buffer_free_list_t *
385vlib_buffer_get_free_list (vlib_main_t * vm, u32 free_list_index)
386{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400387 vlib_buffer_main_t *bm = vm->buffer_main;
388 vlib_buffer_free_list_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700389
390 f = pool_elt_at_index (bm->buffer_free_list_pool, free_list_index);
391
392 /* Sanity: indices must match. */
393 ASSERT (f->index == free_list_index);
394
395 return f;
396}
397
398always_inline u32
399vlib_buffer_free_list_buffer_size (vlib_main_t * vm, u32 free_list_index)
400{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400401 vlib_buffer_free_list_t *f =
402 vlib_buffer_get_free_list (vm, free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403 return f->n_data_bytes;
404}
405
Dave Barach9b8ffd92016-07-08 08:13:45 -0400406void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407
408/* Reasonably fast buffer copy routine. */
409always_inline void
410vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
411{
412 while (n >= 4)
413 {
414 dst[0] = src[0];
415 dst[1] = src[1];
416 dst[2] = src[2];
417 dst[3] = src[3];
418 dst += 4;
419 src += 4;
420 n -= 4;
421 }
422 while (n > 0)
423 {
424 dst[0] = src[0];
425 dst += 1;
426 src += 1;
427 n -= 1;
428 }
429}
430
431always_inline void *
432vlib_physmem_alloc_aligned (vlib_main_t * vm, clib_error_t ** error,
433 uword n_bytes, uword alignment)
434{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400435 void *r =
436 vm->os_physmem_alloc_aligned (&vm->physmem_main, n_bytes, alignment);
437 if (!r)
438 *error =
439 clib_error_return (0, "failed to allocate %wd bytes of I/O memory",
440 n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700441 else
442 *error = 0;
443 return r;
444}
445
446/* By default allocate I/O memory with cache line alignment. */
447always_inline void *
448vlib_physmem_alloc (vlib_main_t * vm, clib_error_t ** error, uword n_bytes)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400449{
450 return vlib_physmem_alloc_aligned (vm, error, n_bytes,
451 CLIB_CACHE_LINE_BYTES);
452}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453
454always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400455vlib_physmem_free (vlib_main_t * vm, void *mem)
456{
457 return vm->os_physmem_free (mem);
458}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459
460always_inline u64
Dave Barach9b8ffd92016-07-08 08:13:45 -0400461vlib_physmem_virtual_to_physical (vlib_main_t * vm, void *mem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400463 vlib_physmem_main_t *pm = &vm->physmem_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464 uword o = pointer_to_uword (mem) - pm->virtual.start;
465 return vlib_physmem_offset_to_physical (pm, o);
466}
467
468/* Append given data to end of buffer, possibly allocating new buffers. */
469u32 vlib_buffer_add_data (vlib_main_t * vm,
470 u32 free_list_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400471 u32 buffer_index, void *data, u32 n_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100473/* duplicate all buffers in chain */
474always_inline vlib_buffer_t *
475vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
476{
477 vlib_buffer_t *s, *d, *fd;
478 uword n_alloc, n_buffers = 1;
Damjan Marion67655492016-11-15 12:50:28 +0100479 u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100480 int i;
481
482 s = b;
483 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
484 {
485 n_buffers++;
486 s = vlib_get_buffer (vm, s->next_buffer);
487 }
Neale Ranns9d676af2017-03-15 01:28:31 -0700488 u32 new_buffers[n_buffers];
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100489
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100490 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
Dave Barach26cd8c12017-02-23 17:11:26 -0500491
492 /* No guarantee that we'll get all the buffers we asked for */
493 if (PREDICT_FALSE (n_alloc < n_buffers))
494 {
495 if (n_alloc > 0)
496 vlib_buffer_free (vm, new_buffers, n_alloc);
Dave Barach26cd8c12017-02-23 17:11:26 -0500497 return 0;
498 }
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100499
500 /* 1st segment */
501 s = b;
502 fd = d = vlib_get_buffer (vm, new_buffers[0]);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100503 d->current_data = s->current_data;
504 d->current_length = s->current_length;
Damjan Marion67655492016-11-15 12:50:28 +0100505 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100506 d->total_length_not_including_first_buffer =
507 s->total_length_not_including_first_buffer;
508 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
Damjan Mariondce05452016-12-01 11:59:33 +0100509 clib_memcpy (vlib_buffer_get_current (d),
510 vlib_buffer_get_current (s), s->current_length);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100511
512 /* next segments */
513 for (i = 1; i < n_buffers; i++)
514 {
515 /* previous */
516 d->next_buffer = new_buffers[i];
517 /* current */
518 s = vlib_get_buffer (vm, s->next_buffer);
519 d = vlib_get_buffer (vm, new_buffers[i]);
520 d->current_data = s->current_data;
521 d->current_length = s->current_length;
522 clib_memcpy (vlib_buffer_get_current (d),
523 vlib_buffer_get_current (s), s->current_length);
Damjan Marion67655492016-11-15 12:50:28 +0100524 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100525 }
526
527 return fd;
528}
529
Damjan Marionc47ed032017-01-25 14:18:03 +0100530/** \brief Create multiple clones of buffer and store them in the supplied array
531
532 @param vm - (vlib_main_t *) vlib main data structure pointer
533 @param src_buffer - (u32) source buffer index
534 @param buffers - (u32 * ) buffer index array
535 @param n_buffers - (u8) number of buffer clones requested
536 @param head_end_offset - (u16) offset relative to current position
537 where packet head ends
538 @return - (u8) number of buffers actually cloned, may be
539 less than the number requested or zero
540*/
541
542always_inline u8
543vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
544 u8 n_buffers, u16 head_end_offset)
545{
546 u8 i;
547 vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
548
549 ASSERT (s->n_add_refs == 0);
550 ASSERT (n_buffers);
551
552 if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
553 {
554 buffers[0] = src_buffer;
555 for (i = 1; i < n_buffers; i++)
556 {
557 vlib_buffer_t *d;
558 d = vlib_buffer_copy (vm, s);
559 if (d == 0)
560 return i;
561 buffers[i] = vlib_get_buffer_index (vm, d);
562
563 }
564 return n_buffers;
565 }
566
567 n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
568 s->free_list_index);
569 if (PREDICT_FALSE (n_buffers == 0))
570 {
571 buffers[0] = src_buffer;
572 return 1;
573 }
574
575 for (i = 0; i < n_buffers; i++)
576 {
577 vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
578 d->current_data = s->current_data;
579 d->current_length = head_end_offset;
580 d->free_list_index = s->free_list_index;
581 d->total_length_not_including_first_buffer =
582 s->total_length_not_including_first_buffer + s->current_length -
583 head_end_offset;
584 d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
585 d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
586 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
587 clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
588 head_end_offset);
589 d->next_buffer = src_buffer;
590 }
591 vlib_buffer_advance (s, head_end_offset);
592 s->n_add_refs = n_buffers - 1;
593 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
594 {
595 s = vlib_get_buffer (vm, s->next_buffer);
596 s->n_add_refs = n_buffers - 1;
597 }
598
599 return n_buffers;
600}
601
602/** \brief Attach cloned tail to the buffer
603
604 @param vm - (vlib_main_t *) vlib main data structure pointer
605 @param head - (vlib_buffer_t *) head buffer
606 @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
607*/
608
609always_inline void
610vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
611 vlib_buffer_t * tail)
612{
613 ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
614 ASSERT (head->free_list_index == tail->free_list_index);
615
616 head->flags |= VLIB_BUFFER_NEXT_PRESENT;
617 head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
618 head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
619 head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
620 head->next_buffer = vlib_get_buffer_index (vm, tail);
621 head->total_length_not_including_first_buffer = tail->current_length +
622 tail->total_length_not_including_first_buffer;
623
624next_segment:
625 __sync_add_and_fetch (&tail->n_add_refs, 1);
626
627 if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
628 {
629 tail = vlib_get_buffer (vm, tail->next_buffer);
630 goto next_segment;
631 }
632}
633
Pierre Pfister328e99b2016-02-12 13:18:42 +0000634/* Initializes the buffer as an empty packet with no chained buffers. */
635always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400636vlib_buffer_chain_init (vlib_buffer_t * first)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000637{
638 first->total_length_not_including_first_buffer = 0;
639 first->current_length = 0;
640 first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
641 first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000642}
643
644/* The provided next_bi buffer index is appended to the end of the packet. */
645always_inline vlib_buffer_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400646vlib_buffer_chain_buffer (vlib_main_t * vm,
647 vlib_buffer_t * first,
648 vlib_buffer_t * last, u32 next_bi)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000649{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400650 vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000651 last->next_buffer = next_bi;
652 last->flags |= VLIB_BUFFER_NEXT_PRESENT;
653 next_buffer->current_length = 0;
654 next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000655 return next_buffer;
656}
657
658/* Increases or decreases the packet length.
659 * It does not allocate or deallocate new buffers.
660 * Therefore, the added length must be compatible
661 * with the last buffer. */
662always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400663vlib_buffer_chain_increase_length (vlib_buffer_t * first,
664 vlib_buffer_t * last, i32 len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000665{
666 last->current_length += len;
667 if (first != last)
668 first->total_length_not_including_first_buffer += len;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000669}
670
671/* Copy data to the end of the packet and increases its length.
672 * It does not allocate new buffers.
673 * Returns the number of copied bytes. */
674always_inline u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400675vlib_buffer_chain_append_data (vlib_main_t * vm,
676 u32 free_list_index,
677 vlib_buffer_t * first,
678 vlib_buffer_t * last, void *data, u16 data_len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000679{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400680 u32 n_buffer_bytes =
681 vlib_buffer_free_list_buffer_size (vm, free_list_index);
682 ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
683 u16 len = clib_min (data_len,
684 n_buffer_bytes - last->current_length -
685 last->current_data);
686 clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
687 len);
688 vlib_buffer_chain_increase_length (first, last, len);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000689 return len;
690}
691
692/* Copy data to the end of the packet and increases its length.
693 * Allocates additional buffers from the free list if necessary.
694 * Returns the number of copied bytes.
695 * 'last' value is modified whenever new buffers are allocated and
696 * chained and points to the last buffer in the chain. */
697u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400698vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
699 u32 free_list_index,
700 vlib_buffer_t * first,
701 vlib_buffer_t ** last,
702 void *data, u16 data_len);
703void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000704
Dave Barach9b8ffd92016-07-08 08:13:45 -0400705format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
706 format_vlib_buffer_contents;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707
Dave Barach9b8ffd92016-07-08 08:13:45 -0400708typedef struct
709{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710 /* Vector of packet data. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400711 u8 *packet_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700712
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713 /* Number of buffers to allocate in each call to physmem
714 allocator. */
715 u32 min_n_buffers_each_physmem_alloc;
716
717 /* Buffer free list for this template. */
718 u32 free_list_index;
719
Dave Barach9b8ffd92016-07-08 08:13:45 -0400720 u32 *free_buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721} vlib_packet_template_t;
722
723void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
724 vlib_packet_template_t * t);
725
726void vlib_packet_template_init (vlib_main_t * vm,
727 vlib_packet_template_t * t,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400728 void *packet_data,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700729 uword n_packet_data_bytes,
730 uword min_n_buffers_each_physmem_alloc,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400731 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700732
Dave Barach9b8ffd92016-07-08 08:13:45 -0400733void *vlib_packet_template_get_packet (vlib_main_t * vm,
734 vlib_packet_template_t * t,
735 u32 * bi_result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736
737always_inline void
738vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
739{
740 vec_free (t->packet_data);
741}
742
743always_inline u32
744unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
745{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400746 serialize_stream_t *s = &m->stream;
747 vlib_serialize_buffer_main_t *sm
748 = uword_to_pointer (m->stream.data_function_opaque,
749 vlib_serialize_buffer_main_t *);
750 vlib_main_t *vm = sm->vlib_main;
751 u32 n, *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752
753 n = s->n_buffer_bytes - s->current_buffer_index;
754 if (sm->last_buffer != ~0)
755 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400756 vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700757 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
758 {
759 b = vlib_get_buffer (vm, b->next_buffer);
760 n += b->current_length;
761 }
762 }
763
Dave Barach9b8ffd92016-07-08 08:13:45 -0400764 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765 clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
766 n += vlib_buffer_index_length_in_chain (vm, f[0]);
767 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400768/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700769
770 return n;
771}
772
Ed Warnickecb9cada2015-12-08 15:45:58 -0700773/* Set a buffer quickly into "uninitialized" state. We want this to
774 be extremely cheap and arrange for all fields that need to be
775 initialized to be in the first 128 bits of the buffer. */
776always_inline void
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100777vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700778 vlib_buffer_free_list_t * fl)
779{
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100780 vlib_buffer_t *src = &fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700781
Damjan Marion19010202016-03-24 17:17:47 +0100782 /* Make sure vlib_buffer_t is cacheline aligned and sized */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400783 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
784 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
785 CLIB_CACHE_LINE_BYTES);
786 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
787 CLIB_CACHE_LINE_BYTES * 2);
Damjan Marion19010202016-03-24 17:17:47 +0100788
Ed Warnickecb9cada2015-12-08 15:45:58 -0700789 /* Make sure buffer template is sane. */
790 ASSERT (fl->index == fl->buffer_init_template.free_list_index);
791
Dave Barachf8690282017-03-01 11:38:02 -0500792 clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
793 STRUCT_MARK_PTR (src, template_start),
794 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
795 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
796
797 /* Not in the first 16 octets. */
798 dst->n_add_refs = src->n_add_refs;
799
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800 /* Make sure it really worked. */
Dave Barachf8690282017-03-01 11:38:02 -0500801#define _(f) ASSERT (dst->f == src->f);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400802 _(current_data);
803 _(current_length);
804 _(flags);
805 _(free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700806#undef _
Dave Barachf8690282017-03-01 11:38:02 -0500807 ASSERT (dst->total_length_not_including_first_buffer == 0);
Damjan Marionc47ed032017-01-25 14:18:03 +0100808 ASSERT (dst->n_add_refs == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809}
810
811always_inline void
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100812vlib_buffer_add_to_free_list (vlib_main_t * vm,
813 vlib_buffer_free_list_t * f,
814 u32 buffer_index, u8 do_init)
815{
816 vlib_buffer_t *b;
817 b = vlib_get_buffer (vm, buffer_index);
818 if (PREDICT_TRUE (do_init))
819 vlib_buffer_init_for_free_list (b, f);
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100820 vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100821}
822
823always_inline void
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100824vlib_buffer_init_two_for_free_list (vlib_buffer_t * dst0,
825 vlib_buffer_t * dst1,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700826 vlib_buffer_free_list_t * fl)
827{
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100828 vlib_buffer_t *src = &fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700829
830 /* Make sure buffer template is sane. */
831 ASSERT (fl->index == fl->buffer_init_template.free_list_index);
832
Dave Barachf8690282017-03-01 11:38:02 -0500833 clib_memcpy (STRUCT_MARK_PTR (dst0, template_start),
834 STRUCT_MARK_PTR (src, template_start),
835 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
836 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
837
838 clib_memcpy (STRUCT_MARK_PTR (dst1, template_start),
839 STRUCT_MARK_PTR (src, template_start),
840 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
841 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
842
843 /* Not in the first 16 octets. */
844 dst0->n_add_refs = src->n_add_refs;
845 dst1->n_add_refs = src->n_add_refs;
846
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847 /* Make sure it really worked. */
Dave Barachf8690282017-03-01 11:38:02 -0500848#define _(f) ASSERT (dst0->f == src->f); ASSERT( dst1->f == src->f)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400849 _(current_data);
850 _(current_length);
851 _(flags);
852 _(free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700853#undef _
Dave Barachf8690282017-03-01 11:38:02 -0500854
855 ASSERT (dst0->total_length_not_including_first_buffer == 0);
856 ASSERT (dst1->total_length_not_including_first_buffer == 0);
Damjan Marionc47ed032017-01-25 14:18:03 +0100857 ASSERT (dst0->n_add_refs == 0);
858 ASSERT (dst1->n_add_refs == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700859}
860
861#if CLIB_DEBUG > 0
Damjan Marion6a7acc22016-12-19 16:28:36 +0100862extern u32 *vlib_buffer_state_validation_lock;
863extern uword *vlib_buffer_state_validation_hash;
864extern void *vlib_buffer_state_heap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865#endif
866
Dave Barach9b8ffd92016-07-08 08:13:45 -0400867static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
869{
870#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400871 uword *p;
872 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873
874 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
875
876 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
877 ;
878
879 p = hash_get (vlib_buffer_state_validation_hash, b);
880
881 /* If we don't know about b, declare it to be in the expected state */
882 if (!p)
883 {
884 hash_set (vlib_buffer_state_validation_hash, b, expected);
885 goto out;
886 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400887
Ed Warnickecb9cada2015-12-08 15:45:58 -0700888 if (p[0] != expected)
889 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400890 void cj_stop (void);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700891 u32 bi;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400892 vlib_main_t *vm = &vlib_global_main;
893
894 cj_stop ();
895
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896 bi = vlib_get_buffer_index (vm, b);
897
898 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400899 clib_warning ("%.6f buffer %llx (%d): %s, not %s",
900 vlib_time_now (vm), bi,
901 p[0] ? "busy" : "free", expected ? "busy" : "free");
902 os_panic ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400904out:
905 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700906 *vlib_buffer_state_validation_lock = 0;
907 clib_mem_set_heap (oldheap);
908#endif
909}
910
Dave Barach9b8ffd92016-07-08 08:13:45 -0400911static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700912vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
913{
914#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400915 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916
917 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
918
919 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
920 ;
921
922 hash_set (vlib_buffer_state_validation_hash, b, expected);
923
Dave Barach9b8ffd92016-07-08 08:13:45 -0400924 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700925 *vlib_buffer_state_validation_lock = 0;
926 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400927#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700928}
929
930#endif /* included_vlib_buffer_funcs_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400931
932/*
933 * fd.io coding-style-patch-verification: ON
934 *
935 * Local Variables:
936 * eval: (c-set-style "gnu")
937 * End:
938 */