@@ -337,6 +337,96 @@ test_reorder_drain(void)
return ret;
}
+static void
+buffer_to_reorder_move(struct rte_mbuf **mbuf, struct rte_reorder_buffer *b)
+{
+ rte_reorder_insert(b, *mbuf);
+ *mbuf = NULL;
+}
+
+static int
+test_reorder_drain_up_to_seqn(void)
+{
+ struct rte_mempool *p = test_params->p;
+ struct rte_reorder_buffer *b = NULL;
+ const unsigned int num_bufs = 10;
+ const unsigned int size = 4;
+ unsigned int i, cnt;
+ int ret = 0;
+
+ struct rte_mbuf *bufs[num_bufs];
+ struct rte_mbuf *robufs[num_bufs];
+
+ /* initialize all robufs to NULL */
+ memset(robufs, 0, sizeof(robufs));
+
+ /* This would create a reorder buffer instance consisting of:
+ * reorder_seq = 0
+ * ready_buf: RB[size] = {NULL, NULL, NULL, NULL}
+ * order_buf: OB[size] = {NULL, NULL, NULL, NULL}
+ */
+ b = rte_reorder_create("test_drain_up_to_seqn", rte_socket_id(), size);
+ TEST_ASSERT_NOT_NULL(b, "Failed to create reorder buffer");
+
+ for (i = 0; i < num_bufs; i++) {
+ bufs[i] = rte_pktmbuf_alloc(p);
+ TEST_ASSERT_NOT_NULL(bufs[i], "Packet allocation failed\n");
+ *rte_reorder_seqn(bufs[i]) = i;
+ }
+
+ /* Insert packet with seqn 1 and 3:
+ * RB[] = {NULL, NULL, NULL, NULL}
+ * OB[] = {1, 2, 3, NULL}
+ */
+ buffer_to_reorder_move(&bufs[1], b);
+ buffer_to_reorder_move(&bufs[2], b);
+ buffer_to_reorder_move(&bufs[3], b);
+ /* Draining 1, 2 */
+ cnt = rte_reorder_drain_up_to_seqn(b, robufs, num_bufs, 3);
+ if (cnt != 2) {
+ printf("%s:%d:%d: number of expected packets not drained\n",
+ __func__, __LINE__, cnt);
+ ret = -1;
+ goto exit;
+ }
+ for (i = 0; i < 2; i++)
+ rte_pktmbuf_free(robufs[i]);
+ memset(robufs, 0, sizeof(robufs));
+
+ /* Insert more packets
+ * RB[] = {NULL, NULL, NULL, NULL}
+ * OB[] = {3, 4, NULL, 6}
+ */
+ buffer_to_reorder_move(&bufs[4], b);
+ buffer_to_reorder_move(&bufs[6], b);
+ /* Insert more packets to utilize Ready buffer
+ * RB[] = {3, NULL, 5, 6}
+ * OB[] = {NULL, NULL, 8, NULL}
+ */
+ buffer_to_reorder_move(&bufs[8], b);
+
+ /* Drain 3 and 5 */
+ cnt = rte_reorder_drain_up_to_seqn(b, robufs, num_bufs, 6);
+ if (cnt != 2) {
+ printf("%s:%d:%d: number of expected packets not drained\n",
+ __func__, __LINE__, cnt);
+ ret = -1;
+ goto exit;
+ }
+ for (i = 0; i < 2; i++)
+ rte_pktmbuf_free(robufs[i]);
+ memset(robufs, 0, sizeof(robufs));
+
+ ret = 0;
+exit:
+ rte_reorder_free(b);
+ for (i = 0; i < num_bufs; i++) {
+ rte_pktmbuf_free(bufs[i]);
+ rte_pktmbuf_free(robufs[i]);
+ }
+ return ret;
+}
+
static int
test_setup(void)
{
@@ -387,6 +477,7 @@ static struct unit_test_suite reorder_test_suite = {
TEST_CASE(test_reorder_free),
TEST_CASE(test_reorder_insert),
TEST_CASE(test_reorder_drain),
+ TEST_CASE(test_reorder_drain_up_to_seqn),
TEST_CASES_END()
}
};
@@ -407,3 +407,81 @@ rte_reorder_drain(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
return drain_cnt;
}
+
+/* Binary search seqn in ready buffer */
+static inline uint32_t
+ready_buffer_seqn_find(const struct cir_buffer *ready_buf, const uint32_t seqn)
+{
+ uint32_t mid, value, position, high;
+ uint32_t low = 0;
+
+ if (ready_buf->tail > ready_buf->head)
+ high = ready_buf->tail - ready_buf->head;
+ else
+ high = ready_buf->head - ready_buf->tail;
+
+ while (low <= high) {
+ mid = low + (high - low) / 2;
+ position = (ready_buf->tail + mid) & ready_buf->mask;
+ value = *rte_reorder_seqn(ready_buf->entries[position]);
+ if (seqn == value)
+ return mid;
+ else if (seqn > value)
+ low = mid + 1;
+ else
+ high = mid - 1;
+ }
+
+ return low;
+}
+
+unsigned int
+rte_reorder_drain_up_to_seqn(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
+ const unsigned int max_mbufs, const rte_reorder_seqn_t seqn)
+{
+ uint32_t i, position, offset;
+ unsigned int drain_cnt = 0;
+
+ struct cir_buffer *order_buf = &b->order_buf,
+ *ready_buf = &b->ready_buf;
+
+ /* Seqn in Ready buffer */
+ if (seqn < b->min_seqn) {
+ /* All sequence numbers are higher then given */
+ if ((ready_buf->tail == ready_buf->head) ||
+ (*rte_reorder_seqn(ready_buf->entries[ready_buf->tail]) > seqn))
+ return 0;
+
+ offset = ready_buffer_seqn_find(ready_buf, seqn);
+
+ for (i = 0; (i < offset) && (drain_cnt < max_mbufs); i++) {
+ position = (ready_buf->tail + i) & ready_buf->mask;
+ mbufs[drain_cnt++] = ready_buf->entries[position];
+ ready_buf->entries[position] = NULL;
+ }
+ ready_buf->tail = (ready_buf->tail + i) & ready_buf->mask;
+
+ return drain_cnt;
+ }
+
+ /* Seqn in Order buffer, add all buffers from Ready buffer */
+ while ((drain_cnt < max_mbufs) && (ready_buf->tail != ready_buf->head)) {
+ mbufs[drain_cnt++] = ready_buf->entries[ready_buf->tail];
+ ready_buf->entries[ready_buf->tail] = NULL;
+ ready_buf->tail = (ready_buf->tail + 1) & ready_buf->mask;
+ }
+
+ /* Fetch buffers from Order buffer up to given sequence number (exclusive) */
+ offset = RTE_MIN(seqn - b->min_seqn, b->order_buf.size);
+ for (i = 0; (i < offset) && (drain_cnt < max_mbufs); i++) {
+ position = (order_buf->head + i) & order_buf->mask;
+ if (order_buf->entries[position] == NULL)
+ continue;
+ mbufs[drain_cnt++] = order_buf->entries[position];
+ order_buf->entries[position] = NULL;
+ }
+ b->min_seqn += i;
+ order_buf->head = (order_buf->head + i) & order_buf->mask;
+
+ return drain_cnt;
+}
@@ -167,6 +167,32 @@ unsigned int
rte_reorder_drain(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
unsigned max_mbufs);
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Fetch set of reordered packets up to specified sequence number (exclusive)
+ *
+ * Returns a set of in-order packets from the reorder buffer structure.
+ * Gaps may be present since reorder buffer will try to fetch all possible packets up to given
+ * sequence number.
+ *
+ * @param b
+ * Reorder buffer instance from which packets are to be drained.
+ * @param mbufs
+ * Array of mbufs where reordered packets will be inserted from reorder buffer.
+ * @param max_mbufs
+ * The number of elements in the mbufs array.
+ * @param seqn
+ * Sequence number up to which buffer will be drained.
+ * @return
+ * Number of mbuf pointers written to mbufs. 0 <= N < max_mbufs.
+ */
+__rte_experimental
+unsigned int
+rte_reorder_drain_up_to_seqn(struct rte_reorder_buffer *b, struct rte_mbuf **mbufs,
+ unsigned int max_mbufs, rte_reorder_seqn_t seqn);
+
#ifdef __cplusplus
}
#endif
@@ -16,4 +16,6 @@ EXPERIMENTAL {
global:
rte_reorder_seqn_dynfield_offset;
+ # added in 23.03
+ rte_reorder_drain_up_to_seqn;
};