Skip to content

Commit 47e4075

Browse files
magnus-karlssonborkmann
authored andcommitted
xsk: Batched buffer allocation for the pool
Add a new driver interface xsk_buff_alloc_batch() offering batched buffer allocations to improve performance. The new interface takes three arguments: the buffer pool to allocated from, a pointer to an array of struct xdp_buff pointers which will contain pointers to the allocated xdp_buffs, and an unsigned integer specifying the max number of buffers to allocate. The return value is the actual number of buffers that the allocator managed to allocate and it will be in the range 0 <= N <= max, where max is the third parameter to the function. u32 xsk_buff_alloc_batch(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max); A second driver interface is also introduced that need to be used in conjunction with xsk_buff_alloc_batch(). It is a helper that sets the size of struct xdp_buff and is used by the NIC Rx irq routine when receiving a packet. This helper sets the three struct members data, data_meta, and data_end. The two first ones is in the xsk_buff_alloc() case set in the allocation routine and data_end is set when a packet is received in the receive irq function. This unfortunately leads to worse performance since the xdp_buff is touched twice with a long time period in between leading to an extra cache miss. Instead, we fill out the xdp_buff with all 3 fields at one single point in time in the driver, when the size of the packet is known. Hence this helper. Note that the driver has to use this helper (or set all three fields itself) when using xsk_buff_alloc_batch(). xsk_buff_alloc() works as before and does not require this. void xsk_buff_set_size(struct xdp_buff *xdp, u32 size); Signed-off-by: Magnus Karlsson <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 10a5e00 commit 47e4075

File tree

4 files changed

+118
-4
lines changed

4 files changed

+118
-4
lines changed

include/net/xdp_sock_drv.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ static inline struct xdp_buff *xsk_buff_alloc(struct xsk_buff_pool *pool)
7777
return xp_alloc(pool);
7878
}
7979

80+
/* Returns as many entries as possible up to max. 0 <= N <= max. */
81+
static inline u32 xsk_buff_alloc_batch(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max)
82+
{
83+
return xp_alloc_batch(pool, xdp, max);
84+
}
85+
8086
static inline bool xsk_buff_can_alloc(struct xsk_buff_pool *pool, u32 count)
8187
{
8288
return xp_can_alloc(pool, count);
@@ -89,6 +95,13 @@ static inline void xsk_buff_free(struct xdp_buff *xdp)
8995
xp_free(xskb);
9096
}
9197

98+
static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size)
99+
{
100+
xdp->data = xdp->data_hard_start + XDP_PACKET_HEADROOM;
101+
xdp->data_meta = xdp->data;
102+
xdp->data_end = xdp->data + size;
103+
}
104+
92105
static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool,
93106
u64 addr)
94107
{
@@ -212,6 +225,11 @@ static inline struct xdp_buff *xsk_buff_alloc(struct xsk_buff_pool *pool)
212225
return NULL;
213226
}
214227

228+
static inline u32 xsk_buff_alloc_batch(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max)
229+
{
230+
return 0;
231+
}
232+
215233
static inline bool xsk_buff_can_alloc(struct xsk_buff_pool *pool, u32 count)
216234
{
217235
return false;
@@ -221,6 +239,10 @@ static inline void xsk_buff_free(struct xdp_buff *xdp)
221239
{
222240
}
223241

242+
static inline void xsk_buff_set_size(struct xdp_buff *xdp, u32 size)
243+
{
244+
}
245+
224246
static inline dma_addr_t xsk_buff_raw_get_dma(struct xsk_buff_pool *pool,
225247
u64 addr)
226248
{

include/net/xsk_buff_pool.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ int xp_dma_map(struct xsk_buff_pool *pool, struct device *dev,
104104
unsigned long attrs, struct page **pages, u32 nr_pages);
105105
void xp_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs);
106106
struct xdp_buff *xp_alloc(struct xsk_buff_pool *pool);
107+
u32 xp_alloc_batch(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max);
107108
bool xp_can_alloc(struct xsk_buff_pool *pool, u32 count);
108109
void *xp_raw_get_data(struct xsk_buff_pool *pool, u64 addr);
109110
dma_addr_t xp_raw_get_dma(struct xsk_buff_pool *pool, u64 addr);

net/xdp/xsk_buff_pool.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,93 @@ struct xdp_buff *xp_alloc(struct xsk_buff_pool *pool)
507507
}
508508
EXPORT_SYMBOL(xp_alloc);
509509

