From: Andrea Parri <parri.andrea@gmail.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>,
Florian Westphal <fw@strlen.de>,
netfilter-devel@vger.kernel.org
Cc: Andrea Parri <parri.andrea@gmail.com>, Phil Sutter <phil@nwl.cc>,
Nikolay Aleksandrov <razor@blackwall.org>,
Ido Schimmel <idosch@nvidia.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
Bernhard Thaler <bernhard.thaler@wvnet.at>,
coreteam@netfilter.org, bridge@lists.linux.dev,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
Subject: [PATCH nf v2 1/2] netfilter: br_netfilter: restore VLAN tag on refragmented IPv6 packets
Date: Sun, 4 Oct 2026 23:24:27 +0200 [thread overview]
Message-ID: <20261004212429.3648-2-parri.andrea@gmail.com> (raw)
In-Reply-To: <20261004212429.3648-1-parri.andrea@gmail.com>
Bridged IPv6 packets can lose their VLAN tag or acquire an unrelated tag
when conntrack-reassembled packets are refragmented. On a VLAN-aware
bridge, or on any bridge with bridge-nf-filter-vlan-tagged enabled, this
can send fragments with a different VLAN tag from the one selected for
forwarding.
br_nf_push_frag_xmit() restores the VLAN tag from per-CPU storage, but
only the IPv4 branch of br_nf_dev_queue_xmit() saves it. The IPv6 branch
leaves the saved tag from the previous IPv4 refragmentation on that CPU.
Newly allocated fragments do not inherit the tag through
ip6_copy_metadata().
Commit d7b597421519 ("netfilter: bridge: restore vlan tag when
refragmenting") added VLAN tag restoration for IPv4 only, shortly after
IPv6 refragmentation was introduced.
This was reproduced on a VLAN-aware bridge by first refragmenting an IPv4
VLAN 100 flow on the same CPU. All fragments of subsequent IPv6 flows left
with stale VLAN 100 instead of the VLAN selected for their egress ports.
Move saving the L2 header and VLAN tag into br_nf_save_frag_data() and
call it from both branches, so the fragments that ip6_fragment() builds
use the current packet's VLAN information.
Fixes: efb6de9b4ba0 ("netfilter: bridge: forward IPv6 fragmented packets")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Andrea Parri <parri.andrea@gmail.com>
---
net/bridge/br_netfilter_hooks.c | 45 +++++++++++++++------------------
1 file changed, 21 insertions(+), 24 deletions(-)
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 0a394e5f43916..fe8d2910dae21 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -832,6 +832,25 @@ static unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb)
return 0;
}
+/* Saved for br_nf_push_frag_xmit() to restore on every fragment. */
+static void br_nf_save_frag_data(const struct sk_buff *skb)
+{
+ struct brnf_frag_data *data = this_cpu_ptr(&brnf_frag_data_storage);
+
+ if (skb_vlan_tag_present(skb)) {
+ data->vlan_tci = skb->vlan_tci;
+ data->vlan_proto = skb->vlan_proto;
+ } else {
+ data->vlan_proto = 0;
+ }
+
+ data->encap_size = nf_bridge_encap_header_len(skb);
+ data->size = ETH_HLEN + data->encap_size;
+
+ skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
+ data->size);
+}
+
static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct nf_bridge_info *nf_bridge = nf_bridge_info_get(skb);
@@ -866,28 +885,13 @@ static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff
*/
if (IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) &&
skb->protocol == htons(ETH_P_IP)) {
- struct brnf_frag_data *data;
-
if (br_validate_ipv4(net, skb))
goto drop;
IPCB(skb)->frag_max_size = nf_bridge->frag_max_size;
local_lock_nested_bh(&brnf_frag_data_storage.bh_lock);
- data = this_cpu_ptr(&brnf_frag_data_storage);
-
- if (skb_vlan_tag_present(skb)) {
- data->vlan_tci = skb->vlan_tci;
- data->vlan_proto = skb->vlan_proto;
- } else {
- data->vlan_proto = 0;
- }
-
- data->encap_size = nf_bridge_encap_header_len(skb);
- data->size = ETH_HLEN + data->encap_size;
-
- skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
- data->size);
+ br_nf_save_frag_data(skb);
ret = br_nf_ip_fragment(net, sk, skb, br_nf_push_frag_xmit);
local_unlock_nested_bh(&brnf_frag_data_storage.bh_lock);
@@ -895,20 +899,13 @@ static int br_nf_dev_queue_xmit(struct net *net, struct sock *sk, struct sk_buff
}
if (IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) &&
skb->protocol == htons(ETH_P_IPV6)) {
- struct brnf_frag_data *data;
-
if (br_validate_ipv6(net, skb))
goto drop;
IP6CB(skb)->frag_max_size = nf_bridge->frag_max_size;
local_lock_nested_bh(&brnf_frag_data_storage.bh_lock);
- data = this_cpu_ptr(&brnf_frag_data_storage);
- data->encap_size = nf_bridge_encap_header_len(skb);
- data->size = ETH_HLEN + data->encap_size;
-
- skb_copy_from_linear_data_offset(skb, -data->size, data->mac,
- data->size);
+ br_nf_save_frag_data(skb);
ret = ip6_fragment(net, sk, skb, br_nf_push_frag_xmit);
local_unlock_nested_bh(&brnf_frag_data_storage.bh_lock);
--
2.53.0
next prev parent reply other threads:[~2026-10-04 21:24 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-04 21:24 [PATCH nf v2 0/2] netfilter: preserve bridge egress VLAN tags Andrea Parri
2026-10-04 21:24 ` Andrea Parri [this message]
2026-10-04 21:24 ` [PATCH nf v2 2/2] netfilter: br_netfilter: clear stale VLAN tag on refragmented packets Andrea Parri
2026-10-04 21:29 ` [PATCH nf v2 0/2] netfilter: preserve bridge egress VLAN tags netdev-bot+sinfo
2026-10-04 21:42 ` Andrea Parri
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=20261004212429.3648-2-parri.andrea@gmail.com \
--to=parri.andrea@gmail.com \
--cc=bernhard.thaler@wvnet.at \
--cc=bridge@lists.linux.dev \
--cc=coreteam@netfilter.org \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pablo@netfilter.org \
--cc=phil@nwl.cc \
--cc=razor@blackwall.org \
--cc=stable@vger.kernel.org \
/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
all inboxes | Powered by JetHome®