mbox series

[v4,net-next,0/9] Handle multiple received packets at each stage

Message ID 5bf84d99-8f77-54ee-7543-ada13a730361@solarflare.com
Headers show
Series Handle multiple received packets at each stage | expand

Message

Edward Cree July 2, 2018, 3:11 p.m. UTC
This patch series adds the capability for the network stack to receive a
 list of packets and process them as a unit, rather than handling each
 packet singly in sequence.  This is done by factoring out the existing
 datapath code at each layer and wrapping it in list handling code.

The motivation for this change is twofold:
* Instruction cache locality.  Currently, running the entire network
  stack receive path on a packet involves more code than will fit in the
  lowest-level icache, meaning that when the next packet is handled, the
  code has to be reloaded from more distant caches.  By handling packets
  in "row-major order", we ensure that the code at each layer is hot for
  most of the list.  (There is a corresponding downside in _data_ cache
  locality, since we are now touching every packet at every layer, but in
  practice there is easily enough room in dcache to hold one cacheline of
  each of the 64 packets in a NAPI poll.)
* Reduction of indirect calls.  Owing to Spectre mitigations, indirect
  function calls are now more expensive than ever; they are also heavily
  used in the network stack's architecture (see [1]).  By replacing 64
  indirect calls to the next-layer per-packet function with a single
  indirect call to the next-layer list function, we can save CPU cycles.

Drivers pass an SKB list to the stack at the end of the NAPI poll; this
 gives a natural batch size (the NAPI poll weight) and avoids waiting at
 the software level for further packets to make a larger batch (which
 would add latency).  It also means that the batch size is automatically
 tuned by the existing interrupt moderation mechanism.
The stack then runs each layer of processing over all the packets in the
 list before proceeding to the next layer.  Where the 'next layer' (or
 the context in which it must run) differs among the packets, the stack
 splits the list; this 'late demux' means that packets which differ only
 in later headers (e.g. same L2/L3 but different L4) can traverse the
 early part of the stack together.
Also, where the next layer is not (yet) list-aware, the stack can revert
 to calling the rest of the stack in a loop; this allows gradual/creeping
 listification, with no 'flag day' patch needed to listify everything.