510+
static u32 xp_alloc_new_from_fq(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max)
511+
{
512+
u32 i, cached_cons, nb_entries;
513+
514+
if (max > pool->free_heads_cnt)
515+
max = pool->free_heads_cnt;
516+
max = xskq_cons_nb_entries(pool->fq, max);
517+
518+
cached_cons = pool->fq->cached_cons;
519+
nb_entries = max;
520+
i = max;
521+
while (i--) {
522+
struct xdp_buff_xsk *xskb;
523+
u64 addr;
524+
bool ok;
525+
526+
__xskq_cons_read_addr_unchecked(pool->fq, cached_cons++, &addr);
527+
528+
ok = pool->unaligned ? xp_check_unaligned(pool, &addr) :
529+
xp_check_aligned(pool, &addr);
530+
if (unlikely(!ok)) {
531+
pool->fq->invalid_descs++;
532+
nb_entries--;
533+
continue;
534+
}
535+
536+
xskb = pool->free_heads[--pool->free_heads_cnt];
537+
*xdp = &xskb->xdp;
538+
xskb->orig_addr = addr;
539+
xskb->xdp.data_hard_start = pool->addrs + addr + pool->headroom;
540+
xskb->frame_dma = (pool->dma_pages[addr >> PAGE_SHIFT] &
541+
~XSK_NEXT_PG_CONTIG_MASK) + (addr & ~PAGE_MASK);
542+
xskb->dma = xskb->frame_dma + pool->headroom + XDP_PACKET_HEADROOM;
543+
xdp++;
544+
}
545+
546+
xskq_cons_release_n(pool->fq, max);
547+
return nb_entries;
548+
}
549+
550+
static u32 xp_alloc_reused(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 nb_entries)
551+
{
552+
struct xdp_buff_xsk *xskb;
553+
u32 i;
554+
555+
nb_entries = min_t(u32, nb_entries, pool->free_list_cnt);
556+
557+
i = nb_entries;
558+
while (i--) {
559+
xskb = list_first_entry(&pool->free_list, struct xdp_buff_xsk, free_list_node);
560+
list_del(&xskb->free_list_node);
561+
562+
*xdp = &xskb->xdp;
563+
xdp++;
564+
}
565+
pool->free_list_cnt -= nb_entries;
566+
567+
return nb_entries;
568+
}
569+
570+
u32 xp_alloc_batch(struct xsk_buff_pool *pool, struct xdp_buff **xdp, u32 max)
571+
{
572+
u32 nb_entries1 = 0, nb_entries2;
573+
574+
if (unlikely(pool->dma_need_sync)) {
575+
/* Slow path */
576+
*xdp = xp_alloc(pool);
577+
return !!*xdp;
578+
}
579+
580+
if (unlikely(pool->free_list_cnt)) {
581+
nb_entries1 = xp_alloc_reused(pool, xdp, max);
582+
if (nb_entries1 == max)
583+
return nb_entries1;
584+
585+
max -= nb_entries1;
586+
xdp += nb_entries1;
587+
}
588+
589+
nb_entries2 = xp_alloc_new_from_fq(pool, xdp, max);
590+
if (!nb_entries2)
591+
pool->fq->queue_empty_descs++;
592+
593+
return nb_entries1 + nb_entries2;
594+
}
595+
EXPORT_SYMBOL(xp_alloc_batch);
596+
510597
bool xp_can_alloc(struct xsk_buff_pool *pool, u32 count)
511598
{
512599
if (pool->free_list_cnt >= count)

net/xdp/xsk_queue.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,18 @@ struct xsk_queue {
111111

112112
/* Functions that read and validate content from consumer rings. */
113113

114-
static inline bool xskq_cons_read_addr_unchecked(struct xsk_queue *q, u64 *addr)
114+
static inline void __xskq_cons_read_addr_unchecked(struct xsk_queue *q, u32 cached_cons, u64 *addr)
115115
{
116116
struct xdp_umem_ring *ring = (struct xdp_umem_ring *)q->ring;
117+
u32 idx = cached_cons & q->ring_mask;
117118

118-
if (q->cached_cons != q->cached_prod) {
119-
u32 idx = q->cached_cons & q->ring_mask;
119+
*addr = ring->desc[idx];
120+
}
120121

121-
*addr = ring->desc[idx];
122+
static inline bool xskq_cons_read_addr_unchecked(struct xsk_queue *q, u64 *addr)
123+
{
124+
if (q->cached_cons != q->cached_prod) {
125+
__xskq_cons_read_addr_unchecked(q, q->cached_cons, addr);
122126
return true;
123127
}
124128

0 commit comments

Comments
 (0)