From 1b1258243b7cd1bfc042a914775452354efb2857 Mon Sep 17 00:00:00 2001
From: Joel Cunningham <joel.cunningham@me.com>
Date: Thu, 21 Jan 2016 14:38:24 -0600
Subject: [PATCH] Optimzie sendmsg UDP pbuf chain creation

This commit optimizes the sendmsg UDP pbuf chain creation by not
allocating/freeing a netbuf per io vector

This adds a new API (netbuf_ref_vectors()) which takes an array of
struct iovecs and creates a chain of PBUF_REFs in the provided netbuf.
The logic is a combination of netbuf_ref() and netbuf_chain()
---
 src/api/netbuf.c          | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 src/api/sockets.c         | 21 ++------------------
 src/include/lwip/netbuf.h |  2 ++
 3 files changed, 53 insertions(+), 19 deletions(-)

diff --git a/src/api/netbuf.c b/src/api/netbuf.c
index 9ab76a4..d59b4db 100644
--- a/src/api/netbuf.c
+++ b/src/api/netbuf.c
@@ -165,6 +165,55 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
 }
 
 /**
+ * Let a netbuf reference a vector of existing (non-volatile) data by
+ * creating a chain of pbufs
+ *
+ * @param buf netbuf which should reference the data
+ * @param vectors an array of vectors
+ * @param count how many vectors in the array
+ * @return ERR_OK if data is referenced
+ *         ERR_MEM if data couldn't be referenced due to lack of memory
+ */
+err_t
+netbuf_ref_vectors(struct netbuf *buf, struct iovec *vectors, int count)
+{
+  int i;
+  struct pbuf *p;
+
+  LWIP_ERROR("netbuf_ref_vector: invalid buf", (buf != NULL), return ERR_ARG;);
+  LWIP_ERROR("netbuf_ref_vector: invalid vector", (vectors != NULL && count > 0), return ERR_ARG;);
+  if (buf->p != NULL) {
+    pbuf_free(buf->p);
+    buf->p = buf->ptr = NULL;
+  }
+  /* loop through vectors, creating a chain of pbufs */
+  for (i = 0; i < count; i++) {
+    p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
+    if (p == NULL) {
+      break;
+    }
+    ((struct pbuf_rom*)p)->payload = vectors[i].iov_base;
+    LWIP_ASSERT("iov_len < u16_t", vectors[i].iov_len <= 0xFFFF);
+    p->len = p->tot_len = (u16_t)vectors[i].iov_len;
+    /* netbuf empty, add new pbuf */
+    if (buf->p == NULL) {
+      buf->p = buf->ptr = p;
+    /* add pbuf to existing pbuf chain */
+    } else {
+      pbuf_cat(buf->p, p);
+      buf->ptr = buf->p;
+    }
+  }
+  /* we hit an error during chain building, clean up */
+  if ((i != count) && (buf->p != NULL)) {
+    pbuf_free(buf->p);
+    buf->p = buf->ptr = NULL;
+    return ERR_MEM;
+  }
+  return ERR_OK;
+}
+
+/**
  * Chain one netbuf to another (@see pbuf_chain)
  *
  * @param head the first netbuf
diff --git a/src/api/sockets.c b/src/api/sockets.c
index 2304c93..db73b37 100644
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -1072,26 +1072,9 @@ lwip_sendmsg(int s, const struct msghdr *msg, int flags)
   }
 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
   /* create a chained netbuf from the IO vectors */
-  err = netbuf_ref(chain_buf, msg->msg_iov[0].iov_base, (u16_t)msg->msg_iov[0].iov_len);
+  err = netbuf_ref_vectors(chain_buf, msg->msg_iov, msg->msg_iovlen);
   if (err == ERR_OK) {
-    struct netbuf *tail_buf;
-    size = msg->msg_iov[0].iov_len;
-    for (i = 1; i < msg->msg_iovlen; i++) {
-      tail_buf = netbuf_new();
-      if (!tail_buf) {
-        err = ERR_MEM;
-        break;
-      } else {
-        err = netbuf_ref(tail_buf, msg->msg_iov[i].iov_base, (u16_t)msg->msg_iov[i].iov_len);
-        if (err == ERR_OK) {
-          netbuf_chain(chain_buf, tail_buf);
-          size += msg->msg_iov[i].iov_len;
-        } else {
-          netbuf_delete(tail_buf);
-          break;
-        }
-      }
-    }
+    size = netbuf_len(chain_buf);
   }
 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
 
diff --git a/src/include/lwip/netbuf.h b/src/include/lwip/netbuf.h
index 8875e12..42e885f 100644
--- a/src/include/lwip/netbuf.h
+++ b/src/include/lwip/netbuf.h
@@ -73,6 +73,8 @@ void *            netbuf_alloc    (struct netbuf *buf, u16_t size);
 void              netbuf_free     (struct netbuf *buf);
 err_t             netbuf_ref      (struct netbuf *buf,
                                    const void *dataptr, u16_t size);
+err_t             netbuf_ref_vectors(struct netbuf *buf,
+                                   struct iovec *vectors, int count);
 void              netbuf_chain    (struct netbuf *head, struct netbuf *tail);
 
 err_t             netbuf_data     (struct netbuf *buf,
-- 
1.9.5.msysgit.0

