From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: davem@davemloft.net, netdev@vger.kernel.org, kuba@kernel.org,
pabeni@redhat.com, edumazet@google.com, fw@strlen.de,
horms@kernel.org
Subject: [PATCH net 13/14] netfilter: flowtable: fix inline pppoe encapsulation in xmit path
Date: Fri, 1 May 2026 14:22:36 +0200 [thread overview]
Message-ID: <20260501122237.296262-14-pablo@netfilter.org> (raw)
In-Reply-To: <20260501122237.296262-1-pablo@netfilter.org>
Address two issues in the inline pppoe encapsulation:
- Add needs_gso_segment flag to segment PPPoE packets in software
given that there is no GSO support for this.
- Use FLOW_OFFLOAD_XMIT_DIRECT since neighbour cache is not available
in point-to-point device, use the hardware address that is obtained
via flowtable path discovery (ie. fill_forward_path).
Fixes: 18d27bed0880 ("netfilter: flowtable: inline pppoe encapsulation in xmit path")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_flow_table.h | 4 ++-
net/netfilter/nf_flow_table_core.c | 1 +
net/netfilter/nf_flow_table_ip.c | 42 +++++++++++++++++++++++++--
net/netfilter/nf_flow_table_path.c | 7 ++++-
4 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index b09c11c048d5..7b23b245a5a8 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -148,9 +148,10 @@ struct flow_offload_tuple {
/* All members above are keys for lookups, see flow_offload_hash(). */
struct { } __hash;
- u8 dir:2,
+ u16 dir:2,
xmit_type:3,
encap_num:2,
+ needs_gso_segment:1,
tun_num:2,
in_vlan_ingress:2;
u16 mtu;
@@ -232,6 +233,7 @@ struct nf_flow_route {
u32 hw_ifindex;
u8 h_source[ETH_ALEN];
u8 h_dest[ETH_ALEN];
+ u8 needs_gso_segment:1;
} out;
enum flow_offload_xmit_type xmit_type;
} tuple[FLOW_OFFLOAD_DIR_MAX];
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 2c4140e6f53c..785d8c244a77 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -122,6 +122,7 @@ static int flow_offload_fill_route(struct flow_offload *flow,
flow_tuple->tun = route->tuple[dir].in.tun;
flow_tuple->encap_num = route->tuple[dir].in.num_encaps;
+ flow_tuple->needs_gso_segment = route->tuple[dir].out.needs_gso_segment;
flow_tuple->tun_num = route->tuple[dir].in.num_tuns;
switch (route->tuple[dir].xmit_type) {
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 0ce3c209050c..2eba64eb393a 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -553,7 +553,8 @@ static int nf_flow_vlan_push(struct sk_buff *skb, __be16 proto, u16 id,
return 0;
}
-static int nf_flow_pppoe_push(struct sk_buff *skb, u16 id)
+static int nf_flow_pppoe_push(struct sk_buff *skb, u16 id,
+ u32 needed_headroom)
{
int data_len = skb->len + sizeof(__be16);
struct ppp_hdr {
@@ -562,7 +563,7 @@ static int nf_flow_pppoe_push(struct sk_buff *skb, u16 id)
} *ph;
__be16 proto;
- if (skb_cow_head(skb, PPPOE_SES_HLEN))
+ if (skb_cow_head(skb, needed_headroom + PPPOE_SES_HLEN))
return -1;
switch (skb->protocol) {
@@ -755,7 +756,8 @@ static int nf_flow_encap_push(struct sk_buff *skb,
return -1;
break;
case htons(ETH_P_PPP_SES):
- if (nf_flow_pppoe_push(skb, tuple->encap[i].id) < 0)
+ if (nf_flow_pppoe_push(skb, tuple->encap[i].id,
+ needed_headroom) < 0)
return -1;
break;
}
@@ -769,6 +771,7 @@ struct nf_flow_xmit {
const void *source;
struct net_device *outdev;
struct flow_offload_tuple *tuple;
+ bool needs_gso_segment;
};
static void __nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
@@ -789,10 +792,41 @@ static void __nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
dev_queue_xmit(skb);
}
+static unsigned int nf_flow_encap_gso_xmit(struct net *net, struct sk_buff *skb,
+ struct nf_flow_xmit *xmit)
+{
+ struct sk_buff *segs, *nskb;
+
+ segs = skb_gso_segment(skb, 0);
+ if (IS_ERR(segs))
+ return NF_DROP;
+
+ if (segs)
+ consume_skb(skb);
+ else
+ segs = skb;
+
+ skb_list_walk_safe(segs, segs, nskb) {
+ skb_mark_not_on_list(segs);
+
+ if (nf_flow_encap_push(segs, xmit->tuple, xmit->outdev) < 0) {
+ kfree_skb(segs);
+ kfree_skb_list(nskb);
+ return NF_STOLEN;
+ }
+ __nf_flow_queue_xmit(net, segs, xmit);
+ }
+
+ return NF_STOLEN;
+}
+
static unsigned int nf_flow_queue_xmit(struct net *net, struct sk_buff *skb,
struct nf_flow_xmit *xmit)
{
if (xmit->tuple->encap_num) {
+ if (skb_is_gso(skb) && xmit->needs_gso_segment)
+ return nf_flow_encap_gso_xmit(net, skb, xmit);
+
if (nf_flow_encap_push(skb, xmit->tuple, xmit->outdev) < 0)
return NF_DROP;
}
@@ -876,6 +910,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
return NF_DROP;
}
xmit.tuple = other_tuple;
+ xmit.needs_gso_segment = tuplehash->tuple.needs_gso_segment;
return nf_flow_queue_xmit(state->net, skb, &xmit);
}
@@ -1196,6 +1231,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
return NF_DROP;
}
xmit.tuple = other_tuple;
+ xmit.needs_gso_segment = tuplehash->tuple.needs_gso_segment;
return nf_flow_queue_xmit(state->net, skb, &xmit);
}
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 6bb9579dcc2a..9e88ea6a2eef 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -86,6 +86,7 @@ struct nft_forward_info {
u8 ingress_vlans;
u8 h_source[ETH_ALEN];
u8 h_dest[ETH_ALEN];
+ bool needs_gso_segment;
enum flow_offload_xmit_type xmit_type;
};
@@ -138,8 +139,11 @@ static void nft_dev_path_info(const struct net_device_path_stack *stack,
path->encap.proto;
info->num_encaps++;
}
- if (path->type == DEV_PATH_PPPOE)
+ if (path->type == DEV_PATH_PPPOE) {
memcpy(info->h_dest, path->encap.h_dest, ETH_ALEN);
+ info->xmit_type = FLOW_OFFLOAD_XMIT_DIRECT;
+ info->needs_gso_segment = 1;
+ }
break;
case DEV_PATH_BRIDGE:
if (is_zero_ether_addr(info->h_source))
@@ -279,6 +283,7 @@ static void nft_dev_forward_path(const struct nft_pktinfo *pkt,
memcpy(route->tuple[dir].out.h_dest, info.h_dest, ETH_ALEN);
route->tuple[dir].xmit_type = info.xmit_type;
}
+ route->tuple[dir].out.needs_gso_segment = info.needs_gso_segment;
}
int nft_flow_route(const struct nft_pktinfo *pkt, const struct nf_conn *ct,
--
2.47.3
next prev parent reply other threads:[~2026-05-01 12:23 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-01 12:22 [PATCH net 00/14] Netfilter fixes for net Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 01/14] netfilter: replace skb_try_make_writable() by skb_ensure_writable() Pablo Neira Ayuso
2026-05-01 23:50 ` patchwork-bot+netdevbpf
2026-05-01 12:22 ` [PATCH net 02/14] netfilter: nft_fwd_netdev: add device and headroom validate with neigh forwarding Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 03/14] netfilter: nft_fwd_netdev: use recursion counter in neigh egress path Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 04/14] netfilter: x_tables: add .check_hooks to matches and targets Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 05/14] netfilter: nft_compat: run xt_check_hooks_{match,target}() from .validate Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 06/14] netfilter: xt_CT: fix usersize for v1 and v2 revision Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 07/14] netfilter: nf_tables: fix netdev hook allocation memleak with dormant tables Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 08/14] netfilter: nf_socket: skip socket lookup for non-first fragments Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 09/14] netfilter: nf_tables: skip L4 header parsing " Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 10/14] netfilter: xtables: fix " Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 11/14] netfilter: flowtable: ensure sufficient headroom in xmit path Pablo Neira Ayuso
2026-05-01 12:22 ` [PATCH net 12/14] netfilter: flowtable: fix inline vlan encapsulation " Pablo Neira Ayuso
2026-05-01 12:22 ` Pablo Neira Ayuso [this message]
2026-05-01 12:22 ` [PATCH net 14/14] netfilter: flowtable: use skb_pull_rcsum() to pop vlan/pppoe header Pablo Neira Ayuso
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=20260501122237.296262-14-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.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