From: Duncan Roe <duncan_roe@optusnet.com.au>
To: pablo@netfilter.org
Cc: netfilter-devel@vger.kernel.org
Subject: [PATCH libnetfilter_queue v2] src: Add faster alternatives to pktb_alloc()
Date: Sat, 1 Feb 2020 17:21:27 +1100 [thread overview]
Message-ID: <20200201062127.4729-1-duncan_roe@optusnet.com.au> (raw)
In-Reply-To: <20200108225323.io724vuxuzsydjzs@salvia>
Functions pktb_alloc_data, pktb_make and pktb_make_data are defined.
The pktb_make pair are syggested as replacements for the pktb_alloc (now) pair
because they are always faster.
- Add prototypes to include/libnetfilter_queue/pktbuff.h
- Add pktb_alloc_data much as per Pablo's email of Wed, 8 Jan 2020
speedup: point to packet data in netlink receive buffer rather than copy to
area immediately following pktb struct
- Add pktb_make much like pktb_usebuf proposed on 10 Dec 2019
2 sppedups: 1. Use an existing buffer rather than calloc and (later) free one.
2. Only zero struct and extra parts of pktb - the rest is
overwritten by copy (calloc has to zero the lot).
- Add pktb_make_data
3 speedups: All of the above
- Document the new functions
- Move pktb_alloc and pktb_alloc_data into the "other functions" group since
they are slower than the "make" equivalent functions
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
include/libnetfilter_queue/pktbuff.h | 3 +
| 296 ++++++++++++++++++++++++++++++-----
2 files changed, 261 insertions(+), 38 deletions(-)
diff --git a/include/libnetfilter_queue/pktbuff.h b/include/libnetfilter_queue/pktbuff.h
index 42bc153..fc6bf01 100644
--- a/include/libnetfilter_queue/pktbuff.h
+++ b/include/libnetfilter_queue/pktbuff.h
@@ -4,6 +4,9 @@
struct pkt_buff;
struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra);
+struct pkt_buff *pktb_alloc_data(int family, void *data, size_t len);
+struct pkt_buff *pktb_make(int family, void *data, size_t len, size_t extra, void *buf, size_t bufsize);
+struct pkt_buff *pktb_make_data(int family, void *data, size_t len, void *buf, size_t bufsize);
void pktb_free(struct pkt_buff *pktb);
uint8_t *pktb_data(struct pkt_buff *pktb);
--git a/src/extra/pktbuff.c b/src/extra/pktbuff.c
index 6dd0ca9..cfd9f15 100644
--- a/src/extra/pktbuff.c
+++ b/src/extra/pktbuff.c
@@ -29,6 +29,59 @@
* @{
*/
+static struct pkt_buff *__pktb_alloc(size_t len, size_t extra)
+{
+ struct pkt_buff *pktb;
+
+ pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
+
+ return pktb;
+}
+
+static int pktb_setup_family(struct pkt_buff *pktb, int family)
+{
+ struct ethhdr *ethhdr;
+
+ switch(family) {
+ case AF_INET:
+ case AF_INET6:
+ pktb->network_header = pktb->data;
+ break;
+ case AF_BRIDGE:
+ ethhdr = (struct ethhdr *)pktb->data;
+
+ pktb->mac_header = pktb->data;
+
+ switch(ethhdr->h_proto) {
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ pktb->network_header = pktb->data + ETH_HLEN;
+ break;
+ default:
+ /* This protocol is unsupported. */
+ errno = EPROTONOSUPPORT;
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void pktb_setup_metadata(struct pkt_buff *pktb, void *pkt_data,
+ size_t len, size_t extra)
+{
+ pktb->len = len;
+ pktb->data_len = len + extra;
+
+ pktb->data = pkt_data;
+}
+
+/**
+ * \addtogroup otherfns
+ * @{
+ */
+
/**
* pktb_alloc - allocate a new packet buffer
* \param family Indicate what family. Currently supported families are
@@ -52,10 +105,9 @@ EXPORT_SYMBOL
struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
{
struct pkt_buff *pktb;
- struct ethhdr *ethhdr;
void *pkt_data;
- pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
+ pktb = __pktb_alloc(len, extra);
if (pktb == NULL)
return NULL;
@@ -63,32 +115,198 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra)
pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff);
memcpy(pkt_data, data, len);
- pktb->len = len;
- pktb->data_len = len + extra;
+ pktb_setup_metadata(pktb, pkt_data, len, extra);
- pktb->data = pkt_data;
+ if (pktb_setup_family(pktb, family) < 0) {
+ free(pktb);
+ return NULL;
+ }
- switch(family) {
- case AF_INET:
- case AF_INET6:
- pktb->network_header = pktb->data;
- break;
- case AF_BRIDGE:
- ethhdr = (struct ethhdr *)pktb->data;
- pktb->mac_header = pktb->data;
+ return pktb;
+}
- switch(ethhdr->h_proto) {
- case ETH_P_IP:
- case ETH_P_IPV6:
- pktb->network_header = pktb->data + ETH_HLEN;
- break;
- default:
- /* This protocol is unsupported. */
- errno = EPROTONOSUPPORT;
- free(pktb);
- return NULL;
- }
- break;
+/**
+ * pktb_alloc_data - fast version of pktb_alloc with some restrictions
+ * \param family Indicate what family. Currently supported families are
+ * AF_BRIDGE, AF_INET & AF_INET6.
+ * \param data Pointer to packet data
+ * \param len Packet length
+ *
+ * This function returns a packet buffer that points to the packet data which
+ * remains in its original netlink receive buffer.
+ * This saves the time to copy the data but restricts mangling to leaving the
+ * packet the same size or making it shorter.
+ *
+ * \sa pktb_make_data(), expecially Notes and Warnings
+ */
+EXPORT_SYMBOL
+struct pkt_buff *pktb_alloc_data(int family, void *data, size_t len)
+{
+ struct pkt_buff *pktb;
+
+ pktb = __pktb_alloc(0, 0);
+ if (!pktb)
+ return NULL;
+
+ pktb->data = data;
+ pktb_setup_metadata(pktb, data, len, 0);
+
+ if (pktb_setup_family(pktb, family) < 0) {
+ free(pktb);
+ return NULL;
+ }
+
+ return pktb;
+}
+
+/**
+ * @}
+ */
+
+static struct pkt_buff *__pktb_make(size_t len, size_t extra, void *buf,
+ size_t bufsize)
+{
+ struct pkt_buff *pktb;
+
+ /* Better make sure alignment is correct. */
+ size_t extra2 =
+ (size_t)buf & 0x3 ? (~((size_t)buf & 0x3) & 0x3) + 1 : 0;
+
+ pktb = buf + extra2;
+ if (extra2 + sizeof(struct pkt_buff) + len + extra > bufsize)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ /* Zero the front bit. memcpy looks after next part */
+ memset(pktb, 0, sizeof(struct pkt_buff) + extra2);
+
+ return pktb;
+}
+
+/**
+ * pktb_make - make a packet buffer from an existing buffer
+ * \param family Indicate what family. Currently supported families are
+ * AF_BRIDGE, AF_INET & AF_INET6.
+ * \param data Pointer to packet data
+ * \param len Packet length
+ * \param extra Extra memory in the tail to be allocated (for mangling)
+ * \param buf Existing buffer to use
+ * \param bufsize Size of _buf_
+ *
+ * This function builds a userspace packet buffer inside a supplied buffer.
+ * The packet buffer contains the packet data and some extra memory room in the
+ * tail (if requested).
+ *
+ * This function uses less CPU cycles than pktb_alloc() + pktb_free().
+ * Users can expect a decrease in overall CPU time in the order of 5%.
+ *
+ * \return Pointer to a userspace packet buffer aligned within _buf_ or NULL on
+ * failure.
+ * \par Errors
+ * __ENOMEM__ _bufsize_ is too small to accomodate _len_
+ * \n
+ * __EPROTONOSUPPORT__ _family_ was __AF_BRIDGE__ and this is not an IP packet
+ * (v4 or v6)
+ * \note Be sure not to __malloc__ _buf_ inside your callback function,
+ * otherwise the performance improvement over pktb_alloc() will be lost.
+ * A static buffer works well in single-threaded programs, especially if
+ * debugging.
+ * Or, declare the buffer as a local (stack) variable in
+ * the callback function.
+ * (Each thread has its own stack of size __uname -s__ (typically 8MB, plenty
+ * of room)).
+ * \warning Do __not__ call pktb_free() on the returned pointer
+ */
+EXPORT_SYMBOL
+struct pkt_buff *pktb_make(int family, void *data, size_t len, size_t extra,
+ void *buf, size_t bufsize)
+{
+ struct pkt_buff *pktb;
+ void *pkt_data;
+
+ pktb = __pktb_make(len, extra, buf, bufsize);
+
+ if (pktb)
+ {
+ pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff);
+ memcpy(pkt_data, data, len);
+
+ pktb_setup_metadata(pktb, pkt_data, len, extra);
+ if (pktb_setup_family(pktb, family) < 0)
+ pktb = NULL;
+ if (pktb && extra)
+ memset(pktb_tail(pktb), 0, extra);
+ }
+ return pktb;
+}
+/**
+ * pktb_make_data - fast version of pktb_make with some restrictions
+ * \param family Indicate what family. Currently supported families are
+ * AF_BRIDGE, AF_INET & AF_INET6.
+ * \param data Pointer to packet data
+ * \param len Packet length
+ * \param buf Existing buffer to use
+ * \param bufsize Size of _buf_
+ *
+ * This function builds a userspace packet buffer where the packet data is left
+ * in the original receive buffer and pointed to.
+ * This saves the time to copy the data but restricts mangling to leaving the
+ * packet the same size or making it shorter.
+ *
+ * \par Relative performance timings
+ * The table below shows relative timings for pktb_alloc(), pktb_make(),
+ * pktb_alloc_data() and pktb_make_data().
+ * Timings for the functions with __alloc__ in their name include a call to
+ * __pktb_free__. Tests were done for 50-byte and 1500-byte packets.
+ * <TABLE>
+ * <TR>
+ * <TD><B>Bytes</B></TD>
+ * <TD><B>pktb_alloc</B></TD>
+ * <TD><B>pktb_make</B></TD>
+ * <TD><B>pktb_alloc_data</B></TD>
+ * <TD><B>pktb_make_data</B></TD>
+ * </TR>
+ * <TR>
+ * <TD>50</TD>
+ * <TD>100%</TD>
+ * <TD>51%</TD>
+ * <TD>56%</TD>
+ * <TD>29%</TD>
+ * </TR>
+ * <TR>
+ * <TD>1500</TD>
+ * <TD>100%</TD>
+ * <TD>60%</TD>
+ * <TD>23%</TD>
+ * <TD>12%</TD>
+ * </TR>
+ * </TABLE>
+ *
+ * \note If mangling, one must use different buffers for netlink receive and
+ * send from and to the kernel.
+ * Otherwise, there may be overlapping moves or worse.
+ * examples/nf-queue.c does this anyway.
+ * \note _bufsize_ only needs to be __sizeof(struct pkt_buff)__, since no data
+ * is copied.
+ * \warning The function prototype may change before the next library release,
+ * to accomodate other _data fast function variants
+ * \sa pktb_make(), expecially Notes and Warnings
+ */
+
+EXPORT_SYMBOL
+struct pkt_buff *pktb_make_data(int family, void *data, size_t len, void *buf,
+ size_t bufsize)
+{
+ struct pkt_buff *pktb;
+
+ pktb = __pktb_make(0, 0, buf, bufsize);
+
+ if (pktb)
+ {
+ pktb_setup_metadata(pktb, data, len, 0);
+ if (pktb_setup_family(pktb, family) < 0)
+ pktb = NULL;
}
return pktb;
}
@@ -121,30 +339,32 @@ uint32_t pktb_len(struct pkt_buff *pktb)
return pktb->len;
}
-/**
- * pktb_free - release packet buffer
- * \param pktb Pointer to userspace packet buffer
- */
-EXPORT_SYMBOL
-void pktb_free(struct pkt_buff *pktb)
-{
- free(pktb);
-}
-
/**
* \defgroup otherfns Other functions
*
* The library provides a number of other functions which many user-space
- * programs will never need. These divide into 2 groups:
+ * programs will never need. These divide into 3 groups:
* \n
* 1. Functions to get values of members of opaque __struct pktbuff__, described
* below
* \n
- * 2. Internal functions, described in Module __Internal functions__
+ * 2. Slower functions that __malloc__ and __free__ the memory to make a buffer
+ * \n
+ * 3. Internal functions, described in Module __Internal functions__
*
* @{
*/
+/**
+ * pktb_free - release packet buffer
+ * \param pktb Pointer to userspace packet buffer
+ */
+EXPORT_SYMBOL
+void pktb_free(struct pkt_buff *pktb)
+{
+ free(pktb);
+}
+
/**
* \defgroup uselessfns Internal functions
*
@@ -195,7 +415,7 @@ void pktb_put(struct pkt_buff *pktb, unsigned int len)
/**
* pktb_trim - set new length for this packet buffer
* \param pktb Pointer to userspace packet buffer
- * \param len New packet length (tail is adjusted to reflect this)
+ * \param len New packet length
*/
EXPORT_SYMBOL
void pktb_trim(struct pkt_buff *pktb, unsigned int len)
--
2.14.5
next prev parent reply other threads:[~2020-02-01 6:21 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-10 11:26 [PATCH libnetfilter_queue 0/1] New pktb_usebuf() function Duncan Roe
2019-12-10 11:26 ` [PATCH libnetfilter_queue 1/1] src: Add alternative function to pktb_alloc to avoid malloc / free overhead Duncan Roe
2019-12-22 2:09 ` [PATCH libnetfilter_queue 0/1] New pktb_usebuf() function Duncan Roe
2020-01-03 2:47 ` Duncan Roe
2020-01-06 3:17 ` [PATCH libnetfilter_queue v2 0/1] New pktb_make() function Duncan Roe
2020-01-08 22:53 ` Pablo Neira Ayuso
2020-01-10 2:27 ` Duncan Roe
2020-01-13 18:51 ` Pablo Neira Ayuso
2020-01-27 2:11 ` Duncan Roe
2020-01-27 1:44 ` Duncan Roe
2020-02-01 6:21 ` Duncan Roe [this message]
2020-02-07 22:39 ` [PATCH libnetfilter_queue v2] src: Add faster alternatives to pktb_alloc() Duncan Roe
2020-02-19 18:04 ` Pablo Neira Ayuso
2020-02-20 23:22 ` Duncan Roe
2020-02-20 23:50 ` Duncan Roe
2020-04-06 6:17 ` Duncan Roe
2020-04-11 7:24 ` [PATCH libnetfilter_queue 0/1] src & doc: pktb_alloc2 Duncan Roe
2020-04-11 7:24 ` [PATCH libnetfilter_queue 1/1] New faster pktb_alloc2 replaces pktb_alloc & pktb_free Duncan Roe
2020-01-06 3:17 ` [PATCH libnetfilter_queue v2 1/1] src: Add alternative function to pktb_alloc to avoid malloc / free overhead Duncan Roe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200201062127.4729-1-duncan_roe@optusnet.com.au \
--to=duncan_roe@optusnet.com.au \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).