New function pktb_usebuf() works like pktb_alloc() except it has 2 extra arguments, being a user-supplied buffer and its length. Performance testing is ongoing, so the 5% improvement claimed in the documentation is conservative. Updated: include/libnetfilter_queue/pktbuff.h: Add pktb_usebuf() prototype src/extra/pktbuff.c: Implement pktb_usebuf() Signed-off-by: Duncan Roe <duncan_roe@xxxxxxxxxxxxxxx> --- include/libnetfilter_queue/pktbuff.h | 2 + src/extra/pktbuff.c | 82 ++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/include/libnetfilter_queue/pktbuff.h b/include/libnetfilter_queue/pktbuff.h index b15ee1e..ec75727 100644 --- a/include/libnetfilter_queue/pktbuff.h +++ b/include/libnetfilter_queue/pktbuff.h @@ -4,6 +4,8 @@ struct pkt_buff; struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra); +struct pkt_buff *pktb_usebuf(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 c4f3da3..774e4ab 100644 --- a/src/extra/pktbuff.c +++ b/src/extra/pktbuff.c @@ -96,6 +96,88 @@ struct pkt_buff *pktb_alloc(int family, void *data, size_t len, size_t extra) return pktb; } +/** + * pktb_usebuf - 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_usebuf(int family, void *data, size_t len, size_t extra, + void *buf, size_t bufsize) +{ + struct pkt_buff *pktb; + void *pkt_data; + + /* 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); + + pkt_data = (uint8_t *)pktb + sizeof(struct pkt_buff); + memcpy(pkt_data, data, len); + + pktb->len = len; + pktb->data_len = len + extra; + + pktb->head = pkt_data; + pktb->data = pkt_data; + pktb->tail = pktb->head + len; + + switch(family) { + case AF_INET: + case AF_INET6: + pktb->network_header = pktb->data; + break; + case AF_BRIDGE: { + struct ethhdr *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; + free(pktb); + return NULL; + } + break; + } + } + return pktb; +} + /** * pktb_data - get pointer to network packet * \param pktb Pointer to userspace packet buffer -- 2.14.5