Skip to content

Commit

Permalink
xsk: add support to allow unaligned chunk placement
Browse files Browse the repository at this point in the history
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 <kevin.laatz@intel.com>
Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
Acked-by: Jonathan Lemon <jonathan.lemon@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
  • Loading branch information
Kevin Laatz authored and Daniel Borkmann committed Aug 30, 2019
1 parent b35a2d3 commit c05cd36
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 36 deletions.
75 changes: 71 additions & 4 deletions include/net/xdp_sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
struct net_device;
struct xsk_queue;

/* Masks for xdp_umem_page flags.
* The low 12-bits of the addr will be 0 since this is the page address, so we
* can use them for flags.
*/
#define XSK_NEXT_PG_CONTIG_SHIFT 0
#define XSK_NEXT_PG_CONTIG_MASK (1ULL << XSK_NEXT_PG_CONTIG_SHIFT)

struct xdp_umem_page {
void *addr;
dma_addr_t dma;
Expand All @@ -27,8 +34,12 @@ struct xdp_umem_fq_reuse {
u64 handles[];
};

/* Flags for the umem flags field. */
#define XDP_UMEM_USES_NEED_WAKEUP (1 << 0)
/* Flags for the umem flags field.
*
* The NEED_WAKEUP flag is 1 due to the reuse of the flags field for public
* flags. See inlude/uapi/include/linux/if_xdp.h.
*/
#define XDP_UMEM_USES_NEED_WAKEUP (1 << 1)

struct xdp_umem {
struct xsk_queue *fq;
Expand Down Expand Up @@ -124,14 +135,36 @@ void xsk_map_try_sock_delete(struct xsk_map *map, struct xdp_sock *xs,
int xsk_map_inc(struct xsk_map *map);
void xsk_map_put(struct xsk_map *map);

static inline u64 xsk_umem_extract_addr(u64 addr)
{
return addr & XSK_UNALIGNED_BUF_ADDR_MASK;
}

static inline u64 xsk_umem_extract_offset(u64 addr)
{
return addr >> XSK_UNALIGNED_BUF_OFFSET_SHIFT;
}

static inline u64 xsk_umem_add_offset_to_addr(u64 addr)
{
return xsk_umem_extract_addr(addr) + xsk_umem_extract_offset(addr);
}

static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
{
return umem->pages[addr >> PAGE_SHIFT].addr + (addr & (PAGE_SIZE - 1));
unsigned long page_addr;

addr = xsk_umem_add_offset_to_addr(addr);
page_addr = (unsigned long)umem->pages[addr >> PAGE_SHIFT].addr;

return (char *)(page_addr & PAGE_MASK) + (addr & ~PAGE_MASK);
}

static inline dma_addr_t xdp_umem_get_dma(struct xdp_umem *umem, u64 addr)
{
return umem->pages[addr >> PAGE_SHIFT].dma + (addr & (PAGE_SIZE - 1));
addr = xsk_umem_add_offset_to_addr(addr);

return umem->pages[addr >> PAGE_SHIFT].dma + (addr & ~PAGE_MASK);
}

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

rq->handles[rq->length++] = addr;
}

/* Handle the offset appropriately depending on aligned or unaligned mode.
* For unaligned mode, we store the offset in the upper 16-bits of the address.
* For aligned mode, we simply add the offset to the address.
*/
static inline u64 xsk_umem_adjust_offset(struct xdp_umem *umem, u64 address,
u64 offset)
{
if (umem->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG)
return address + (offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT);
else
return address + offset;
}
#else
static inline int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
{
Expand Down Expand Up @@ -241,6 +287,21 @@ static inline struct xdp_umem *xdp_get_umem_from_qid(struct net_device *dev,
return NULL;
}

static inline u64 xsk_umem_extract_addr(u64 addr)
{
return 0;
}

static inline u64 xsk_umem_extract_offset(u64 addr)
{
return 0;
}

static inline u64 xsk_umem_add_offset_to_addr(u64 addr)
{
return 0;
}

static inline char *xdp_umem_get_data(struct xdp_umem *umem, u64 addr)
{
return NULL;
Expand Down Expand Up @@ -290,6 +351,12 @@ static inline bool xsk_umem_uses_need_wakeup(struct xdp_umem *umem)
return false;
}

static inline u64 xsk_umem_adjust_offset(struct xdp_umem *umem, u64 handle,
u64 offset)
{
return 0;
}

#endif /* CONFIG_XDP_SOCKETS */

#endif /* _LINUX_XDP_SOCK_H */
9 changes: 9 additions & 0 deletions include/uapi/linux/if_xdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
*/
#define XDP_USE_NEED_WAKEUP (1 << 3)

/* Flags for xsk_umem_config flags */
#define XDP_UMEM_UNALIGNED_CHUNK_FLAG (1 << 0)

struct sockaddr_xdp {
__u16 sxdp_family;
__u16 sxdp_flags;
Expand Down Expand Up @@ -66,6 +69,7 @@ struct xdp_umem_reg {
__u64 len; /* Length of packet data area */
__u32 chunk_size;
__u32 headroom;
__u32 flags;
};

struct xdp_statistics {
Expand All @@ -87,6 +91,11 @@ struct xdp_options {
#define XDP_UMEM_PGOFF_FILL_RING 0x100000000ULL
#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000ULL

/* Masks for unaligned chunks mode */
#define XSK_UNALIGNED_BUF_OFFSET_SHIFT 48
#define XSK_UNALIGNED_BUF_ADDR_MASK \
((1ULL << XSK_UNALIGNED_BUF_OFFSET_SHIFT) - 1)

/* Rx/Tx descriptor */
struct xdp_desc {
__u64 addr;
Expand Down
19 changes: 14 additions & 5 deletions net/xdp/xdp_umem.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ static int xdp_umem_account_pages(struct xdp_umem *umem)

static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
{
bool unaligned_chunks = mr->flags & XDP_UMEM_UNALIGNED_CHUNK_FLAG;
u32 chunk_size = mr->chunk_size, headroom = mr->headroom;
unsigned int chunks, chunks_per_page;
u64 addr = mr->addr, size = mr->len;
Expand All @@ -355,7 +356,11 @@ static int xdp_umem_reg(struct xdp_umem *umem, struct xdp_umem_reg *mr)
return -EINVAL;
}

if (!is_power_of_2(chunk_size))
if (mr->flags & ~(XDP_UMEM_UNALIGNED_CHUNK_FLAG |
XDP_UMEM_USES_NEED_WAKEUP))
return -EINVAL;

if (!unaligned_chunks && !is_power_of_2(chunk_size))
return -EINVAL;

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

chunks_per_page = PAGE_SIZE / chunk_size;
if (chunks < chunks_per_page || chunks % chunks_per_page)
return -EINVAL;
if (!unaligned_chunks) {
chunks_per_page = PAGE_SIZE / chunk_size;
if (chunks < chunks_per_page || chunks % chunks_per_page)
return -EINVAL;
}

headroom = ALIGN(headroom, 64);

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

umem->address = (unsigned long)addr;
umem->chunk_mask = ~((u64)chunk_size - 1);
umem->chunk_mask = unaligned_chunks ? XSK_UNALIGNED_BUF_ADDR_MASK
: ~((u64)chunk_size - 1);
umem->size = size;
umem->headroom = headroom;
umem->chunk_size_nohr = chunk_size - headroom;
umem->npgs = size / PAGE_SIZE;
umem->pgs = NULL;
umem->user = NULL;
umem->flags = mr->flags;
INIT_LIST_HEAD(&umem->xsk_list);
spin_lock_init(&umem->xsk_list_lock);

Expand Down
Loading

0 comments on commit c05cd36

Please sign in to comment.