From: Björn Töpel <bjorn.to...@intel.com>

Extend the xsk_rcv to support the new MEM_TYPE_ZERO_COPY memory, and
wireup ndo_bpf call in bind.

Signed-off-by: Björn Töpel <bjorn.to...@intel.com>
---
 include/net/xdp_sock.h |  7 +++++
 net/xdp/xdp_umem.c     | 60 +++++++++++++++++++++++++++++++++++++++++++
 net/xdp/xdp_umem.h     |  3 +++
 net/xdp/xsk.c          | 69 ++++++++++++++++++++++++++++++++++++++++----------
 4 files changed, 125 insertions(+), 14 deletions(-)

diff --git a/include/net/xdp_sock.h b/include/net/xdp_sock.h
index 09068c4f068e..644684eb2caf 100644
--- a/include/net/xdp_sock.h
+++ b/include/net/xdp_sock.h
@@ -31,6 +31,7 @@ struct xdp_umem_props {
 
 struct xdp_umem_frame {
        void *addr;
+       dma_addr_t dma;
 };
 
 struct xdp_umem {
@@ -47,6 +48,8 @@ struct xdp_umem {
        size_t size;
        atomic_t users;
        struct work_struct work;
+       struct net_device *dev;
+       u16 queue_id;
 };
 
 struct xdp_sock {
@@ -69,6 +72,10 @@ int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff 
*xdp);
 int xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp);
 void xsk_flush(struct xdp_sock *xs);
 bool xsk_is_setup_for_bpf_map(struct xdp_sock *xs);
+
+u32 *xsk_umem_peek_id(struct xdp_umem *umem);
+void xsk_umem_discard_id(struct xdp_umem *umem);
+
 #else
 static inline int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
 {
diff --git a/net/xdp/xdp_umem.c b/net/xdp/xdp_umem.c
index b426cbe3151a..f70cdaa2ef4d 100644
--- a/net/xdp/xdp_umem.c
+++ b/net/xdp/xdp_umem.c
@@ -26,6 +26,64 @@
 
 #define XDP_UMEM_MIN_FRAME_SIZE 2048
 
+int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
+                       u16 queue_id)
+{
+       struct netdev_bpf bpf;
+       int err;
+
+       if (umem->dev) {
+               if (dev != umem->dev || queue_id != umem->queue_id)
+                       return -EBUSY;
+               return 0;
+       }
+
+       dev_hold(dev);
+       if (dev->netdev_ops->ndo_bpf) {
+               bpf.command = XDP_SETUP_XSK_UMEM;
+               bpf.xsk.umem = umem;
+               bpf.xsk.queue_id = queue_id;
+
+               rtnl_lock();
+               err = dev->netdev_ops->ndo_bpf(dev, &bpf);
+               rtnl_unlock();
+
+               if (err) {
+                       dev_put(dev);
+                       return 0;
+               }
+
+               umem->dev = dev;
+               umem->queue_id = queue_id;
+               return 0;
+       }
+
+       dev_put(dev);
+       return 0;
+}
+
+void xdp_umem_clear_dev(struct xdp_umem *umem)
+{
+       struct netdev_bpf bpf;
+       int err;
+
+       if (umem->dev) {
+               bpf.command = XDP_SETUP_XSK_UMEM;
+               bpf.xsk.umem = NULL;
+               bpf.xsk.queue_id = umem->queue_id;
+
+               rtnl_lock();
+               err = umem->dev->netdev_ops->ndo_bpf(umem->dev, &bpf);
+               rtnl_unlock();
+
+               if (err)
+                       WARN(1, "failed to disable umem!\n");
+
+               dev_put(umem->dev);
+               umem->dev = NULL;
+       }
+}
+
 int xdp_umem_create(struct xdp_umem **umem)
 {
        *umem = kzalloc(sizeof(**umem), GFP_KERNEL);
@@ -66,6 +124,8 @@ static void xdp_umem_release(struct xdp_umem *umem)
        struct task_struct *task;
        struct mm_struct *mm;
 
+       xdp_umem_clear_dev(umem);
+
        if (umem->fq) {
                xskq_destroy(umem->fq);
                umem->fq = NULL;
diff --git a/net/xdp/xdp_umem.h b/net/xdp/xdp_umem.h
index 0a969384af93..3bb96d156b40 100644
--- a/net/xdp/xdp_umem.h
+++ b/net/xdp/xdp_umem.h
@@ -34,4 +34,7 @@ void xdp_get_umem(struct xdp_umem *umem);
 void xdp_put_umem(struct xdp_umem *umem);
 int xdp_umem_create(struct xdp_umem **umem);
 
+int xdp_umem_assign_dev(struct xdp_umem *umem, struct net_device *dev,
+                       u16 queue_id);
+
 #endif /* XDP_UMEM_H_ */
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index e59ca8e2618d..a0cf9c042ed2 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -43,6 +43,18 @@ static struct xdp_sock *xdp_sk(struct sock *sk)
        return (struct xdp_sock *)sk;
 }
 
+u32 *xsk_umem_peek_id(struct xdp_umem *umem)
+{
+       return xskq_peek_id(umem->fq);
+}
+EXPORT_SYMBOL(xsk_umem_peek_id);
+
+void xsk_umem_discard_id(struct xdp_umem *umem)
+{
+       xskq_discard_id(umem->fq);
+}
+EXPORT_SYMBOL(xsk_umem_discard_id);
+
 bool xsk_is_setup_for_bpf_map(struct xdp_sock *xs)
 {
        return !!xs->rx;
@@ -50,40 +62,54 @@ bool xsk_is_setup_for_bpf_map(struct xdp_sock *xs)
 
 static int __xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
 {
-       u32 *id, len = xdp->data_end - xdp->data;
+       u32 *id, len;
        void *buffer;
        int err = 0;
 
-       if (xs->dev != xdp->rxq->dev || xs->queue_id != xdp->rxq->queue_index)
-               return -EINVAL;
-
        id = xskq_peek_id(xs->umem->fq);
        if (!id)
                return -ENOSPC;
 
        buffer = xdp_umem_get_data_with_headroom(xs->umem, *id);
+       len = xdp->data_end - xdp->data;
        memcpy(buffer, xdp->data, len);
        err = xskq_produce_batch_desc(xs->rx, *id, len,
                                      xs->umem->frame_headroom);
-       if (!err)
+       if (!err) {
                xskq_discard_id(xs->umem->fq);
+               xdp_return_buff(xdp);
+               return 0;
+       }
 
+       xs->rx_dropped++;
        return err;
 }
 
-int xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
+static int __xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff *xdp)
 {
+       u16 off = xdp->data - xdp->data_hard_start;
+       u32 len = xdp->data_end - xdp->data;
        int err;
 
-       err = __xsk_rcv(xs, xdp);
-       if (likely(!err))
+       err = xskq_produce_batch_desc(xs->rx, (u32)xdp->handle, len,
+                                     xs->umem->frame_headroom + off);
+       if (err) {
                xdp_return_buff(xdp);
-       else
                xs->rx_dropped++;
+       }
 
        return err;
 }
 
+int xsk_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
+{
+       if (xs->dev != xdp->rxq->dev || xs->queue_id != xdp->rxq->queue_index)
+               return -EINVAL;
+
+       return (xdp->rxq->mem.type == MEM_TYPE_ZERO_COPY) ?
+               __xsk_rcv_zc(xs, xdp) : __xsk_rcv(xs, xdp);
+}
+
 void xsk_flush(struct xdp_sock *xs)
 {
        xskq_produce_flush_desc(xs->rx);
@@ -92,14 +118,26 @@ void xsk_flush(struct xdp_sock *xs)
 
 int xsk_generic_rcv(struct xdp_sock *xs, struct xdp_buff *xdp)
 {
-       int err;
+       u32 *id, len;
+       void *buffer;
+       int err = 0;
 
-       err = __xsk_rcv(xs, xdp);
-       if (!err)
+       id = xskq_peek_id(xs->umem->fq);
+       if (!id)
+               return -ENOSPC;
+
+       buffer = xdp_umem_get_data_with_headroom(xs->umem, *id);
+       len = xdp->data_end - xdp->data;
+       memcpy(buffer, xdp->data, len);
+       err = xskq_produce_batch_desc(xs->rx, *id, len,
+                                     xs->umem->frame_headroom);
+       if (!err) {
+               xskq_discard_id(xs->umem->fq);
                xsk_flush(xs);
-       else
-               xs->rx_dropped++;
+               return 0;
+       }
 
+       xs->rx_dropped++;
        return err;
 }
 
@@ -362,6 +400,9 @@ static int xsk_bind(struct socket *sock, struct sockaddr 
*addr, int addr_len)
 
        xs->dev = dev;
        xs->queue_id = sxdp->sxdp_queue_id;
+       err = xdp_umem_assign_dev(xs->umem, dev, xs->queue_id);
+       if (err)
+               goto out_unlock;
 
        xskq_set_umem(xs->rx, &xs->umem->props);
        xskq_set_umem(xs->tx, &xs->umem->props);
-- 
2.14.1

Reply via email to