|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH v5 02/11] lib/uknetdev: Introduce Netbufs
Adds `struct uk_netbuf`, a structure for describing network
packets. It is designed to support zero-copy operation and simple
embedding to existing network stacks. Netbufs can be (1) initialized
on user-supplied memory regions, intended for network stacks that come
with a packet buffer allocator, or (2) uk_alloc-based allocation.
This commit introduces the netbuf struct and intialization and
allocation functions.
Signed-off-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
Reviewed-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
---
lib/uknetdev/Config.uk | 1 +
lib/uknetdev/Makefile.uk | 2 +
lib/uknetdev/exportsyms.uk | 4 +
lib/uknetdev/include/uk/netbuf.h | 289 +++++++++++++++++++++++++++++++++++++++
lib/uknetdev/netbuf.c | 190 +++++++++++++++++++++++++
5 files changed, 486 insertions(+)
create mode 100644 lib/uknetdev/exportsyms.uk
create mode 100644 lib/uknetdev/include/uk/netbuf.h
create mode 100644 lib/uknetdev/netbuf.c
diff --git a/lib/uknetdev/Config.uk b/lib/uknetdev/Config.uk
index b5e11a9..878b822 100644
--- a/lib/uknetdev/Config.uk
+++ b/lib/uknetdev/Config.uk
@@ -3,3 +3,4 @@ config LIBUKNETDEV
default n
select LIBNOLIBC if !HAVE_LIBC
select LIBUKDEBUG
+ select LIBUKALLOC
diff --git a/lib/uknetdev/Makefile.uk b/lib/uknetdev/Makefile.uk
index 34f30be..81afae4 100644
--- a/lib/uknetdev/Makefile.uk
+++ b/lib/uknetdev/Makefile.uk
@@ -2,3 +2,5 @@ $(eval $(call addlib_s,libuknetdev,$(CONFIG_LIBUKNETDEV)))
CINCLUDES-$(CONFIG_LIBUKNETDEV) += -I$(LIBUKNETDEV_BASE)/include
CXXINCLUDES-$(CONFIG_LIBUKNETDEV) += -I$(LIBUKNETDEV_BASE)/include
+
+LIBUKNETDEV_SRCS-y += $(LIBUKNETDEV_BASE)/netbuf.c
diff --git a/lib/uknetdev/exportsyms.uk b/lib/uknetdev/exportsyms.uk
new file mode 100644
index 0000000..5473bba
--- /dev/null
+++ b/lib/uknetdev/exportsyms.uk
@@ -0,0 +1,4 @@
+uk_netbuf_init_indir
+uk_netbuf_alloc_indir
+uk_netbuf_alloc_buf
+uk_netbuf_prepare_buf
diff --git a/lib/uknetdev/include/uk/netbuf.h b/lib/uknetdev/include/uk/netbuf.h
new file mode 100644
index 0000000..551793a
--- /dev/null
+++ b/lib/uknetdev/include/uk/netbuf.h
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+#ifndef __UK_NETBUF__
+#define __UK_NETBUF__
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <limits.h>
+#include <errno.h>
+#include <uk/assert.h>
+#include <uk/refcount.h>
+#include <uk/alloc.h>
+#include <uk/essentials.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct uk_netbuf;
+
+typedef void (*uk_netbuf_dtor_t)(struct uk_netbuf *);
+
+/**
+ * The netbuf structure is used to describe a single contiguous packet buffer.
+ * The structure can be chained to describe a packet with multiple scattered
+ * buffers.
+ *
+ * NETBUF
+ * +----------------------+
+ * | struct uk_netbuf |
+ * | |
+ * +----------------------+
+ *
+ * PRIVATE META DATA
+ * *priv -> +----------------------+
+ * | private meta |
+ * | data area |
+ * +----------------------+
+ *
+ * PACKET BUFFER
+ * *buf -> +----------------------+ \
+ * | HEAD ROOM | |
+ * | ^ ^ | |
+ * *data -> +---|--------------|---+ | contiguous
+ * | v v | | buffer
+ * | PACKET DATA | | area
+ * | ^ ^ | |
+ * *data + len -> +---|--------------|---+ |
+ * | v v | |
+ * | TAIL ROOM | |
+ * *buf + buflen -> +----------------------+ /
+ *
+ *
+ * The private data area is intended for glue code that wants to embed stack-
+ * specific data to the netbuf (e.g., `struct pbuf` for lwIP). This avoids
+ * separate memory management for stack-specific packet meta-data. libuknetdev
+ * or device drivers are not inspecting or modifying these data.
+ *
+ * The buffer region contains the packet data. `struct uk_netbuf` is pointing
+ * with `*data` to the first byte of the packet data within the buffer.
+ * `len` describes the number of bytes used. All packet data has to fit into
the
+ * given buffer. The buffer is described with the `buf` and `buflen` field.
+ * These two fields should not change during the netbuf life time.
+ * The available headroom bytes are calculated by subtracting the `*data`
+ * pointer from `*buf` pointer. The available tailroom bytes are calculated
+ * with: (*buf + buflen) - (*data + len).
+ * When more packet data space is required or whenever packet data is scattered
+ * in memory, netbufs can be chained.
+ *
+ * The netbuf structure, private meta data area, and buffer area can be backed
+ * by independent memory allocations. uk_netbuf_alloc_buf() and
+ * uk_netbuf_prepare_buf() are placing all these three regions into a single
+ * allocation.
+ */
+struct uk_netbuf {
+ struct uk_netbuf *next;
+ struct uk_netbuf *prev;
+
+ void *data; /**< Payload start, is part of buf. */
+ uint16_t len; /**< Payload length (should be <= buflen). */
+ __atomic refcount; /**< Reference counter */
+
+ void *priv; /**< Reference to user-provided private data */
+
+ void *buf; /**< Start address of contiguous buffer. */
+ size_t buflen; /**< Length of buffer. */
+
+ uk_netbuf_dtor_t dtor; /**< Destructor callback */
+ struct uk_alloc *_a; /**< @internal Allocator for free'ing */
+};
+
+/**
+ * Initializes an external allocated netbuf.
+ * This netbuf has no data area assigned. It is intended
+ * that m->buf, m->buflen, and m->data is initialized by the caller.
+ * m->len is initialized with 0.
+ * Note: On the last free, only the destructor is called,
+ * no memory is released by the API.
+ * @param m
+ * reference to uk_netbuf that shall be initialized
+ * @param priv
+ * Reference to external (meta) data that corresponds to this netbuf.
+ * @param dtor
+ * Destructor that is called when netbuf's refcount reaches zero
(recommended)
+ */
+#define uk_netbuf_init(m, priv, dtor) \
+ uk_netbuf_init_indir((m), NULL, 0, 0, (priv), (dtor))
+
+/**
+ * Initializes an external allocated netbuf.
+ * This netbuf will point to an user-provided contiguous buffer area.
+ * m->len is initialized with 0.
+ * Note: On the last free, only the destructor is called,
+ * no memory is released by the API.
+ * @param m
+ * reference to uk_netbuf that shall be initialized
+ * @param buf
+ * Reference to buffer area that is belonging to this netbuf
+ * @param buflen
+ * Size of the buffer area
+ * @param headroom
+ * Number of bytes reserved as headroom from buf, `m->data` will point to
+ * to the first byte in `buf` after the headroom. `headroom` has to be
smaller
+ * or equal to `buflen`.
+ * Note: Some drivers may require extra headroom space in the first netbuf of
+ * a chain in order to do a packet transmission.
+ * @param priv
+ * Reference to external (meta) data that corresponds to this netbuf.
+ * @param dtor
+ * Destructor that is called when netbuf's refcount reaches zero
(recommended)
+ */
+void uk_netbuf_init_indir(struct uk_netbuf *m,
+ void *buf, size_t buflen, uint16_t headroom,
+ void *priv, uk_netbuf_dtor_t dtor);
+
+/**
+ * Allocates and initializes a netbuf.
+ * This netbuf has no buffer area assigned. It is intended
+ * that m->buf, m->buflen, and m->data is initialized by the caller.
+ * m->len is initialized with 0.
+ * Note: On the last free, the buffer area is not free'd. It is intended
+ * to provide a destructor for this operation.
+ * @param a
+ * Allocator to use for allocating `struct uk_netbuf` and the
+ * corresponding private data area.
+ * @param dtor
+ * Destructor that is called when netbuf is free'd (recommended)
+ * @param privlen
+ * Length for reserved memory to store private data. This memory is free'd
+ * together with this netbuf. If privlen is 0, either no private data is
+ * required or external meta data corresponds to this netbuf. m->priv can be
+ * modified after the allocation.
+ * @returns
+ * - (NULL): Allocation failed
+ * - initialized uk_netbuf
+ */
+#define uk_netbuf_alloc(a, privlen, dtor) \
+ uk_netbuf_alloc_indir((a), NULL, 0, 0, (privlen), (dtor))
+
+/**
+ * Allocate and initialize netbuf to reference to an existing
+ * contiguous data area
+ * m->len is initialized with 0.
+ * It will not be free'd together with this netbuf on the last free call.
+ * @param a
+ * Allocator to be used for allocating `struct uk_netbuf`
+ * On uk_netdev_free() and refcount == 0 the allocation is free'd
+ * to this allocator.
+ * @param buf
+ * Reference to the buffer area that is belonging to this netbuf
+ * @param buflen
+ * Size of the buffer area
+ * @param headroom
+ * Number of bytes reserved as headroom from buf.
+ * headroom has to be smaller or equal to buflen.
+ * Please note that m->data is aligned when reserved headroom is 0.
+ * In order to keep this property align up the headroom value.
+ * @param privlen
+ * Length for reserved memory to store private data. This memory is free'd
+ * together with this netbuf. If privlen is 0, either no private data is
+ * required or external meta data corresponds to this netbuf. m->priv can be
+ * modified after the allocation.
+ * @param dtor
+ * Destructor that is called when netbuf is free'd (recommended)
+ * @returns
+ * - (NULL): Allocation failed
+ * - initialized uk_netbuf
+ */
+struct uk_netbuf *uk_netbuf_alloc_indir(struct uk_alloc *a,
+ void *buf, size_t buflen,
+ uint16_t headroom,
+ size_t privlen, uk_netbuf_dtor_t dtor);
+
+/**
+ * Allocate and initialize netbuf with data buffer area.
+ * m->len is initialized with 0.
+ * @param a
+ * Allocator to be used for allocating `struct uk_netbuf` and the
+ * corresponding buffer area (single allocation).
+ * On uk_netbuf_free() and refcount == 0 the allocation is free'd
+ * to this allocator.
+ * @param buflen
+ * Size of the buffer area
+ * @param headroom
+ * Number of bytes reserved as headroom from the buffer area.
+ * `headroom` has to be smaller or equal to `buflen`.
+ * Please note that `m->data` is aligned when `headroom` is 0.
+ * In order to keep this property when a headroom is used,
+ * it is recommended to align up the required headroom.
+ * @param privlen
+ * Length for reserved memory to store private data. This memory is free'd
+ * together with this netbuf. If privlen is 0, either no private data is
+ * required or external meta data corresponds to this netbuf. m->priv can be
+ * modified after the allocation.
+ * @param dtor
+ * Destructor that is called when netbuf is free'd (optional)
+ * @returns
+ * - (NULL): Allocation failed
+ * - initialized uk_netbuf
+ */
+struct uk_netbuf *uk_netbuf_alloc_buf(struct uk_alloc *a, size_t buflen,
+ uint16_t headroom,
+ size_t privlen, uk_netbuf_dtor_t dtor);
+
+/**
+ * Initialize netbuf with data buffer on a user given allocated memory area
+ * m->len is initialized with 0.
+ * @param mem
+ * Reference to user provided memory region
+ * @param buflen
+ * Size of the data that shall be allocated together with this netbuf
+ * @param headroom
+ * Number of bytes reserved as headroom from the buffer area.
+ * `headroom` has to be smaller or equal to `buflen`.
+ * Please note that `m->data` is aligned when `headroom` is 0.
+ * In order to keep this property when a headroom is used,
+ * it is recommended to align up the required headroom.
+ * @param privlen
+ * Length for reserved memory to store private data. This memory will be
+ * embedded together with this netbuf. If privlen is 0, either no private
data
+ * is required or external meta data corresponds to this netbuf. m->priv can
+ * be modified after the preparation.
+ * @param dtor
+ * Destructor that is called when netbuf's refcount reaches zero
(recommended)
+ * @returns
+ * - (NULL): given failed
+ * - initialized uk_netbuf
+ */
+struct uk_netbuf *uk_netbuf_prepare_buf(void *mem, size_t size,
+ uint16_t headroom,
+ size_t privlen, uk_netbuf_dtor_t dtor);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __UK_NETBUF__ */
diff --git a/lib/uknetdev/netbuf.c b/lib/uknetdev/netbuf.c
new file mode 100644
index 0000000..72c349b
--- /dev/null
+++ b/lib/uknetdev/netbuf.c
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
+ *
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+#include <uk/netbuf.h>
+#include <uk/essentials.h>
+
+/* Used to align netbuf's priv and data areas to `long long` data type */
+#define NETBUF_ADDR_ALIGNMENT (sizeof(long long))
+#define NETBUF_ADDR_ALIGN_UP(x) ALIGN_UP((x), NETBUF_ADDR_ALIGNMENT)
+
+void uk_netbuf_init_indir(struct uk_netbuf *m,
+ void *buf, size_t buflen, uint16_t headroom,
+ void *priv, uk_netbuf_dtor_t dtor)
+{
+ UK_ASSERT(m);
+ UK_ASSERT(buf || (buf == NULL && buflen == 0));
+ UK_ASSERT(headroom <= buflen);
+
+ m->buf = buf;
+ m->buflen = buflen;
+ m->data = (void *) ((uintptr_t) buf + headroom);
+ m->len = 0;
+ m->prev = NULL;
+ m->next = NULL;
+
+ uk_refcount_init(&m->refcount, 1);
+
+ m->priv = priv;
+ m->dtor = dtor;
+ m->_a = NULL;
+}
+
+struct uk_netbuf *uk_netbuf_alloc_indir(struct uk_alloc *a,
+ void *buf, size_t buflen,
+ uint16_t headroom,
+ size_t privlen, uk_netbuf_dtor_t dtor)
+{
+ struct uk_netbuf *m;
+
+ if (privlen)
+ m = uk_malloc(a, NETBUF_ADDR_ALIGN_UP(sizeof(*m)) + privlen);
+ else
+ m = uk_malloc(a, sizeof(*m));
+ if (!m)
+ return NULL;
+
+ uk_netbuf_init_indir(m,
+ buf,
+ buflen,
+ headroom,
+ privlen > 0
+ ? (void *)((uintptr_t) m
+ + NETBUF_ADDR_ALIGN_UP(sizeof(*m)))
+ : NULL,
+ dtor);
+
+ /* Save reference to allocator that is used
+ * for free'ing this uk_netbuf.
+ */
+ m->_a = a;
+
+ return m;
+}
+
+struct uk_netbuf *uk_netbuf_alloc_buf(struct uk_alloc *a, size_t buflen,
+ uint16_t headroom,
+ size_t privlen, uk_netbuf_dtor_t dtor)
+{
+ struct uk_netbuf *m;
+ size_t buf_offset = 0;
+ size_t priv_offset = 0;
+ size_t headroom_extra = 0;
+
+ UK_ASSERT(buflen > 0);
+ UK_ASSERT(headroom <= buflen);
+
+ m = uk_malloc(a, NETBUF_ADDR_ALIGN_UP(sizeof(*m))
+ + NETBUF_ADDR_ALIGN_UP(privlen)
+ + buflen);
+ if (!m)
+ return NULL;
+
+ /* Place buf right behind `m` or `m->priv` region if privlen > 0.
+ * In order to keep `m->data - headroom` aligned the padding bytes
+ * are added to the headroom.
+ * We can only do this if the given headroom stays within
+ * uint16_t bounds after the operation.
+ */
+ if (likely(UINT16_MAX - headroom > NETBUF_ADDR_ALIGNMENT)) {
+ if (privlen == 0) {
+ priv_offset = 0;
+ buf_offset = sizeof(*m);
+ headroom_extra = NETBUF_ADDR_ALIGN_UP(sizeof(*m))
+ - sizeof(*m);
+ } else {
+ priv_offset = NETBUF_ADDR_ALIGN_UP(sizeof(*m));
+ buf_offset = priv_offset + privlen;
+ headroom_extra = NETBUF_ADDR_ALIGN_UP(privlen)
+ - privlen;
+ }
+ }
+
+ uk_netbuf_init_indir(m,
+ (void *) m + buf_offset,
+ buflen + headroom_extra,
+ headroom + headroom_extra,
+ privlen > 0 ? ((void *) m + priv_offset) : NULL,
+ dtor);
+
+ /* Save reference to allocator that is used
+ * for free'ing this uk_netbuf.
+ */
+ m->_a = a;
+
+ return m;
+}
+
+struct uk_netbuf *uk_netbuf_prepare_buf(void *mem, size_t size,
+ uint16_t headroom,
+ size_t privlen, uk_netbuf_dtor_t dtor)
+{
+ struct uk_netbuf *m;
+ size_t buf_offset = 0;
+ size_t priv_offset = 0;
+
+ UK_ASSERT(mem);
+ if ((NETBUF_ADDR_ALIGN_UP(sizeof(*m))
+ + NETBUF_ADDR_ALIGN_UP(privlen)
+ + headroom) > size)
+ return NULL;
+
+ /* Place buf right behind `m` or `m->priv` region if privlen > 0.
+ * In order to keep `m->data - headroom` aligned the padding bytes
+ * are added to the headroom.
+ * We can only do this if the given headroom stays within
+ * uint16_t bounds after the operation.
+ */
+ if (likely(UINT16_MAX - headroom > NETBUF_ADDR_ALIGNMENT)) {
+ if (privlen == 0) {
+ priv_offset = 0;
+ buf_offset = sizeof(*m);
+ headroom += NETBUF_ADDR_ALIGN_UP(sizeof(*m))
+ - sizeof(*m);
+ } else {
+ priv_offset = NETBUF_ADDR_ALIGN_UP(sizeof(*m));
+ buf_offset = priv_offset + privlen;
+ headroom += NETBUF_ADDR_ALIGN_UP(privlen)
+ - privlen;
+ }
+ }
+
+ m = (struct uk_netbuf *) mem;
+ uk_netbuf_init_indir(m,
+ mem + buf_offset,
+ size - buf_offset,
+ headroom,
+ privlen > 0 ? (mem + priv_offset) : NULL,
+ dtor);
+ return m;
+}
--
2.7.4
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |