Skip to content

Commit c05cd36

Browse files
kevin-laatz-intelborkmann
authored andcommitted
xsk: add support to allow unaligned chunk placement
Currently, addresses are chunk size aligned. This means, we are very restricted in terms of where we can place chunk within the umem. For example, if we have a chunk size of 2k, then our chunks can only be placed at 0,2k,4k,6k,8k... and so on (ie. every 2k starting from 0). This patch introduces the ability to use unaligned chunks. With these changes, we are no longer bound to having to place chunks at a 2k (or whatever your chunk size is) interval. Since we are no longer dealing with aligned chunks, they can now cross page boundaries. Checks for page contiguity have been added in order to keep track of which pages are followed by a physically contiguous page. Signed-off-by: Kevin Laatz <[email protected]> Signed-off-by: Ciara Loftus <[email protected]> Signed-off-by: Bruce Richardson <[email protected]> Acked-by: Jonathan Lemon <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent b35a2d3 commit c05cd36

File tree

6 files changed

+233
-36
lines changed

6 files changed

+233
-36
lines changed

include/net/xdp_sock.h

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616
struct net_device;
1717
struct xsk_queue;
1818

19+
/* Masks for xdp_umem_page flags.
20+
* The low 12-bits of the addr will be 0 since this is the page address, so we
21+
* can use them for flags.
22+
*/
23+
#define XSK_NEXT_PG_CONTIG_SHIFT 0
24+
#define XSK_NEXT_PG_CONTIG_MASK (1ULL << XSK_NEXT_PG_CONTIG_SHIFT)
25+
1926
struct xdp_umem_page {
2027
void *addr;
2128
dma_addr_t dma;
@@ -27,8 +34,12 @@ struct xdp_umem_fq_reuse {
2734
u64 handles[];
2835
};
2936

30-
/* Flags for the umem flags field. */
31-
#define XDP_UMEM_USES_NEED_WAKEUP (1 << 0)
37+
/* Flags for the umem flags field.
38+
*
39+
* The NEED_WAKEUP flag is 1 due to the reuse of the flags field for public
40+
* flags. See inlude/uapi/include/linux/if_xdp.h.
41+
*/
42+
#define XDP_UMEM_USES_NEED_WAKEUP (1 << 1)
3243

3344
struct xdp_umem {
3445
struct xsk_queue *fq;
@@ -124,14 +135,36 @@ void xsk_map_try_sock_delete(struct xsk_map *map, struct xdp_sock *xs,
124135
int xsk_map_inc(struct xsk_map *map);
125136
void xsk_map_put(struct xsk_map *map);
126137

138+
static inline u64 xsk_umem_extract_addr(u64 addr)
139+
{
140+
return addr & XSK_UNALIGNED_BUF_ADDR_MASK;
141+
}
142+
143+
static inline u64 xsk_umem_extract_offset(u64 addr)
144+
{
145+
return addr >> XSK_UNALIGNED_BUF_OFFSET_SHIFT;
146+
}
147+
148+
static inline u64 xsk_umem_add_offset_to_addr(u64 addr)
149+
{
150+
return xsk_umem_extract_addr(addr) + xsk_umem_extract_offset(addr);
151+
}
152+
127153
static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
128154
{
129-
return umem->pages[addr >> PAGE_SHIFT].addr + (addr & (PAGE_SIZE - 1));
155+
unsigned long page_addr;
156+
157+
addr = xsk_umem_add_offset_to_addr(addr);
158+
page_addr = (unsigned long)umem->pages[addr >> PAGE_SHIFT].addr;
159+
160+
return (char *)(page_addr & PAGE_MASK) + (addr & ~PAGE_MASK);
130161
}
131162

132163
static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr)
133164
{
134-
return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1));
165+
addr = xsk_umem_add_offset_to_addr(addr);
166+
167+
return umem->pages[addr >> PAGE_SHIFT].dma + (addr & ~PAGE_MASK);
135168
}
136169

137170
/* Reuse-queue aware version of FILL queue helpers */
@@ -172,6 +205,19 @@ static inline void xsk_umem_fq_reuse(struct xdp_umem *umem, u64 addr)
172205

173206
rq->handles[rq->length++] = addr;
174207
}
208+
209+
/* Handle the offset appropriately depending on aligned or unaligned mode.
210+
* For unaligned mode, we store the offset in the upper 16-bits of the address.
211+
* For aligned mode, we simply add the offset to the address.
212+
*/
213+
static inline u64 xsk_umem_adjust_offset(struct xdp_umem *umem, u64 address,
214+
u64 offset)
215+
{
216+
if (umem->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG)
217+
return address + (offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT);
218+
else
219+
return address + offset;
220+
}
175221
#else
176222
static inline int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
177223
{
@@ -241,6 +287,21 @@ static inline struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev,
241287
return NULL;
242288
}
243289

