[ovs-dev] [RFC 4/4] netlink: COW mmap Netlink messages to avoid memcpy()

Thomas Graf tgraf at suug.ch
Thu May 22 23:16:01 UTC 2014


If the message was received via a shared memory ring the frame
is usable as ofpbuf base directly without copying the buffer
unnecessarily. A new destructor() callback is introduced which
allows marking the frame unused after the ofpbuf has been
uninitialized.

Signed-off-by: Thomas Graf <tgraf at suug.ch>
---
 lib/netlink-socket.c | 26 +++++++++++++++++++++++++-
 lib/ofpbuf.c         |  6 ++++++
 lib/ofpbuf.h         |  2 ++
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c
index a264a0a..fd2810d 100644
--- a/lib/netlink-socket.c
+++ b/lib/netlink-socket.c
@@ -539,6 +539,14 @@ nl_sock_recv_linear(struct nl_sock *sock, struct ofpbuf *buf, bool wait,
     return 0;
 }
 
+static void
+nl_mmap_ofpbuf_destructor(struct ofpbuf *b)
+{
+    struct nl_mmap_hdr *hdr = b->destructor_data;
+
+    hdr->nm_status = NL_MMAP_STATUS_UNUSED;
+}
+
 static int
 nl_sock_recv_mmap(struct nl_sock *sock, struct ofpbuf *buf, bool wait,
                   uint8_t *tail, size_t taillen)
@@ -558,8 +566,22 @@ restart:
             goto restart;
         }
 
-        ofpbuf_put(buf, (char *) hdr + NL_MMAP_HDRLEN, hdr->nm_len);
         COVERAGE_INC(netlink_recv_mmap);
+
+        /* Recycle empty buffers and do copy-on-write by referring to
+         * the memory ring. The frame of the ring is marked unused as
+         * the ofpbuf is uninitialized.
+         */
+        if (ofpbuf_size(buf) == 0) {
+            ofpbuf_uninit(buf);
+            ofpbuf_use_stub(buf, (char *) hdr + NL_MMAP_HDRLEN, hdr->nm_len);
+            ofpbuf_set_size(buf, hdr->nm_len);
+            buf->destructor = nl_mmap_ofpbuf_destructor;
+            buf->destructor_data = hdr;
+            goto dont_release;
+        } else {
+            ofpbuf_put(buf, (char *) hdr + NL_MMAP_HDRLEN, hdr->nm_len);
+        }
         break;
 
     case NL_MMAP_STATUS_COPY:
@@ -582,6 +604,8 @@ restart:
     }
 
     hdr->nm_status = NL_MMAP_STATUS_UNUSED;
+
+dont_release:
     mmap_advance_rx_ring(sock);
 
     return retval;
diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c
index 1f4b61d..88ef6a6 100644
--- a/lib/ofpbuf.c
+++ b/lib/ofpbuf.c
@@ -29,6 +29,8 @@ ofpbuf_init__(struct ofpbuf *b, size_t allocated, enum ofpbuf_source source)
     b->source = source;
     b->frame = NULL;
     b->l2_5_ofs = b->l3_ofs = b->l4_ofs = UINT16_MAX;
+    b->destructor = NULL;
+    b->destructor_data = NULL;
     list_poison(&b->list_node);
 }
 
@@ -132,6 +134,10 @@ void
 ofpbuf_uninit(struct ofpbuf *b)
 {
     if (b) {
+        if (b->destructor) {
+            b->destructor(b);
+            b->destructor = NULL;
+        }
         if (b->source == OFPBUF_MALLOC) {
             free(ofpbuf_base(b));
         }
diff --git a/lib/ofpbuf.h b/lib/ofpbuf.h
index 85be899..8757518 100644
--- a/lib/ofpbuf.h
+++ b/lib/ofpbuf.h
@@ -75,6 +75,8 @@ struct ofpbuf {
                                    or UINT16_MAX. */
     enum ofpbuf_source source;  /* Source of memory allocated as 'base'. */
     struct list list_node;      /* Private list element for use by owner. */
+    void (*destructor)(struct ofpbuf *); /* User specified destructor */
+    void *destructor_data;      /* Data pointer owned by destructor */
 };
 
 static inline void * ofpbuf_data(const struct ofpbuf *);
-- 
1.8.3.1




More information about the dev mailing list