xsk: add umem completion queue support and mmap
authorMagnus Karlsson <magnus.karlsson@intel.com>
Wed, 2 May 2018 11:01:31 +0000 (13:01 +0200)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 3 May 2018 22:55:24 +0000 (15:55 -0700)
Here, we add another setsockopt for registered user memory (umem)
called XDP_UMEM_COMPLETION_QUEUE. Using this socket option, the
process can ask the kernel to allocate a queue (ring buffer) and also
mmap it (XDP_UMEM_PGOFF_COMPLETION_QUEUE) into the process.

The queue is used to explicitly pass ownership of umem frames from the
kernel to user process. This will be used by the TX path to tell user
space that a certain frame has been transmitted and user space can use
it for something else, if it wishes.

Signed-off-by: Magnus Karlsson <magnus.karlsson@intel.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/uapi/linux/if_xdp.h
net/xdp/xdp_umem.c
net/xdp/xdp_umem.h
net/xdp/xsk.c

index e5091881f776f1dbb2b110118b699b1a03fedf18..71581a139f26538905f759a2e1a2c84a780934d3 100644 (file)
@@ -36,6 +36,7 @@ struct sockaddr_xdp {
 #define XDP_RX_RING                    1
 #define XDP_UMEM_REG                   3
 #define XDP_UMEM_FILL_RING             4
+#define XDP_UMEM_COMPLETION_RING       5
 
 struct xdp_umem_reg {
        __u64 addr; /* Start of packet data area */
@@ -47,6 +48,7 @@ struct xdp_umem_reg {
 /* Pgoff for mmaping the rings */
 #define XDP_PGOFF_RX_RING                        0
 #define XDP_UMEM_PGOFF_FILL_RING       0x100000000
+#define XDP_UMEM_PGOFF_COMPLETION_RING 0x180000000
 
 struct xdp_desc {
        __u32 idx;
index 9bac1ad570fad996313808ce39d0ce0558bab015..881dfdefe235926b9fe48b1359c67e96f2e06e1b 100644 (file)
@@ -70,6 +70,11 @@ static void xdp_umem_release(struct xdp_umem *umem)
                umem->fq = NULL;
        }
 
+       if (umem->cq) {
+               xskq_destroy(umem->cq);
+               umem->cq = NULL;
+       }
+
        if (umem->pgs) {
                xdp_umem_unpin_pages(umem);
 
@@ -251,5 +256,5 @@ out:
 
 bool xdp_umem_validate_queues(struct xdp_umem *umem)
 {
-       return umem->fq;
+       return (umem->fq && umem->cq);
 }
index c7378a11721f30d481849040108db12410aac2e8..7e0b2fab852291d968532e6c7d28a1f53b74d73a 100644 (file)
@@ -24,6 +24,7 @@
 
 struct xdp_umem {
        struct xsk_queue *fq;
+       struct xsk_queue *cq;
        struct page **pgs;
        struct xdp_umem_props props;
        u32 npgs;
index b931a0db5588971638dc814377b17df758f1fa82..f4a2c5bc6da9446e2a0c9760ee0db29f66f2aea7 100644 (file)
@@ -255,6 +255,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
        } else {
                /* This xsk has its own umem. */
                xskq_set_umem(xs->umem->fq, &xs->umem->props);
+               xskq_set_umem(xs->umem->cq, &xs->umem->props);
        }
 
        /* Rebind? */
@@ -334,6 +335,7 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
                return 0;
        }
        case XDP_UMEM_FILL_RING:
+       case XDP_UMEM_COMPLETION_RING:
        {
                struct xsk_queue **q;
                int entries;
@@ -345,7 +347,8 @@ static int xsk_setsockopt(struct socket *sock, int level, int optname,
                        return -EFAULT;
 
                mutex_lock(&xs->mutex);
-               q = &xs->umem->fq;
+               q = (optname == XDP_UMEM_FILL_RING) ? &xs->umem->fq :
+                       &xs->umem->cq;
                err = xsk_init_queue(entries, q, true);
                mutex_unlock(&xs->mutex);
                return err;
@@ -375,6 +378,8 @@ static int xsk_mmap(struct file *file, struct socket *sock,
 
                if (offset == XDP_UMEM_PGOFF_FILL_RING)
                        q = xs->umem->fq;
+               else if (offset == XDP_UMEM_PGOFF_COMPLETION_RING)
+                       q = xs->umem->cq;
                else
                        return -EINVAL;
        }