From: ThisSeanZhang <thisseanzhang@gmail.com>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
netdev@vger.kernel.org, Nick Hudson <nhudson@akamai.com>,
Felix Fietkau <nbd@nbd.name>, Qingfang Deng <dqfext@gmail.com>
Subject: [RFC bpf-next v2 1/3] bpf: Add PPPoE encap support to bpf_skb_adjust_room
Date: Sat, 3 Oct 2026 15:33:45 -0400 [thread overview]
Message-ID: <20261003193347.1137527-2-thisseanzhang@gmail.com> (raw)
In-Reply-To: <20261003193347.1137527-1-thisseanzhang@gmail.com>
Add a new BPF_F_ADJ_ROOM_ENCAP_PPPOE flag to bpf_skb_adjust_room() so
that a TC BPF program can encapsulate an IPv4 or IPv6 packet into a
PPPoE session header:
bpf_skb_adjust_room(skb, PPPOE_SES_HLEN, BPF_ADJ_ROOM_MAC,
BPF_F_ADJ_ROOM_ENCAP_PPPOE);
The flag inserts eight bytes between the MAC and network headers: the
six-byte PPPoE session header followed by the two-byte PPP protocol
field. It then updates the skb metadata, including skb->protocol and
skb->mac_len. The BPF program remains responsible for filling in the
PPPoE header and the Ethernet ethertype, for example with
bpf_skb_store_bytes().
Previously, a TC program could add the header bytes manually, but the
skb would continue to be treated as a plain IP packet because its
protocol metadata was unchanged. With the stale skb->protocol, software
GSO may select a non-PPPoE segmentation handler and process the packet
incorrectly.
This makes the skb metadata compatible with the PPPoE GRO/GSO handlers
registered for ETH_P_PPP_SES. The PPPoE GRO/GSO support must be built in
or loaded before receive-side GRO or software GSO uses those handlers.
Signed-off-by: ThisSeanZhang <thisseanzhang@gmail.com>
---
include/uapi/linux/bpf.h | 12 ++++++++++++
net/core/filter.c | 22 ++++++++++++++++++++++
tools/include/uapi/linux/bpf.h | 12 ++++++++++++
3 files changed, 46 insertions(+)
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 732b35cc0..30481d040 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -3036,6 +3036,17 @@ union bpf_attr {
* Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the
* L2 type as Ethernet.
*
+ * * **BPF_F_ADJ_ROOM_ENCAP_PPPOE**:
+ * Encapsulate the packet in a PPPoE session header. Must be
+ * used with **BPF_ADJ_ROOM_MAC** mode and *len_diff* equal to
+ * the size of the PPPoE session header plus the PPP protocol
+ * field (8 bytes in total). The room is inserted between the
+ * MAC header and the network header, *skb->protocol* is set
+ * to **ETH_P_PPP_SES** and *skb->mac_len* is updated
+ * accordingly. The PPPoE header itself and the ethertype of
+ * the MAC header are filled in by the BPF program, e.g. via
+ * **bpf_skb_store_bytes**.
+ *
* * **BPF_F_ADJ_ROOM_DECAP_L3_IPV4**,
* **BPF_F_ADJ_ROOM_DECAP_L3_IPV6**:
* Indicate the new IP header version after decapsulating the
@@ -6323,6 +6334,7 @@ enum bpf_adj_room_flags {
BPF_F_ADJ_ROOM_DECAP_L4_UDP = (1ULL << 10),
BPF_F_ADJ_ROOM_DECAP_IPXIP4 = (1ULL << 11),
BPF_F_ADJ_ROOM_DECAP_IPXIP6 = (1ULL << 12),
+ BPF_F_ADJ_ROOM_ENCAP_PPPOE = (1ULL << 13),
};
enum {
diff --git a/net/core/filter.c b/net/core/filter.c
index 70dc62167..5b204e316 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -47,6 +47,7 @@
#include <linux/ratelimit.h>
#include <linux/seccomp.h>
#include <linux/if_vlan.h>
+#include <linux/if_pppox.h>
#include <linux/bpf.h>
#include <linux/btf.h>
#include <net/sch_generic.h>
@@ -3583,6 +3584,7 @@ static u32 bpf_skb_net_base_len(const struct sk_buff *skb)
BPF_F_ADJ_ROOM_ENCAP_L4_GRE | \
BPF_F_ADJ_ROOM_ENCAP_L4_UDP | \
BPF_F_ADJ_ROOM_ENCAP_L2_ETH | \
+ BPF_F_ADJ_ROOM_ENCAP_PPPOE | \
BPF_F_ADJ_ROOM_ENCAP_L2( \
BPF_ADJ_ROOM_ENCAP_L2_MASK))
@@ -3688,6 +3690,14 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
skb_dst_drop(skb);
}
+ if (flags & BPF_F_ADJ_ROOM_ENCAP_PPPOE) {
+ /* Network header points at the inserted PPPoE header. */
+ skb->protocol = htons(ETH_P_PPP_SES);
+ skb_reset_mac_len(skb);
+ if (skb_valid_dst(skb))
+ skb_dst_drop(skb);
+ }
+
if (skb_is_gso(skb)) {
struct skb_shared_info *shinfo = skb_shinfo(skb);
@@ -3874,6 +3884,18 @@ BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
return -ENOTSUPP;
}
+ if (flags & BPF_F_ADJ_ROOM_ENCAP_PPPOE) {
+ /* The PPPoE session header has a fixed size and is
+ * inserted directly after the MAC header.
+ */
+ if (shrink || mode != BPF_ADJ_ROOM_MAC ||
+ len_diff != PPPOE_SES_HLEN ||
+ flags & ((BPF_F_ADJ_ROOM_ENCAP_MASK |
+ BPF_F_ADJ_ROOM_DECAP_MASK) &
+ ~BPF_F_ADJ_ROOM_ENCAP_PPPOE))
+ return -EINVAL;
+ }
+
if (flags & BPF_F_ADJ_ROOM_DECAP_MASK) {
u32 len_decap_min = 0;
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index 732b35cc0..30481d040 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -3036,6 +3036,17 @@ union bpf_attr {
* Use with BPF_F_ADJ_ROOM_ENCAP_L2 flag to further specify the
* L2 type as Ethernet.
*
+ * * **BPF_F_ADJ_ROOM_ENCAP_PPPOE**:
+ * Encapsulate the packet in a PPPoE session header. Must be
+ * used with **BPF_ADJ_ROOM_MAC** mode and *len_diff* equal to
+ * the size of the PPPoE session header plus the PPP protocol
+ * field (8 bytes in total). The room is inserted between the
+ * MAC header and the network header, *skb->protocol* is set
+ * to **ETH_P_PPP_SES** and *skb->mac_len* is updated
+ * accordingly. The PPPoE header itself and the ethertype of
+ * the MAC header are filled in by the BPF program, e.g. via
+ * **bpf_skb_store_bytes**.
+ *
* * **BPF_F_ADJ_ROOM_DECAP_L3_IPV4**,
* **BPF_F_ADJ_ROOM_DECAP_L3_IPV6**:
* Indicate the new IP header version after decapsulating the
@@ -6323,6 +6334,7 @@ enum bpf_adj_room_flags {
BPF_F_ADJ_ROOM_DECAP_L4_UDP = (1ULL << 10),
BPF_F_ADJ_ROOM_DECAP_IPXIP4 = (1ULL << 11),
BPF_F_ADJ_ROOM_DECAP_IPXIP6 = (1ULL << 12),
+ BPF_F_ADJ_ROOM_ENCAP_PPPOE = (1ULL << 13),
};
enum {
--
2.47.3
next prev parent reply other threads:[~2026-10-03 19:34 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-03 19:33 [RFC bpf-next v2 0/3] bpf: Add PPPoE encap/decap support to bpf_skb_adjust_room ThisSeanZhang
2026-10-03 19:33 ` ThisSeanZhang [this message]
2026-10-03 19:33 ` [RFC bpf-next v2 2/3] bpf: Add PPPoE decap " ThisSeanZhang
2026-10-03 19:33 ` [RFC bpf-next v2 3/3] selftests/bpf: Add a test for the PPPoE encap/decap adjust_room flags ThisSeanZhang
2026-10-03 20:11 ` bot+bpf-ci
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=20261003193347.1137527-2-thisseanzhang@gmail.com \
--to=thisseanzhang@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=dqfext@gmail.com \
--cc=eddyz87@gmail.com \
--cc=nbd@nbd.name \
--cc=netdev@vger.kernel.org \
--cc=nhudson@akamai.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox