[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