Patches 1-2 simply place received packets on a list during the event
 processing loop on the sfc EF10 architecture, then call the normal stack
 for each packet singly at the end of the NAPI poll.  (Analogues of patch
 #2 for other NIC drivers should be fairly straightforward.)
Patches 3-9 extend the list processing as far as the IP receive handler.

Patches 1-2 alone give about a 10% improvement in packet rate in the
 baseline test; adding patches 3-9 raises this to around 25%.

Performance measurements were made with NetPerf UDP_STREAM, using 1-byte
 packets and a single core to handle interrupts on the RX side; this was
 in order to measure as simply as possible the packet rate handled by a
 single core.  Figures are in Mbit/s; divide by 8 to obtain Mpps.  The
 setup was tuned for maximum reproducibility, rather than raw performance.
 Full details and more results (both with and without retpolines) from a
 previous version of the patch series are presented in [2].

The baseline test uses four streams, and multiple RXQs all bound to a
 single CPU (the netperf binary is bound to a neighbouring CPU).  These
 tests were run with retpolines.
net-next: 6.91 Mb/s (datum)
 after 9: 8.46 Mb/s (+22.5%)
Note however that these results are not robust; changes in the parameters
 of the test sometimes shrink the gain to single-digit percentages.  For
 instance, when using only a single RXQ, only a 4% gain was seen.

One test variation was the use of software filtering/firewall rules.
 Adding a single iptables rule (UDP port drop on a port range not matching
 the test traffic), thus making the netfilter hook have work to do,
 reduced baseline performance but showed a similar gain from the patches:
net-next: 5.02 Mb/s (datum)
 after 9: 6.78 Mb/s (+35.1%)

Similarly, testing with a set of TC flower filters (kindly supplied by
 Cong Wang) gave the following:
net-next: 6.83 Mb/s (datum)
 after 9: 8.86 Mb/s (+29.7%)

These data suggest that the batching approach remains effective in the
 presence of software switching rules, and perhaps even improves the
 performance of those rules by allowing them and their codepaths to stay
 in cache between packets.

Changes from v3:
* Fixed build error when CONFIG_NETFILTER=n (thanks kbuild).

Changes from v2:
* Used standard list handling (and skb->list) instead of the skb-queue
  functions (that use skb->next, skb->prev).
  - As part of this, changed from a "dequeue, process, enqueue" model to
    using list_for_each_safe, list_del, and (new) list_cut_before.
* Altered __netif_receive_skb_core() changes in patch 6 as per Willem de
  Bruijn's suggestions (separate **ppt_prev from *pt_prev; renaming).
* Removed patches to Generic XDP, since they were producing no benefit.
  I may revisit them later.
* Removed RFC tags.

Changes from v1:
* Rebased across 2 years' net-next movement (surprisingly straightforward).
  - Added Generic XDP handling to netif_receive_skb_list_internal()
  - Dealt with changes to PFMEMALLOC setting APIs
* General cleanup of code and comments.
* Skipped function calls for empty lists at various points in the stack
  (patch #9).
* Added listified Generic XDP handling (patches 10-12), though it doesn't
  seem to help (see above).
* Extended testing to cover software firewalls / netfilter etc.

[1] http://vger.kernel.org/netconf2018_files/DavidMiller_netconf2018.pdf
[2] http://vger.kernel.org/netconf2018_files/EdwardCree_netconf2018.pdf

Edward Cree (9):
  net: core: trivial netif_receive_skb_list() entry point
  sfc: batch up RX delivery
  net: core: unwrap skb list receive slightly further
  net: core: Another step of skb receive list processing
  net: core: another layer of lists, around PF_MEMALLOC skb handling
  net: core: propagate SKB lists through packet_type lookup
  net: ipv4: listified version of ip_rcv
  net: ipv4: listify ip_rcv_finish
  net: don't bother calling list RX functions on empty lists

 drivers/net/ethernet/sfc/efx.c        |  12 +++
 drivers/net/ethernet/sfc/net_driver.h |   3 +
 drivers/net/ethernet/sfc/rx.c         |   7 +-
 include/linux/list.h                  |  30 ++++++
 include/linux/netdevice.h             |   4 +
 include/linux/netfilter.h             |  22 +++++
 include/net/ip.h                      |   2 +
 include/trace/events/net.h            |   7 ++
 net/core/dev.c                        | 174 ++++++++++++++++++++++++++++++++--
 net/ipv4/af_inet.c                    |   1 +
 net/ipv4/ip_input.c                   | 114 ++++++++++++++++++++--
 11 files changed, 360 insertions(+), 16 deletions(-)

Comments

David Ahern July 2, 2018, 3:40 p.m. UTC | #1
On 7/2/18 9:11 AM, Edward Cree wrote:
> This patch series adds the capability for the network stack to receive a
>  list of packets and process them as a unit, rather than handling each
>  packet singly in sequence.  This is done by factoring out the existing
>  datapath code at each layer and wrapping it in list handling code.
> 

...

>  drivers/net/ethernet/sfc/efx.c        |  12 +++
>  drivers/net/ethernet/sfc/net_driver.h |   3 +
>  drivers/net/ethernet/sfc/rx.c         |   7 +-
>  include/linux/list.h                  |  30 ++++++
>  include/linux/netdevice.h             |   4 +
>  include/linux/netfilter.h             |  22 +++++
>  include/net/ip.h                      |   2 +
>  include/trace/events/net.h            |   7 ++
>  net/core/dev.c                        | 174 ++++++++++++++++++++++++++++++++--
>  net/ipv4/af_inet.c                    |   1 +
>  net/ipv4/ip_input.c                   | 114 ++++++++++++++++++++--
>  11 files changed, 360 insertions(+), 16 deletions(-)
> 

Nice work. Have you looked at IPv6 support yet?
Edward Cree July 2, 2018, 6:09 p.m. UTC | #2
On 02/07/18 16:40, David Ahern wrote:
> Nice work. Have you looked at IPv6 support yet? 
I hadn't looked at it yet, no.  After a quick glance at ip6_rcv() and
 ip6_rcv_finish(), it looks like it'd be basically the same as the IPv4
 code in patches 7 and 8.  I'll probably add it in a followup when (if)
 this series gets applied.

-Ed
Paolo Abeni July 3, 2018, 7:51 a.m. UTC | #3
On Mon, 2018-07-02 at 09:40 -0600, David Ahern wrote:
> On 7/2/18 9:11 AM, Edward Cree wrote:
> > This patch series adds the capability for the network stack to receive a
> >  list of packets and process them as a unit, rather than handling each
> >  packet singly in sequence.  This is done by factoring out the existing
> >  datapath code at each layer and wrapping it in list handling code.
> > 
> 
> ...
> 
> >  drivers/net/ethernet/sfc/efx.c        |  12 +++
> >  drivers/net/ethernet/sfc/net_driver.h |   3 +
> >  drivers/net/ethernet/sfc/rx.c         |   7 +-
> >  include/linux/list.h                  |  30 ++++++
> >  include/linux/netdevice.h             |   4 +
> >  include/linux/netfilter.h             |  22 +++++
> >  include/net/ip.h                      |   2 +
> >  include/trace/events/net.h            |   7 ++
> >  net/core/dev.c                        | 174 ++++++++++++++++++++++++++++++++--
> >  net/ipv4/af_inet.c                    |   1 +
> >  net/ipv4/ip_input.c                   | 114 ++++++++++++++++++++--
> >  11 files changed, 360 insertions(+), 16 deletions(-)
> > 
> 
> Nice work. Have you looked at IPv6 support yet?

I think this work opens opportunities for a lot of follow-ups, if there
is agreement on extending this approach to other areas. Onother item
I'd like to investigate is TC processing.

Cheers,

Paolo
David Miller July 4, 2018, 5:09 a.m. UTC | #4
From: Edward Cree <ecree@solarflare.com>
Date: Mon, 2 Jul 2018 16:11:36 +0100

> This patch series adds the capability for the network stack to receive a
>  list of packets and process them as a unit, rather than handling each
>  packet singly in sequence.  This is done by factoring out the existing
>  datapath code at each layer and wrapping it in list handling code.
 ...

This is really nice stuff.

I'll apply this, but please work on the ipv6 side too.

I hope that driver maintainers take a look at using the new
netif_receive_skb_list() interface and see how much it helps
performance with their devices.

Thanks!