[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20180131135356.19134-18-bjorn.topel@gmail.com>
Date: Wed, 31 Jan 2018 14:53:49 +0100
From: Björn Töpel <bjorn.topel@...il.com>
To: bjorn.topel@...il.com, magnus.karlsson@...el.com,
alexander.h.duyck@...el.com, alexander.duyck@...il.com,
john.fastabend@...il.com, ast@...com, brouer@...hat.com,
willemdebruijn.kernel@...il.com, daniel@...earbox.net,
netdev@...r.kernel.org
Cc: Björn Töpel <bjorn.topel@...el.com>,
michael.lundkvist@...csson.com, jesse.brandeburg@...el.com,
anjali.singhai@...el.com, jeffrey.b.shaw@...el.com,
ferruh.yigit@...el.com, qi.z.zhang@...el.com
Subject: [RFC PATCH 17/24] xsk: introduce xsk_buff_pool
From: Björn Töpel <bjorn.topel@...el.com>
The xsk_buff_pool is a buff_pool implementation, that uses frames
(buffs) provided by userspace instead of the page allocator.
Signed-off-by: Björn Töpel <bjorn.topel@...el.com>
---
net/xdp/Makefile | 2 +-
net/xdp/xsk_buff_pool.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++
net/xdp/xsk_buff_pool.h | 17 ++++
3 files changed, 243 insertions(+), 1 deletion(-)
create mode 100644 net/xdp/xsk_buff_pool.c
create mode 100644 net/xdp/xsk_buff_pool.h
diff --git a/net/xdp/Makefile b/net/xdp/Makefile
index b9d5d6b8823c..42727a32490c 100644
--- a/net/xdp/Makefile
+++ b/net/xdp/Makefile
@@ -1 +1 @@
-obj-$(CONFIG_XDP_SOCKETS) += xsk.o xsk_ring.o xsk_packet_array.o
+obj-$(CONFIG_XDP_SOCKETS) += xsk.o xsk_ring.o xsk_packet_array.o xsk_buff_pool.o
diff --git a/net/xdp/xsk_buff_pool.c b/net/xdp/xsk_buff_pool.c
new file mode 100644
index 000000000000..b0760ba2b188
--- /dev/null
+++ b/net/xdp/xsk_buff_pool.c
@@ -0,0 +1,225 @@
+#include "xsk_buff_pool.h"
+
+#include <linux/skbuff.h>
+#include <linux/buff_pool.h>
+
+#include "xsk_packet_array.h" /* XDP_KERNEL_HEADROOM */
+#include "xsk_buff.h"
+#include "xsk_ring.h"
+
+#define BATCH_SIZE 32
+
+static bool xsk_bp_alloc_from_freelist(struct xsk_buff_pool *impl,
+ unsigned long *handle)
+{
+ struct xsk_buff *buff;
+
+ if (impl->free_list) {
+ buff = impl->free_list;
+ impl->free_list = buff->next;
+ buff->next = NULL;
+ *handle = (unsigned long)buff;
+
+ return true;
+ }
+
+ return false;
+}
+
+static int xsk_bp_alloc(void *pool, unsigned long *handle)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+ struct xsk_buff *buff;
+ struct xskq_iter it;
+ u32 id;
+
+ if (xsk_bp_alloc_from_freelist(impl, handle))
+ return 0;
+
+ it = xskq_deq_iter(impl->q, BATCH_SIZE);
+
+ while (!xskq_iter_end(&it)) {
+ id = xskq_deq_iter_get_id(impl->q, &it);
+ buff = &impl->bi->buffs[id];
+ buff->next = impl->free_list;
+ impl->free_list = buff;
+ xskq_deq_iter_next(impl->q, &it);
+ }
+
+ xskq_deq_iter_done(impl->q, &it);
+
+ if (xsk_bp_alloc_from_freelist(impl, handle))
+ return 0;
+
+ return -ENOMEM;
+}
+
+static void xsk_bp_free(void *pool, unsigned long handle)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+ struct xsk_buff *buff = (struct xsk_buff *)handle;
+
+ buff->next = impl->free_list;
+ impl->free_list = buff;
+}
+
+static unsigned int xsk_bp_buff_size(void *pool)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+
+ return impl->bi->buff_len - impl->bi->rx_headroom -
+ XDP_KERNEL_HEADROOM;
+}
+
+static unsigned int xsk_bp_total_buff_size(void *pool)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+
+ return impl->bi->buff_len - impl->bi->rx_headroom;
+}
+
+static unsigned int xsk_bp_buff_headroom(void *pool)
+{
+ (void)pool;
+
+ return XSK_KERNEL_HEADROOM;
+}
+
+static unsigned int xsk_bp_buff_truesize(void *pool)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+
+ return impl->bi->buff_len;
+}
+
+static void *xsk_bp_buff_ptr(void *pool, unsigned long handle)
+{
+ struct xsk_buff *buff = (struct xsk_buff *)handle;
+
+ (void)pool;
+ return buff->data + buff->offset;
+}
+
+static int xsk_bp_buff_convert_to_page(void *pool,
+ unsigned long handle,
+ struct page **pg, unsigned int *pg_off)
+{
+ unsigned int req_len, buff_len, pg_order = 0;
+ void *data;
+
+ buff_len = xsk_bp_total_buff_size(pool);
+ req_len = buff_len + SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ /* XXX too sloppy? clean up... */
+ if (req_len > PAGE_SIZE) {
+ pg_order++;
+ if (req_len > (PAGE_SIZE << pg_order))
+ return -ENOMEM;
+ }
+
+ *pg = dev_alloc_pages(pg_order);
+ if (unlikely(!*pg))
+ return -ENOMEM;
+
+ data = page_address(*pg);
+ memcpy(data, xsk_bp_buff_ptr(pool, handle),
+ xsk_bp_total_buff_size(pool));
+ *pg_off = 0;
+
+ xsk_bp_free(pool, handle);
+
+ return 0;
+}
+
+static dma_addr_t xsk_bp_buff_dma(void *pool,
+ unsigned long handle)
+{
+ struct xsk_buff *buff = (struct xsk_buff *)handle;
+
+ (void)pool;
+ return buff->dma + buff->offset;
+}
+
+static void xsk_bp_buff_dma_sync_cpu(void *pool,
+ unsigned long handle,
+ unsigned int off,
+ unsigned int size)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+ struct xsk_buff *buff = (struct xsk_buff *)handle;
+
+ dma_sync_single_range_for_cpu(impl->bi->dev, buff->dma,
+ off, size, impl->bi->dir);
+}
+
+static void xsk_bp_buff_dma_sync_dev(void *pool,
+ unsigned long handle,
+ unsigned int off,
+ unsigned int size)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+ struct xsk_buff *buff = (struct xsk_buff *)handle;
+
+ dma_sync_single_range_for_device(impl->bi->dev, buff->dma,
+ off, size, impl->bi->dir);
+}
+
+static void xsk_bp_destroy(void *pool)
+{
+ struct xsk_buff_pool *impl = (struct xsk_buff_pool *)pool;
+ struct xsk_buff *buff = impl->free_list;
+
+ while (buff) {
+ xskq_return_id(impl->q, buff->id);
+ buff = buff->next;
+ }
+
+ kfree(impl);
+}
+
+struct buff_pool *xsk_buff_pool_create(struct xsk_buff_info *buff_info,
+ struct xsk_queue *queue)
+{
+ struct buff_pool_ops *pool_ops;
+ struct xsk_buff_pool *impl;
+ struct buff_pool *pool;
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return NULL;
+
+ pool_ops = kzalloc(sizeof(*pool_ops), GFP_KERNEL);
+ if (!pool_ops) {
+ kfree(pool);
+ return NULL;
+ }
+
+ impl = kzalloc(sizeof(*impl), GFP_KERNEL);
+ if (!impl) {
+ kfree(pool_ops);
+ kfree(pool);
+ return NULL;
+ }
+
+ impl->bi = buff_info;
+ impl->q = queue;
+
+ pool_ops->alloc = xsk_bp_alloc;
+ pool_ops->free = xsk_bp_free;
+ pool_ops->buff_size = xsk_bp_buff_size;
+ pool_ops->total_buff_size = xsk_bp_total_buff_size;
+ pool_ops->buff_headroom = xsk_bp_buff_headroom;
+ pool_ops->buff_truesize = xsk_bp_buff_truesize;
+ pool_ops->buff_ptr = xsk_bp_buff_ptr;
+ pool_ops->buff_convert_to_page = xsk_bp_buff_convert_to_page;
+ pool_ops->buff_dma = xsk_bp_buff_dma;
+ pool_ops->buff_dma_sync_cpu = xsk_bp_buff_dma_sync_cpu;
+ pool_ops->buff_dma_sync_dev = xsk_bp_buff_dma_sync_dev;
+ pool_ops->destroy = xsk_bp_destroy;
+
+ pool->pool = impl;
+ pool->ops = pool_ops;
+
+ return pool;
+}
+
diff --git a/net/xdp/xsk_buff_pool.h b/net/xdp/xsk_buff_pool.h
new file mode 100644
index 000000000000..302c3e40cae4
--- /dev/null
+++ b/net/xdp/xsk_buff_pool.h
@@ -0,0 +1,17 @@
+#ifndef XSK_BUFF_POOL_H_
+#define XSK_BUFF_POOL_H_
+
+struct xsk_buff;
+struct xsk_buff_info;
+struct xsk_queue;
+
+struct xsk_buff_pool {
+ struct xsk_buff *free_list;
+ struct xsk_buff_info *bi;
+ struct xsk_queue *q;
+};
+
+struct buff_pool *xsk_buff_pool_create(struct xsk_buff_info *buff_info,
+ struct xsk_queue *queue);
+
+#endif /* XSK_BUFF_POOL_H_ */
--
2.14.1
Powered by blists - more mailing lists