[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180131135356.19134-13-bjorn.topel@gmail.com>
Date: Wed, 31 Jan 2018 14:53:44 +0100
From: Björn Töpel <bjorn.topel@...il.com>
To: bjorn.topel@...il.com, magnus.karlsson@...el.com,
alexander.h.duyck@...el.com, alexander.duyck@...il.com,
john.fastabend@...il.com, ast@...com, brouer@...hat.com,
willemdebruijn.kernel@...il.com, daniel@...earbox.net,
netdev@...r.kernel.org
Cc: Björn Töpel <bjorn.topel@...el.com>,
michael.lundkvist@...csson.com, jesse.brandeburg@...el.com,
anjali.singhai@...el.com, jeffrey.b.shaw@...el.com,
ferruh.yigit@...el.com, qi.z.zhang@...el.com
Subject: [RFC PATCH 12/24] xsk: add iterator functions to xsk_ring
From: Björn Töpel <bjorn.topel@...el.com>
Add packet array like functionality that acts directly on the
user/kernel shared ring. We'll use this in the zerocopy Rx scenario.
TODO Better naming...
Signed-off-by: Björn Töpel <bjorn.topel@...el.com>
---
net/xdp/xsk_ring.c | 3 +-
net/xdp/xsk_ring.h | 136 ++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 126 insertions(+), 13 deletions(-)
diff --git a/net/xdp/xsk_ring.c b/net/xdp/xsk_ring.c
index 11b590506ddf..f154ddfabcfc 100644
--- a/net/xdp/xsk_ring.c
+++ b/net/xdp/xsk_ring.c
@@ -41,7 +41,8 @@ struct xsk_queue *xskq_create(u32 nentries)
q->queue_ops.enqueue = xskq_enqueue_from_array;
q->queue_ops.enqueue_completed = xskq_enqueue_completed_from_array;
q->queue_ops.dequeue = xskq_dequeue_to_array;
- q->used_idx = 0;
+ q->used_idx_head = 0;
+ q->used_idx_tail = 0;
q->last_avail_idx = 0;
q->ring_mask = nentries - 1;
q->num_free = 0;
diff --git a/net/xdp/xsk_ring.h b/net/xdp/xsk_ring.h
index c9d61195ab2d..43c841d55093 100644
--- a/net/xdp/xsk_ring.h
+++ b/net/xdp/xsk_ring.h
@@ -27,7 +27,8 @@ struct xsk_queue {
struct xsk_user_queue queue_ops;
struct xdp_desc *ring;
- u32 used_idx;
+ u32 used_idx_head;
+ u32 used_idx_tail;
u32 last_avail_idx;
u32 ring_mask;
u32 num_free;
@@ -51,8 +52,7 @@ static inline unsigned int xsk_get_data_headroom(struct xsk_umem *umem)
*
* Returns true if the entry is a valid, otherwise false
**/
-static inline bool xskq_is_valid_entry(struct xsk_queue *q,
- struct xdp_desc *d)
+static inline bool xskq_is_valid_entry(struct xsk_queue *q, struct xdp_desc *d)
{
unsigned int buff_len;
@@ -115,7 +115,7 @@ static inline int xskq_nb_avail(struct xsk_queue *q, int dcnt)
static inline int xskq_enqueue(struct xsk_queue *q,
const struct xdp_desc *d, int dcnt)
{
- unsigned int used_idx = q->used_idx;
+ unsigned int used_idx = q->used_idx_tail;
int i;
if (q->num_free < dcnt)
@@ -136,11 +136,12 @@ static inline int xskq_enqueue(struct xsk_queue *q,
smp_wmb();
for (i = dcnt - 1; i >= 0; i--) {
- unsigned int idx = (q->used_idx + i) & q->ring_mask;
+ unsigned int idx = (q->used_idx_tail + i) & q->ring_mask;
q->ring[idx].flags = d[i].flags & ~XDP_DESC_KERNEL;
}
- q->used_idx += dcnt;
+ q->used_idx_head += dcnt;
+ q->used_idx_tail += dcnt;
return 0;
}
@@ -157,7 +158,7 @@ static inline int xskq_enqueue_from_array(struct xsk_packet_array *a,
u32 dcnt)
{
struct xsk_queue *q = (struct xsk_queue *)a->q_ops;
- unsigned int used_idx = q->used_idx;
+ unsigned int used_idx = q->used_idx_tail;
struct xdp_desc *d = a->items;
int i;
@@ -180,12 +181,13 @@ static inline int xskq_enqueue_from_array(struct xsk_packet_array *a,
smp_wmb();
for (i = dcnt - 1; i >= 0; i--) {
- unsigned int idx = (q->used_idx + i) & q->ring_mask;
+ unsigned int idx = (q->used_idx_tail + i) & q->ring_mask;
unsigned int didx = (a->start + i) & a->mask;
q->ring[idx].flags = d[didx].flags & ~XDP_DESC_KERNEL;
}
- q->used_idx += dcnt;
+ q->used_idx_tail += dcnt;
+ q->used_idx_head += dcnt;
return 0;
}
@@ -204,7 +206,7 @@ static inline int xskq_enqueue_completed_from_array(struct xsk_packet_array *a,
u32 dcnt)
{
struct xsk_queue *q = (struct xsk_queue *)a->q_ops;
- unsigned int used_idx = q->used_idx;
+ unsigned int used_idx = q->used_idx_tail;
struct xdp_desc *d = a->items;
int i, j;
@@ -233,13 +235,14 @@ static inline int xskq_enqueue_completed_from_array(struct xsk_packet_array *a,
smp_wmb();
for (j = i - 1; j >= 0; j--) {
- unsigned int idx = (q->used_idx + j) & q->ring_mask;
+ unsigned int idx = (q->used_idx_tail + j) & q->ring_mask;
unsigned int didx = (a->start + j) & a->mask;
q->ring[idx].flags = d[didx].flags & ~XDP_DESC_KERNEL;
}
q->num_free -= i;
- q->used_idx += i;
+ q->used_idx_tail += i;
+ q->used_idx_head += i;
return i;
}
@@ -301,6 +304,115 @@ static inline void xskq_set_buff_info(struct xsk_queue *q,
q->validation = validation;
}
+/* --- */
+
+struct xskq_iter {
+ unsigned int head;
+ unsigned int tail;
+};
+
+static inline bool xskq_iter_end(struct xskq_iter *it)
+{
+ return it->tail == it->head;
+}
+
+static inline void xskq_iter_validate(struct xsk_queue *q, struct xskq_iter *it)
+{
+ while (it->head != it->tail) {
+ unsigned int idx = it->head & q->ring_mask;
+ struct xdp_desc *d, *du;
+
+ d = &q->ring[idx];
+ if (xskq_is_valid_entry(q, d))
+ break;
+
+ /* Slow error path! */
+ du = &q->ring[q->used_idx_tail & q->ring_mask];
+ du->idx = d->idx;
+ du->len = d->len;
+ du->offset = d->offset;
+ du->error = EINVAL;
+
+ q->last_avail_idx++;
+ it->head++;
+
+ smp_wmb();
+
+ du->flags = d->flags & ~XDP_DESC_KERNEL;
+ }
+}
+
+static inline struct xskq_iter xskq_deq_iter(struct xsk_queue *q,
+ int cnt)
+{
+ struct xskq_iter it;
+
+ it.head = q->last_avail_idx;
+ it.tail = it.head + (unsigned int)xskq_nb_avail(q, cnt);
+
+ smp_rmb();
+
+ xskq_iter_validate(q, &it);
+
+ return it;
+}
+
+static inline void xskq_deq_iter_next(struct xsk_queue *q, struct xskq_iter *it)
+{
+ it->head++;
+ xskq_iter_validate(q, it);
+}
+
+static inline void xskq_deq_iter_done(struct xsk_queue *q, struct xskq_iter *it)
+{
+ int entries = it->head - q->last_avail_idx;
+
+ q->num_free += entries;
+ q->last_avail_idx = it->head;
+}
+
+static inline u32 xskq_deq_iter_get_id(struct xsk_queue *q,
+ struct xskq_iter *it)
+{
+ return q->ring[it->head & q->ring_mask].idx;
+}
+
+static inline void xskq_return_id(struct xsk_queue *q, u32 id)
+{
+ struct xdp_desc d = { .idx = id };
+
+ WARN(xskq_enqueue(q, &d, 1), "%s failed!\n", __func__);
+}
+
+static inline void xskq_enq_lazy(struct xsk_queue *q,
+ u32 id, u32 len, u16 offset)
+{
+ unsigned int idx;
+
+ if (q->num_free == 0) {
+ WARN(1, "%s xsk_queue deq/enq out of sync!\n", __func__);
+ return;
+ }
+
+ q->num_free--;
+ idx = (q->used_idx_tail++) & q->ring_mask;
+ q->ring[idx].idx = id;
+ q->ring[idx].len = len;
+ q->ring[idx].offset = offset;
+ q->ring[idx].error = 0;
+}
+
+static inline void xskq_enq_flush(struct xsk_queue *q)
+{
+ smp_wmb();
+
+ while (q->used_idx_head != q->used_idx_tail) {
+ unsigned int idx = (q->used_idx_head++) & q->ring_mask;
+
+ q->ring[idx].flags = 0;
+ }
+}
+
struct xsk_queue *xskq_create(u32 nentries);
void xskq_destroy(struct xsk_queue *q_ops);
--
2.14.1
Powered by blists - more mailing lists