290+
static inline u64 xsk_umem_extract_addr(u64 addr)
291+
{
292+
return 0;
293+
}
294+
295+
static inline u64 xsk_umem_extract_offset(u64 addr)
296+
{
297+
return 0;
298+
}
299+
300+
static inline u64 xsk_umem_add_offset_to_addr(u64 addr)
301+
{
302+
return 0;
303+
}
304+
244305
static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
245306
{
246307
return NULL;
@@ -290,6 +351,12 @@ static inline bool xsk_umem_uses_need_wakeup(struct xdp_umem *umem)
290351
return false;
291352
}
292353

354+
static inline u64 xsk_umem_adjust_offset(struct xdp_umem *umem, u64 handle,
355+
u64 offset)
356+
{
357+
return 0;
358+
}
359+
293360
#endif /* CONFIG_XDP_SOCKETS */
294361

295362
#endif /* _LINUX_XDP_SOCK_H */

include/uapi/linux/if_xdp.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
*/
2727
#define XDP_USE_NEED_WAKEUP (1 << 3)
2828

29+
/* Flags for xsk_umem_config flags */
30+
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)
31+
2932
struct sockaddr_xdp {
3033
__u16 sxdp_family;
3134
__u16 sxdp_flags;
@@ -66,6 +69,7 @@ struct xdp_umem_reg {
6669
__u64 len; /* Length of packet data area */
6770
__u32 chunk_size;
6871
__u32 headroom;
72+
__u32 flags;
6973
};
7074

7175
struct xdp_statistics {
@@ -87,6 +91,11 @@ struct xdp_options {
8791
#define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
8892
#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL
8993

94+
/* Masks for unaligned chunks mode */
95+
#define XSK_UNALIGNED_BUF_OFFSET_SHIFT 48
96+
#define XSK_UNALIGNED_BUF_ADDR_MASK \
97+
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)
98+
9099
/* Rx/Tx descriptor */
91100
struct xdp_desc {
92101
__u64 addr;

net/xdp/xdp_umem.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ static int xdp_umem_account_pages(struct xdp_umem *umem)
340340

341341
static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
342342
{
343+
bool unaligned_chunks = mr->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG;
343344
u32 chunk_size = mr->chunk_size, headroom = mr->headroom;
344345
unsigned int chunks, chunks_per_page;
345346
u64 addr = mr->addr, size = mr->len;
@@ -355,7 +356,11 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
355356
return -EINVAL;
356357
}
357358

358-
if (!is_power_of_2(chunk_size))
359+
if (mr->flags & ~(XDP_UMEM_UNALIGNED_CHUNK_FLAG |
360+
XDP_UMEM_USES_NEED_WAKEUP))
361+
return -EINVAL;
362+
363+
if (!unaligned_chunks && !is_power_of_2(chunk_size))
359364
return -EINVAL;
360365

361366
if (!PAGE_ALIGNED(addr)) {
@@ -372,9 +377,11 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
372377
if (chunks == 0)
373378
return -EINVAL;
374379

375-
chunks_per_page = PAGE_SIZE / chunk_size;
376-
if (chunks < chunks_per_page || chunks % chunks_per_page)
377-
return -EINVAL;
380+
if (!unaligned_chunks) {
381+
chunks_per_page = PAGE_SIZE / chunk_size;
382+
if (chunks < chunks_per_page || chunks % chunks_per_page)
383+
return -EINVAL;
384+
}
378385

379386
headroom = ALIGN(headroom, 64);
380387

@@ -383,13 +390,15 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
383390
return -EINVAL;
384391

385392
umem->address = (unsigned long)addr;
386-
umem->chunk_mask = ~((u64)chunk_size - 1);
393+
umem->chunk_mask = unaligned_chunks ? XSK_UNALIGNED_BUF_ADDR_MASK
394+
: ~((u64)chunk_size - 1);
387395
umem->size = size;
388396
umem->headroom = headroom;
389397
umem->chunk_size_nohr = chunk_size - headroom;
390398
umem->npgs = size / PAGE_SIZE;
391399
umem->pgs = NULL;
392400
umem->user = NULL;
401+
umem->flags = mr->flags;
393402
INIT_LIST_HEAD(&umem->xsk_list);
394403
spin_lock_init(&umem->xsk_list_lock);
395404

0 commit comments

Comments
 (0)