[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250209193840.20509-4-justin.iurman@uliege.be>
Date: Sun, 9 Feb 2025 20:38:40 +0100
From: Justin Iurman <justin.iurman@...ege.be>
To: netdev@...r.kernel.org
Cc: davem@...emloft.net,
dsahern@...nel.org,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
horms@...nel.org,
justin.iurman@...ege.be
Subject: [PATCH net 3/3] net: ipv6: fix consecutive input and output transformation in lwtunnels
Some lwtunnel users implement both lwt input and output handlers. If the
post-transformation destination on input is the same, the output handler
is also called and the same transformation is applied (again). Here are
the users: ila, bpf, rpl, seg6. The first one (ila) does not need this
fix, since it already implements a check to avoid such a duplicate. The
second (bpf) may need this fix, but I'm not familiar with that code path
and will keep it out of this patch. The two others (rpl and seg6) do
need this patch.
Due to the ila implementation (as an example), we cannot fix the issue
in lwtunnel_input() and lwtunnel_output() directly. Instead, we need to
do it on a case-by-case basis. This patch fixes both rpl_iptunnel and
seg6_iptunnel users. The fix re-uses skb->redirected in input handlers
to notify corresponding output handlers that the transformation was
already applied and to skip it. The "redirected" field seems safe to be
used here.
Fixes a7a29f9c361f ("net: ipv6: add rpl sr tunnel")
Fixes 6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels")
Signed-off-by: Justin Iurman <justin.iurman@...ege.be>
---
net/ipv6/rpl_iptunnel.c | 14 ++++++++++++--
net/ipv6/seg6_iptunnel.c | 16 +++++++++++++---
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c
index dc004e9aa649..2dc1f2297e39 100644
--- a/net/ipv6/rpl_iptunnel.c
+++ b/net/ipv6/rpl_iptunnel.c
@@ -208,6 +208,12 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
struct rpl_lwt *rlwt;
int err;
+ /* Don't re-apply the transformation when rpl_input() already did it */
+ if (skb_is_redirected(skb)) {
+ skb_reset_redirect(skb);
+ return orig_dst->lwtstate->orig_output(net, sk, skb);
+ }
+
rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate);
local_bh_disable();
@@ -311,9 +317,13 @@ static int rpl_input(struct sk_buff *skb)
skb_dst_set(skb, dst);
}
- /* avoid a lwtunnel_input() loop when dst_entry is the same */
- if (lwtst == dst->lwtstate)
+ /* avoid a lwtunnel_input() loop when dst_entry is the same, and make
+ * sure rpl_output() does not apply the transformation one more time
+ */
+ if (lwtst == dst->lwtstate) {
+ skb_set_redirected_noclear(skb, true);
return dst->lwtstate->orig_input(skb);
+ }
return dst_input(skb);
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 9fce6b2dbd54..539c79903ffa 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -522,11 +522,15 @@ static int seg6_input_core(struct net *net, struct sock *sk,
skb_dst_set(skb, dst);
}
- /* avoid a lwtunnel_input() loop when dst_entry is the same */
- if (lwtst == dst->lwtstate)
+ /* avoid a lwtunnel_input() loop when dst_entry is the same, and make
+ * sure seg6_output() does not apply the transformation one more time
+ */
+ if (lwtst == dst->lwtstate) {
+ skb_set_redirected_noclear(skb, true);
input_func = seg6_input_redirect_finish;
- else
+ } else {
input_func = seg6_input_finish;
+ }
if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled))
return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
@@ -573,6 +577,12 @@ static int seg6_output_core(struct net *net, struct sock *sk,
struct seg6_lwt *slwt;
int err;
+ /* Don't re-apply the transformation when seg6_input() already did it */
+ if (skb_is_redirected(skb)) {
+ skb_reset_redirect(skb);
+ return orig_dst->lwtstate->orig_output(net, sk, skb);
+ }
+
slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
local_bh_disable();
--
2.34.1
Powered by blists - more mailing lists