New function pktb_make() works like pktb_alloc() except it has 2 extra arguments, being a user-supplied buffer and its length. Performance testing using a program derived from examples/nf_queue.c shows 6% improvement, so the 5% improvement claimed in the documentation is conservative. Updated: include/libnetfilter_queue/pktbuff.h: Add pktb_make() prototype src/extra/pktbuff.c: Implement pktb_make() Signed-off-by: Duncan Roe <duncan_roe@xxxxxxxxxxxxxxx> --- include/libnetfilter_queue/pktbuff.h | 1 + src/extra/pktbuff.c | 60 ++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/include/libnetfilter_queue/pktbuff.h b/include/libnetfilter_queue/pktbuff.h index 42bc153..481ed59 100644 --- a/include/libnetfilter_queue/pktbuff.h +++ b/include/libnetfilter_queue/pktbuff.h @@ -4,6 +4,7 @@ struct pkt_buff; struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra); +struct pkt_buff *pktb_make(int family, void *data, size_t len, size_t extra, void *buf, size_t bufsize); void pktb_free(struct pkt_buff *pktb); uint8_t *pktb_data(struct pkt_buff *pktb); diff --git a/src/extra/pktbuff.c b/src/extra/pktbuff.c index 37f6bc0..d85121c 100644 --- a/src/extra/pktbuff.c +++ b/src/extra/pktbuff.c @@ -29,6 +29,8 @@ * @{ */ +static struct pkt_buff *pktb_alloc_make_common(int family, void *data, + size_t len, size_t extra, struct pkt_buff *pktb, bool malloc_used); /** * pktb_alloc - allocate a new packet buffer * \param family Indicate what family. Currently supported families are @@ -52,11 +54,17 @@ EXPORT_SYMBOL struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra) { struct pkt_buff *pktb; - void *pkt_data; pktb = calloc(1, sizeof(struct pkt_buff) + len + extra); if (pktb == NULL) return NULL; + return pktb_alloc_make_common(family, data, len, extra, pktb, true); +} + +static struct pkt_buff *pktb_alloc_make_common(int family, void *data, + size_t len, size_t extra, struct pkt_buff *pktb, bool malloc_used) +{ + void *pkt_data; /* Better make sure alignment is correct. */ pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff); @@ -87,7 +95,8 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra) default: /* This protocol is unsupported. */ errno = EPROTONOSUPPORT; - free(pktb); + if (malloc_used) + free(pktb); return NULL; } break; @@ -96,6 +105,53 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra) 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) + * \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; + + /* Better make sure alignment is correct. */ + size_t extra2 = + (size_t)buf & 0x7 ? (~((size_t)buf & 0x7) & 0x7) + 1 : 0; + + pktb = buf + extra2; + if (extra2 + sizeof(struct pkt_buff) + len + extra > bufsize) + { + errno = ENOMEM; + return NULL; + } + memset(pktb, 0, sizeof(struct pkt_buff) + len + extra); + + return pktb_alloc_make_common(family, data, len, extra, pktb, false); +} + /** * pktb_data - get pointer to network packet * \param pktb Pointer to userspace packet buffer -- 2.14.5