Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <string.h>
6 : : #include <sys/queue.h>
7 : :
8 : : #include <rte_string_fns.h>
9 : : #include <rte_log.h>
10 : : #include <rte_mbuf.h>
11 : : #include <rte_mbuf_dyn.h>
12 : : #include <rte_eal_memconfig.h>
13 : : #include <rte_errno.h>
14 : : #include <rte_malloc.h>
15 : : #include <rte_tailq.h>
16 : :
17 : : #include "rte_reorder.h"
18 : :
19 [ - + ]: 235 : RTE_LOG_REGISTER_DEFAULT(reorder_logtype, INFO);
20 : : #define RTE_LOGTYPE_REORDER reorder_logtype
21 : : #define REORDER_LOG(level, ...) \
22 : : RTE_LOG_LINE(level, REORDER, "" __VA_ARGS__)
23 : :
24 : : TAILQ_HEAD(rte_reorder_list, rte_tailq_entry);
25 : :
26 : : static struct rte_tailq_elem rte_reorder_tailq = {
27 : : .name = "RTE_REORDER",
28 : : };
29 [ - + ]: 235 : EAL_REGISTER_TAILQ(rte_reorder_tailq)
30 : :
31 : : #define NO_FLAGS 0
32 : : #define RTE_REORDER_PREFIX "RO_"
33 : : #define RTE_REORDER_NAMESIZE 32
34 : :
35 : : #define RTE_REORDER_SEQN_DYNFIELD_NAME "rte_reorder_seqn_dynfield"
36 : : int rte_reorder_seqn_dynfield_offset = -1;
37 : :
38 : : /* A generic circular buffer */
39 : : struct cir_buffer {
40 : : unsigned int size; /**< Number of entries that can be stored */
41 : : unsigned int mask; /**< [buffer_size - 1]: used for wrap-around */
42 : : unsigned int head; /**< insertion point in buffer */
43 : : unsigned int tail; /**< extraction point in buffer */
44 : : struct rte_mbuf **entries;
45 : : } __rte_cache_aligned;
46 : :
47 : : /* The reorder buffer data structure itself */
48 : : struct rte_reorder_buffer {
49 : : char name[RTE_REORDER_NAMESIZE];
50 : : uint32_t min_seqn; /**< Lowest seq. number that can be in the buffer */
51 : : unsigned int memsize; /**< memory area size of reorder buffer */
52 : : bool is_initialized; /**< flag indicates that buffer was initialized */
53 : :
54 : : struct cir_buffer ready_buf; /**< temp buffer for dequeued entries */
55 : : struct cir_buffer order_buf; /**< buffer used to reorder entries */
56 : : } __rte_cache_aligned;
57 : :
58 : : static void
59 : : rte_reorder_free_mbufs(struct rte_reorder_buffer *b);
60 : :
61 : : unsigned int
62 : 22 : rte_reorder_memory_footprint_get(unsigned int size)
63 : : {
64 : 22 : return sizeof(struct rte_reorder_buffer) + (2 * size * sizeof(struct rte_mbuf *));
65 : : }
66 : :
67 : : struct rte_reorder_buffer *
68 : 11 : rte_reorder_init(struct rte_reorder_buffer *b, unsigned int bufsize,
69 : : const char *name, unsigned int size)
70 : : {
71 : 11 : const unsigned int min_bufsize = rte_reorder_memory_footprint_get(size);
72 : : static const struct rte_mbuf_dynfield reorder_seqn_dynfield_desc = {
73 : : .name = RTE_REORDER_SEQN_DYNFIELD_NAME,
74 : : .size = sizeof(rte_reorder_seqn_t),
75 : : .align = __alignof__(rte_reorder_seqn_t),
76 : : };
77 : :
78 [ + + ]: 11 : if (b == NULL) {
79 : 2 : REORDER_LOG(ERR, "Invalid reorder buffer parameter:"
80 : : " NULL");
81 : 2 : rte_errno = EINVAL;
82 : 2 : return NULL;
83 : : }
84 : : if (!rte_is_power_of_2(size)) {
85 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer size"
86 : : " - Not a power of 2");
87 : 1 : rte_errno = EINVAL;
88 : 1 : return NULL;
89 : : }
90 [ - + ]: 8 : if (name == NULL) {
91 : 0 : REORDER_LOG(ERR, "Invalid reorder buffer name ptr:"
92 : : " NULL");
93 : 0 : rte_errno = EINVAL;
94 : 0 : return NULL;
95 : : }
96 [ + + ]: 8 : if (bufsize < min_bufsize) {
97 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer memory size: %u, "
98 : : "minimum required: %u", bufsize, min_bufsize);
99 : 1 : rte_errno = EINVAL;
100 : 1 : return NULL;
101 : : }
102 : :
103 : 7 : rte_reorder_seqn_dynfield_offset = rte_mbuf_dynfield_register(&reorder_seqn_dynfield_desc);
104 [ - + ]: 7 : if (rte_reorder_seqn_dynfield_offset < 0) {
105 : 0 : REORDER_LOG(ERR,
106 : : "Failed to register mbuf field for reorder sequence number, rte_errno: %i",
107 : : rte_errno);
108 : 0 : rte_errno = ENOMEM;
109 : 0 : return NULL;
110 : : }
111 : :
112 : 7 : memset(b, 0, bufsize);
113 : 7 : strlcpy(b->name, name, sizeof(b->name));
114 : 7 : b->memsize = bufsize;
115 : 7 : b->order_buf.size = b->ready_buf.size = size;
116 : 7 : b->order_buf.mask = b->ready_buf.mask = size - 1;
117 : 7 : b->ready_buf.entries = (void *)&b[1];
118 : 7 : b->order_buf.entries = RTE_PTR_ADD(&b[1],
119 : : size * sizeof(b->ready_buf.entries[0]));
120 : :
121 : 7 : return b;
122 : : }
123 : :
124 : : /*
125 : : * Insert new entry into global list.
126 : : * Returns pointer to already inserted entry if such exists, or to newly inserted one.
127 : : */
128 : : static struct rte_tailq_entry *
129 : 7 : rte_reorder_entry_insert(struct rte_tailq_entry *new_te)
130 : : {
131 : : struct rte_reorder_list *reorder_list;
132 : : struct rte_reorder_buffer *b, *nb;
133 : : struct rte_tailq_entry *te;
134 : :
135 : 7 : rte_mcfg_tailq_write_lock();
136 : :
137 : 7 : reorder_list = RTE_TAILQ_CAST(rte_reorder_tailq.head, rte_reorder_list);
138 : : /* guarantee there's no existing */
139 [ + + ]: 12 : TAILQ_FOREACH(te, reorder_list, next) {
140 : 6 : b = (struct rte_reorder_buffer *) te->data;
141 : 6 : nb = (struct rte_reorder_buffer *) new_te->data;
142 [ + + ]: 6 : if (strncmp(nb->name, b->name, RTE_REORDER_NAMESIZE) == 0)
143 : : break;
144 : : }
145 : :
146 [ + + ]: 7 : if (te == NULL) {
147 : 6 : TAILQ_INSERT_TAIL(reorder_list, new_te, next);
148 : : te = new_te;
149 : : }
150 : :
151 : 7 : rte_mcfg_tailq_write_unlock();
152 : :
153 : 7 : return te;
154 : : }
155 : :
156 : : struct rte_reorder_buffer*
157 : 9 : rte_reorder_create(const char *name, unsigned socket_id, unsigned int size)
158 : : {
159 : : struct rte_reorder_buffer *b = NULL;
160 : : struct rte_tailq_entry *te, *te_inserted;
161 : :
162 : 9 : const unsigned int bufsize = rte_reorder_memory_footprint_get(size);
163 : :
164 : : /* Check user arguments. */
165 : : if (!rte_is_power_of_2(size)) {
166 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer size"
167 : : " - Not a power of 2");
168 : 1 : rte_errno = EINVAL;
169 : 1 : return NULL;
170 : : }
171 [ + + ]: 8 : if (name == NULL) {
172 : 1 : REORDER_LOG(ERR, "Invalid reorder buffer name ptr:"
173 : : " NULL");
174 : 1 : rte_errno = EINVAL;
175 : 1 : return NULL;
176 : : }
177 : :
178 : : /* allocate tailq entry */
179 : 7 : te = rte_zmalloc("REORDER_TAILQ_ENTRY", sizeof(*te), 0);
180 [ - + ]: 7 : if (te == NULL) {
181 : 0 : REORDER_LOG(ERR, "Failed to allocate tailq entry");
182 : 0 : rte_errno = ENOMEM;
183 : 0 : return NULL;
184 : : }
185 : :
186 : : /* Allocate memory to store the reorder buffer structure. */
187 : 7 : b = rte_zmalloc_socket("REORDER_BUFFER", bufsize, 0, socket_id);
188 [ - + ]: 7 : if (b == NULL) {
189 : 0 : REORDER_LOG(ERR, "Memzone allocation failed");
190 : 0 : rte_errno = ENOMEM;
191 : 0 : rte_free(te);
192 : 0 : return NULL;
193 : : } else {
194 [ - + ]: 7 : if (rte_reorder_init(b, bufsize, name, size) == NULL) {
195 : 0 : rte_free(b);
196 : 0 : rte_free(te);
197 : 0 : return NULL;
198 : : }
199 : 7 : te->data = (void *)b;
200 : : }
201 : :
202 : 7 : te_inserted = rte_reorder_entry_insert(te);
203 [ + + ]: 7 : if (te_inserted != te) {
204 : 1 : rte_free(b);
205 : 1 : rte_free(te);
206 : 1 : return te_inserted->data;
207 : : }
208 : :
209 : : return b;
210 : : }
211 : :
212 : : void
213 : 0 : rte_reorder_reset(struct rte_reorder_buffer *b)
214 : : {
215 : : char name[RTE_REORDER_NAMESIZE];
216 : :
217 : 0 : rte_reorder_free_mbufs(b);
218 : 0 : strlcpy(name, b->name, sizeof(name));
219 : : /* No error checking as current values should be valid */
220 : 0 : rte_reorder_init(b, b->memsize, name, b->order_buf.size);
221 : 0 : }
222 : :
223 : : static void
224 : 6 : rte_reorder_free_mbufs(struct rte_reorder_buffer *b)
225 : : {
226 : : unsigned i;
227 : :
228 : : /* Free up the mbufs of order buffer & ready buffer */
229 [ + + ]: 16414 : for (i = 0; i < b->order_buf.size; i++) {
230 : 16408 : rte_pktmbuf_free(b->order_buf.entries[i]);
231 : 16408 : rte_pktmbuf_free(b->ready_buf.entries[i]);
232 : : }
233 : 6 : }
234 : :
235 : : void
236 : 6 : rte_reorder_free(struct rte_reorder_buffer *b)
237 : : {
238 : : struct rte_reorder_list *reorder_list;
239 : : struct rte_tailq_entry *te;
240 : :
241 : : /* Check user arguments. */
242 [ + - ]: 6 : if (b == NULL)
243 : : return;
244 : :
245 : 6 : reorder_list = RTE_TAILQ_CAST(rte_reorder_tailq.head, rte_reorder_list);
246 : :
247 : 6 : rte_mcfg_tailq_write_lock();
248 : :
249 : : /* find our tailq entry */
250 [ + - ]: 11 : TAILQ_FOREACH(te, reorder_list, next) {
251 [ + + ]: 11 : if (te->data == (void *) b)
252 : : break;
253 : : }
254 [ - + ]: 6 : if (te == NULL) {
255 : 0 : rte_mcfg_tailq_write_unlock();
256 : 0 : return;
257 : : }
258 : :
259 [ - + ]: 6 : TAILQ_REMOVE(reorder_list, te, next);
260 : :
261 : 6 : rte_mcfg_tailq_write_unlock();
262 : :
263 : 6 : rte_reorder_free_mbufs(b);
264 : :
265 : 6 : rte_free(b);
266 : 6 : rte_free(te);
267 : : }
268 : :
269 : : struct rte_reorder_buffer *
270 : 4 : rte_reorder_find_existing(const char *name)
271 : : {
272 : : struct rte_reorder_buffer *b = NULL;
273 : : struct rte_tailq_entry *te;
274 : : struct rte_reorder_list *reorder_list;
275 : :
276 [ - + ]: 4 : if (name == NULL) {
277 : 0 : rte_errno = EINVAL;
278 : 0 : return NULL;
279 : : }
280 : :
281 : 4 : reorder_list = RTE_TAILQ_CAST(rte_reorder_tailq.head, rte_reorder_list);
282 : :
283 : 4 : rte_mcfg_tailq_read_lock();
284 [ + + ]: 7 : TAILQ_FOREACH(te, reorder_list, next) {
285 : 5 : b = (struct rte_reorder_buffer *) te->data;
286 [ + + ]: 5 : if (strncmp(name, b->name, RTE_REORDER_NAMESIZE) == 0)
287 : : break;
288 : : }
289 : 4 : rte_mcfg_tailq_read_unlock();
290 : :
291 [ + + ]: 4 : if (te == NULL) {
292 : 2 : rte_errno = ENOENT;
293 : 2 : return NULL;
294 : : }
295 : :
296 : : return b;
297 : : }
298 : :
299 : : static unsigned
300 : 4 : rte_reorder_fill_overflow(struct rte_reorder_buffer *b, unsigned n)
301 : : {
302 : : /*
303 : : * 1. Move all ready entries that fit to the ready_buf
304 : : * 2. check if we meet the minimum needed (n).
305 : : * 3. If not, then skip any gaps and keep moving.
306 : : * 4. If at any point the ready buffer is full, stop
307 : : * 5. Return the number of positions the order_buf head has moved
308 : : */
309 : :
310 : : struct cir_buffer *order_buf = &b->order_buf,
311 : : *ready_buf = &b->ready_buf;
312 : :
313 : : unsigned int order_head_adv = 0;
314 : :
315 : : /*
316 : : * move at least n packets to ready buffer, assuming ready buffer
317 : : * has room for those packets.
318 : : */
319 [ + + ]: 11 : while (order_head_adv < n &&
320 [ + + ]: 4 : ((ready_buf->head + 1) & ready_buf->mask) != ready_buf->tail) {
321 : :
322 : : /* if we are blocked waiting on a packet, skip it */
323 [ - + ]: 3 : if (order_buf->entries[order_buf->head] == NULL) {
324 : 0 : order_buf->head = (order_buf->head + 1) & order_buf->mask;
325 : 0 : order_head_adv++;
326 : : }
327 : :
328 : : /* Move all ready entries that fit to the ready_buf */
329 [ + + ]: 11 : while (order_buf->entries[order_buf->head] != NULL) {
330 : 9 : ready_buf->entries[ready_buf->head] =
331 : : order_buf->entries[order_buf->head];
332 : :
333 : 9 : order_buf->entries[order_buf->head] = NULL;
334 : 9 : order_head_adv++;
335 : :
336 : 9 : order_buf->head = (order_buf->head + 1) & order_buf->mask;
337 : :
338 [ + + ]: 9 : if (((ready_buf->head + 1) & ready_buf->mask) == ready_buf->tail)
339 : : break;
340 : :
341 : 8 : ready_buf->head = (ready_buf->head + 1) & ready_buf->mask;
342 : : }
343 : : }
344 : :
345 : 4 : b->min_seqn += order_head_adv;
346 : : /* Return the number of positions the order_buf head has moved */
347 : 4 : return order_head_adv;
348 : : }
349 : :
350 : : int
351 : 20 : rte_reorder_insert(struct rte_reorder_buffer *b, struct rte_mbuf *mbuf)
352 : : {
353 : : uint32_t offset, position;
354 : : struct cir_buffer *order_buf;
355 : :
356 [ - + ]: 20 : if (b == NULL || mbuf == NULL) {
357 : 0 : rte_errno = EINVAL;
358 : 0 : return -1;
359 : : }
360 : :
361 : : order_buf = &b->order_buf;
362 [ + + ]: 20 : if (!b->is_initialized) {
363 : 3 : b->min_seqn = *rte_reorder_seqn(mbuf);
364 : 3 : b->is_initialized = 1;
365 : : }
366 : :
367 : : /*
368 : : * calculate the offset from the head pointer we need to go.
369 : : * The subtraction takes care of the sequence number wrapping.
370 : : * For example (using 16-bit for brevity):
371 : : * min_seqn = 0xFFFD
372 : : * mbuf_seqn = 0x0010
373 : : * offset = 0x0010 - 0xFFFD = 0x13
374 : : */
375 : 20 : offset = *rte_reorder_seqn(mbuf) - b->min_seqn;
376 : :
377 : : /*
378 : : * action to take depends on offset.
379 : : * offset < buffer->size: the mbuf fits within the current window of
380 : : * sequence numbers we can reorder. EXPECTED CASE.
381 : : * offset > buffer->size: the mbuf is outside the current window. There
382 : : * are a number of cases to consider:
383 : : * 1. The packet sequence is just outside the window, then we need
384 : : * to see about shifting the head pointer and taking any ready
385 : : * to return packets out of the ring. If there was a delayed
386 : : * or dropped packet preventing drains from shifting the window
387 : : * this case will skip over the dropped packet instead, and any
388 : : * packets dequeued here will be returned on the next drain call.
389 : : * 2. The packet sequence number is vastly outside our window, taken
390 : : * here as having offset greater than twice the buffer size. In
391 : : * this case, the packet is probably an old or late packet that
392 : : * was previously skipped, so just enqueue the packet for
393 : : * immediate return on the next drain call, or else return error.
394 : : */
395 [ + + ]: 20 : if (offset < b->order_buf.size) {
396 : 14 : position = (order_buf->head + offset) & order_buf->mask;
397 : 14 : order_buf->entries[position] = mbuf;
398 [ + + ]: 6 : } else if (offset < 2 * b->order_buf.size) {
399 [ + + ]: 4 : if (rte_reorder_fill_overflow(b, offset + 1 - order_buf->size)
400 : : < (offset + 1 - order_buf->size)) {
401 : : /* Put in handling for enqueue straight to output */
402 : 1 : rte_errno = ENOSPC;
403 : 1 : return -1;
404 : : }
405 : 3 : offset = *rte_reorder_seqn(mbuf) - b->min_seqn;
406 : 3 : position = (order_buf->head + offset) & order_buf->mask;
407 : 3 : order_buf->entries[position] = mbuf;
408 : : } else {
409 : : /* Put in handling for enqueue straight to output */
410 : 2 : rte_errno = ERANGE;
411 : 2 : return -1;
412 : : }
413 : : return 0;
414 : : }
415 : :
416 : : unsigned int
417 : 4 : rte_reorder_drain(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
418 : : unsigned max_mbufs)
419 : : {
420 : : unsigned int drain_cnt = 0;
421 : :
422 : : struct cir_buffer *order_buf = &b->order_buf,
423 : : *ready_buf = &b->ready_buf;
424 : :
425 : : /* Try to fetch requested number of mbufs from ready buffer */
426 [ - + + + ]: 7 : while ((drain_cnt < max_mbufs) && (ready_buf->tail != ready_buf->head)) {
427 : 3 : mbufs[drain_cnt++] = ready_buf->entries[ready_buf->tail];
428 : 3 : ready_buf->entries[ready_buf->tail] = NULL;
429 : 3 : ready_buf->tail = (ready_buf->tail + 1) & ready_buf->mask;
430 : : }
431 : :
432 : : /*
433 : : * If requested number of buffers not fetched from ready buffer, fetch
434 : : * remaining buffers from order buffer
435 : : */
436 [ + + ]: 5 : while ((drain_cnt < max_mbufs) &&
437 [ + + ]: 4 : (order_buf->entries[order_buf->head] != NULL)) {
438 : 1 : mbufs[drain_cnt++] = order_buf->entries[order_buf->head];
439 : 1 : order_buf->entries[order_buf->head] = NULL;
440 : 1 : b->min_seqn++;
441 : 1 : order_buf->head = (order_buf->head + 1) & order_buf->mask;
442 : : }
443 : :
444 : 4 : return drain_cnt;
445 : : }
446 : :
447 : : /* Binary search seqn in ready buffer */
448 : : static inline uint32_t
449 : 0 : ready_buffer_seqn_find(const struct cir_buffer *ready_buf, const uint32_t seqn)
450 : : {
451 : : uint32_t mid, value, position, high;
452 : : uint32_t low = 0;
453 : :
454 [ # # ]: 0 : if (ready_buf->tail > ready_buf->head)
455 : 0 : high = ready_buf->tail - ready_buf->head;
456 : : else
457 : 0 : high = ready_buf->head - ready_buf->tail;
458 : :
459 [ # # ]: 0 : while (low <= high) {
460 : 0 : mid = low + (high - low) / 2;
461 : 0 : position = (ready_buf->tail + mid) & ready_buf->mask;
462 [ # # ]: 0 : value = *rte_reorder_seqn(ready_buf->entries[position]);
463 [ # # ]: 0 : if (seqn == value)
464 : 0 : return mid;
465 [ # # ]: 0 : else if (seqn > value)
466 : 0 : low = mid + 1;
467 : : else
468 : 0 : high = mid - 1;
469 : : }
470 : :
471 : : return low;
472 : : }
473 : :
474 : : unsigned int
475 : 2 : rte_reorder_drain_up_to_seqn(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
476 : : const unsigned int max_mbufs, const rte_reorder_seqn_t seqn)
477 : : {
478 : : uint32_t i, position, offset;
479 : : unsigned int drain_cnt = 0;
480 : :
481 : : struct cir_buffer *order_buf = &b->order_buf,
482 : 2 : *ready_buf = &b->ready_buf;
483 : :
484 : : /* Seqn in Ready buffer */
485 [ - + ]: 2 : if (seqn < b->min_seqn) {
486 : : /* All sequence numbers are higher then given */
487 [ # # # # ]: 0 : if ((ready_buf->tail == ready_buf->head) ||
488 [ # # ]: 0 : (*rte_reorder_seqn(ready_buf->entries[ready_buf->tail]) > seqn))
489 : : return 0;
490 : :
491 : 0 : offset = ready_buffer_seqn_find(ready_buf, seqn);
492 : :
493 [ # # ]: 0 : for (i = 0; (i < offset) && (drain_cnt < max_mbufs); i++) {
494 : 0 : position = (ready_buf->tail + i) & ready_buf->mask;
495 : 0 : mbufs[drain_cnt++] = ready_buf->entries[position];
496 : 0 : ready_buf->entries[position] = NULL;
497 : : }
498 : 0 : ready_buf->tail = (ready_buf->tail + i) & ready_buf->mask;
499 : :
500 : 0 : return drain_cnt;
501 : : }
502 : :
503 : : /* Seqn in Order buffer, add all buffers from Ready buffer */
504 [ + - + + ]: 4 : while ((drain_cnt < max_mbufs) && (ready_buf->tail != ready_buf->head)) {
505 : 2 : mbufs[drain_cnt++] = ready_buf->entries[ready_buf->tail];
506 : 2 : ready_buf->entries[ready_buf->tail] = NULL;
507 : 2 : ready_buf->tail = (ready_buf->tail + 1) & ready_buf->mask;
508 : : }
509 : :
510 : : /* Fetch buffers from Order buffer up to given sequence number (exclusive) */
511 : 2 : offset = RTE_MIN(seqn - b->min_seqn, b->order_buf.size);
512 [ + + ]: 5 : for (i = 0; (i < offset) && (drain_cnt < max_mbufs); i++) {
513 : 3 : position = (order_buf->head + i) & order_buf->mask;
514 [ + + ]: 3 : if (order_buf->entries[position] == NULL)
515 : 1 : continue;
516 : 2 : mbufs[drain_cnt++] = order_buf->entries[position];
517 : 2 : order_buf->entries[position] = NULL;
518 : : }
519 : 2 : b->min_seqn += i;
520 : 2 : order_buf->head = (order_buf->head + i) & order_buf->mask;
521 : :
522 : 2 : return drain_cnt;
523 : : }
524 : :
525 : : static bool
526 : : rte_reorder_is_empty(const struct rte_reorder_buffer *b)
527 : : {
528 : : const struct cir_buffer *order_buf = &b->order_buf, *ready_buf = &b->ready_buf;
529 : : unsigned int i;
530 : :
531 : : /* Ready buffer does not have gaps */
532 : 2 : if (ready_buf->tail != ready_buf->head)
533 : : return false;
534 : :
535 : : /* Order buffer could have gaps, iterate */
536 [ + + ]: 6 : for (i = 0; i < order_buf->size; i++) {
537 [ + + ]: 5 : if (order_buf->entries[i] != NULL)
538 : : return false;
539 : : }
540 : :
541 : : return true;
542 : : }
543 : :
544 : : unsigned int
545 [ + - ]: 2 : rte_reorder_min_seqn_set(struct rte_reorder_buffer *b, rte_reorder_seqn_t min_seqn)
546 : : {
547 [ + + ]: 2 : if (!rte_reorder_is_empty(b))
548 : : return -ENOTEMPTY;
549 : :
550 : 1 : b->min_seqn = min_seqn;
551 : 1 : b->is_initialized = true;
552 : :
553 : 1 : return 0;
554 : : }
|