From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0C039405F7 for ; Thu, 16 Jul 2026 00:44:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.179 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784162654; cv=none; b=CG1kGwqF34RQqpOH110Xzi/Kux1QInef7EvGLSu+OUKTeZOYofa+N3FtH0FO3g3ayqatVimj+zOdblorsUm7CL2rkGoJjdktRzXMoipgDoo0sFt2KG7YDZtCAmp8ul8VTDdRQqKVVjqg9f37LVcx7al9f05OTTk5pIadmORsu90= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784162654; c=relaxed/simple; bh=/mWKmgPPP3TeTo5213fkgzBCXwFcfeZrukW48TpwrP4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CLnCAPxg5ovahkzQe0THGxmk5wvlVT0xEWXCjf3LOH46JcIsYfz+7EUCULGOATC7OX4LiyUYwAX9E8H+CjocabeqmsslumkVoJmSbLspAVXjz9IlpWGjF23+sraK5//WcFgiL6GnNN8pJ5Ob3/L6XZCdeR3Cr7Nzm8jI4QWFYPs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hmQ7wj3N; arc=none smtp.client-ip=209.85.210.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hmQ7wj3N" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-8486ac3f347so51363b3a.1 for ; Wed, 15 Jul 2026 17:44:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784162645; x=1784767445; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=4KYs6bF4G5Lma9vSvx/+axD0veNKsucRJ9eKrQH9KOc=; b=hmQ7wj3NWek2tmasKCWePocY+59m7HFcM0+AEmb3tY9H5yahHIR85V6GVN8PMeDXFE vdm4e/sdZLHdoKV5folV8HpLUsLe/5NEAPoVpA4BamyVXDoZ8B99DZxv/fxrmo9U8b5y 26B5x5NjO5IP3RuMeYqdZ9lB987tnlncxsVv+7btJlrOwtH1h7JGfbXqIGsXRKnccZDg RjISeEo2rEDCNlqwA0wttmPNTWtXMMydUnl1I1usYEFHCmrbpWs6DG+T/Ai2UbyPUQuu UEDIkhV4lZNZ0ExAm6CmR5zShKWUvfaA53Gio1KAL5Ynk9COZGkJzr4hX4QCqpOmMb4B 8NSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784162645; x=1784767445; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=4KYs6bF4G5Lma9vSvx/+axD0veNKsucRJ9eKrQH9KOc=; b=egy0aKbMr8HYj0BhspSMW2XOtcxLF2k3KusIviIOZhkVuvqKUF1251onBC7+aTqCeo 35ht8noYHxzIWfoh3aR9QKP28ysg79rF5X2k8JSqaFoseCtl8LpzYG9vOx92Mkh2SnLW x0g4TGHK/mvxKNBkhBUuFkdYI1i0A7Z3llDZtISLWcQj08d+9hYO1M39vAlAC6ugJSgg lShzcLdvnk5BanEPMCzIjVRu5QWrCnzmAFc5an0ieEqKzHmFEZmmY9RMk8bVdEg3f6f6 HypNgSksHm7+SbLIl4LhFDxY78fj6xhO/k/q+ViKjJNf2pLwwxXzrGNyKaKYzhV5iXCA 5Pvw== X-Forwarded-Encrypted: i=1; AHgh+RrOpHRblFC9CrP6A5n9LSiHuQKGYOEdHfG1dS4Q4bfrNjpJzMmlU2uNU6f1kqhdkvWK5SERvrg3+m19Wo4=@vger.kernel.org X-Gm-Message-State: AOJu0YxIwknA4w472gjDB/17HYpMeKPrlfrmRnv32a6ZCeeU2DIgs1E9 +dnHMlIcduncyYo7CSXTa1XmgKu5LtiQRKK+uW+5h1LE5U5bpoIxZm6x X-Gm-Gg: AfdE7cmLSIQ3ss8TlbAD8q5XUvoCxK5SJkiC/yIWCdN8qbpsaMPR8ZmT80WMOXJPIwq AYINxMHDKq8Ua5bptCBjuMLtfuqL4RuqJ7gLg+KFgQ7nxT5ZvD8pdfJjVfmqwtktBIRE+hmTbav d/y2tJj44yzW7jMXQQs3YvOYwb8dyRzU/9lwlKNJ+tvnTR9CJt7y6/YjwGzbpuaD/GsmCPicKV4 96hmSmCs8tUlDnlwOtX2LPXMnhoWEIBPDoA33bqGP6Quw1wNU4Tkob8UP3iM2RzXdQw83CjxeT0 abYF/Z+i6h6KfqXs3Hc9Ns+ODECI131vuMPYVGnx9moL3VG7yAXtJ38zfnVSvJvnpuPnRkIEEro yFNkwTBF0W6JEf0rr+bF+nrnfJno0LCZ/gDpamMgtBrO/uR7Nq7qN75FpnOmKWZY1uIu+f0PnmD 5igQf4BSqeErGkjz+YwPeMxjCGevr8BeOI4t6uPtIyugyebv8OVlPdv8UqISNvGeM52e4orNm+1 NE+ltULaA== X-Received: by 2002:a05:6a20:244c:b0:3bf:a8fa:a7b1 with SMTP id adf61e73a8af0-3c38dc1bbd0mr378449637.37.1784162645332; Wed, 15 Jul 2026 17:44:05 -0700 (PDT) Received: from l.localdomain ([76.166.220.66]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-13cd4284a92sm4107620c88.4.2026.07.15.17.44.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Jul 2026 17:44:04 -0700 (PDT) From: Dave Seddon To: netdev@vger.kernel.org Cc: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Stanislav Fomichev , Tom Herbert , Willem de Bruijn , linux-kernel@vger.kernel.org, Dave Seddon Subject: [PATCH net-next v1 04/11] net: flow_dissector: add fast-path for PPPoE session + IPv{4,6} + TCP/UDP Date: Wed, 15 Jul 2026 17:43:50 -0700 Message-ID: <20260716004357.3652679-5-dave.seddon.ca@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260716004357.3652679-1-dave.seddon.ca@gmail.com> References: <20260716004357.3652679-1-dave.seddon.ca@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds flow_dissect_fast_pppoe() — a straight-line extractor for PPPoE session frames (ETH_P_PPP_SES, EtherType 0x8864 per RFC 2516) carrying IPv4 or IPv6 inside PPP. Strips the 6-byte pppoe_hdr + 2-byte PPP protocol field, writes FLOW_DISSECTOR_KEY_PPPOE (session_id, ppp_proto, type) when requested, and tail-calls into the eth_ip fast-path for the inner IPv4 or IPv6 + TCP/UDP. Byte-identical with the slow path's `case htons(ETH_P_PPP_SES)` block for the eligible shape (RFC-2516-valid header + PPP_IP / PPP_IPV6 + straight-line IP). On any miss — invalid header, PFC-compressed PPP proto, PPP_MPLS_UC / PPP_MPLS_MC (defer until MPLS fast-path lands), LCP / IPCP / other control frames — returns false so the dispatcher falls through to the slow path. Output is exactly what the slow path would produce. Why this matters: PPPoE is the dominant L2 over millions of ISP last- mile DSL/FTTH links, and the existing slow-path PPPoE block does a __skb_header_pointer + per-field switch on every packet at the graph-walk entry. The fast-path saves the walk overhead for the common IPv4 / IPv6 inner case while keeping the slow path as the escape valve for control / less-common inner protos. Gated by: - new DEFINE_STATIC_KEY_FALSE(flow_dissector_pppoe_key) - new sysctl /proc/sys/net/flow_dissector/pppoe (default 0) - dispatcher case `htons(ETH_P_PPP_SES)` with `static_branch_unlikely(&flow_dissector_pppoe_key)` guard When the sysctl is 0, the dispatcher hits a forward not-taken JMP — same per-call cost as the vlan / qinq cases. The new dispatcher case also doesn't widen the switch table (it adds one case to a switch the compiler can already lower to a jump table on the ETH_P_* constants). Documentation/admin-guide/sysctl/net.rst grows a `pppoe` subsection under the existing `/proc/sys/net/flow_dissector/` chapter, between qinq and the next chapter, matching the existing per-shape layout. Assisted-by: Claude:claude-fable-5 sparse smatch Signed-off-by: Dave Seddon --- Documentation/admin-guide/sysctl/net.rst | 18 ++++++ include/net/flow_dissector.h | 1 + net/core/flow_dissector.c | 76 ++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst index 824f4b735caa..1096e6ddca39 100644 --- a/Documentation/admin-guide/sysctl/net.rst +++ b/Documentation/admin-guide/sysctl/net.rst @@ -516,6 +516,24 @@ the outer entry is off). Default: 0 +pppoe +~~~~~ + +PPPoE session frames (RFC 2516, EtherType ``ETH_P_PPP_SES`` 0x8864) +carrying IPv4 or IPv6 inside PPP. The fast-path strips the 6-byte +PPPoE session header + 2-byte PPP protocol field, writes +FLOW_DISSECTOR_KEY_PPPOE (session_id, ppp_proto, type) when the +dissector requests it, and tail-calls into the eth_ip fast-path for +the inner IPv4 / IPv6 + TCP/UDP. Byte-identical with the slow path +for the eligible shape. + +Defers to slow path for: PPP_MPLS_UC / PPP_MPLS_MC (until an MPLS +fast-path lands), PFC-compressed PPP protocol fields, LCP/IPCP/etc. +control frames, and any malformed PPPoE header (ver != 1, type != 1, +code != 0). + +Default: 0 + 3. /proc/sys/net/unix - Parameters for Unix domain sockets ---------------------------------------------------------- diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 4f36f3889a28..df85162959cc 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -431,6 +431,7 @@ extern struct flow_dissector flow_keys_basic_dissector; extern struct static_key_false flow_dissector_eth_ip_key; extern struct static_key_false flow_dissector_vlan_key; extern struct static_key_false flow_dissector_qinq_key; +extern struct static_key_false flow_dissector_pppoe_key; /* struct flow_keys_digest: * diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 826314e28db0..21a3f5e0ea05 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -46,6 +46,8 @@ DEFINE_STATIC_KEY_FALSE(flow_dissector_vlan_key); EXPORT_SYMBOL(flow_dissector_vlan_key); DEFINE_STATIC_KEY_FALSE(flow_dissector_qinq_key); EXPORT_SYMBOL(flow_dissector_qinq_key); +DEFINE_STATIC_KEY_FALSE(flow_dissector_pppoe_key); +EXPORT_SYMBOL(flow_dissector_pppoe_key); /* IPv4 version/IHL byte of an option-less header: version 4, IHL 5. */ #define FLOW_DIS_IPV4_VIHL_NOOPT 0x45 @@ -1333,6 +1335,67 @@ static bool flow_dissect_fast_vlan(const struct sk_buff *skb, } } +/* PPPoE session (RFC 2516) + 2-byte PPP protocol: write + * FLOW_DISSECTOR_KEY_PPPOE if requested, then tail-call the eth_ip + * fast-path for PPP_IP / PPP_IPV6. Anything else (PFC-compressed + * protocol, LCP, MPLS) defers. + */ +static bool flow_dissect_fast_pppoe(const struct sk_buff *skb, + struct flow_dissector *flow_dissector, + void *target_container, + const void *data, + int nhoff, int hlen) +{ + struct flow_dissector_key_pppoe *key_pppoe; + const struct { + struct pppoe_hdr hdr; + __be16 proto; + } *hdr; + __be16 inner_eth_proto; + u16 ppp_proto; + + if (unlikely(hlen - nhoff < (int)sizeof(*hdr))) + return false; + hdr = (const void *)((const u8 *)data + nhoff); + if (!is_pppoe_ses_hdr_valid(&hdr->hdr)) + return false; + + ppp_proto = ntohs(hdr->proto); + switch (ppp_proto) { + case PPP_IP: + inner_eth_proto = htons(ETH_P_IP); + break; + case PPP_IPV6: + inner_eth_proto = htons(ETH_P_IPV6); + break; + default: + /* MPLS unicast/multicast + everything else (LCP, IPCP, + * compressed PFC, ...) defers to the slow path. + */ + return false; + } + + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_PPPOE)) { + key_pppoe = skb_flow_dissector_target(flow_dissector, + FLOW_DISSECTOR_KEY_PPPOE, + target_container); + key_pppoe->session_id = hdr->hdr.sid; + key_pppoe->ppp_proto = htons(ppp_proto); + key_pppoe->type = htons(ETH_P_PPP_SES); + } + + nhoff += PPPOE_SES_HLEN; + + if (inner_eth_proto == htons(ETH_P_IP)) + return flow_dissect_fast_ipv4(skb, flow_dissector, + target_container, data, + nhoff, hlen); + return flow_dissect_fast_ipv6(skb, flow_dissector, + target_container, data, + nhoff, hlen); +} + /* Top-level dispatcher: eligibility check (only the two standard * dissectors and flag subset) + per-proto switch with per-shape * static_branch gating. Each case's branch is a forward not-taken JMP @@ -1380,6 +1443,12 @@ static bool flow_dissect_fast(const struct sk_buff *skb, return flow_dissect_fast_ipv6(skb, flow_dissector, target_container, data, nhoff, hlen); + case htons(ETH_P_PPP_SES): + if (!static_branch_unlikely(&flow_dissector_pppoe_key)) + return false; + return flow_dissect_fast_pppoe(skb, flow_dissector, + target_container, data, + nhoff, hlen); default: return false; } @@ -2522,6 +2591,13 @@ static struct ctl_table flow_dissector_sysctl_table[] = { .mode = 0644, .proc_handler = proc_set_qinq_key, }, + { + .procname = "pppoe", + .data = &flow_dissector_pppoe_key.key, + .maxlen = sizeof(flow_dissector_pppoe_key), + .mode = 0644, + .proc_handler = proc_do_static_key, + }, }; static int __init flow_dissector_sysctl_init(void) -- 2.54.0