Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xsk: Optimize for aligned case

Optimize for the aligned case by precomputing the parameter values of
the xdp_buff_xsk and xdp_buff structures in the heads array. We can do
this as the heads array size is equal to the number of chunks in the
umem for the aligned case. Then every entry in this array will reflect
a certain chunk/frame and can therefore be prepopulated with the
correct values and we can drop the use of the free_heads stack. Note
that it is not possible to allocate more buffers than what has been
allocated in the aligned case since each chunk can only contain a
single buffer.

We can unfortunately not do this in the unaligned case as one chunk
might contain multiple buffers. In this case, we keep the old scheme
of populating a heads entry every time it is used and using
the free_heads stack.

Also move xp_release() and xp_get_handle() to xsk_buff_pool.h. They
were for some reason in xsk.c even though they are buffer pool
operations.

Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20210922075613.12186-7-magnus.karlsson@gmail.com

authored by

Magnus Karlsson and committed by
Daniel Borkmann
94033cd8 6aab0bb0

+79 -38
+45 -1
include/net/xsk_buff_pool.h
··· 7 7 #include <linux/if_xdp.h> 8 8 #include <linux/types.h> 9 9 #include <linux/dma-mapping.h> 10 + #include <linux/bpf.h> 10 11 #include <net/xdp.h> 11 12 12 13 struct xsk_buff_pool; ··· 67 66 u32 free_heads_cnt; 68 67 u32 headroom; 69 68 u32 chunk_size; 69 + u32 chunk_shift; 70 70 u32 frame_len; 71 71 u8 cached_need_wakeup; 72 72 bool uses_need_wakeup; ··· 82 80 struct xdp_buff_xsk *free_heads[]; 83 81 }; 84 82 83 + /* Masks for xdp_umem_page flags. 84 + * The low 12-bits of the addr will be 0 since this is the page address, so we 85 + * can use them for flags. 86 + */ 87 + #define XSK_NEXT_PG_CONTIG_SHIFT 0 88 + #define XSK_NEXT_PG_CONTIG_MASK BIT_ULL(XSK_NEXT_PG_CONTIG_SHIFT) 89 + 85 90 /* AF_XDP core. */ 86 91 struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs, 87 92 struct xdp_umem *umem); ··· 97 88 int xp_assign_dev_shared(struct xsk_buff_pool *pool, struct xdp_umem *umem, 98 89 struct net_device *dev, u16 queue_id); 99 90 void xp_destroy(struct xsk_buff_pool *pool); 100 - void xp_release(struct xdp_buff_xsk *xskb); 101 91 void xp_get_pool(struct xsk_buff_pool *pool); 102 92 bool xp_put_pool(struct xsk_buff_pool *pool); 103 93 void xp_clear_dev(struct xsk_buff_pool *pool); ··· 105 97 106 98 /* AF_XDP, and XDP core. */ 107 99 void xp_free(struct xdp_buff_xsk *xskb); 100 + 101 + static inline void xp_init_xskb_addr(struct xdp_buff_xsk *xskb, struct xsk_buff_pool *pool, 102 + u64 addr) 103 + { 104 + xskb->orig_addr = addr; 105 + xskb->xdp.data_hard_start = pool->addrs + addr + pool->headroom; 106 + } 107 + 108 + static inline void xp_init_xskb_dma(struct xdp_buff_xsk *xskb, struct xsk_buff_pool *pool, 109 + dma_addr_t *dma_pages, u64 addr) 110 + { 111 + xskb->frame_dma = (dma_pages[addr >> PAGE_SHIFT] & ~XSK_NEXT_PG_CONTIG_MASK) + 112 + (addr & ~PAGE_MASK); 113 + xskb->dma = xskb->frame_dma + pool->headroom + XDP_PACKET_HEADROOM; 114 + } 108 115 109 116 /* AF_XDP ZC drivers, via xdp_sock_buff.h */ 110 117 void xp_set_rxq_info(struct xsk_buff_pool *pool, struct xdp_rxq_info *rxq); ··· 201 178 { 202 179 return xp_unaligned_extract_addr(addr) + 203 180 xp_unaligned_extract_offset(addr); 181 + } 182 + 183 + static inline u32 xp_aligned_extract_idx(struct xsk_buff_pool *pool, u64 addr) 184 + { 185 + return xp_aligned_extract_addr(pool, addr) >> pool->chunk_shift; 186 + } 187 + 188 + static inline void xp_release(struct xdp_buff_xsk *xskb) 189 + { 190 + if (xskb->pool->unaligned) 191 + xskb->pool->free_heads[xskb->pool->free_heads_cnt++] = xskb; 192 + } 193 + 194 + static inline u64 xp_get_handle(struct xdp_buff_xsk *xskb) 195 + { 196 + u64 offset = xskb->xdp.data - xskb->xdp.data_hard_start; 197 + 198 + offset += xskb->pool->headroom; 199 + if (!xskb->pool->unaligned) 200 + return xskb->orig_addr + offset; 201 + return xskb->orig_addr + (offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT); 204 202 } 205 203 206 204 #endif /* XSK_BUFF_POOL_H_ */
-15
net/xdp/xsk.c
··· 134 134 return 0; 135 135 } 136 136 137 - void xp_release(struct xdp_buff_xsk *xskb) 138 - { 139 - xskb->pool->free_heads[xskb->pool->free_heads_cnt++] = xskb; 140 - } 141 - 142 - static u64 xp_get_handle(struct xdp_buff_xsk *xskb) 143 - { 144 - u64 offset = xskb->xdp.data - xskb->xdp.data_hard_start; 145 - 146 - offset += xskb->pool->headroom; 147 - if (!xskb->pool->unaligned) 148 - return xskb->orig_addr + offset; 149 - return xskb->orig_addr + (offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT); 150 - } 151 - 152 137 static int __xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len) 153 138 { 154 139 struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp);
+34 -22
net/xdp/xsk_buff_pool.c
··· 44 44 struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs, 45 45 struct xdp_umem *umem) 46 46 { 47 + bool unaligned = umem->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG; 47 48 struct xsk_buff_pool *pool; 48 49 struct xdp_buff_xsk *xskb; 49 - u32 i; 50 + u32 i, entries; 50 51 51 - pool = kvzalloc(struct_size(pool, free_heads, umem->chunks), 52 - GFP_KERNEL); 52 + entries = unaligned ? umem->chunks : 0; 53 + pool = kvzalloc(struct_size(pool, free_heads, entries), GFP_KERNEL); 53 54 if (!pool) 54 55 goto out; 55 56 ··· 64 63 pool->free_heads_cnt = umem->chunks; 65 64 pool->headroom = umem->headroom; 66 65 pool->chunk_size = umem->chunk_size; 67 - pool->unaligned = umem->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG; 66 + pool->chunk_shift = ffs(umem->chunk_size) - 1; 67 + pool->unaligned = unaligned; 68 68 pool->frame_len = umem->chunk_size - umem->headroom - 69 69 XDP_PACKET_HEADROOM; 70 70 pool->umem = umem; ··· 83 81 xskb = &pool->heads[i]; 84 82 xskb->pool = pool; 85 83 xskb->xdp.frame_sz = umem->chunk_size - umem->headroom; 86 - pool->free_heads[i] = xskb; 84 + if (pool->unaligned) 85 + pool->free_heads[i] = xskb; 86 + else 87 + xp_init_xskb_addr(xskb, pool, i * pool->chunk_size); 87 88 } 88 89 89 90 return pool; ··· 411 406 412 407 if (pool->unaligned) 413 408 xp_check_dma_contiguity(dma_map); 409 + else 410 + for (i = 0; i < pool->heads_cnt; i++) { 411 + struct xdp_buff_xsk *xskb = &pool->heads[i]; 412 + 413 + xp_init_xskb_dma(xskb, pool, dma_map->dma_pages, xskb->orig_addr); 414 + } 414 415 415 416 err = xp_init_dma_info(pool, dma_map); 416 417 if (err) { ··· 459 448 if (pool->free_heads_cnt == 0) 460 449 return NULL; 461 450 462 - xskb = pool->free_heads[--pool->free_heads_cnt]; 463 - 464 451 for (;;) { 465 452 if (!xskq_cons_peek_addr_unchecked(pool->fq, &addr)) { 466 453 pool->fq->queue_empty_descs++; ··· 475 466 } 476 467 break; 477 468 } 478 - xskq_cons_release(pool->fq); 479 469 480 - xskb->orig_addr = addr; 481 - xskb->xdp.data_hard_start = pool->addrs + addr + pool->headroom; 482 - if (pool->dma_pages_cnt) { 483 - xskb->frame_dma = (pool->dma_pages[addr >> PAGE_SHIFT] & 484 - ~XSK_NEXT_PG_CONTIG_MASK) + 485 - (addr & ~PAGE_MASK); 486 - xskb->dma = xskb->frame_dma + pool->headroom + 487 - XDP_PACKET_HEADROOM; 470 + if (pool->unaligned) { 471 + xskb = pool->free_heads[--pool->free_heads_cnt]; 472 + xp_init_xskb_addr(xskb, pool, addr); 473 + if (pool->dma_pages_cnt) 474 + xp_init_xskb_dma(xskb, pool, pool->dma_pages, addr); 475 + } else { 476 + xskb = &pool->heads[xp_aligned_extract_idx(pool, addr)]; 488 477 } 478 + 479 + xskq_cons_release(pool->fq); 489 480 return xskb; 490 481 } 491 482 ··· 542 533 continue; 543 534 } 544 535 545 - xskb = pool->free_heads[--pool->free_heads_cnt]; 536 + if (pool->unaligned) { 537 + xskb = pool->free_heads[--pool->free_heads_cnt]; 538 + xp_init_xskb_addr(xskb, pool, addr); 539 + if (pool->dma_pages_cnt) 540 + xp_init_xskb_dma(xskb, pool, pool->dma_pages, addr); 541 + } else { 542 + xskb = &pool->heads[xp_aligned_extract_idx(pool, addr)]; 543 + } 544 + 546 545 *xdp = &xskb->xdp; 547 - xskb->orig_addr = addr; 548 - xskb->xdp.data_hard_start = pool->addrs + addr + pool->headroom; 549 - xskb->frame_dma = (pool->dma_pages[addr >> PAGE_SHIFT] & 550 - ~XSK_NEXT_PG_CONTIG_MASK) + (addr & ~PAGE_MASK); 551 - xskb->dma = xskb->frame_dma + pool->headroom + XDP_PACKET_HEADROOM; 552 546 xdp++; 553 547 } 554 548