blob: ba87d9566c7a722a2491c83e35d01c99118f9ad7 [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 Mariond1274cb2018-03-13 21:32:17 +010059 vlib_buffer_main_t *bm = &buffer_main;
Damjan Marion04a7f052017-07-10 15:06:17 +020060 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 Mariond1274cb2018-03-13 21:32:17 +010076 vlib_buffer_main_t *bm = &buffer_main;
Damjan Marion04a7f052017-07-10 15:06:17 +020077 uword offset = pointer_to_uword (p) - bm->buffer_mem_start;
78 ASSERT (pointer_to_uword (p) >= bm->buffer_mem_start);
79 ASSERT (offset < bm->buffer_mem_size);
Dave Barach9b8ffd92016-07-08 08:13:45 -040080 ASSERT ((offset % (1 << CLIB_LOG2_CACHE_LINE_BYTES)) == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070081 return offset >> CLIB_LOG2_CACHE_LINE_BYTES;
82}
83
84/** \brief Get next buffer in buffer linklist, or zero for end of list.
85
86 @param vm - (vlib_main_t *) vlib main data structure pointer
87 @param b - (void *) buffer pointer
88 @return - (vlib_buffer_t *) next buffer, or NULL
Dave Barach9b8ffd92016-07-08 08:13:45 -040089*/
Ed Warnickecb9cada2015-12-08 15:45:58 -070090always_inline vlib_buffer_t *
91vlib_get_next_buffer (vlib_main_t * vm, vlib_buffer_t * b)
92{
93 return (b->flags & VLIB_BUFFER_NEXT_PRESENT
Dave Barach9b8ffd92016-07-08 08:13:45 -040094 ? vlib_get_buffer (vm, b->next_buffer) : 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070095}
96
Dave Barach9b8ffd92016-07-08 08:13:45 -040097uword vlib_buffer_length_in_chain_slow_path (vlib_main_t * vm,
98 vlib_buffer_t * b_first);
Ed Warnickecb9cada2015-12-08 15:45:58 -070099
100/** \brief Get length in bytes of the buffer chain
101
102 @param vm - (vlib_main_t *) vlib main data structure pointer
103 @param b - (void *) buffer pointer
104 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400105*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106always_inline uword
107vlib_buffer_length_in_chain (vlib_main_t * vm, vlib_buffer_t * b)
108{
Damjan Marion072401e2017-07-13 18:53:27 +0200109 uword len = b->current_length;
110
111 if (PREDICT_TRUE ((b->flags & VLIB_BUFFER_NEXT_PRESENT) == 0))
112 return len;
113
114 if (PREDICT_TRUE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
115 return len + b->total_length_not_including_first_buffer;
116
117 return vlib_buffer_length_in_chain_slow_path (vm, b);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118}
119
120/** \brief Get length in bytes of the buffer index buffer chain
121
122 @param vm - (vlib_main_t *) vlib main data structure pointer
123 @param bi - (u32) buffer index
124 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400125*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126always_inline uword
127vlib_buffer_index_length_in_chain (vlib_main_t * vm, u32 bi)
128{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400129 vlib_buffer_t *b = vlib_get_buffer (vm, bi);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130 return vlib_buffer_length_in_chain (vm, b);
131}
132
133/** \brief Copy buffer contents to memory
134
135 @param vm - (vlib_main_t *) vlib main data structure pointer
Chris Luked4024f52016-09-06 09:32:36 -0400136 @param buffer_index - (u32) buffer index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137 @param contents - (u8 *) memory, <strong>must be large enough</strong>
138 @return - (uword) length of buffer chain
Dave Barach9b8ffd92016-07-08 08:13:45 -0400139*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140always_inline uword
141vlib_buffer_contents (vlib_main_t * vm, u32 buffer_index, u8 * contents)
142{
143 uword content_len = 0;
144 uword l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400145 vlib_buffer_t *b;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
147 while (1)
148 {
149 b = vlib_get_buffer (vm, buffer_index);
150 l = b->current_length;
Damjan Marionf1213b82016-03-13 02:22:06 +0100151 clib_memcpy (contents + content_len, b->data + b->current_data, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152 content_len += l;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400153 if (!(b->flags & VLIB_BUFFER_NEXT_PRESENT))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154 break;
155 buffer_index = b->next_buffer;
156 }
157
158 return content_len;
159}
160
161/* Return physical address of buffer->data start. */
162always_inline u64
163vlib_get_buffer_data_physical_address (vlib_main_t * vm, u32 buffer_index)
164{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100165 vlib_buffer_main_t *bm = &buffer_main;
Damjan Marion149ba772017-10-12 13:09:26 +0200166 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_index);
Damjan Marioncef87f12017-10-05 15:32:41 +0200167 vlib_buffer_pool_t *pool = vec_elt_at_index (bm->buffer_pools,
168 b->buffer_pool_index);
169
170 return vlib_physmem_virtual_to_physical (vm, pool->physmem_region, b->data);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171}
172
173/** \brief Prefetch buffer metadata by buffer index
174 The first 64 bytes of buffer contains most header information
175
176 @param vm - (vlib_main_t *) vlib main data structure pointer
177 @param bi - (u32) buffer index
178 @param type - LOAD, STORE. In most cases, STORE is the right answer
179*/
180/* Prefetch buffer header given index. */
181#define vlib_prefetch_buffer_with_index(vm,bi,type) \
182 do { \
183 vlib_buffer_t * _b = vlib_get_buffer (vm, bi); \
184 vlib_prefetch_buffer_header (_b, type); \
185 } while (0)
186
187#if 0
188/* Iterate over known allocated vlib bufs. You probably do not want
189 * to do this!
190 @param vm the vlib_main_t
191 @param bi found allocated buffer index
192 @param body operation to perform on buffer index
193 function executes body for each allocated buffer index
194 */
195#define vlib_buffer_foreach_allocated(vm,bi,body) \
196do { \
197 vlib_main_t * _vmain = (vm); \
198 vlib_buffer_main_t * _bmain = &_vmain->buffer_main; \
199 hash_pair_t * _vbpair; \
200 hash_foreach_pair(_vbpair, _bmain->buffer_known_hash, ({ \
201 if (VLIB_BUFFER_KNOWN_ALLOCATED == _vbpair->value[0]) { \
202 (bi) = _vbpair->key; \
203 body; \
204 } \
205 })); \
206} while (0)
207#endif
208
Dave Barach9b8ffd92016-07-08 08:13:45 -0400209typedef enum
210{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 /* Index is unknown. */
212 VLIB_BUFFER_UNKNOWN,
213
214 /* Index is known and free/allocated. */
215 VLIB_BUFFER_KNOWN_FREE,
216 VLIB_BUFFER_KNOWN_ALLOCATED,
217} vlib_buffer_known_state_t;
218
Damjan Marionc8a26c62017-11-24 20:15:23 +0100219void vlib_buffer_validate_alloc_free (vlib_main_t * vm, u32 * buffers,
220 uword n_buffers,
221 vlib_buffer_known_state_t
222 expected_state);
223
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224always_inline vlib_buffer_known_state_t
Steven899a84b2018-01-29 20:09:09 -0800225vlib_buffer_is_known (u32 buffer_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100227 vlib_buffer_main_t *bm = &buffer_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228
Damjan Marion6b0f5892017-07-27 04:01:24 -0400229 clib_spinlock_lock (&bm->buffer_known_hash_lockp);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400230 uword *p = hash_get (bm->buffer_known_hash, buffer_index);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400231 clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232 return p ? p[0] : VLIB_BUFFER_UNKNOWN;
233}
234
235always_inline void
Steven899a84b2018-01-29 20:09:09 -0800236vlib_buffer_set_known_state (u32 buffer_index,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 vlib_buffer_known_state_t state)
238{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100239 vlib_buffer_main_t *bm = &buffer_main;
Steven899a84b2018-01-29 20:09:09 -0800240
Damjan Marion6b0f5892017-07-27 04:01:24 -0400241 clib_spinlock_lock (&bm->buffer_known_hash_lockp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 hash_set (bm->buffer_known_hash, buffer_index, state);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400243 clib_spinlock_unlock (&bm->buffer_known_hash_lockp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244}
245
246/* Validates sanity of a single buffer.
247 Returns format'ed vector with error message if any. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400248u8 *vlib_validate_buffer (vlib_main_t * vm, u32 buffer_index,
249 uword follow_chain);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251always_inline u32
252vlib_buffer_round_size (u32 size)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400253{
254 return round_pow2 (size, sizeof (vlib_buffer_t));
255}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256
Damjan Mariondac03522018-02-01 15:30:13 +0100257always_inline vlib_buffer_free_list_index_t
Damjan Marion072401e2017-07-13 18:53:27 +0200258vlib_buffer_get_free_list_index (vlib_buffer_t * b)
259{
Damjan Mariondac03522018-02-01 15:30:13 +0100260 if (PREDICT_FALSE (b->flags & VLIB_BUFFER_NON_DEFAULT_FREELIST))
261 return b->free_list_index;
262
263 return 0;
Damjan Marion072401e2017-07-13 18:53:27 +0200264}
265
266always_inline void
Damjan Mariondac03522018-02-01 15:30:13 +0100267vlib_buffer_set_free_list_index (vlib_buffer_t * b,
268 vlib_buffer_free_list_index_t index)
Damjan Marion072401e2017-07-13 18:53:27 +0200269{
Damjan Mariondac03522018-02-01 15:30:13 +0100270 if (PREDICT_FALSE (index))
271 {
272 b->flags |= VLIB_BUFFER_NON_DEFAULT_FREELIST;
273 b->free_list_index = index;
274 }
275 else
276 b->flags &= ~VLIB_BUFFER_NON_DEFAULT_FREELIST;
Damjan Marion072401e2017-07-13 18:53:27 +0200277}
278
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279/** \brief Allocate buffers from specific freelist into supplied array
280
281 @param vm - (vlib_main_t *) vlib main data structure pointer
282 @param buffers - (u32 * ) buffer index array
283 @param n_buffers - (u32) number of buffers requested
Dave Barach9b8ffd92016-07-08 08:13:45 -0400284 @return - (u32) number of buffers actually allocated, may be
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285 less than the number requested or zero
286*/
Damjan Marion878c6092017-01-04 13:19:27 +0100287always_inline u32
288vlib_buffer_alloc_from_free_list (vlib_main_t * vm,
289 u32 * buffers,
Damjan Mariondac03522018-02-01 15:30:13 +0100290 u32 n_buffers,
291 vlib_buffer_free_list_index_t index)
Damjan Marion878c6092017-01-04 13:19:27 +0100292{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100293 vlib_buffer_main_t *bm = &buffer_main;
Damjan Marionc8a26c62017-11-24 20:15:23 +0100294 vlib_buffer_free_list_t *fl;
295 u32 *src;
296 uword len;
Damjan Marion878c6092017-01-04 13:19:27 +0100297
Damjan Marionc8a26c62017-11-24 20:15:23 +0100298 ASSERT (bm->cb.vlib_buffer_fill_free_list_cb);
Damjan Marion878c6092017-01-04 13:19:27 +0100299
Damjan Mariond1274cb2018-03-13 21:32:17 +0100300 fl = pool_elt_at_index (vm->buffer_free_list_pool, index);
Damjan Marionc8a26c62017-11-24 20:15:23 +0100301
302 len = vec_len (fl->buffers);
303
304 if (PREDICT_FALSE (len < n_buffers))
305 {
306 bm->cb.vlib_buffer_fill_free_list_cb (vm, fl, n_buffers);
Damjan Marionc22fcba2018-03-06 18:46:54 +0100307 if (PREDICT_FALSE ((len = vec_len (fl->buffers)) == 0))
308 return 0;
Damjan Marionc8a26c62017-11-24 20:15:23 +0100309
310 /* even if fill free list didn't manage to refill free list
311 we should give what we have */
312 n_buffers = clib_min (len, n_buffers);
313
314 /* following code is intentionaly duplicated to allow compiler
315 to optimize fast path when n_buffers is constant value */
316 src = fl->buffers + len - n_buffers;
317 clib_memcpy (buffers, src, n_buffers * sizeof (u32));
318 _vec_len (fl->buffers) -= n_buffers;
319
320 /* Verify that buffers are known free. */
321 vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
322 VLIB_BUFFER_KNOWN_FREE);
323
324 return n_buffers;
325 }
326
327 src = fl->buffers + len - n_buffers;
328 clib_memcpy (buffers, src, n_buffers * sizeof (u32));
329 _vec_len (fl->buffers) -= n_buffers;
330
331 /* Verify that buffers are known free. */
332 vlib_buffer_validate_alloc_free (vm, buffers, n_buffers,
333 VLIB_BUFFER_KNOWN_FREE);
334
335 return n_buffers;
336}
337
338/** \brief Allocate buffers into supplied array
339
340 @param vm - (vlib_main_t *) vlib main data structure pointer
341 @param buffers - (u32 * ) buffer index array
342 @param n_buffers - (u32) number of buffers requested
343 @return - (u32) number of buffers actually allocated, may be
344 less than the number requested or zero
345*/
346always_inline u32
347vlib_buffer_alloc (vlib_main_t * vm, u32 * buffers, u32 n_buffers)
348{
349 return vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
350 VLIB_BUFFER_DEFAULT_FREE_LIST_INDEX);
Damjan Marion878c6092017-01-04 13:19:27 +0100351}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Damjan Marionc58408c2018-01-18 14:54:04 +0100353/** \brief Allocate buffers into ring
354
355 @param vm - (vlib_main_t *) vlib main data structure pointer
356 @param buffers - (u32 * ) buffer index ring
357 @param start - (u32) first slot in the ring
358 @param ring_size - (u32) ring size
359 @param n_buffers - (u32) number of buffers requested
360 @return - (u32) number of buffers actually allocated, may be
361 less than the number requested or zero
362*/
363always_inline u32
364vlib_buffer_alloc_to_ring (vlib_main_t * vm, u32 * ring, u32 start,
365 u32 ring_size, u32 n_buffers)
366{
367 u32 n_alloc;
368
369 ASSERT (n_buffers <= ring_size);
370
371 if (PREDICT_TRUE (start + n_buffers <= ring_size))
372 return vlib_buffer_alloc (vm, ring + start, n_buffers);
373
374 n_alloc = vlib_buffer_alloc (vm, ring + start, ring_size - start);
375
376 if (PREDICT_TRUE (n_alloc == ring_size - start))
377 n_alloc += vlib_buffer_alloc (vm, ring, n_buffers - n_alloc);
378
379 return n_alloc;
380}
381
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382/** \brief Free buffers
383 Frees the entire buffer chain for each buffer
384
385 @param vm - (vlib_main_t *) vlib main data structure pointer
386 @param buffers - (u32 * ) buffer index array
387 @param n_buffers - (u32) number of buffers to free
388
389*/
Damjan Marion878c6092017-01-04 13:19:27 +0100390always_inline void
391vlib_buffer_free (vlib_main_t * vm,
392 /* pointer to first buffer */
393 u32 * buffers,
394 /* number of buffers to free */
395 u32 n_buffers)
396{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100397 vlib_buffer_main_t *bm = &buffer_main;
Damjan Marion878c6092017-01-04 13:19:27 +0100398
399 ASSERT (bm->cb.vlib_buffer_free_cb);
400
401 return bm->cb.vlib_buffer_free_cb (vm, buffers, n_buffers);
402}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403
404/** \brief Free buffers, does not free the buffer chain for each buffer
405
406 @param vm - (vlib_main_t *) vlib main data structure pointer
407 @param buffers - (u32 * ) buffer index array
408 @param n_buffers - (u32) number of buffers to free
409
410*/
Damjan Marion878c6092017-01-04 13:19:27 +0100411always_inline void
412vlib_buffer_free_no_next (vlib_main_t * vm,
413 /* pointer to first buffer */
414 u32 * buffers,
415 /* number of buffers to free */
416 u32 n_buffers)
417{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100418 vlib_buffer_main_t *bm = &buffer_main;
Damjan Marion878c6092017-01-04 13:19:27 +0100419
420 ASSERT (bm->cb.vlib_buffer_free_no_next_cb);
421
422 return bm->cb.vlib_buffer_free_no_next_cb (vm, buffers, n_buffers);
423}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424
425/** \brief Free one buffer
Dave Barach9b8ffd92016-07-08 08:13:45 -0400426 Shorthand to free a single buffer chain.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700427
428 @param vm - (vlib_main_t *) vlib main data structure pointer
429 @param buffer_index - (u32) buffer index to free
430*/
431always_inline void
432vlib_buffer_free_one (vlib_main_t * vm, u32 buffer_index)
433{
434 vlib_buffer_free (vm, &buffer_index, /* n_buffers */ 1);
435}
436
Damjan Mariona3731492018-02-25 22:50:39 +0100437/** \brief Free buffers from ring
438
439 @param vm - (vlib_main_t *) vlib main data structure pointer
440 @param buffers - (u32 * ) buffer index ring
441 @param start - (u32) first slot in the ring
442 @param ring_size - (u32) ring size
443 @param n_buffers - (u32) number of buffers
444*/
445always_inline void
446vlib_buffer_free_from_ring (vlib_main_t * vm, u32 * ring, u32 start,
447 u32 ring_size, u32 n_buffers)
448{
449 ASSERT (n_buffers <= ring_size);
450
451 if (PREDICT_TRUE (start + n_buffers <= ring_size))
452 {
453 vlib_buffer_free (vm, ring + start, n_buffers);
454 }
455 else
456 {
457 vlib_buffer_free (vm, ring + start, ring_size - start);
458 vlib_buffer_free (vm, ring, n_buffers - (ring_size - start));
459 }
460}
461
Damjan Marioncef1db92018-03-28 18:27:38 +0200462/** \brief Free buffers from ring without freeing tail buffers
463
464 @param vm - (vlib_main_t *) vlib main data structure pointer
465 @param buffers - (u32 * ) buffer index ring
466 @param start - (u32) first slot in the ring
467 @param ring_size - (u32) ring size
468 @param n_buffers - (u32) number of buffers
469*/
470always_inline void
471vlib_buffer_free_from_ring_no_next (vlib_main_t * vm, u32 * ring, u32 start,
472 u32 ring_size, u32 n_buffers)
473{
474 ASSERT (n_buffers <= ring_size);
475
476 if (PREDICT_TRUE (start + n_buffers <= ring_size))
477 {
478 vlib_buffer_free (vm, ring + start, n_buffers);
479 }
480 else
481 {
482 vlib_buffer_free_no_next (vm, ring + start, ring_size - start);
483 vlib_buffer_free_no_next (vm, ring, n_buffers - (ring_size - start));
484 }
485}
Damjan Mariona3731492018-02-25 22:50:39 +0100486
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487/* Add/delete buffer free lists. */
Damjan Mariondac03522018-02-01 15:30:13 +0100488vlib_buffer_free_list_index_t vlib_buffer_create_free_list (vlib_main_t * vm,
489 u32 n_data_bytes,
490 char *fmt, ...);
Damjan Marion878c6092017-01-04 13:19:27 +0100491always_inline void
Damjan Mariondac03522018-02-01 15:30:13 +0100492vlib_buffer_delete_free_list (vlib_main_t * vm,
493 vlib_buffer_free_list_index_t free_list_index)
Damjan Marion878c6092017-01-04 13:19:27 +0100494{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100495 vlib_buffer_main_t *bm = &buffer_main;
Damjan Marion878c6092017-01-04 13:19:27 +0100496
497 ASSERT (bm->cb.vlib_buffer_delete_free_list_cb);
498
499 bm->cb.vlib_buffer_delete_free_list_cb (vm, free_list_index);
500}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100502/* Make sure we have at least given number of unaligned buffers. */
503void vlib_buffer_free_list_fill_unaligned (vlib_main_t * vm,
504 vlib_buffer_free_list_t *
505 free_list,
506 uword n_unaligned_buffers);
507
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100508always_inline vlib_buffer_free_list_t *
509vlib_buffer_get_buffer_free_list (vlib_main_t * vm, vlib_buffer_t * b,
Damjan Mariondac03522018-02-01 15:30:13 +0100510 vlib_buffer_free_list_index_t * index)
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100511{
Damjan Mariondac03522018-02-01 15:30:13 +0100512 vlib_buffer_free_list_index_t i;
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100513
Damjan Marion072401e2017-07-13 18:53:27 +0200514 *index = i = vlib_buffer_get_free_list_index (b);
Damjan Mariond1274cb2018-03-13 21:32:17 +0100515 return pool_elt_at_index (vm->buffer_free_list_pool, i);
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100516}
517
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518always_inline vlib_buffer_free_list_t *
Damjan Mariondac03522018-02-01 15:30:13 +0100519vlib_buffer_get_free_list (vlib_main_t * vm,
520 vlib_buffer_free_list_index_t free_list_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400522 vlib_buffer_free_list_t *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523
Damjan Mariond1274cb2018-03-13 21:32:17 +0100524 f = pool_elt_at_index (vm->buffer_free_list_pool, free_list_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525
526 /* Sanity: indices must match. */
527 ASSERT (f->index == free_list_index);
528
529 return f;
530}
531
532always_inline u32
Damjan Mariondac03522018-02-01 15:30:13 +0100533vlib_buffer_free_list_buffer_size (vlib_main_t * vm,
534 vlib_buffer_free_list_index_t index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535{
Damjan Mariondac03522018-02-01 15:30:13 +0100536 vlib_buffer_free_list_t *f = vlib_buffer_get_free_list (vm, index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537 return f->n_data_bytes;
538}
539
Dave Barach9b8ffd92016-07-08 08:13:45 -0400540void vlib_aligned_memcpy (void *_dst, void *_src, int n_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700541
542/* Reasonably fast buffer copy routine. */
543always_inline void
544vlib_copy_buffers (u32 * dst, u32 * src, u32 n)
545{
546 while (n >= 4)
547 {
548 dst[0] = src[0];
549 dst[1] = src[1];
550 dst[2] = src[2];
551 dst[3] = src[3];
552 dst += 4;
553 src += 4;
554 n -= 4;
555 }
556 while (n > 0)
557 {
558 dst[0] = src[0];
559 dst += 1;
560 src += 1;
561 n -= 1;
562 }
563}
564
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565/* Append given data to end of buffer, possibly allocating new buffers. */
566u32 vlib_buffer_add_data (vlib_main_t * vm,
Damjan Mariondac03522018-02-01 15:30:13 +0100567 vlib_buffer_free_list_index_t free_list_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400568 u32 buffer_index, void *data, u32 n_data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100570/* duplicate all buffers in chain */
571always_inline vlib_buffer_t *
572vlib_buffer_copy (vlib_main_t * vm, vlib_buffer_t * b)
573{
574 vlib_buffer_t *s, *d, *fd;
575 uword n_alloc, n_buffers = 1;
Damjan Marion67655492016-11-15 12:50:28 +0100576 u32 flag_mask = VLIB_BUFFER_NEXT_PRESENT | VLIB_BUFFER_TOTAL_LENGTH_VALID;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100577 int i;
578
579 s = b;
580 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
581 {
582 n_buffers++;
583 s = vlib_get_buffer (vm, s->next_buffer);
584 }
Neale Ranns9d676af2017-03-15 01:28:31 -0700585 u32 new_buffers[n_buffers];
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100586
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100587 n_alloc = vlib_buffer_alloc (vm, new_buffers, n_buffers);
Dave Barach26cd8c12017-02-23 17:11:26 -0500588
589 /* No guarantee that we'll get all the buffers we asked for */
590 if (PREDICT_FALSE (n_alloc < n_buffers))
591 {
592 if (n_alloc > 0)
593 vlib_buffer_free (vm, new_buffers, n_alloc);
Dave Barach26cd8c12017-02-23 17:11:26 -0500594 return 0;
595 }
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100596
597 /* 1st segment */
598 s = b;
599 fd = d = vlib_get_buffer (vm, new_buffers[0]);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100600 d->current_data = s->current_data;
601 d->current_length = s->current_length;
Damjan Marion67655492016-11-15 12:50:28 +0100602 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100603 d->total_length_not_including_first_buffer =
604 s->total_length_not_including_first_buffer;
605 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
Damjan Mariondce05452016-12-01 11:59:33 +0100606 clib_memcpy (vlib_buffer_get_current (d),
607 vlib_buffer_get_current (s), s->current_length);
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100608
609 /* next segments */
610 for (i = 1; i < n_buffers; i++)
611 {
612 /* previous */
613 d->next_buffer = new_buffers[i];
614 /* current */
615 s = vlib_get_buffer (vm, s->next_buffer);
616 d = vlib_get_buffer (vm, new_buffers[i]);
617 d->current_data = s->current_data;
618 d->current_length = s->current_length;
619 clib_memcpy (vlib_buffer_get_current (d),
620 vlib_buffer_get_current (s), s->current_length);
Damjan Marion67655492016-11-15 12:50:28 +0100621 d->flags = s->flags & flag_mask;
Damjan Marion05ab8cb2016-11-03 20:16:04 +0100622 }
623
624 return fd;
625}
626
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800627/** \brief Create a maximum of 256 clones of buffer and store them
628 in the supplied array
Damjan Marionc47ed032017-01-25 14:18:03 +0100629
630 @param vm - (vlib_main_t *) vlib main data structure pointer
631 @param src_buffer - (u32) source buffer index
632 @param buffers - (u32 * ) buffer index array
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800633 @param n_buffers - (u16) number of buffer clones requested (<=256)
Damjan Marionc47ed032017-01-25 14:18:03 +0100634 @param head_end_offset - (u16) offset relative to current position
635 where packet head ends
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800636 @return - (u16) number of buffers actually cloned, may be
Damjan Marionc47ed032017-01-25 14:18:03 +0100637 less than the number requested or zero
638*/
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800639always_inline u16
640vlib_buffer_clone_256 (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
641 u16 n_buffers, u16 head_end_offset)
Damjan Marionc47ed032017-01-25 14:18:03 +0100642{
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800643 u16 i;
Damjan Marionc47ed032017-01-25 14:18:03 +0100644 vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
645
646 ASSERT (s->n_add_refs == 0);
647 ASSERT (n_buffers);
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800648 ASSERT (n_buffers <= 256);
Damjan Marionc47ed032017-01-25 14:18:03 +0100649
650 if (s->current_length <= head_end_offset + CLIB_CACHE_LINE_BYTES * 2)
651 {
652 buffers[0] = src_buffer;
653 for (i = 1; i < n_buffers; i++)
654 {
655 vlib_buffer_t *d;
656 d = vlib_buffer_copy (vm, s);
657 if (d == 0)
658 return i;
659 buffers[i] = vlib_get_buffer_index (vm, d);
660
661 }
662 return n_buffers;
663 }
664
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800665 if (PREDICT_FALSE (n_buffers == 1))
Damjan Marionc47ed032017-01-25 14:18:03 +0100666 {
667 buffers[0] = src_buffer;
668 return 1;
669 }
670
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800671 n_buffers = vlib_buffer_alloc_from_free_list (vm, buffers, n_buffers,
672 vlib_buffer_get_free_list_index
673 (s));
674
Damjan Marionc47ed032017-01-25 14:18:03 +0100675 for (i = 0; i < n_buffers; i++)
676 {
677 vlib_buffer_t *d = vlib_get_buffer (vm, buffers[i]);
678 d->current_data = s->current_data;
679 d->current_length = head_end_offset;
Damjan Marion072401e2017-07-13 18:53:27 +0200680 vlib_buffer_set_free_list_index (d,
681 vlib_buffer_get_free_list_index (s));
Damjan Marionc47ed032017-01-25 14:18:03 +0100682 d->total_length_not_including_first_buffer =
683 s->total_length_not_including_first_buffer + s->current_length -
684 head_end_offset;
685 d->flags = s->flags | VLIB_BUFFER_NEXT_PRESENT;
686 d->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
687 clib_memcpy (d->opaque, s->opaque, sizeof (s->opaque));
688 clib_memcpy (vlib_buffer_get_current (d), vlib_buffer_get_current (s),
689 head_end_offset);
690 d->next_buffer = src_buffer;
691 }
692 vlib_buffer_advance (s, head_end_offset);
693 s->n_add_refs = n_buffers - 1;
694 while (s->flags & VLIB_BUFFER_NEXT_PRESENT)
695 {
696 s = vlib_get_buffer (vm, s->next_buffer);
697 s->n_add_refs = n_buffers - 1;
698 }
699
700 return n_buffers;
701}
702
Neale Ranns8f36e4a2018-01-11 09:02:01 -0800703/** \brief Create multiple clones of buffer and store them
704 in the supplied array
705
706 @param vm - (vlib_main_t *) vlib main data structure pointer
707 @param src_buffer - (u32) source buffer index
708 @param buffers - (u32 * ) buffer index array
709 @param n_buffers - (u16) number of buffer clones requested (<=256)
710 @param head_end_offset - (u16) offset relative to current position
711 where packet head ends
712 @return - (u16) number of buffers actually cloned, may be
713 less than the number requested or zero
714*/
715always_inline u16
716vlib_buffer_clone (vlib_main_t * vm, u32 src_buffer, u32 * buffers,
717 u16 n_buffers, u16 head_end_offset)
718{
719 vlib_buffer_t *s = vlib_get_buffer (vm, src_buffer);
720 u16 n_cloned = 0;
721
722 while (n_buffers > 256)
723 {
724 vlib_buffer_t *copy;
725 copy = vlib_buffer_copy (vm, s);
726 n_cloned += vlib_buffer_clone_256 (vm,
727 vlib_get_buffer_index (vm, copy),
728 (buffers + n_cloned),
729 256, head_end_offset);
730 n_buffers -= 256;
731 }
732 n_cloned += vlib_buffer_clone_256 (vm, src_buffer,
733 buffers + n_cloned,
734 n_buffers, head_end_offset);
735
736 return n_cloned;
737}
738
Damjan Marionc47ed032017-01-25 14:18:03 +0100739/** \brief Attach cloned tail to the buffer
740
741 @param vm - (vlib_main_t *) vlib main data structure pointer
742 @param head - (vlib_buffer_t *) head buffer
743 @param tail - (Vlib buffer_t *) tail buffer to clone and attach to head
744*/
745
746always_inline void
747vlib_buffer_attach_clone (vlib_main_t * vm, vlib_buffer_t * head,
748 vlib_buffer_t * tail)
749{
750 ASSERT ((head->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
Damjan Marion072401e2017-07-13 18:53:27 +0200751 ASSERT (vlib_buffer_get_free_list_index (head) ==
752 vlib_buffer_get_free_list_index (tail));
Damjan Marionc47ed032017-01-25 14:18:03 +0100753
754 head->flags |= VLIB_BUFFER_NEXT_PRESENT;
755 head->flags &= ~VLIB_BUFFER_TOTAL_LENGTH_VALID;
756 head->flags &= ~VLIB_BUFFER_EXT_HDR_VALID;
757 head->flags |= (tail->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID);
758 head->next_buffer = vlib_get_buffer_index (vm, tail);
759 head->total_length_not_including_first_buffer = tail->current_length +
760 tail->total_length_not_including_first_buffer;
761
762next_segment:
763 __sync_add_and_fetch (&tail->n_add_refs, 1);
764
765 if (tail->flags & VLIB_BUFFER_NEXT_PRESENT)
766 {
767 tail = vlib_get_buffer (vm, tail->next_buffer);
768 goto next_segment;
769 }
770}
771
Pierre Pfister328e99b2016-02-12 13:18:42 +0000772/* Initializes the buffer as an empty packet with no chained buffers. */
773always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400774vlib_buffer_chain_init (vlib_buffer_t * first)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000775{
776 first->total_length_not_including_first_buffer = 0;
777 first->current_length = 0;
778 first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
779 first->flags |= VLIB_BUFFER_TOTAL_LENGTH_VALID;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000780}
781
782/* The provided next_bi buffer index is appended to the end of the packet. */
783always_inline vlib_buffer_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400784vlib_buffer_chain_buffer (vlib_main_t * vm,
785 vlib_buffer_t * first,
786 vlib_buffer_t * last, u32 next_bi)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000787{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400788 vlib_buffer_t *next_buffer = vlib_get_buffer (vm, next_bi);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000789 last->next_buffer = next_bi;
790 last->flags |= VLIB_BUFFER_NEXT_PRESENT;
791 next_buffer->current_length = 0;
792 next_buffer->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000793 return next_buffer;
794}
795
796/* Increases or decreases the packet length.
797 * It does not allocate or deallocate new buffers.
798 * Therefore, the added length must be compatible
799 * with the last buffer. */
800always_inline void
Dave Barach9b8ffd92016-07-08 08:13:45 -0400801vlib_buffer_chain_increase_length (vlib_buffer_t * first,
802 vlib_buffer_t * last, i32 len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000803{
804 last->current_length += len;
805 if (first != last)
806 first->total_length_not_including_first_buffer += len;
Pierre Pfister328e99b2016-02-12 13:18:42 +0000807}
808
809/* Copy data to the end of the packet and increases its length.
810 * It does not allocate new buffers.
811 * Returns the number of copied bytes. */
812always_inline u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400813vlib_buffer_chain_append_data (vlib_main_t * vm,
Damjan Mariondac03522018-02-01 15:30:13 +0100814 vlib_buffer_free_list_index_t free_list_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400815 vlib_buffer_t * first,
816 vlib_buffer_t * last, void *data, u16 data_len)
Pierre Pfister328e99b2016-02-12 13:18:42 +0000817{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400818 u32 n_buffer_bytes =
819 vlib_buffer_free_list_buffer_size (vm, free_list_index);
820 ASSERT (n_buffer_bytes >= last->current_length + last->current_data);
821 u16 len = clib_min (data_len,
822 n_buffer_bytes - last->current_length -
823 last->current_data);
824 clib_memcpy (vlib_buffer_get_current (last) + last->current_length, data,
825 len);
826 vlib_buffer_chain_increase_length (first, last, len);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000827 return len;
828}
829
830/* Copy data to the end of the packet and increases its length.
831 * Allocates additional buffers from the free list if necessary.
832 * Returns the number of copied bytes.
833 * 'last' value is modified whenever new buffers are allocated and
834 * chained and points to the last buffer in the chain. */
835u16
Dave Barach9b8ffd92016-07-08 08:13:45 -0400836vlib_buffer_chain_append_data_with_alloc (vlib_main_t * vm,
Damjan Mariondac03522018-02-01 15:30:13 +0100837 vlib_buffer_free_list_index_t
838 free_list_index,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400839 vlib_buffer_t * first,
Damjan Mariondac03522018-02-01 15:30:13 +0100840 vlib_buffer_t ** last, void *data,
841 u16 data_len);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400842void vlib_buffer_chain_validate (vlib_main_t * vm, vlib_buffer_t * first);
Pierre Pfister328e99b2016-02-12 13:18:42 +0000843
Dave Barach9b8ffd92016-07-08 08:13:45 -0400844format_function_t format_vlib_buffer, format_vlib_buffer_and_data,
845 format_vlib_buffer_contents;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700846
Dave Barach9b8ffd92016-07-08 08:13:45 -0400847typedef struct
848{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700849 /* Vector of packet data. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400850 u8 *packet_data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700851
Damjan Mariond1274cb2018-03-13 21:32:17 +0100852 /* Number of buffers to allocate in each call to allocator. */
853 u32 min_n_buffers_each_alloc;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854
855 /* Buffer free list for this template. */
Damjan Mariondac03522018-02-01 15:30:13 +0100856 vlib_buffer_free_list_index_t free_list_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857
Dave Barach9b8ffd92016-07-08 08:13:45 -0400858 u32 *free_buffers;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700859} vlib_packet_template_t;
860
861void vlib_packet_template_get_packet_helper (vlib_main_t * vm,
862 vlib_packet_template_t * t);
863
864void vlib_packet_template_init (vlib_main_t * vm,
865 vlib_packet_template_t * t,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400866 void *packet_data,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867 uword n_packet_data_bytes,
Damjan Mariond1274cb2018-03-13 21:32:17 +0100868 uword min_n_buffers_each_alloc,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400869 char *fmt, ...);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700870
Dave Barach9b8ffd92016-07-08 08:13:45 -0400871void *vlib_packet_template_get_packet (vlib_main_t * vm,
872 vlib_packet_template_t * t,
873 u32 * bi_result);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700874
875always_inline void
876vlib_packet_template_free (vlib_main_t * vm, vlib_packet_template_t * t)
877{
878 vec_free (t->packet_data);
879}
880
881always_inline u32
882unserialize_vlib_buffer_n_bytes (serialize_main_t * m)
883{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400884 serialize_stream_t *s = &m->stream;
885 vlib_serialize_buffer_main_t *sm
886 = uword_to_pointer (m->stream.data_function_opaque,
887 vlib_serialize_buffer_main_t *);
888 vlib_main_t *vm = sm->vlib_main;
889 u32 n, *f;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700890
891 n = s->n_buffer_bytes - s->current_buffer_index;
892 if (sm->last_buffer != ~0)
893 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400894 vlib_buffer_t *b = vlib_get_buffer (vm, sm->last_buffer);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700895 while (b->flags & VLIB_BUFFER_NEXT_PRESENT)
896 {
897 b = vlib_get_buffer (vm, b->next_buffer);
898 n += b->current_length;
899 }
900 }
901
Dave Barach9b8ffd92016-07-08 08:13:45 -0400902 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700903 clib_fifo_foreach (f, sm->rx.buffer_fifo, ({
904 n += vlib_buffer_index_length_in_chain (vm, f[0]);
905 }));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400906/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907
908 return n;
909}
910
Ed Warnickecb9cada2015-12-08 15:45:58 -0700911/* Set a buffer quickly into "uninitialized" state. We want this to
912 be extremely cheap and arrange for all fields that need to be
913 initialized to be in the first 128 bits of the buffer. */
914always_inline void
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100915vlib_buffer_init_for_free_list (vlib_buffer_t * dst,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916 vlib_buffer_free_list_t * fl)
917{
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100918 vlib_buffer_t *src = &fl->buffer_init_template;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700919
Damjan Marion19010202016-03-24 17:17:47 +0100920 /* Make sure vlib_buffer_t is cacheline aligned and sized */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400921 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline0) == 0);
922 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline1) ==
923 CLIB_CACHE_LINE_BYTES);
924 ASSERT (STRUCT_OFFSET_OF (vlib_buffer_t, cacheline2) ==
925 CLIB_CACHE_LINE_BYTES * 2);
Damjan Marion19010202016-03-24 17:17:47 +0100926
Ed Warnickecb9cada2015-12-08 15:45:58 -0700927 /* Make sure buffer template is sane. */
Damjan Marion072401e2017-07-13 18:53:27 +0200928 ASSERT (fl->index == vlib_buffer_get_free_list_index (src));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700929
Dave Barachf8690282017-03-01 11:38:02 -0500930 clib_memcpy (STRUCT_MARK_PTR (dst, template_start),
931 STRUCT_MARK_PTR (src, template_start),
932 STRUCT_OFFSET_OF (vlib_buffer_t, template_end) -
933 STRUCT_OFFSET_OF (vlib_buffer_t, template_start));
934
935 /* Not in the first 16 octets. */
936 dst->n_add_refs = src->n_add_refs;
Damjan Mariondac03522018-02-01 15:30:13 +0100937 vlib_buffer_set_free_list_index (dst, fl->index);
Dave Barachf8690282017-03-01 11:38:02 -0500938
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939 /* Make sure it really worked. */
Dave Barachf8690282017-03-01 11:38:02 -0500940#define _(f) ASSERT (dst->f == src->f);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400941 _(current_data);
942 _(current_length);
943 _(flags);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700944#undef _
Florin Corasb2215d62017-08-01 16:56:58 -0700945 /* ASSERT (dst->total_length_not_including_first_buffer == 0); */
946 /* total_length_not_including_first_buffer is not in the template anymore
947 * so it may actually not zeroed for some buffers. One option is to
948 * uncomment the line lower (comes at a cost), the other, is to just not
949 * care */
950 /* dst->total_length_not_including_first_buffer = 0; */
Damjan Marionc47ed032017-01-25 14:18:03 +0100951 ASSERT (dst->n_add_refs == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700952}
953
954always_inline void
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100955vlib_buffer_add_to_free_list (vlib_main_t * vm,
956 vlib_buffer_free_list_t * f,
957 u32 buffer_index, u8 do_init)
958{
Damjan Mariond1274cb2018-03-13 21:32:17 +0100959 vlib_buffer_pool_t *bp = vlib_buffer_pool_get (f->buffer_pool_index);
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100960 vlib_buffer_t *b;
961 b = vlib_get_buffer (vm, buffer_index);
962 if (PREDICT_TRUE (do_init))
963 vlib_buffer_init_for_free_list (b, f);
Damjan Marionbd69a5f2017-02-05 23:44:42 +0100964 vec_add1_aligned (f->buffers, buffer_index, CLIB_CACHE_LINE_BYTES);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400965
Damjan Marionb6a8ed72017-08-29 00:15:35 +0200966 if (vec_len (f->buffers) > 4 * VLIB_FRAME_SIZE)
Damjan Marion6b0f5892017-07-27 04:01:24 -0400967 {
Damjan Mariond1274cb2018-03-13 21:32:17 +0100968 clib_spinlock_lock (&bp->lock);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400969 /* keep last stored buffers, as they are more likely hot in the cache */
Damjan Mariond1274cb2018-03-13 21:32:17 +0100970 vec_add_aligned (bp->buffers, f->buffers, VLIB_FRAME_SIZE,
Damjan Marionb6a8ed72017-08-29 00:15:35 +0200971 CLIB_CACHE_LINE_BYTES);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400972 vec_delete (f->buffers, VLIB_FRAME_SIZE, 0);
Klement Sekera75e974b2017-11-09 09:12:12 +0100973 f->n_alloc -= VLIB_FRAME_SIZE;
Damjan Mariond1274cb2018-03-13 21:32:17 +0100974 clib_spinlock_unlock (&bp->lock);
Damjan Marion6b0f5892017-07-27 04:01:24 -0400975 }
Damjan Marion8a6a3b22017-01-17 14:12:42 +0100976}
977
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978#if CLIB_DEBUG > 0
Damjan Marion6a7acc22016-12-19 16:28:36 +0100979extern u32 *vlib_buffer_state_validation_lock;
980extern uword *vlib_buffer_state_validation_hash;
981extern void *vlib_buffer_state_heap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982#endif
983
Dave Barach9b8ffd92016-07-08 08:13:45 -0400984static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -0700985vlib_validate_buffer_in_use (vlib_buffer_t * b, u32 expected)
986{
987#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -0400988 uword *p;
989 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700990
991 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
992
993 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
994 ;
995
996 p = hash_get (vlib_buffer_state_validation_hash, b);
997
998 /* If we don't know about b, declare it to be in the expected state */
999 if (!p)
1000 {
1001 hash_set (vlib_buffer_state_validation_hash, b, expected);
1002 goto out;
1003 }
Dave Barach9b8ffd92016-07-08 08:13:45 -04001004
Ed Warnickecb9cada2015-12-08 15:45:58 -07001005 if (p[0] != expected)
1006 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001007 void cj_stop (void);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008 u32 bi;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001009 vlib_main_t *vm = &vlib_global_main;
1010
1011 cj_stop ();
1012
Ed Warnickecb9cada2015-12-08 15:45:58 -07001013 bi = vlib_get_buffer_index (vm, b);
1014
1015 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001016 clib_warning ("%.6f buffer %llx (%d): %s, not %s",
1017 vlib_time_now (vm), bi,
1018 p[0] ? "busy" : "free", expected ? "busy" : "free");
1019 os_panic ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020 }
Dave Barach9b8ffd92016-07-08 08:13:45 -04001021out:
1022 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023 *vlib_buffer_state_validation_lock = 0;
1024 clib_mem_set_heap (oldheap);
1025#endif
1026}
1027
Dave Barach9b8ffd92016-07-08 08:13:45 -04001028static inline void
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029vlib_validate_buffer_set_in_use (vlib_buffer_t * b, u32 expected)
1030{
1031#if CLIB_DEBUG > 0
Dave Barach9b8ffd92016-07-08 08:13:45 -04001032 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001033
1034 oldheap = clib_mem_set_heap (vlib_buffer_state_heap);
1035
1036 while (__sync_lock_test_and_set (vlib_buffer_state_validation_lock, 1))
1037 ;
1038
1039 hash_set (vlib_buffer_state_validation_hash, b, expected);
1040
Dave Barach9b8ffd92016-07-08 08:13:45 -04001041 CLIB_MEMORY_BARRIER ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042 *vlib_buffer_state_validation_lock = 0;
1043 clib_mem_set_heap (oldheap);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001044#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -07001045}
1046
Klement Sekera75e7d132017-09-20 08:26:30 +02001047/** minimum data size of first buffer in a buffer chain */
1048#define VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE (256)
1049
1050/**
1051 * @brief compress buffer chain in a way where the first buffer is at least
1052 * VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE long
1053 *
1054 * @param[in] vm - vlib_main
1055 * @param[in,out] first - first buffer in chain
1056 * @param[in,out] discard_vector - vector of buffer indexes which were removed
1057 * from the chain
1058 */
1059always_inline void
1060vlib_buffer_chain_compress (vlib_main_t * vm,
1061 vlib_buffer_t * first, u32 ** discard_vector)
1062{
1063 if (first->current_length >= VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE ||
1064 !(first->flags & VLIB_BUFFER_NEXT_PRESENT))
1065 {
1066 /* this is already big enough or not a chain */
1067 return;
1068 }
1069 /* probe free list to find allocated buffer size to avoid overfill */
Damjan Mariondac03522018-02-01 15:30:13 +01001070 vlib_buffer_free_list_index_t index;
Klement Sekera75e7d132017-09-20 08:26:30 +02001071 vlib_buffer_free_list_t *free_list =
1072 vlib_buffer_get_buffer_free_list (vm, first, &index);
1073
1074 u32 want_first_size = clib_min (VLIB_BUFFER_CHAIN_MIN_FIRST_DATA_SIZE,
1075 free_list->n_data_bytes -
1076 first->current_data);
1077 do
1078 {
1079 vlib_buffer_t *second = vlib_get_buffer (vm, first->next_buffer);
1080 u32 need = want_first_size - first->current_length;
1081 u32 amount_to_copy = clib_min (need, second->current_length);
1082 clib_memcpy (((u8 *) vlib_buffer_get_current (first)) +
1083 first->current_length,
1084 vlib_buffer_get_current (second), amount_to_copy);
1085 first->current_length += amount_to_copy;
1086 vlib_buffer_advance (second, amount_to_copy);
1087 if (first->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID)
1088 {
1089 first->total_length_not_including_first_buffer -= amount_to_copy;
1090 }
1091 if (!second->current_length)
1092 {
1093 vec_add1 (*discard_vector, first->next_buffer);
1094 if (second->flags & VLIB_BUFFER_NEXT_PRESENT)
1095 {
1096 first->next_buffer = second->next_buffer;
1097 }
1098 else
1099 {
1100 first->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1101 }
1102 second->flags &= ~VLIB_BUFFER_NEXT_PRESENT;
1103 }
1104 }
1105 while ((first->current_length < want_first_size) &&
1106 (first->flags & VLIB_BUFFER_NEXT_PRESENT));
1107}
1108
Ed Warnickecb9cada2015-12-08 15:45:58 -07001109#endif /* included_vlib_buffer_funcs_h */
Dave Barach9b8ffd92016-07-08 08:13:45 -04001110
1111/*
1112 * fd.io coding-style-patch-verification: ON
1113 *
1114 * Local Variables:
1115 * eval: (c-set-style "gnu")
1116 * End:
1117 */