From: Duncan Roe <duncan_roe@optusnet.com.au>
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: Netfilter Development <netfilter-devel@vger.kernel.org>
Subject: Re: [PATCH libnetfilter_queue v2 0/1] New pktb_make() function
Date: Mon, 27 Jan 2020 12:44:31 +1100 [thread overview]
Message-ID: <20200127014431.GA15669@dimstar.local.net> (raw)
In-Reply-To: <20200108225323.io724vuxuzsydjzs@salvia>
Hi Pablo,
On Wed, Jan 08, 2020 at 11:53:23PM +0100, Pablo Neira Ayuso wrote:
> On Mon, Jan 06, 2020 at 02:17:13PM +1100, Duncan Roe wrote:
> > This patch offers a faster alternative / replacement function to pktb_alloc().
> >
> > pktb_make() is a copy of the first part of pktb_alloc() modified to use a
> > supplied buffer rather than calloc() one. It then calls the second part of
> > pktb_alloc() which is modified to be a static function.
> >
> > Can't think of a use case where one would choose to use pktb_alloc over
> > pktb_make.
> > In a furure documentation update, might relegate pktb_alloc and pktb_free to
> > "other functions".
>
> This is very useful.
>
> Would you explore something looking similar to what I'm attaching?
>
> Warning: Compile tested only :-)
>
> Thanks.
> diff --git a/src/extra/pktbuff.c b/src/extra/pktbuff.c
> index 6250fbf3ac8b..985bb48ac986 100644
> --- a/src/extra/pktbuff.c
> +++ b/src/extra/pktbuff.c
> @@ -29,6 +29,58 @@
> * @{
> */
>
> +static struct pkt_buff *__pktb_alloc(int family, void *data, size_t len,
> + size_t extra)
> +{
> + struct pkt_buff *pktb;
> +
> + pktb = calloc(1, sizeof(struct pkt_buff) + len + extra);
> + if (pktb == NULL)
> + return NULL;
> +
> + return pktb;
> +}
> +
> +static int pktb_setup_family(struct pkt_buff *pktb, int family)
> +{
> + 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;
> + 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->head = pkt_data;
> + pktb->data = pkt_data;
> + pktb->tail = pktb->head + len;
> +}
> +
> /**
> * pktb_alloc - allocate a new packet buffer
> * \param family Indicate what family. Currently supported families are
> @@ -54,45 +106,41 @@ 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)
> + pktb = __pktb_alloc(family, data, len, extra);
> + if (!pktb)
> return NULL;
>
> /* Better make sure alignment is correct. */
> 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->head = pkt_data;
> - pktb->data = pkt_data;
> - pktb->tail = pktb->head + len;
> + 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: {
> - struct ethhdr *ethhdr = (struct ethhdr *)pktb->data;
> + return pktb;
> +}
>
> - pktb->mac_header = pktb->data;
> +EXPORT_SYMBOL
> +struct pkt_buff *pktb_alloc_data(int family, void *data, size_t len)
> +{
> + struct pkt_buff *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 = __pktb_alloc(family, data, 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;
> }
>
The results are in. The spreadsheet is available at
https://github.com/duncan-roe/nfq/blob/master/nfq6/nfq6_timings.ods, but I'll
summarise them here.
Four functions are compared: pktb_alloc(), pktb_alloc_data(), pktb_make() and
pktb_make_data(). The timings for pktb_alloc & pktb_alloc_data include a call to
pktb_free(). When using pktb_make, one must not call pktb_free.
The test is to time calling the function (pair) 100000000 (1e8) times. In all
cases, this takes < 60 seconds. Two series of tests: one with 50-byte packets
(udp/IPv6, 2 data chars) and the other with 1500-byte (max MTU) packets.
Part-way through testing, pktb_make was improved to not zeroise the area into
which packet data will be copied. This is actually a tiny performance hit at
50-byte, could determine a crossover point at which to zeroise in 1 go but
didn't consider the extra complexity to be warrantied.
Here's a table of percentages:
bytes|pktb_alloc|pktb_alloc_data|pktb_make|pktb_make_data
-----|----------|---------------|---------|--------------
50| 100| 56.2| 50.8| 28.9
-----|----------|---------------|---------|--------------
1500| 100| 22.9| 59.6| 11.5
I have yet to do the doxygen documentation for the _data variants, then can send
in the code.
Cheers ... Duncan.
next prev parent reply other threads:[~2020-01-27 1:44 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 [this message]
2020-02-01 6:21 ` [PATCH libnetfilter_queue v2] src: Add faster alternatives to pktb_alloc() Duncan Roe
2020-02-07 22:39 ` 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=20200127014431.GA15669@dimstar.local.net \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.