* [PATCH net-next v2] seg6: enable route leak for encap routes
@ 2026-03-27 14:06 Nicolas Dichtel
0 siblings, 0 replies; only message in thread
From: Nicolas Dichtel @ 2026-03-27 14:06 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni, Eric Dumazet,
David Lebrun, Andrea Mayer, Paolo Lungaroni, David Ahern
Cc: netdev, Nicolas Dichtel
The goal is to support x-vrf route. To avoid breaking existing setup, a new
flag is introduced: nh-vrf.
The dev parameter is mandatory when a seg6 encap route is configured, but
before this commit, it is ignored/not used. After the srv6 encapsulation, a
second route lookup in the same vrf is performed.
The new nh-vrf flag specifies to use the vrf associated with the dev
parameter to perform this second route lookup.
The l3vpn tests show the inconsistency: the specified nexthop dev is
ignored and a second route is added in the same vrf for the segment address
(before the commit, the route to 'fc00:21:100::6046' was put in the vrf-100
table while the encap route was pointing to veth0, which is not associated
with a vrf).
The tests are updated to use the nh-vrf flag when available.
Before:
> $ ip -n rt_2-Rh5GP7 -6 r list vrf vrf-100 | grep fc00:21:100::6046
> cafe::1 encap seg6 mode encap segs 1 [ fc00:21:100::6046 ] dev veth0 metric 1024 pref medium
> fc00:21:100::6046 via fd00::1 dev veth0 metric 1024 pref medium
After:
> $ ip -n rt_2-Rh5GP7 -6 r list vrf vrf-100 | grep fc00:21:100::6046
> cafe::1 encap seg6 mode encap segs 1 [ fc00:21:100::6046 ] nh-vrf dev veth0 metric 1024 pref medium
> $ ip -n rt_2-Rh5GP7 -6 r list | grep fc00:21:100::6046
> fc00:21:100::6046 via fd00::1 dev veth0 metric 1024 pref medium
Fixes: 6c8702c60b88 ("ipv6: sr: add support for SRH encapsulation and injection with lwtunnels")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
---
v1 -> v2:
- target net-next instead of net
- add a new attribute to avoid breaking the legacy behavior
- use dst_dev_rcu()
include/uapi/linux/seg6_iptunnel.h | 1 +
net/ipv6/seg6_iptunnel.c | 23 ++++++++++--
.../selftests/net/srv6_end_dt46_l3vpn_test.sh | 35 +++++++++++++++++--
.../selftests/net/srv6_end_dt4_l3vpn_test.sh | 33 +++++++++++++++--
.../selftests/net/srv6_end_dt6_l3vpn_test.sh | 33 +++++++++++++++--
5 files changed, 116 insertions(+), 9 deletions(-)
diff --git a/include/uapi/linux/seg6_iptunnel.h b/include/uapi/linux/seg6_iptunnel.h
index 485889b19900..d7d6aa2f72c5 100644
--- a/include/uapi/linux/seg6_iptunnel.h
+++ b/include/uapi/linux/seg6_iptunnel.h
@@ -21,6 +21,7 @@ enum {
SEG6_IPTUNNEL_UNSPEC,
SEG6_IPTUNNEL_SRH,
SEG6_IPTUNNEL_SRC, /* struct in6_addr */
+ SEG6_IPTUNNEL_NH_VRF,
__SEG6_IPTUNNEL_MAX,
};
#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index e76cc0cc481e..f8c6f0d719be 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -50,6 +50,7 @@ static size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
struct seg6_lwt {
struct dst_cache cache;
struct in6_addr tunsrc;
+ bool nh_vrf;
struct seg6_iptunnel_encap tuninfo[];
};
@@ -67,6 +68,7 @@ seg6_encap_lwtunnel(struct lwtunnel_state *lwt)
static const struct nla_policy seg6_iptunnel_policy[SEG6_IPTUNNEL_MAX + 1] = {
[SEG6_IPTUNNEL_SRH] = { .type = NLA_BINARY },
[SEG6_IPTUNNEL_SRC] = NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
+ [SEG6_IPTUNNEL_NH_VRF] = { .type = NLA_FLAG },
};
static int nla_put_srh(struct sk_buff *skb, int attrtype,
@@ -499,9 +501,15 @@ static int seg6_input_core(struct net *net, struct sock *sk,
* now and use it later as a comparison.
*/
lwtst = orig_dst->lwtstate;
-
slwt = seg6_lwt_lwtunnel(lwtst);
+ if (slwt->nh_vrf) {
+ rcu_read_lock();
+ skb->dev = l3mdev_master_dev_rcu(dst_dev_rcu(orig_dst)) ?:
+ dev_net(skb->dev)->loopback_dev;
+ rcu_read_unlock();
+ }
+
local_bh_disable();
dst = dst_cache_get(&slwt->cache);
local_bh_enable();
@@ -724,6 +732,7 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
if (err)
goto free_lwt_state;
+ slwt->nh_vrf = !!tb[SEG6_IPTUNNEL_NH_VRF];
memcpy(&slwt->tuninfo, tuninfo, tuninfo_len);
if (tb[SEG6_IPTUNNEL_SRC]) {
@@ -775,6 +784,10 @@ static int seg6_fill_encap_info(struct sk_buff *skb,
nla_put_in6_addr(skb, SEG6_IPTUNNEL_SRC, &slwt->tunsrc))
return -EMSGSIZE;
+ if (slwt->nh_vrf &&
+ nla_put_flag(skb, SEG6_IPTUNNEL_NH_VRF))
+ return -EMSGSIZE;
+
return 0;
}
@@ -786,9 +799,14 @@ static int seg6_encap_nlsize(struct lwtunnel_state *lwtstate)
nlsize = nla_total_size(SEG6_IPTUN_ENCAP_SIZE(tuninfo));
+ /* SEG6_IPTUNNEL_SRC */
if (!ipv6_addr_any(&slwt->tunsrc))
nlsize += nla_total_size(sizeof(slwt->tunsrc));
+ /* SEG6_IPTUNNEL_NH_VRF */
+ if (slwt->nh_vrf)
+ nlsize += nla_total_size(0);
+
return nlsize;
}
@@ -803,7 +821,8 @@ static int seg6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
if (len != SEG6_IPTUN_ENCAP_SIZE(b_hdr))
return 1;
- if (!ipv6_addr_equal(&a_slwt->tunsrc, &b_slwt->tunsrc))
+ if (!ipv6_addr_equal(&a_slwt->tunsrc, &b_slwt->tunsrc) ||
+ a_slwt->nh_vrf != b_slwt->nh_vrf)
return 1;
return memcmp(a_hdr, b_hdr, len);
diff --git a/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh b/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh
index a5e959a080bb..abf0a523518a 100755
--- a/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh
+++ b/tools/testing/selftests/net/srv6_end_dt46_l3vpn_test.sh
@@ -201,6 +201,7 @@ readonly IPv6_HS_NETWORK=cafe
readonly IPv4_HS_NETWORK=10.0.0
readonly VPN_LOCATOR_SERVICE=fc00
PING_TIMEOUT_SEC=4
+NH_VRF_FLAG=
ret=0
@@ -319,6 +320,7 @@ setup_vpn_config()
local hsdst=$3
local rtdst=$4
local tid=$5
+ local vrf=
eval local rtsrc_name=\${rt_${rtsrc}}
eval local rtdst_name=\${rt_${rtdst}}
@@ -330,10 +332,11 @@ setup_vpn_config()
# set the encap route for encapsulating packets which arrive from the
# host hssrc and destined to the access router rtsrc.
ip -netns ${rtsrc_name} -6 route add ${IPv6_HS_NETWORK}::${hsdst}/128 vrf vrf-${tid} \
- encap seg6 mode encap segs ${vpn_sid} dev veth0
+ encap seg6 mode encap segs ${vpn_sid} ${NH_VRF_FLAG} dev veth0
ip -netns ${rtsrc_name} -4 route add ${IPv4_HS_NETWORK}.${hsdst}/32 vrf vrf-${tid} \
- encap seg6 mode encap segs ${vpn_sid} dev veth0
- ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 vrf vrf-${tid} \
+ encap seg6 mode encap segs ${vpn_sid} ${NH_VRF_FLAG} dev veth0
+ [ -z ${NH_VRF_FLAG} ] && vrf="vrf vrf-${tid}"
+ ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 ${vrf} \
via fd00::${rtdst} dev veth0
# set the decap route for decapsulating packets which arrive from
@@ -536,6 +539,26 @@ host_vpn_isolation_tests()
done
}
+# check if the nh-vrf flag is supported
+check_nh_vrf_support()
+{
+ setup_ns nh_vrf_ns
+
+ if ! ip -netns "${nh_vrf_ns}" nexthop add id 1235 encap seg6 \
+ mode encap nh-vrf segs 2001:db8:1:1:1::2 dev lo &>/dev/null; then
+ cleanup_ns "${nh_vrf_ns}"
+ return
+ fi
+
+ if ! ip -netns "${nh_vrf_ns}" nexthop get id 1235 &>/dev/null; then
+ cleanup_ns "${nh_vrf_ns}"
+ return
+ fi
+
+ cleanup_ns "${nh_vrf_ns}"
+ NH_VRF_FLAG="nh-vrf"
+}
+
if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges"
exit $ksft_skip
@@ -554,6 +577,12 @@ fi
cleanup &>/dev/null
+check_nh_vrf_support
+if [ -z ${NH_VRF_FLAG} ]; then
+ echo "nh-vrf support: no"
+else
+ echo "nh-vrf support: yes"
+fi
setup
router_tests
diff --git a/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh b/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh
index a649dba3cb77..e1ae80bcb86d 100755
--- a/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh
+++ b/tools/testing/selftests/net/srv6_end_dt4_l3vpn_test.sh
@@ -170,6 +170,7 @@ readonly IPv6_RT_NETWORK=fd00
readonly IPv4_HS_NETWORK=10.0.0
readonly VPN_LOCATOR_SERVICE=fc00
PING_TIMEOUT_SEC=4
+NH_VRF_FLAG=
ret=0
@@ -278,6 +279,7 @@ setup_vpn_config()
local hsdst=$3
local rtdst=$4
local tid=$5
+ local vrf=
eval local rtsrc_name=\${rt_${rtsrc}}
eval local rtdst_name=\${rt_${rtdst}}
@@ -286,8 +288,9 @@ setup_vpn_config()
# set the encap route for encapsulating packets which arrive from the
# host hssrc and destined to the access router rtsrc.
ip -netns ${rtsrc_name} -4 route add ${IPv4_HS_NETWORK}.${hsdst}/32 vrf vrf-${tid} \
- encap seg6 mode encap segs ${vpn_sid} dev veth0
- ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 vrf vrf-${tid} \
+ encap seg6 mode encap segs ${vpn_sid} ${NH_VRF_FLAG} dev veth0
+ [ -z ${NH_VRF_FLAG} ] && vrf="vrf vrf-${tid}"
+ ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 ${vrf} \
via fd00::${rtdst} dev veth0
# set the decap route for decapsulating packets which arrive from
@@ -459,6 +462,26 @@ host_vpn_isolation_tests()
done
}
+# check if the nh-vrf flag is supported
+check_nh_vrf_support()
+{
+ setup_ns nh_vrf_ns
+
+ if ! ip -netns "${nh_vrf_ns}" nexthop add id 1235 encap seg6 \
+ mode encap nh-vrf segs 2001:db8:1:1:1::2 dev lo &>/dev/null; then
+ cleanup_ns "${nh_vrf_ns}"
+ return
+ fi
+
+ if ! ip -netns "${nh_vrf_ns}" nexthop get id 1235 &>/dev/null; then
+ cleanup_ns "${nh_vrf_ns}"
+ return
+ fi
+
+ cleanup_ns "${nh_vrf_ns}"
+ NH_VRF_FLAG="nh-vrf"
+}
+
if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges"
exit $ksft_skip
@@ -477,6 +500,12 @@ fi
cleanup &>/dev/null
+check_nh_vrf_support
+if [ -z ${NH_VRF_FLAG} ]; then
+ echo "nh-vrf support: no"
+else
+ echo "nh-vrf support: yes"
+fi
setup
router_tests
diff --git a/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh b/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh
index e408406d8489..3a8ff96a78ef 100755
--- a/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh
+++ b/tools/testing/selftests/net/srv6_end_dt6_l3vpn_test.sh
@@ -171,6 +171,7 @@ readonly IPv6_RT_NETWORK=fd00
readonly IPv6_HS_NETWORK=cafe
readonly VPN_LOCATOR_SERVICE=fc00
PING_TIMEOUT_SEC=4
+NH_VRF_FLAG=
ret=0
@@ -285,6 +286,7 @@ setup_vpn_config()
local hsdst=$3
local rtdst=$4
local tid=$5
+ local vrf=
eval local rtsrc_name=\${rt_${rtsrc}}
eval local rtdst_name=\${rt_${rtdst}}
@@ -296,8 +298,9 @@ setup_vpn_config()
# set the encap route for encapsulating packets which arrive from the
# host hssrc and destined to the access router rtsrc.
ip -netns ${rtsrc_name} -6 route add ${IPv6_HS_NETWORK}::${hsdst}/128 vrf vrf-${tid} \
- encap seg6 mode encap segs ${vpn_sid} dev veth0
- ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 vrf vrf-${tid} \
+ encap seg6 mode encap segs ${vpn_sid} ${NH_VRF_FLAG} dev veth0
+ [ -z ${NH_VRF_FLAG} ] && vrf="vrf vrf-${tid}"
+ ip -netns ${rtsrc_name} -6 route add ${vpn_sid}/128 ${vrf} \
via fd00::${rtdst} dev veth0
# set the decap route for decapsulating packets which arrive from
@@ -469,6 +472,26 @@ host_vpn_isolation_tests()
done
}
+# check if the nh-vrf flag is supported
+check_nh_vrf_support()
+{
+ setup_ns nh_vrf_ns
+
+ if ! ip -netns "${nh_vrf_ns}" nexthop add id 1235 encap seg6 \
+ mode encap nh-vrf segs 2001:db8:1:1:1::2 dev lo &>/dev/null; then
+ cleanup_ns "${nh_vrf_ns}"
+ return
+ fi
+
+ if ! ip -netns "${nh_vrf_ns}" nexthop get id 1235 &>/dev/null; then
+ cleanup_ns "${nh_vrf_ns}"
+ return
+ fi
+
+ cleanup_ns "${nh_vrf_ns}"
+ NH_VRF_FLAG="nh-vrf"
+}
+
if [ "$(id -u)" -ne 0 ];then
echo "SKIP: Need root privileges"
exit $ksft_skip
@@ -487,6 +510,12 @@ fi
cleanup &>/dev/null
+check_nh_vrf_support
+if [ -z ${NH_VRF_FLAG} ]; then
+ echo "nh-vrf support: no"
+else
+ echo "nh-vrf support: yes"
+fi
setup
router_tests
--
2.52.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-03-27 14:07 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-27 14:06 [PATCH net-next v2] seg6: enable route leak for encap routes Nicolas Dichtel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox