[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[UNIKRAFT PATCH 2/4] lib/uknetdev: netbuf: Metadata at the end of an allocation



Place the netbuf metadata (`struct netbuf`) at the end of an allocation.
This enables forwarding possible alignments of an underlying allocation
to the buffer area of a netbuf. The metadata will no longer cause an offset
of the buffer start address (`m->buf`).

Signed-off-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
---
 lib/uknetdev/include/uk/netbuf.h | 29 +++++-----
 lib/uknetdev/netbuf.c            | 97 ++++++++++++--------------------
 2 files changed, 50 insertions(+), 76 deletions(-)

diff --git a/lib/uknetdev/include/uk/netbuf.h b/lib/uknetdev/include/uk/netbuf.h
index f21d082b..ea803ae8 100644
--- a/lib/uknetdev/include/uk/netbuf.h
+++ b/lib/uknetdev/include/uk/netbuf.h
@@ -57,18 +57,6 @@ typedef void (*uk_netbuf_dtor_t)(struct uk_netbuf *);
  * 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       |  |
@@ -82,6 +70,17 @@ typedef void (*uk_netbuf_dtor_t)(struct uk_netbuf *);
  *                  |      TAIL ROOM       |  |
  * *buf + buflen -> +----------------------+ /
  *
+ * NETBUF
+ *                  +----------------------+
+ *                  |   struct uk_netbuf   |
+ *                  |                      |
+ *                  +----------------------+
+ *
+ * PRIVATE META DATA
+ *         *priv -> +----------------------+
+ *                  |      private meta    |
+ *                  |       data area      |
+ *                  +----------------------+
  *
  * 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
@@ -237,7 +236,8 @@ struct uk_netbuf *uk_netbuf_alloc_indir(struct uk_alloc *a,
 
 /**
  * Allocate and initialize netbuf with data buffer area.
- * m->len is initialized with 0.
+ * m->len is initialized with 0. Metadata (struct uknetbuf, priv)
+ * is placed at the end of the according allocation.
  * @param a
  *   Allocator to be used for allocating `struct uk_netbuf` and the
  *   corresponding buffer area (single allocation).
@@ -268,7 +268,8 @@ struct uk_netbuf *uk_netbuf_alloc_buf(struct uk_alloc *a, 
size_t buflen,
 
 /**
  * Initialize netbuf with data buffer on a user given allocated memory area
- * m->len is initialized with 0.
+ * m->len is initialized with 0. Metadata (struct uknetbuf, priv)
+ * is placed at the end of the given allocation.
  * @param mem
  *   Reference to user provided memory region
  * @param buflen
diff --git a/lib/uknetdev/netbuf.c b/lib/uknetdev/netbuf.c
index 5156e808..c5cf662e 100644
--- a/lib/uknetdev/netbuf.c
+++ b/lib/uknetdev/netbuf.c
@@ -37,7 +37,10 @@
 
 /* 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)
+#define NETBUF_ADDR_ALIGN_UP(x)   ALIGN_UP((__uptr) (x), \
+                                          NETBUF_ADDR_ALIGNMENT)
+#define NETBUF_ADDR_ALIGN_DOWN(x) ALIGN_DOWN((__uptr) (x), \
+                                            NETBUF_ADDR_ALIGNMENT)
 
 void uk_netbuf_init_indir(struct uk_netbuf *m,
                          void *buf, size_t buflen, uint16_t headroom,
@@ -99,52 +102,34 @@ 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)
 {
+       void *mem;
+       size_t alloc_len;
        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)
+       alloc_len = NETBUF_ADDR_ALIGN_UP(buflen)
+                   + NETBUF_ADDR_ALIGN_UP(sizeof(*m) + privlen);
+       mem = uk_malloc(a, alloc_len);
+       if (!mem)
                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((size_t)(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;
-               }
+       m = uk_netbuf_prepare_buf(mem,
+                                 alloc_len,
+                                 headroom,
+                                 privlen,
+                                 dtor);
+       if (!m) {
+               uk_free(a, mem);
+               return NULL;
        }
 
-       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 and allocation
         * that is used for free'ing this uk_netbuf.
         */
        m->_a = a;
-       m->_b = m;
+       m->_b = mem;
 
        return m;
 }
@@ -154,41 +139,29 @@ struct uk_netbuf *uk_netbuf_prepare_buf(void *mem, size_t 
size,
                                        size_t privlen, uk_netbuf_dtor_t dtor)
 {
        struct uk_netbuf *m;
-       size_t buf_offset = 0;
-       size_t priv_offset = 0;
+       size_t meta_len = 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.
+       /* Place headroom and buf at the beginning of the allocation,
+        * This is done in order to forward potential alignments of the
+        * underlying allocation directly to the netbuf data area.
+        * `m` (followed by `m->priv` if privlen > 0) will be placed at
+        * the end of the given memory.
         */
-       if (likely((size_t)(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;
-               }
-       }
+       meta_len = NETBUF_ADDR_ALIGN_UP(sizeof(*m) + privlen);
+       if (meta_len > NETBUF_ADDR_ALIGN_DOWN((__uptr) mem + size))
+               return NULL;
+
+       m = (struct uk_netbuf *) (NETBUF_ADDR_ALIGN_DOWN((__uptr) mem + size)
+                                 - meta_len);
 
-       m = (struct uk_netbuf *) mem;
        uk_netbuf_init_indir(m,
-                            mem + buf_offset,
-                            size - buf_offset,
+                            mem,
+                            (size_t) ((__uptr) m - (__uptr) mem),
                             headroom,
-                            privlen > 0 ? (mem + priv_offset) : NULL,
+                            privlen > 0 ? (void *) ((__uptr) m+ sizeof(*m))
+                                        : NULL,
                             dtor);
        return m;
 }
-- 
2.20.1



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.