DPDK based dp-packets points to data buffers that can't be expanded
dynamically.
Their layout is as follows:
- a 128 bytes headroom chosen at DPDK build time (RTE_PKTMBUF_HEADROOM),
- a maximum size chosen at mempool creation,

In some usecases though (like encapsulating with multiple tunnels),
a 128 bytes headroom is too short.

Dynamically allocate buffers in DPDK memory and make use of DPDK
external buffers API (previously used for userspace TSO).

Signed-off-by: David Marchand <david.march...@redhat.com>
---
 lib/dp-packet.c   | 17 ++++++++++++++++-
 lib/netdev-dpdk.c | 47 +++++++++++++++++++++++++++++++++++------------
 lib/netdev-dpdk.h |  3 +++
 3 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/lib/dp-packet.c b/lib/dp-packet.c
index 35c72542a2..07fa67b1a1 100644
--- a/lib/dp-packet.c
+++ b/lib/dp-packet.c
@@ -250,8 +250,23 @@ dp_packet_resize(struct dp_packet *b, size_t new_headroom, 
size_t new_tailroom)
     new_allocated = new_headroom + dp_packet_size(b) + new_tailroom;
 
     switch (b->source) {
-    case DPBUF_DPDK:
+    case DPBUF_DPDK: {
+#ifdef DPDK_NETDEV
+        uint32_t buf_len;
+
+        buf_len = new_allocated;
+        new_base = netdev_dpdk_extbuf_allocate(&buf_len);
+        if (!new_base) {
+            out_of_memory();
+        }
+        ovs_assert(buf_len <= UINT16_MAX);
+        dp_packet_copy__(b, new_base, new_headroom, new_tailroom);
+        netdev_dpdk_extbuf_replace(b, new_base, buf_len);
+        break;
+#else
         OVS_NOT_REACHED();
+#endif
+    }
 
     case DPBUF_MALLOC:
         if (new_headroom == dp_packet_headroom(b)) {
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index fbc3b42d84..47e16f22c5 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -2646,41 +2646,64 @@ out:
     }
 }
 
+void *
+netdev_dpdk_extbuf_allocate(uint32_t *data_len)
+{
+    *data_len += sizeof(struct rte_mbuf_ext_shared_info) + sizeof(uintptr_t);
+    *data_len = RTE_ALIGN_CEIL(*data_len, sizeof(uintptr_t));
+    return rte_malloc(NULL, *data_len, RTE_CACHE_LINE_SIZE);
+}
+
 static void
 netdev_dpdk_extbuf_free(void *addr OVS_UNUSED, void *opaque)
 {
     rte_free(opaque);
 }
 
+void
+netdev_dpdk_extbuf_replace(struct dp_packet *b, void *buf, uint32_t data_len)
+{
+    struct rte_mbuf *pkt = (struct rte_mbuf *) b;
+    struct rte_mbuf_ext_shared_info *shinfo;
+    uint16_t buf_len = data_len;
+
+    shinfo = rte_pktmbuf_ext_shinfo_init_helper(buf, &buf_len,
+                                                netdev_dpdk_extbuf_free,
+                                                buf);
+    ovs_assert(shinfo != NULL);
+
+    if (RTE_MBUF_HAS_EXTBUF(pkt)) {
+        rte_pktmbuf_detach_extbuf(pkt);
+    }
+    rte_pktmbuf_attach_extbuf(pkt, buf, rte_malloc_virt2iova(buf), buf_len,
+                              shinfo);
+}
+
 static struct rte_mbuf *
 dpdk_pktmbuf_attach_extbuf(struct rte_mbuf *pkt, uint32_t data_len)
 {
     uint32_t total_len = RTE_PKTMBUF_HEADROOM + data_len;
-    struct rte_mbuf_ext_shared_info *shinfo = NULL;
+    struct rte_mbuf_ext_shared_info *shinfo;
     uint16_t buf_len;
     void *buf;
 
-    total_len += sizeof *shinfo + sizeof(uintptr_t);
-    total_len = RTE_ALIGN_CEIL(total_len, sizeof(uintptr_t));
-
+    buf = netdev_dpdk_extbuf_allocate(&total_len);
+    if (OVS_UNLIKELY(buf == NULL)) {
+        VLOG_ERR("Failed to allocate memory using rte_malloc: %u", total_len);
+        return NULL;
+    }
     if (OVS_UNLIKELY(total_len > UINT16_MAX)) {
+        netdev_dpdk_extbuf_free(NULL, buf);
         VLOG_ERR("Can't copy packet: too big %u", total_len);
         return NULL;
     }
 
     buf_len = total_len;
-    buf = rte_malloc(NULL, buf_len, RTE_CACHE_LINE_SIZE);
-    if (OVS_UNLIKELY(buf == NULL)) {
-        VLOG_ERR("Failed to allocate memory using rte_malloc: %u", buf_len);
-        return NULL;
-    }
-
-    /* Initialize shinfo. */
     shinfo = rte_pktmbuf_ext_shinfo_init_helper(buf, &buf_len,
                                                 netdev_dpdk_extbuf_free,
                                                 buf);
     if (OVS_UNLIKELY(shinfo == NULL)) {
-        rte_free(buf);
+        netdev_dpdk_extbuf_free(NULL, buf);
         VLOG_ERR("Failed to initialize shared info for mbuf while "
                  "attempting to attach an external buffer.");
         return NULL;
diff --git a/lib/netdev-dpdk.h b/lib/netdev-dpdk.h
index 699be3fb41..95594f07fb 100644
--- a/lib/netdev-dpdk.h
+++ b/lib/netdev-dpdk.h
@@ -31,6 +31,9 @@ struct netdev;
 void netdev_dpdk_register(void);
 void free_dpdk_buf(struct dp_packet *);
 
+void *netdev_dpdk_extbuf_allocate(uint32_t *);
+void netdev_dpdk_extbuf_replace(struct dp_packet *, void *, uint32_t);
+
 bool netdev_dpdk_flow_api_supported(struct netdev *);
 
 int
-- 
2.23.0

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to