From: Dave Seddon <dave.seddon.ca@gmail.com>
To: netdev@vger.kernel.org
Cc: "David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Stanislav Fomichev <sdf@fomichev.me>,
Tom Herbert <tom@herbertland.com>,
Willem de Bruijn <willemdebruijn.kernel@gmail.com>,
linux-kernel@vger.kernel.org,
Dave Seddon <dave.seddon.ca@gmail.com>
Subject: [PATCH net-next v1 11/11] Documentation: networking: add flow_dissector overview and fast-path guide
Date: Wed, 15 Jul 2026 17:43:57 -0700 [thread overview]
Message-ID: <20260716004357.3652679-12-dave.seddon.ca@gmail.com> (raw)
In-Reply-To: <20260716004357.3652679-1-dave.seddon.ca@gmail.com>
The kernel has no general flow_dissector documentation: Documentation/bpf/
prog_flow_dissector.rst covers only the BPF override mechanism (and was
itself in no toctree). Add Documentation/networking/flow_dissector.rst as a
standalone overview -- what the flow dissector is, struct flow_keys and the
consumers of skb->hash (RSS/RPS/RFS, ECMP/multipath, bonding/LAG,
tc-flower,
aRFS), the generic protocol-graph parser, and the relationship to the BPF
flow dissector -- and document the opt-in fast paths added by this series:
the byte-identical per-shape gates, the
break-even model for when to enable a gate (with the observable
/proc/net/flow_dissector_stats). The per-knob
reference stays in Documentation/admin-guide/sysctl/net.rst; this doc links
to it rather than duplicating it.
Also index the previously-orphaned
Documentation/bpf/prog_flow_dissector.rst and cross-link it with the
new overview (the bpf/index.rst hunk can be split out if the BPF
maintainers prefer).
Assisted-by: Claude:claude-fable-5 sparse smatch
Signed-off-by: Dave Seddon <dave.seddon.ca@gmail.com>
---
Documentation/bpf/index.rst | 1 +
Documentation/bpf/prog_flow_dissector.rst | 2 +
Documentation/networking/flow_dissector.rst | 133 ++++++++++++++++++++
Documentation/networking/index.rst | 1 +
4 files changed, 137 insertions(+)
create mode 100644 Documentation/networking/flow_dissector.rst
diff --git a/Documentation/bpf/index.rst b/Documentation/bpf/index.rst
index 0d5c6f659266..6e26731fa06f 100644
--- a/Documentation/bpf/index.rst
+++ b/Documentation/bpf/index.rst
@@ -23,6 +23,7 @@ that goes into great technical depth about the BPF Architecture.
cpumasks
fs_kfuncs
programs
+ prog_flow_dissector
maps
bpf_prog_run
classic_vs_extended.rst
diff --git a/Documentation/bpf/prog_flow_dissector.rst b/Documentation/bpf/prog_flow_dissector.rst
index f24270b8b034..f4c4648461ca 100644
--- a/Documentation/bpf/prog_flow_dissector.rst
+++ b/Documentation/bpf/prog_flow_dissector.rst
@@ -9,6 +9,8 @@ Overview
Flow dissector is a routine that parses metadata out of the packets. It's
used in the various places in the networking subsystem (RFS, flow hash, etc).
+See :doc:`/networking/flow_dissector` for an overview of the flow dissector
+and the built-in C implementation this program type overrides.
BPF flow dissector is an attempt to reimplement C-based flow dissector logic
in BPF to gain all the benefits of BPF verifier (namely, limits on the
diff --git a/Documentation/networking/flow_dissector.rst b/Documentation/networking/flow_dissector.rst
new file mode 100644
index 000000000000..014f6d124b4f
--- /dev/null
+++ b/Documentation/networking/flow_dissector.rst
@@ -0,0 +1,133 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+==============
+Flow Dissector
+==============
+
+Overview
+========
+
+The flow dissector parses a packet's headers into a ``struct flow_keys``: the
+addresses, ports, and other fields that identify the flow the packet belongs
+to. Its entry point is ``__skb_flow_dissect()`` in
+``net/core/flow_dissector.c``.
+
+The dissected keys feed ``skb->hash`` (via ``flow_hash_from_keys()``), which is
+the canonical flow identity consumed all over the stack, including:
+
+* receive-side steering: RSS, RPS, RFS and accelerated RFS (aRFS);
+* transmit-side spreading: ECMP / multipath route selection and bonding / LAG
+ ``xmit_hash_policy``;
+* classification and offload: tc-flower.
+
+A single dissection therefore feeds every one of these, so the dissector sits
+on a hot path in most networking workloads.
+
+Two standard dissectors are built in: ``flow_keys_dissector`` (the general one)
+and ``flow_keys_dissector_symmetric`` (same source and destination hashed
+symmetrically). In addition, subsystems such as tc-flower build **custom**
+dissector instances at run time that request only the keys they need. A custom
+instance carries its own ``used_keys`` bitmask and per-key offset table, so its
+field accesses are resolved dynamically at each dissect.
+
+struct flow_keys
+================
+
+``struct flow_keys`` (see ``include/net/flow_dissector.h``) collects the
+dissected metadata. Its main members are:
+
+* ``control`` -- address type and control flags (for example
+ ``FLOW_DIS_ENCAPSULATION`` when the keys came from inside a tunnel, and
+ ``FLOW_DIS_IS_FRAGMENT``);
+* ``basic`` -- L3 protocol (``n_proto``) and L4 protocol (``ip_proto``);
+* ``addrs`` -- source and destination addresses (IPv4 or IPv6);
+* ``ports`` -- source and destination ports;
+* ``vlan`` / ``cvlan`` -- 802.1Q / 802.1AD tags;
+* ``tags``, ``keyid``, ``icmp`` -- MPLS/flow-label tags, GRE/tunnel key, and
+ ICMP identifiers.
+
+The dissection path
+===================
+
+The built-in dissector is a generic protocol-graph parser: it walks the header
+chain in a loop, dispatching on the current L2/L3 ethertype and then the L4
+protocol, following encapsulation (IP-in-IP, GRE, ...) by re-entering the loop
+on the inner header. The number of headers it will descend through is bounded
+by ``MAX_FLOW_DISSECT_HDRS`` so that a crafted deeply nested packet cannot make
+it loop without limit.
+
+This generic parser is referred to below as the *slow path*: it is table- and
+loop-driven and handles every protocol the dissector knows about.
+
+The BPF flow dissector
+======================
+
+A per-network-namespace BPF program can be attached to replace the built-in
+dissector for the protocols it chooses to handle. When one is attached,
+``__skb_flow_dissect()`` runs it **first**; if the program returns a verdict
+other than ``BPF_FLOW_DISSECTOR_CONTINUE``, its result is used and the built-in
+dissector (including the fast paths below) is not run for that packet. A system
+running an attached BPF dissector therefore sees behaviour defined entirely by
+its program.
+
+See :doc:`/bpf/prog_flow_dissector` for the BPF program type, its API, and its
+reference implementation.
+
+Opt-in fast paths
+=================
+
+For the packet shapes that dominate real deployments, the built-in dissector
+also provides an opt-in, straight-line *fast path* that produces the same
+result as the slow-path graph walk with far fewer instructions. Restricting the
+fast path to the two standard dissectors turns their per-key offsets into
+compile-time constants, so the parse becomes branch-light straight-line code;
+the isolated per-dissect cost of the eligible shapes drops by roughly half,
+with the largest wins on in-order cores.
+
+Each shape has its own gate -- a ``static_branch`` exposed as a sysctl under
+``/proc/sys/net/flow_dissector/`` -- and **every gate is off by default**. When
+a gate is off, the only added cost is one not-taken branch per dissect, and the
+dissector's output is exactly what it was before. The fast path runs only
+*after* the BPF hook described above, so an attached BPF program always takes
+precedence.
+
+The fast paths are **byte-identical by contract**: for any packet, a fast path
+either writes exactly the ``flow_keys`` the slow path would have written, or it
+returns false and the slow path runs. There are only these two outcomes, and
+the equivalence is enforced in-tree by a KUnit test suite
+(``CONFIG_FLOW_DISSECTOR_KUNIT_TEST``). Enabling a byte-identical shape gate
+never changes any consumer's hash; it only makes the dissection cheaper.
+
+The eligible byte-identical shapes are plain Ethernet + IPv4/IPv6 + TCP/UDP,
+single and stacked VLAN (QinQ), PPPoE sessions, a single MPLS label, the
+IP-in-IP family, and plain GRE. The individual knobs are documented in
+:doc:`/admin-guide/sysctl/net` under ``/proc/sys/net/flow_dissector``.
+
+When to enable
+==============
+
+Turning a byte-identical shape gate on is worthwhile when enough traffic matches
+that shape to repay the small cost a non-matching packet pays while the gate is
+on. Concretely, if a matching packet saves ``S`` and a non-matching packet costs
+``C`` (both measured per shape and per micro-architecture), enabling the gate is
+net-positive once the fraction of traffic matching the shape exceeds the
+break-even ``p_be = C / (S + C)``.
+
+That fraction is observable: the read-only file
+``/proc/net/flow_dissector_stats`` reports, per shape, how many packets the slow
+path handled, how many the fast body handled, and the resulting eligible
+fraction, so ``(occurrences + fast_hits) / dissects`` is a gate-invariant
+measure of how much traffic each shape would accelerate.
+
+A separate RFC proposes an optional ``auto`` mode built on these counters: the
+kernel would sample them over a packet-count window and flip the
+byte-identical gates itself, with hysteresis and a flip-rate cap, so the
+operator does not have to tune each shape by hand. That controller is not part
+of this series.
+
+References
+==========
+
+* :doc:`/admin-guide/sysctl/net` -- the ``/proc/sys/net/flow_dissector/``
+ per-shape knob reference and the ``/proc/net/flow_dissector_stats`` file.
+* :doc:`/bpf/prog_flow_dissector` -- the BPF flow dissector program type.
diff --git a/Documentation/networking/index.rst b/Documentation/networking/index.rst
index 44a422ad3b05..65368050ebab 100644
--- a/Documentation/networking/index.rst
+++ b/Documentation/networking/index.rst
@@ -52,6 +52,7 @@ Contents:
eql
fib_trie
filter
+ flow_dissector
generic-hdlc
generic_netlink
../netlink/specs/index
--
2.54.0
next prev parent reply other threads:[~2026-07-16 0:44 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-16 0:43 [PATCH net-next v1 00/11] net: flow_dissector: opt-in byte-identical fast paths for common shapes Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 01/11] net: flow_dissector: gate BPF program lookup behind a static key Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 02/11] net: flow_dissector: opt-in fast-path for eth + IPv{4,6} + {TCP,UDP} Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 03/11] net: flow_dissector: add fast-path for VLAN and QinQ + IP + TCP/UDP Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 04/11] net: flow_dissector: add fast-path for PPPoE session + IPv{4,6} " Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 05/11] net: flow_dissector: add fast-path for single MPLS label + IP Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 06/11] net: flow_dissector: add fast-path for IP-in-IP family (IPIP / 4in6 / 6in4) Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 07/11] net: flow_dissector: add byte-identical fast-path for plain GRE inner Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 08/11] net: flow_dissector: per-shape counters + /proc/net/flow_dissector_stats Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 09/11] net: flow_dissector: bound fast-path tunnel recursion Dave Seddon
2026-07-16 0:43 ` [PATCH net-next v1 10/11] net: flow_dissector: add KUnit fast/slow path equivalence tests Dave Seddon
2026-07-16 0:43 ` Dave Seddon [this message]
2026-07-16 9:50 ` [PATCH net-next v1 00/11] net: flow_dissector: opt-in byte-identical fast paths for common shapes Willem de Bruijn
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=20260716004357.3652679-12-dave.seddon.ca@gmail.com \
--to=dave.seddon.ca@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=tom@herbertland.com \
--cc=willemdebruijn.kernel@gmail.com \
/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.