mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next 0/5] seg6: fixes for the PSP flavor of SRv6 End
@ 2026-10-11 19:23 Andrea Mayer
  2026-10-11 19:23 ` [PATCH net-next 1/5] seg6: handle a Fragment or AH header before the SRH consistently in PSP Andrea Mayer
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Andrea Mayer @ 2026-10-11 19:23 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman
  Cc: netdev, linux-kernel, linux-kselftest, Shuah Khan, Hangbin Liu,
	Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano, Andrea Mayer

This series addresses three related issues of the PSP flavor in the
SRv6 End behavior, all present since commit bdf3c0b9c10b ("seg6: add PSP
flavor support for SRv6 End behavior"). The three fixes build on each
other.

The main one is a route with both the NEXT-C-SID and PSP flavors.
RFC 9800 says that the PSP flavor is unchanged when combined with
NEXT-C-SID (NEXT-CSID in the RFC) [1]. Currently, a packet with a zero
Argument (i.e. when the IPv6 DA carries no further C-SID) is processed
as End without flavors, and PSP is not applied. With this series, such
a packet is processed as End with PSP.

The other two are:

 - A consumed SRH (Segments Left 0) before the SRH to process. This is
   a corner case, e.g. when the seg6 inline mode inserts an SRH in front
   of the one already in the packet, and a later End behavior consumes
   the inserted SRH. End without flavors skips the consumed SRH, while
   End with the PSP flavor alone drops the packet. With this series, End
   with PSP skips the consumed SRH as well.

 - A Fragment or AH header before the SRH. This order does not follow
   RFC 8200 [2] for the Fragment header and RFC 4302 [3] for AH. At the
   penultimate segment, End with the PSP flavor alone handles it
   inconsistently: it drops the packet when other headers come between
   the Fragment or AH header and the SRH, but removes the SRH when
   nothing comes between them. With this series, End with PSP drops the
   packet in both cases. Packets with the Fragment or AH header after
   the SRH are not affected by patch 1/5.

The series is organized as follows:

 - Patch 1/5 fixes the Fragment or AH header case.
 - Patch 2/5 fixes the consumed SRH case. It relies on patch 1/5.
 - Patch 3/5 fixes the NEXT-C-SID and PSP route. It relies on patch 2/5.
 - Patch 4/5 adds the selftests for PSP together with NEXT-C-SID.
 - Patch 5/5 adds the selftests for PSP with a consumed SRH.

The series targets net-next because the three issues have been there
since PSP was added.

Tested on net-next with the srv6_*.sh selftests, including the new tests
of patches 4/5 and 5/5. The ping traffic of srv6_end_flavors_test.sh has
no Fragment or AH header before the SRH. For this reason, patch 1/5 was
also tested with crafted packets. KASAN reports no error.

[1] - https://datatracker.ietf.org/doc/html/rfc9800#section-4.1.7
[2] - https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
[3] - https://datatracker.ietf.org/doc/html/rfc4302#section-3.1.1

Thanks,
Andrea

Andrea Mayer (5):
  seg6: handle a Fragment or AH header before the SRH consistently in
    PSP
  seg6: handle a consumed SRH in SRv6 End with the PSP flavor
  seg6: apply the PSP flavor together with NEXT-C-SID in SRv6 End
  selftests: seg6: add tests for PSP together with NEXT-C-SID
  selftests: seg6: add tests for PSP with a consumed SRH

 net/ipv6/seg6_local.c                         |  87 +++-
 .../selftests/net/srv6_end_flavors_test.sh    | 373 +++++++++++++++++-
 2 files changed, 444 insertions(+), 16 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH net-next 1/5] seg6: handle a Fragment or AH header before the SRH consistently in PSP
  2026-10-11 19:23 [PATCH net-next 0/5] seg6: fixes for the PSP flavor of SRv6 End Andrea Mayer
@ 2026-10-11 19:23 ` Andrea Mayer
  2026-10-12  7:59   ` Hangbin Liu
  2026-10-11 19:23 ` [PATCH net-next 2/5] seg6: handle a consumed SRH in SRv6 End with the PSP flavor Andrea Mayer
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Andrea Mayer @ 2026-10-11 19:23 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman
  Cc: netdev, linux-kernel, linux-kselftest, Shuah Khan, Hangbin Liu,
	Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano, Andrea Mayer

seg6_pop_srh() already fails when a Fragment or AH header comes before
the SRH with other headers in between, and the packet is dropped ("we
expect SRH before FRAG and AUTH" in the code). But when the SRH directly
follows the Fragment or AH header, it is removed:

  (a) IPv6 | FRAG/AH | DOPT | SRH | ...   the packet is dropped
  (b) IPv6 | FRAG/AH | SRH | ...          the SRH is removed

In both packets the Fragment or AH header comes before the SRH.

Align the two cases: check first whether a header is a Fragment or AH
header, and only then look at its Next Header field. In this way, the
packet is dropped also when the Fragment or AH header comes directly
before the SRH. A Fragment or AH header before the SRH, with or without
other headers in between, does not follow RFC 8200 and RFC 4302: a
Fragment header must not come before the Routing header, as the
Per-Fragment headers must include the Routing header [1], and AH should
not come before the routing and fragmentation headers [2].

At the penultimate segment, End with the PSP flavor alone today drops
(a) and forwards (b) with the SRH removed. Packets with the Fragment or
AH header after the SRH are not affected: seg6_pop_srh() does not look
at the headers after the SRH.

Found by manual code inspection and reproduced in a VM without kernel
changes or error injection, by sending to End with PSP the packets
shown in the diagram, both with a Fragment header and with AH. With this
change, the packets are dropped in both cases, all tests in
srv6_end_flavors_test.sh pass, and KASAN reports no error. With the
whole series, all the srv6_*.sh selftests pass.

[1] - https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
[2] - https://datatracker.ietf.org/doc/html/rfc4302#section-3.1.1

Fixes: bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End behavior")
Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
---
 net/ipv6/seg6_local.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index 0c3d1be7f129..da8225591fe3 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -796,11 +796,6 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
 			if (unlikely(!hp))
 				return false;
 
-			if (hp->nexthdr == NEXTHDR_ROUTING) {
-				hp->nexthdr = srh_nexthdr;
-				break;
-			}
-
 			switch (nexthdr) {
 			case NEXTHDR_FRAGMENT:
 				fallthrough;
@@ -812,6 +807,11 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
 				break;
 			}
 
+			if (hp->nexthdr == NEXTHDR_ROUTING) {
+				hp->nexthdr = srh_nexthdr;
+				break;
+			}
+
 			nexthdr = hp->nexthdr;
 		}
 	}
-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH net-next 2/5] seg6: handle a consumed SRH in SRv6 End with the PSP flavor
  2026-10-11 19:23 [PATCH net-next 0/5] seg6: fixes for the PSP flavor of SRv6 End Andrea Mayer
  2026-10-11 19:23 ` [PATCH net-next 1/5] seg6: handle a Fragment or AH header before the SRH consistently in PSP Andrea Mayer
@ 2026-10-11 19:23 ` Andrea Mayer
  2026-10-12  9:28   ` Hangbin Liu
  2026-10-11 19:23 ` [PATCH net-next 3/5] seg6: apply the PSP flavor together with NEXT-C-SID in SRv6 End Andrea Mayer
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Andrea Mayer @ 2026-10-11 19:23 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman
  Cc: netdev, linux-kernel, linux-kselftest, Shuah Khan, Hangbin Liu,
	Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano, Andrea Mayer

With the seg6 inline mode, a packet can carry more than one SRH. The
SRHs with Segments Left 0 are considered consumed SRHs, and they can
come before the SRH to process (Segments Left > 0), as in this packet:

  +------+----------------------+----------------------+---------+
  | IPv6 | SRH, Segments Left 0 | SRH, Segments Left 1 | payload |
  +------+----------------------+----------------------+---------+

End without flavors skips the consumed SRH and processes the next
one [1]. With the PSP flavor, End should do the same. When the SRH to
process arrives with Segments Left 1, as in the diagram, End with PSP
should then also remove it [2]. However, End with PSP alone currently
looks only at the first routing header of the packet, finds Segments
Left 0 there, and drops the packet.

Make End with PSP alone skip the consumed SRHs, and any other routing
header with Segments Left 0, and process the SRH that follows them. If
there is no SRH to process, the packet is dropped as before. When the
SRH to process arrives with Segments Left 1, End with PSP now removes
it even if consumed SRHs come before it.

Found by manual code inspection and reproduced in a VM without kernel
changes or error injection. A following commit adds tests for this case
to srv6_end_flavors_test.sh. Without this change, the new tests with a
consumed SRH fail for End with PSP alone. With this series, all tests
pass and KASAN reports no error.

[1] - https://datatracker.ietf.org/doc/html/rfc8986#section-4.1
[2] - https://datatracker.ietf.org/doc/html/rfc8986#section-4.16.1.2

Fixes: bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End behavior")
Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
---
 net/ipv6/seg6_local.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index da8225591fe3..26cd4facbe36 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -775,11 +775,14 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
 		skb_set_transport_header(skb, thoff);
 
 	iph = ipv6_hdr(skb);
-	if (iph->nexthdr == NEXTHDR_ROUTING) {
+	if (srhoff == sizeof(*iph)) {
 		iph->nexthdr = srh_nexthdr;
 	} else {
 		/* we must look for the extension header (EXTH, for short) that
-		 * immediately precedes the SRH we have just removed.
+		 * immediately precedes the SRH we have just removed, i.e. the
+		 * EXTH that ends at srhoff. We find it by its position and not
+		 * by its nexthdr, since another routing header (e.g. an SRH
+		 * with SL = 0) may come before the removed SRH.
 		 * Then, we update the value of the EXTH nexthdr with the one
 		 * contained in the SRH nexthdr.
 		 */
@@ -807,7 +810,7 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
 				break;
 			}
 
-			if (hp->nexthdr == NEXTHDR_ROUTING) {
+			if (off == srhoff) {
 				hp->nexthdr = srh_nexthdr;
 				break;
 			}
@@ -823,6 +826,24 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
 	return true;
 }
 
+/* look up the SRH to be processed by the RFC8986 flavors. As End does, a
+ * routing header with SL = 0 is skipped (e.g. an SRH already consumed).
+ * This function returns NULL when no valid SRH is found.
+ */
+static struct ipv6_sr_hdr *seg6_flv8986_get_srh(struct sk_buff *skb)
+{
+	struct ipv6_sr_hdr *srh;
+
+	srh = seg6_get_srh(skb, IP6_FH_F_SKIP_RH);
+	if (srh)
+		return srh;
+
+	/* we take the first routing header without skipping it. In this way,
+	 * seg6_get_srh_pktinfo() reports SL = 0 and not a missing SRH.
+	 */
+	return seg6_get_srh(skb, 0);
+}
+
 /* process the packet on the basis of the RFC8986 flavors set for the given
  * SRv6 End behavior instance.
  */
@@ -837,7 +858,7 @@ static int end_flv8986_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 	__u32 flvmask;
 	int srhoff;
 
-	srh = seg6_get_srh(skb, 0);
+	srh = seg6_flv8986_get_srh(skb);
 	srhoff = srh ? ((unsigned char *)srh - skb->data) : 0;
 	pinfo = seg6_get_srh_pktinfo(srh);
 #ifdef CONFIG_IPV6_SEG6_HMAC
-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH net-next 3/5] seg6: apply the PSP flavor together with NEXT-C-SID in SRv6 End
  2026-10-11 19:23 [PATCH net-next 0/5] seg6: fixes for the PSP flavor of SRv6 End Andrea Mayer
  2026-10-11 19:23 ` [PATCH net-next 1/5] seg6: handle a Fragment or AH header before the SRH consistently in PSP Andrea Mayer
  2026-10-11 19:23 ` [PATCH net-next 2/5] seg6: handle a consumed SRH in SRv6 End with the PSP flavor Andrea Mayer
@ 2026-10-11 19:23 ` Andrea Mayer
  2026-10-12  8:17   ` Hangbin Liu
  2026-10-11 19:23 ` [PATCH net-next 4/5] selftests: seg6: add tests for PSP together with NEXT-C-SID Andrea Mayer
  2026-10-11 19:23 ` [PATCH net-next 5/5] selftests: seg6: add tests for PSP with a consumed SRH Andrea Mayer
  4 siblings, 1 reply; 11+ messages in thread
From: Andrea Mayer @ 2026-10-11 19:23 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman
  Cc: netdev, linux-kernel, linux-kselftest, Shuah Khan, Hangbin Liu,
	Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano, Andrea Mayer

Since commit bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End
behavior"), an SRv6 End route can be set up with both the NEXT-C-SID and
the PSP flavors, e.g.:

  ip -6 route add fcbb:0:100::/48 encap seg6local action End \
          flavors next-csid,psp lblen 32 nflen 16 dev dum0

In RFC 9800, the NEXT-C-SID flavor (NEXT-CSID in the RFC) changes the
End processing only when the Argument is not zero [1]. With a zero
Argument (i.e. when the IPv6 DA carries no further C-SID), End is
processed as in RFC 8986, and the PSP flavor (when set) applies
unchanged [2]. If the packet arrives with Segments Left 1, PSP must
then remove the SRH.

However, on a route with both the NEXT-C-SID and PSP flavors,
input_action_end() always uses the NEXT-C-SID processing. The
NEXT-C-SID processing handles a packet with a zero Argument as End
without flavors, ignoring PSP. Therefore, if this packet arrives with
Segments Left 1, the SRH is not removed.

Fix this by using the NEXT-C-SID processing only when the Argument is
not zero or the route has no RFC 8986 flavor. Otherwise, the packet is
processed as End with its RFC 8986 flavors, in end_flv8986_core(). With
a zero Argument and Segments Left 1, PSP now removes the SRH before the
packet is forwarded. If seg6_pop_srh() cannot remove the SRH, the packet
is dropped, as on a route with the PSP flavor alone.

Found by manual code inspection and reproduced in a VM without kernel
changes or error injection. A following commit adds tests for this case
to srv6_end_flavors_test.sh. The tests reproduce the issue: they fail
without this change and pass with it.

[1] - https://datatracker.ietf.org/doc/html/rfc9800#section-4.1.1
[2] - https://datatracker.ietf.org/doc/html/rfc9800#section-4.1.7

Fixes: bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End behavior")
Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
---
 net/ipv6/seg6_local.c | 50 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 47 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index 26cd4facbe36..427d12fedfc3 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -551,6 +551,47 @@ static bool seg6_next_csid_enabled(__u32 fops)
 	return fops & SEG6_F_LOCAL_FLV_NEXT_CSID;
 }
 
+static bool seg6_flv8986_enabled(__u32 fops)
+{
+	return fops & SEG6_LOCAL_FLV8986_SUPP_OPS;
+}
+
+/* check whether the NEXT-C-SID processing has to be used for the packet,
+ * instead of the RFC8986 flavors set for the given SRv6 End* behavior
+ * instance.
+ *
+ * This function returns:
+ *  - true, when the packet has to go through the NEXT-C-SID processing;
+ *  - false, when NEXT-C-SID is not configured or the packet has to be
+ *    processed on the basis of the RFC8986 flavors.
+ */
+static bool seg6_use_next_csid(struct sk_buff *skb,
+			       const struct seg6_flavors_info *finfo)
+{
+	const struct in6_addr *addr;
+	__u32 fops = finfo->flv_ops;
+
+	if (!seg6_next_csid_enabled(fops))
+		return false;
+
+	addr = &ipv6_hdr(skb)->daddr;
+
+	/* NEXT-C-SID and the RFC8986 flavors combine according to the
+	 * DA.Argument (see RFC9800, sections 4.1.1 and 4.1.7):
+	 *
+	 *       DA.Argument   RFC8986 flavors   processing
+	 *   (1) != 0          any               NEXT-C-SID only, SL unchanged
+	 *   (2) == 0          none              the behavior, e.g. End
+	 *   (3) == 0          one or more       the behavior with its flavors,
+	 *                                       e.g. End with PSP
+	 *
+	 * In (2), the packet still goes through the NEXT-C-SID processing,
+	 * which runs the behavior (e.g. End) when the DA.Argument is zero.
+	 */
+	return !seg6_flv8986_enabled(fops) ||
+	       !seg6_next_csid_is_arg_zero(addr, finfo);
+}
+
 /* Processing of SRv6 End, End.X, and End.T behaviors can be extended through
  * the flavors framework. These behaviors must report the subset of (flavor)
  * operations they currently implement. In this way, if a user specifies a
@@ -865,7 +906,10 @@ static int end_flv8986_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 	if (srh && !seg6_hmac_validate_skb(skb, srh))
 		goto drop;
 #endif
-	flvmask = finfo->flv_ops;
+	/* NEXT-C-SID, when configured, has already been evaluated by the
+	 * caller. Only the RFC8986 flavors are left here.
+	 */
+	flvmask = finfo->flv_ops & ~SEG6_F_LOCAL_FLV_NEXT_CSID;
 	if (unlikely(flvmask & ~SEG6_LOCAL_FLV8986_SUPP_OPS)) {
 		pr_warn_once("seg6local: invalid RFC8986 flavors\n");
 		goto drop;
@@ -919,8 +963,8 @@ static int input_action_end(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 	if (!fops)
 		return input_action_end_core(skb, slwt);
 
-	/* check for the presence of NEXT-C-SID since it applies first */
-	if (seg6_next_csid_enabled(fops))
+	/* NEXT-C-SID is evaluated first, when configured */
+	if (seg6_use_next_csid(skb, finfo))
 		return end_next_csid_core(skb, slwt);
 
 	/* the specific processing function to be performed on the packet
-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH net-next 4/5] selftests: seg6: add tests for PSP together with NEXT-C-SID
  2026-10-11 19:23 [PATCH net-next 0/5] seg6: fixes for the PSP flavor of SRv6 End Andrea Mayer
                   ` (2 preceding siblings ...)
  2026-10-11 19:23 ` [PATCH net-next 3/5] seg6: apply the PSP flavor together with NEXT-C-SID in SRv6 End Andrea Mayer
@ 2026-10-11 19:23 ` Andrea Mayer
  2026-10-12  7:54   ` Hangbin Liu
  2026-10-11 19:23 ` [PATCH net-next 5/5] selftests: seg6: add tests for PSP with a consumed SRH Andrea Mayer
  4 siblings, 1 reply; 11+ messages in thread
From: Andrea Mayer @ 2026-10-11 19:23 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman
  Cc: netdev, linux-kernel, linux-kselftest, Shuah Khan, Hangbin Liu,
	Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano, Andrea Mayer

Extend srv6_end_flavors_test.sh with tests for the SRv6 End behavior
with both the NEXT-C-SID and PSP flavors.

The tests use two SRv6 Policies with C-SID containers, where every
router after the ingress one applies End with the NEXT-C-SID and PSP
flavors. To check PSP, set net.ipv6.conf.all.seg6_enabled to 0 on the
hosts in setup_hs(). The hosts then drop any packet that still carries
an SRH, and a ping to an address on the loopback of a host succeeds
only if the router connected to that host has removed the SRH. The tests
fail when PSP is not applied together with NEXT-C-SID.

Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
---
 .../selftests/net/srv6_end_flavors_test.sh    | 229 +++++++++++++++++-
 1 file changed, 226 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/net/srv6_end_flavors_test.sh b/tools/testing/selftests/net/srv6_end_flavors_test.sh
index 30a939392eea..baa1b09a1aab 100755
--- a/tools/testing/selftests/net/srv6_end_flavors_test.sh
+++ b/tools/testing/selftests/net/srv6_end_flavors_test.sh
@@ -16,8 +16,9 @@
 #
 # The End, End.X, and End.T behaviors can support these flavors either
 # individually or in combinations.
-# Currently in this selftest we consider only the PSP flavor for the SRv6 End
-# behavior. However, it is possible to extend the script as soon as other
+# Currently in this selftest we consider the PSP flavor for the SRv6 End
+# behavior, both alone and combined with the NEXT-C-SID flavor defined in
+# RFC9800 [2]. However, it is possible to extend the script as soon as other
 # flavors will be supported in the kernel.
 #
 # The purpose of the PSP flavor consists in instructing the penultimate node
@@ -47,7 +48,20 @@
 #    "standard" End packet processing, ignoring the configured PSP flavor at
 #    all.
 #
+# The NEXT-C-SID flavor (referred to as NEXT-CSID in RFC9800 [2]) and the
+# C-SID containers are described in srv6_end_next_csid_l3vpn_test.sh, which
+# also tests this flavor for the SRv6 End behavior.
+#
+# When the NEXT-C-SID flavor is combined with the PSP, USP or USD flavors, these
+# flavors are left unchanged [2]. The NEXT-C-SID processing comes first: with a
+# non-zero Argument, the IPv6 DA is updated with the next C-SID and the packet
+# is forwarded without changing the SRH, if any. The packet goes through the End
+# behavior with the other flavors only when the Argument is zero, i.e. when the
+# IPv6 DA carries no further C-SID. For example, the PSP operation takes place
+# only for a C-SID container with a zero Argument and SL=1.
+#
 # [1] RFC8986: https://datatracker.ietf.org/doc/html/rfc8986
+# [2] RFC9800: https://datatracker.ietf.org/doc/html/rfc9800
 #
 # Network topology
 # ================
@@ -115,12 +129,30 @@
 #   +---------------------------------------------------------------------+
 #   |fcff:x::e is associated with the SRv6 End behavior                   |
 #   |fcff:x::ef1 is associated with the SRv6 End behavior with PSP flavor |
+#   |fcbb:0:0xyy::/48 is associated with the SRv6 behavior and the        |
+#   |   flavors of the Function yy                                        |
 #   +---------------------------------------------------------------------+
 #
 # The fcff::/16 prefix is reserved by the operator for the SIDs. Reachability of
 # SIDs is ensured by proper configuration of the IPv6 operator's network and
 # SRv6 routers.
 #
+# Similarly, the fcbb:0::/32 prefix is reserved by the operator for the C-SID
+# containers and it is used as their Locator-Block.
+# A C-SID (16 bits) is made of the Locator-Node (8 bits), i.e. the ID of the
+# router, followed by the Function (8 bits). The first digit of the Function
+# selects the SRv6 behavior and the second one the flavors combined with
+# NEXT-C-SID:
+#
+#   +----------+----------+--------------------+
+#   | Function | behavior | flavors            |
+#   +----------+----------+--------------------+
+#   | a1       | End      | NEXT-C-SID and PSP |
+#   +----------+----------+--------------------+
+#
+# For example, fcbb:0:04a1:02a1:: is a C-SID container carrying the C-SID of
+# rt-4 followed by the C-SID of rt-2, both with the NEXT-C-SID and PSP flavors.
+#
 #
 # SRv6 Policies
 # =============
@@ -193,6 +225,39 @@
 # set with the last SID; iii) the SRH is removed from the extension headers
 # after the IPv6 header. At this point, the packet with IPv6 DA=cafe::1 is sent
 # to the destination, i.e. hs-1.
+#
+# Traffic to the loopback addresses of the hosts
+# ----------------------------------------------
+#
+# Each host has an address on its loopback, cafe::x:a1. The traffic from the
+# other host towards this address is steered with C-SID containers: after the
+# ingress router, every router crossed applies the SRv6 End behavior with the
+# NEXT-C-SID and PSP flavors. The following SRv6 Policies are applied by rt-1
+# to the traffic towards cafe::2:a1 (i.c) and by rt-2 to the traffic towards
+# cafe::1:a1 (i.d):
+#
+#   i.c) IPv6 traffic, SID List=fcbb:0:03a1::,fcbb:0:04a1:02a1::,cafe::2:a1
+#   i.d) IPv6 traffic, SID List=fcbb:0:04a1:03a1:01a1::,cafe::1:a1
+#
+# In the Policy (i.c), rt-3 receives a zero Argument with SL=2 and applies the
+# "standard" End processing. rt-4 receives a non-zero Argument with SL=1: it
+# advances to the next C-SID and does *NOT* apply the PSP operation. rt-2
+# receives a zero Argument with SL=1 and applies the PSP operation.
+#
+# In the Policy (i.d), a single C-SID container carries three C-SIDs. rt-4 and
+# rt-3 receive a non-zero Argument with SL=1: they advance to the next C-SID and
+# do *NOT* apply the PSP operation. rt-1 receives a zero Argument with SL=1
+# and applies the PSP operation.
+#
+# The hosts use cafe::x as the source address, not the loopback address. The
+# replies are sent to cafe::x and follow the Policies (i.a) and (i.b), which
+# are tested first. This way, each ping checks a single Policy with the
+# NEXT-C-SID flavor, and a failure points directly to that Policy.
+#
+# The hosts drop the packets that carry an SRH (seg6_enabled is set to 0 on
+# the hosts). The loopback address of a host is reached only through the
+# router connected to that host: the ping succeeds only if the SRH is removed
+# by that router.
 
 # shellcheck source=lib.sh
 source lib.sh
@@ -207,6 +272,17 @@ readonly IPv6_TESTS_ADDR=2001:db8::1
 readonly LOCATOR_SERVICE=fcff
 readonly END_FUNC=000e
 readonly END_PSP_FUNC=0ef1
+readonly END_CSID_PSP_FUNC=a1
+
+readonly LCBLOCK_ADDR=fcbb:0
+readonly LCBLOCK_BLEN=32
+# do not add ':' as separator
+readonly LCNODE_FMT="0%d"
+readonly LCNODE_BLEN=8
+readonly LCNODEFUNC_BLEN=16
+
+readonly LCBLOCK_NODE_BLEN=$((LCBLOCK_BLEN + LCNODE_BLEN))
+readonly LCBLOCK_NODEFUNC_BLEN=$((LCBLOCK_BLEN + LCNODEFUNC_BLEN))
 
 PING_TIMEOUT_SEC=4
 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
@@ -397,6 +473,40 @@ __get_srv6_rtcfg_op()
 		xargs | sed 's/ /,/g'
 }
 
+# Given the ID of a router and a Function, the function returns the C-SID made
+# of the Locator-Node (8 bits), i.e. the ID of the router, followed by the
+# Function (8 bits).
+# e.g. input: "4" "a1"
+#      output: "04a1"
+build_csid()
+{
+	local nodeid="$1"
+	local func="$2"
+
+	printf "${LCNODE_FMT}%s" "${nodeid}" "${func}"
+}
+
+# Given the <nodeid> token of a "next-csid,<flavors>" element, i.e. a
+# comma-separated list of node IDs, and a Function, the function returns the
+# C-SID container carrying the C-SIDs of these nodes.
+# e.g. input: "4,2" "a1"
+#      output: "fcbb:0:04a1:02a1::"
+build_csid_container()
+{
+	local nodeids="$1"
+	local func="$2"
+	local csids=''
+	local nodes
+	local node
+
+	nodes="$(echo "${nodeids}" | sed 's/,/ /g')"
+	for node in ${nodes}; do
+		csids="${csids}:$(build_csid "${node}" "${func}")"
+	done
+
+	echo "${LCBLOCK_ADDR}${csids}::"
+}
+
 # Setup the basic networking for the routers
 setup_rt_networking()
 {
@@ -439,6 +549,7 @@ setup_rt_local_sids()
 	local devname
 	local nsname
 	local neigh
+	local csid
 
 	nsname="$(get_rtname "${rt}")"
 
@@ -452,6 +563,14 @@ setup_rt_local_sids()
 			add "${LOCATOR_SERVICE}:${neigh}::/32" \
 			table "${LOCALSID_TABLE_ID}" \
 			via "${net_prefix}::${neigh}" dev "${devname}"
+
+		# set underlay network routes to reach the C-SID containers
+		# that start with a C-SID of the neighbor, for any Function.
+		csid="$(build_csid "${neigh}" 00)"
+		ip -netns "${nsname}" -6 route \
+			add "${LCBLOCK_ADDR}:${csid}::/${LCBLOCK_NODE_BLEN}" \
+			table "${LOCALSID_TABLE_ID}" \
+			via "${net_prefix}::${neigh}" dev "${devname}"
 	done
 
 	# Local End behavior (note that "dev" is a dummy interface chosen for
@@ -461,6 +580,17 @@ setup_rt_local_sids()
 		table "${LOCALSID_TABLE_ID}" \
 		encap seg6local action End dev "${DUMMY_DEVNAME}"
 
+	# Local End behavior with the NEXT-C-SID and PSP flavors, bound to the
+	# C-SID of the router (e.g. fcbb:0:04a1::/48 on rt-4). The /48 prefix
+	# covers every C-SID container whose first C-SID is this one, whatever
+	# the Argument that follows.
+	csid="$(build_csid "${rt}" "${END_CSID_PSP_FUNC}")"
+	ip -netns "${nsname}" -6 route \
+		add "${LCBLOCK_ADDR}:${csid}::/${LCBLOCK_NODEFUNC_BLEN}" \
+		table "${LOCALSID_TABLE_ID}" \
+		encap seg6local action End flavors next-csid,psp \
+		lblen "${LCBLOCK_BLEN}" nflen "${LCNODEFUNC_BLEN}" \
+		dev "${DUMMY_DEVNAME}"
 
 	# all SIDs start with a common locator. Routes and SRv6 Endpoint
 	# behavior instances are grouped together in the 'localsid' table.
@@ -468,6 +598,12 @@ setup_rt_local_sids()
 		add to "${LOCATOR_SERVICE}::/16" \
 		lookup "${LOCALSID_TABLE_ID}" prio 999
 
+	# the C-SID containers use their own Locator-Block. Their routes and
+	# SRv6 Endpoint behavior instances are in the 'localsid' table too.
+	ip -netns "${nsname}" -6 rule \
+		add to "${LCBLOCK_ADDR}::/${LCBLOCK_BLEN}" \
+		lookup "${LOCALSID_TABLE_ID}" prio 999
+
 	# set default routes to unreachable
 	ip -netns "${nsname}" -6 route \
 		add unreachable default metric 4278198272 \
@@ -479,12 +615,16 @@ setup_rt_local_sids()
 # configures the SRv6 nodes specified in the SID List to process the traffic
 # according to the operations required by the Policy itself.
 # args:
-#  $1 - destination host (i.e. cafe::x host)
+#  $1 - destination host (i.e. cafe::x host), or x:a1 for the address
+#       cafe::x:a1 on the loopback of the host
 #  $2 - SRv6 router configured for enforcing the SRv6 Policy
 #  $3 - compact way to represent a list of SRv6 routers with their operations
 #       (i.e. behaviors) that each of them needs to perform. Every <nodeid:op>
 #       element constructs a SID that is associated with the behavior <op> on
 #       the <nodeid> node. The list of such elements forms an SRv6 Policy.
+#       For "next-csid,psp", <nodeid> is a comma-separated list of node IDs.
+#       The element constructs a C-SID container with the C-SIDs of these
+#       nodes, e.g. "4,2:next-csid,psp" gives fcbb:0:04a1:02a1::.
 __setup_rt_policy()
 {
 	local dst="$1"
@@ -494,6 +634,7 @@ __setup_rt_policy()
 	local in_nsname
 	local rt_nsname
 	local policy=''
+	local container
 	local function
 	local fullsid
 	local op_type
@@ -520,6 +661,15 @@ __setup_rt_policy()
 			behavior_cfg="End flavors psp"
 			;;
 
+		"next-csid,psp")
+			# the behavior is already set up on every router by
+			# setup_rt_local_sids.
+			container="$(build_csid_container "${node}" \
+				"${END_CSID_PSP_FUNC}")"
+			policy="${policy}${container},"
+			continue
+			;;
+
 		*)
 			break
 			;;
@@ -571,6 +721,7 @@ setup_hs()
 
 	ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.accept_dad=0
 	ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.default.accept_dad=0
+	ip netns exec "${hsname}" sysctl -wq net.ipv6.conf.all.seg6_enabled=0
 
 	ip -netns "${hsname}" link add veth0 type veth \
 		peer name "${RT2HS_DEVNAME}" netns "${rtname}"
@@ -590,6 +741,33 @@ setup_hs()
 		sysctl -wq net.ipv6.conf."${RT2HS_DEVNAME}".proxy_ndp=1
 }
 
+# Set up an address on the loopback of a host, and the route towards it on the
+# router connected to the host.
+# args:
+#  $1 - host
+#  $2 - router connected to the host
+#  $3 - suffix of the address (i.e. cafe::<host>:<suffix>)
+setup_hs_lo_addr()
+{
+	local hs="$1"
+	local rt="$2"
+	local suffix="$3"
+	local hsname
+	local rtname
+	local addr
+
+	hsname="$(get_hsname "${hs}")"
+	rtname="$(get_rtname "${rt}")"
+	addr="${IPv6_HS_NETWORK}::${hs}:${suffix}"
+
+	ip -netns "${hsname}" addr \
+		add "${addr}/128" dev lo nodad
+
+	ip -netns "${rtname}" -6 route \
+		add "${addr}" \
+		via "${IPv6_HS_NETWORK}::${hs}" dev "${RT2HS_DEVNAME}"
+}
+
 setup()
 {
 	local i
@@ -622,6 +800,11 @@ setup()
 	setup_hs 1 1
 	setup_hs 2 2
 
+	# set up the loopback addresses of the hosts used by the Policies (i.c)
+	# and (i.d).
+	setup_hs_lo_addr 1 1 "${END_CSID_PSP_FUNC}"
+	setup_hs_lo_addr 2 2 "${END_CSID_PSP_FUNC}"
+
 	# set up default SRv6 Endpoints (i.e. SRv6 End behavior)
 	setup_rt_local_sids 1 "2 3 4"
 	setup_rt_local_sids 2 "1 3 4"
@@ -645,6 +828,21 @@ setup()
 	setup_rt_policy_ipv6 2 1 "3:noflv 4:psp 2:psp"
 	setup_rt_policy_ipv6 1 2 "1:psp"
 
+	# Direction hs-1 -> hs-2 (cafe::2:a1, NEXT-C-SID and PSP flavors)
+	#  - rt-1 (SRv6 H.Insert policy)
+	#  - rt-3 (Argument=0 and SL>1, acting as an End behavior)
+	#  - rt-4 (Argument!=0 and SL=1, advancing the C-SID)
+	#  - rt-2 (Argument=0 and SL=1, PSP)
+	#
+	# Direction hs-2 -> hs-1 (cafe::1:a1, NEXT-C-SID and PSP flavors)
+	#  - rt-2 (SRv6 H.Insert policy)
+	#  - rt-4 (Argument!=0 and SL=1, advancing the C-SID)
+	#  - rt-3 (Argument!=0 and SL=1, advancing the C-SID)
+	#  - rt-1 (Argument=0 and SL=1, PSP)
+	setup_rt_policy_ipv6 "2:${END_CSID_PSP_FUNC}" 1 \
+		"3:next-csid,psp 4,2:next-csid,psp"
+	setup_rt_policy_ipv6 "1:${END_CSID_PSP_FUNC}" 2 "4,3,1:next-csid,psp"
+
 	# testing environment was set up successfully
 	SETUP_ERR=0
 }
@@ -710,6 +908,20 @@ check_and_log_hs_connectivity()
 	check_and_log_hs_ipv6_connectivity "${hssrc}" "${hsdst}"
 }
 
+check_and_log_hs_lo_addr_connectivity()
+{
+	local hssrc="$1"
+	local hsdst="$2"
+	local suffix="$3"
+	local dst
+
+	dst="${IPv6_HS_NETWORK}::${hsdst}:${suffix}"
+
+	check_hs_ipv6_connectivity "${hssrc}" "${hsdst}:${suffix}"
+	log_test $? 0 \
+		"IPv6 Hosts connectivity: hs-${hssrc} -> hs-${hsdst} (${dst})"
+}
+
 router_tests()
 {
 	local i
@@ -747,6 +959,14 @@ host_srv6_end_flv_psp_tests()
 	check_and_log_hs_connectivity 2 1
 }
 
+host_srv6_end_flv_next_csid_psp_tests()
+{
+	log_section "SRv6 connectivity test hosts (h1 <-> h2, NEXT-C-SID,PSP)"
+
+	check_and_log_hs_lo_addr_connectivity 1 2 "${END_CSID_PSP_FUNC}"
+	check_and_log_hs_lo_addr_connectivity 2 1 "${END_CSID_PSP_FUNC}"
+}
+
 test_iproute2_supp_or_ksft_skip()
 {
 	local flavor="$1"
@@ -836,6 +1056,8 @@ test_command_or_ksft_skip sort
 test_command_or_ksft_skip xargs
 
 test_dummy_dev_or_ksft_skip
+# NEXT-C-SID is not checked: every kernel and iproute2 version that
+# supports PSP also supports NEXT-C-SID.
 test_iproute2_supp_or_ksft_skip psp
 test_kernel_supp_or_ksft_skip psp
 
@@ -848,5 +1070,6 @@ set +e
 router_tests
 host2gateway_tests
 host_srv6_end_flv_psp_tests
+host_srv6_end_flv_next_csid_psp_tests
 
 print_log_test_results
-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH net-next 5/5] selftests: seg6: add tests for PSP with a consumed SRH
  2026-10-11 19:23 [PATCH net-next 0/5] seg6: fixes for the PSP flavor of SRv6 End Andrea Mayer
                   ` (3 preceding siblings ...)
  2026-10-11 19:23 ` [PATCH net-next 4/5] selftests: seg6: add tests for PSP together with NEXT-C-SID Andrea Mayer
@ 2026-10-11 19:23 ` Andrea Mayer
  2026-10-12  8:19   ` Hangbin Liu
  4 siblings, 1 reply; 11+ messages in thread
From: Andrea Mayer @ 2026-10-11 19:23 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman
  Cc: netdev, linux-kernel, linux-kselftest, Shuah Khan, Hangbin Liu,
	Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano, Andrea Mayer

Extend srv6_end_flavors_test.sh with tests for the SRv6 End behavior
with the PSP flavor, alone and together with NEXT-C-SID, on packets that
carry a consumed SRH in front of the SRH to process.

Each test sends a ping along an existing SRv6 Policy, and a router on
the path inserts an extra SRH in front of the Policy's SRH. An End
behavior on another router consumes the extra SRH, and the router
connected to the host must then remove only the Policy's SRH. A test
passes if the ping succeeds.

These tests set seg6_enabled to 1 on the hosts, which must accept the
extra SRH, and set it back to 0 at the end. PSP itself is checked
by the other PSP tests, which run with seg6_enabled set to 0.

Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
---
 .../selftests/net/srv6_end_flavors_test.sh    | 144 +++++++++++++++++-
 1 file changed, 142 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/net/srv6_end_flavors_test.sh b/tools/testing/selftests/net/srv6_end_flavors_test.sh
index baa1b09a1aab..b5dbf53a7f23 100755
--- a/tools/testing/selftests/net/srv6_end_flavors_test.sh
+++ b/tools/testing/selftests/net/srv6_end_flavors_test.sh
@@ -22,8 +22,7 @@
 # flavors will be supported in the kernel.
 #
 # The purpose of the PSP flavor consists in instructing the penultimate node
-# listed in the SRv6 policy to remove (i.e. pop) the outermost SRH from the IPv6
-# header.
+# listed in the SRv6 policy to remove (i.e. pop) the SRH from the IPv6 header.
 # A PSP enabled SRv6 End behavior instance processes the SRH by:
 #  - decrementing the Segment Left (SL) value from 1 to 0;
 #  - copying the last SID from the SID List into the IPv6 Destination Address
@@ -258,6 +257,60 @@
 # the hosts). The loopback address of a host is reached only through the
 # router connected to that host: the ping succeeds only if the SRH is removed
 # by that router.
+#
+# Traffic with a consumed SRH
+# ---------------------------
+#
+# A packet can carry more than one SRH. The SRv6 End behavior skips an SRH with
+# SL=0 and processes the next header [1].
+#
+# The traffic of this section reuses the Policies (i.a), (i.b), (i.c) and (i.d).
+# A router on the path inserts an extra SRH in front of the Policy's SRH, and
+# another router then consumes the extra SRH.
+#
+# The Policy (i.a) has SID List=fcff:3::e,fcff:4::ef1,fcff:2::ef1,cafe::2. A
+# packet from hs-1 to hs-2 goes as follows:
+#
+#  - rt-1 applies the Policy and sends the packet to rt-3:
+#      IPv6 DA=fcff:3::e | Policy's SRH, SL=3 | Payload
+#
+#  - rt-3 (End) processes the Policy's SRH and sends the packet to rt-4:
+#      IPv6 DA=fcff:4::ef1 | Policy's SRH, SL=2 | Payload
+#
+#  - rt-4 (End with PSP and SL>1, acting as End) processes the Policy's SRH.
+#    The new DA is fcff:2::ef1:
+#      IPv6 DA=fcff:2::ef1 | Policy's SRH, SL=1 | Payload
+#    On rt-4, the route added by the test for fcff:2::ef1 then inserts the
+#    extra SRH, with SID List=fcff:3::e,fcff:2::ef1, and the packet goes back to
+#    rt-3:
+#      IPv6 DA=fcff:3::e | extra SRH, SL=1 | Policy's SRH, SL=1 | Payload
+#
+#  - rt-3 (End) consumes the extra SRH and sets the DA back to fcff:2::ef1:
+#      IPv6 DA=fcff:2::ef1 | extra SRH, SL=0 | Policy's SRH, SL=1 | Payload
+#
+#  - rt-2 (End with PSP) skips the extra SRH, processes the Policy's SRH and
+#    removes it:
+#      IPv6 DA=cafe::2 | extra SRH, SL=0 | Payload
+#
+# The extra SRH reaches hs-2, which skips it as its SL is 0. The other
+# Policies work in the same way:
+#
+#   (i.b) hs-2 -> hs-1: on the packets with DA=fcff:1::ef1, rt-2 inserts the
+#         extra SRH with SID List=fcff:3::e,fcff:1::ef1, and rt-3 consumes it.
+#   (i.c) hs-1 -> hs-2: on the packets with DA=fcbb:0:02a1::, rt-4 inserts the
+#         extra SRH with SID List=fcff:3::e,fcbb:0:02a1::, and rt-3 consumes it.
+#   (i.d) hs-2 -> hs-1: on the packets with DA=fcbb:0:01a1::, rt-3 inserts the
+#         extra SRH with SID List=fcff:4::e,fcbb:0:01a1::, and rt-4 consumes it.
+#
+# The Policy (i.b) has no router between rt-2 and rt-1. For this reason, rt-2
+# applies the Policy, inserts the extra SRH and sends the packet to rt-3:
+#      IPv6 DA=fcff:3::e | extra SRH, SL=1 | Policy's SRH, SL=1 | Payload
+# rt-3 consumes the extra SRH, and rt-1 removes the Policy's SRH.
+#
+# The hosts need seg6_enabled set to 1 to accept the extra SRH, and it is set
+# back to 0 at the end. These tests only check that the ping succeeds: PSP
+# itself is checked by the PSP flavor and NEXT-C-SID,PSP tests, which run with
+# seg6_enabled set to 0.
 
 # shellcheck source=lib.sh
 source lib.sh
@@ -967,6 +1020,92 @@ host_srv6_end_flv_next_csid_psp_tests()
 	check_and_log_hs_lo_addr_connectivity 2 1 "${END_CSID_PSP_FUNC}"
 }
 
+# On a router, add a route for a SID with seg6 encap in inline mode. The packets
+# that the router forwards to that SID get an extra SRH with the End SID of the
+# router that consumes it.
+# args:
+#  $1 - router on which the route is added
+#  $2 - SID of the route
+#  $3 - router with the SRv6 End behavior that consumes the extra SRH
+setup_rt_consumed_srh()
+{
+	local rt="$1"
+	local sid="$2"
+	local end_rt="$3"
+	local nsname
+
+	nsname="$(get_rtname "${rt}")"
+
+	ip -netns "${nsname}" -6 route \
+		add "${sid}" table "${LOCALSID_TABLE_ID}" \
+		encap seg6 mode inline \
+		segs "${LOCATOR_SERVICE}:${end_rt}::${END_FUNC}" \
+		dev "${DUMMY_DEVNAME}"
+}
+
+cleanup_rt_consumed_srh()
+{
+	local rt="$1"
+	local sid="$2"
+	local nsname
+
+	nsname="$(get_rtname "${rt}")"
+
+	ip -netns "${nsname}" -6 route \
+		del "${sid}" table "${LOCALSID_TABLE_ID}"
+}
+
+set_hs_seg6_enabled()
+{
+	local val="$1"
+	local hsname
+	local hs
+
+	for hs in ${HOSTS}; do
+		hsname="$(get_hsname "${hs}")"
+
+		ip netns exec "${hsname}" \
+			sysctl -wq net.ipv6.conf.all.seg6_enabled="${val}"
+		ip netns exec "${hsname}" \
+			sysctl -wq net.ipv6.conf.veth0.seg6_enabled="${val}"
+	done
+}
+
+host_srv6_end_flv_consumed_srh_tests()
+{
+	local sid
+
+	log_section "SRv6 connectivity test hosts (h1 <-> h2, consumed SRH)"
+
+	set_hs_seg6_enabled 1
+
+	# Policy (i.a): rt-4 inserts the extra SRH consumed by rt-3
+	sid="${LOCATOR_SERVICE}:2::${END_PSP_FUNC}"
+	setup_rt_consumed_srh 4 "${sid}" 3
+	check_and_log_hs_connectivity 1 2
+	cleanup_rt_consumed_srh 4 "${sid}"
+
+	# Policy (i.b): rt-2 inserts the extra SRH consumed by rt-3
+	sid="${LOCATOR_SERVICE}:1::${END_PSP_FUNC}"
+	setup_rt_consumed_srh 2 "${sid}" 3
+	check_and_log_hs_connectivity 2 1
+	cleanup_rt_consumed_srh 2 "${sid}"
+
+	# Policy (i.c): rt-4 inserts the extra SRH consumed by rt-3
+	sid="$(build_csid_container 2 "${END_CSID_PSP_FUNC}")"
+	setup_rt_consumed_srh 4 "${sid}" 3
+	check_and_log_hs_lo_addr_connectivity 1 2 "${END_CSID_PSP_FUNC}"
+	cleanup_rt_consumed_srh 4 "${sid}"
+
+	# Policy (i.d): rt-3 inserts the extra SRH consumed by rt-4
+	sid="$(build_csid_container 1 "${END_CSID_PSP_FUNC}")"
+	setup_rt_consumed_srh 3 "${sid}" 4
+	check_and_log_hs_lo_addr_connectivity 2 1 "${END_CSID_PSP_FUNC}"
+	cleanup_rt_consumed_srh 3 "${sid}"
+
+	set_hs_seg6_enabled 0
+}
+
 test_iproute2_supp_or_ksft_skip()
 {
 	local flavor="$1"
@@ -1071,5 +1210,6 @@ router_tests
 host2gateway_tests
 host_srv6_end_flv_psp_tests
 host_srv6_end_flv_next_csid_psp_tests
+host_srv6_end_flv_consumed_srh_tests
 
 print_log_test_results
-- 
2.43.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net-next 4/5] selftests: seg6: add tests for PSP together with NEXT-C-SID
  2026-10-11 19:23 ` [PATCH net-next 4/5] selftests: seg6: add tests for PSP together with NEXT-C-SID Andrea Mayer
@ 2026-10-12  7:54   ` Hangbin Liu
  0 siblings, 0 replies; 11+ messages in thread
From: Hangbin Liu @ 2026-10-12  7:54 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman, netdev, linux-kernel, linux-kselftest,
	Shuah Khan, Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano

Hi Andrea,
On Sun, Oct 11, 2026 at 09:23:09PM +0200, Andrea Mayer wrote:
> Extend srv6_end_flavors_test.sh with tests for the SRv6 End behavior
> with both the NEXT-C-SID and PSP flavors.
> 
> The tests use two SRv6 Policies with C-SID containers, where every
> router after the ingress one applies End with the NEXT-C-SID and PSP
> flavors. To check PSP, set net.ipv6.conf.all.seg6_enabled to 0 on the
> hosts in setup_hs(). The hosts then drop any packet that still carries
> an SRH, and a ping to an address on the loopback of a host succeeds
> only if the router connected to that host has removed the SRH. The tests
> fail when PSP is not applied together with NEXT-C-SID.
> 
> Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
> ---
>  .../selftests/net/srv6_end_flavors_test.sh    | 229 +++++++++++++++++-
>  1 file changed, 226 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/testing/selftests/net/srv6_end_flavors_test.sh b/tools/testing/selftests/net/srv6_end_flavors_test.sh
> index 30a939392eea..baa1b09a1aab 100755
> --- a/tools/testing/selftests/net/srv6_end_flavors_test.sh
> +++ b/tools/testing/selftests/net/srv6_end_flavors_test.sh
> @@ -439,6 +549,7 @@ setup_rt_local_sids()
>  	local devname
>  	local nsname
>  	local neigh
> +	local csid
>  
>  	nsname="$(get_rtname "${rt}")"
>  
> @@ -452,6 +563,14 @@ setup_rt_local_sids()
>  			add "${LOCATOR_SERVICE}:${neigh}::/32" \
>  			table "${LOCALSID_TABLE_ID}" \
>  			via "${net_prefix}::${neigh}" dev "${devname}"
> +
> +		# set underlay network routes to reach the C-SID containers
> +		# that start with a C-SID of the neighbor, for any Function.
> +		csid="$(build_csid "${neigh}" 00)"
> +		ip -netns "${nsname}" -6 route \
> +			add "${LCBLOCK_ADDR}:${csid}::/${LCBLOCK_NODE_BLEN}" \
> +			table "${LOCALSID_TABLE_ID}" \
> +			via "${net_prefix}::${neigh}" dev "${devname}"
>  	done
>  
>  	# Local End behavior (note that "dev" is a dummy interface chosen for
> @@ -461,6 +580,17 @@ setup_rt_local_sids()
>  		table "${LOCALSID_TABLE_ID}" \
>  		encap seg6local action End dev "${DUMMY_DEVNAME}"
>  
> +	# Local End behavior with the NEXT-C-SID and PSP flavors, bound to the
> +	# C-SID of the router (e.g. fcbb:0:04a1::/48 on rt-4). The /48 prefix
> +	# covers every C-SID container whose first C-SID is this one, whatever
> +	# the Argument that follows.
> +	csid="$(build_csid "${rt}" "${END_CSID_PSP_FUNC}")"
> +	ip -netns "${nsname}" -6 route \
> +		add "${LCBLOCK_ADDR}:${csid}::/${LCBLOCK_NODEFUNC_BLEN}" \
> +		table "${LOCALSID_TABLE_ID}" \
> +		encap seg6local action End flavors next-csid,psp \
> +		lblen "${LCBLOCK_BLEN}" nflen "${LCNODEFUNC_BLEN}" \
> +		dev "${DUMMY_DEVNAME}"

This is a End + PSP specific encapsulation. If there is a new version patch,
can we move this block

> @@ -494,6 +634,7 @@ __setup_rt_policy()
>  	local in_nsname
>  	local rt_nsname
>  	local policy=''
> +	local container
>  	local function
>  	local fullsid
>  	local op_type
> @@ -520,6 +661,15 @@ __setup_rt_policy()
>  			behavior_cfg="End flavors psp"
>  			;;
>  
> +		"next-csid,psp")
> +			# the behavior is already set up on every router by
> +			# setup_rt_local_sids.
> +			container="$(build_csid_container "${node}" \
> +				"${END_CSID_PSP_FUNC}")"
> +			policy="${policy}${container},"
> +			continue
> +			;;
> +

to here? So we can align with the other SRv6 Endpoint behavior?
Because later in the End.X PSP support we also need to cleanup and
re-setup with END.X.

If this version is applied (which is also good), I can do the modification
in my patch set.

Others looks good to me.

Tested-by: Hangbin Liu <liuhangbin@kylinos.cn>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>

Thanks
Hangbin

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net-next 1/5] seg6: handle a Fragment or AH header before the SRH consistently in PSP
  2026-10-11 19:23 ` [PATCH net-next 1/5] seg6: handle a Fragment or AH header before the SRH consistently in PSP Andrea Mayer
@ 2026-10-12  7:59   ` Hangbin Liu
  0 siblings, 0 replies; 11+ messages in thread
From: Hangbin Liu @ 2026-10-12  7:59 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman, netdev, linux-kernel, linux-kselftest,
	Shuah Khan, Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano

On Sun, Oct 11, 2026 at 09:23:06PM +0200, Andrea Mayer wrote:
> seg6_pop_srh() already fails when a Fragment or AH header comes before
> the SRH with other headers in between, and the packet is dropped ("we
> expect SRH before FRAG and AUTH" in the code). But when the SRH directly
> follows the Fragment or AH header, it is removed:
> 
>   (a) IPv6 | FRAG/AH | DOPT | SRH | ...   the packet is dropped
>   (b) IPv6 | FRAG/AH | SRH | ...          the SRH is removed
> 
> In both packets the Fragment or AH header comes before the SRH.
> 
> Align the two cases: check first whether a header is a Fragment or AH
> header, and only then look at its Next Header field. In this way, the
> packet is dropped also when the Fragment or AH header comes directly
> before the SRH. A Fragment or AH header before the SRH, with or without
> other headers in between, does not follow RFC 8200 and RFC 4302: a
> Fragment header must not come before the Routing header, as the
> Per-Fragment headers must include the Routing header [1], and AH should
> not come before the routing and fragmentation headers [2].
> 
> At the penultimate segment, End with the PSP flavor alone today drops
> (a) and forwards (b) with the SRH removed. Packets with the Fragment or
> AH header after the SRH are not affected: seg6_pop_srh() does not look
> at the headers after the SRH.
> 
> Found by manual code inspection and reproduced in a VM without kernel
> changes or error injection, by sending to End with PSP the packets
> shown in the diagram, both with a Fragment header and with AH. With this
> change, the packets are dropped in both cases, all tests in
> srv6_end_flavors_test.sh pass, and KASAN reports no error. With the
> whole series, all the srv6_*.sh selftests pass.
> 
> [1] - https://datatracker.ietf.org/doc/html/rfc8200#section-4.5
> [2] - https://datatracker.ietf.org/doc/html/rfc4302#section-3.1.1
> 
> Fixes: bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End behavior")
> Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
> ---
>  net/ipv6/seg6_local.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
> index 0c3d1be7f129..da8225591fe3 100644
> --- a/net/ipv6/seg6_local.c
> +++ b/net/ipv6/seg6_local.c
> @@ -796,11 +796,6 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
>  			if (unlikely(!hp))
>  				return false;
>  
> -			if (hp->nexthdr == NEXTHDR_ROUTING) {
> -				hp->nexthdr = srh_nexthdr;
> -				break;
> -			}
> -
>  			switch (nexthdr) {
>  			case NEXTHDR_FRAGMENT:
>  				fallthrough;
> @@ -812,6 +807,11 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
>  				break;
>  			}
>  
> +			if (hp->nexthdr == NEXTHDR_ROUTING) {
> +				hp->nexthdr = srh_nexthdr;
> +				break;
> +			}
> +
>  			nexthdr = hp->nexthdr;
>  		}
>  	}
> -- 
> 2.43.0
> 

After changing the order, we can check the FRAG/AH header first and
return false and drop the pkt.

Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net-next 3/5] seg6: apply the PSP flavor together with NEXT-C-SID in SRv6 End
  2026-10-11 19:23 ` [PATCH net-next 3/5] seg6: apply the PSP flavor together with NEXT-C-SID in SRv6 End Andrea Mayer
@ 2026-10-12  8:17   ` Hangbin Liu
  0 siblings, 0 replies; 11+ messages in thread
From: Hangbin Liu @ 2026-10-12  8:17 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman, netdev, linux-kernel, linux-kselftest,
	Shuah Khan, Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano

On Sun, Oct 11, 2026 at 09:23:08PM +0200, Andrea Mayer wrote:
> Since commit bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End
> behavior"), an SRv6 End route can be set up with both the NEXT-C-SID and
> the PSP flavors, e.g.:
> 
>   ip -6 route add fcbb:0:100::/48 encap seg6local action End \
>           flavors next-csid,psp lblen 32 nflen 16 dev dum0
> 
> In RFC 9800, the NEXT-C-SID flavor (NEXT-CSID in the RFC) changes the
> End processing only when the Argument is not zero [1]. With a zero
> Argument (i.e. when the IPv6 DA carries no further C-SID), End is
> processed as in RFC 8986, and the PSP flavor (when set) applies
> unchanged [2]. If the packet arrives with Segments Left 1, PSP must
> then remove the SRH.
> 
> However, on a route with both the NEXT-C-SID and PSP flavors,
> input_action_end() always uses the NEXT-C-SID processing. The
> NEXT-C-SID processing handles a packet with a zero Argument as End
> without flavors, ignoring PSP. Therefore, if this packet arrives with
> Segments Left 1, the SRH is not removed.
> 
> Fix this by using the NEXT-C-SID processing only when the Argument is
> not zero or the route has no RFC 8986 flavor. Otherwise, the packet is
> processed as End with its RFC 8986 flavors, in end_flv8986_core(). With
> a zero Argument and Segments Left 1, PSP now removes the SRH before the
> packet is forwarded. If seg6_pop_srh() cannot remove the SRH, the packet
> is dropped, as on a route with the PSP flavor alone.
> 
> Found by manual code inspection and reproduced in a VM without kernel
> changes or error injection. A following commit adds tests for this case
> to srv6_end_flavors_test.sh. The tests reproduce the issue: they fail
> without this change and pass with it.
> 
> [1] - https://datatracker.ietf.org/doc/html/rfc9800#section-4.1.1
> [2] - https://datatracker.ietf.org/doc/html/rfc9800#section-4.1.7
> 
> Fixes: bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End behavior")
> Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
> ---
>  net/ipv6/seg6_local.c | 50 ++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 47 insertions(+), 3 deletions(-)
> 
> diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
> index 26cd4facbe36..427d12fedfc3 100644
> --- a/net/ipv6/seg6_local.c
> +++ b/net/ipv6/seg6_local.c
> @@ -551,6 +551,47 @@ static bool seg6_next_csid_enabled(__u32 fops)
>  	return fops & SEG6_F_LOCAL_FLV_NEXT_CSID;
>  }
>  
> +static bool seg6_flv8986_enabled(__u32 fops)
> +{
> +	return fops & SEG6_LOCAL_FLV8986_SUPP_OPS;
> +}
> +
> +/* check whether the NEXT-C-SID processing has to be used for the packet,
> + * instead of the RFC8986 flavors set for the given SRv6 End* behavior
> + * instance.
> + *
> + * This function returns:
> + *  - true, when the packet has to go through the NEXT-C-SID processing;
> + *  - false, when NEXT-C-SID is not configured or the packet has to be
> + *    processed on the basis of the RFC8986 flavors.
> + */
> +static bool seg6_use_next_csid(struct sk_buff *skb,
> +			       const struct seg6_flavors_info *finfo)
> +{
> +	const struct in6_addr *addr;
> +	__u32 fops = finfo->flv_ops;
> +
> +	if (!seg6_next_csid_enabled(fops))
> +		return false;
> +
> +	addr = &ipv6_hdr(skb)->daddr;
> +
> +	/* NEXT-C-SID and the RFC8986 flavors combine according to the
> +	 * DA.Argument (see RFC9800, sections 4.1.1 and 4.1.7):
> +	 *
> +	 *       DA.Argument   RFC8986 flavors   processing
> +	 *   (1) != 0          any               NEXT-C-SID only, SL unchanged
> +	 *   (2) == 0          none              the behavior, e.g. End
> +	 *   (3) == 0          one or more       the behavior with its flavors,
> +	 *                                       e.g. End with PSP
> +	 *
> +	 * In (2), the packet still goes through the NEXT-C-SID processing,
> +	 * which runs the behavior (e.g. End) when the DA.Argument is zero.
> +	 */
> +	return !seg6_flv8986_enabled(fops) ||
> +	       !seg6_next_csid_is_arg_zero(addr, finfo);

nit: based on the comment, maybe we can change the order to

	return !seg6_next_csid_is_arg_zero(addr, finfo) ||
	       !seg6_flv8986_enabled(fops);

No need to change if there is no new version patch.

> +}
> +
>  /* Processing of SRv6 End, End.X, and End.T behaviors can be extended through
>   * the flavors framework. These behaviors must report the subset of (flavor)
>   * operations they currently implement. In this way, if a user specifies a
> @@ -865,7 +906,10 @@ static int end_flv8986_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
>  	if (srh && !seg6_hmac_validate_skb(skb, srh))
>  		goto drop;
>  #endif
> -	flvmask = finfo->flv_ops;
> +	/* NEXT-C-SID, when configured, has already been evaluated by the
> +	 * caller. Only the RFC8986 flavors are left here.
> +	 */
> +	flvmask = finfo->flv_ops & ~SEG6_F_LOCAL_FLV_NEXT_CSID;
>  	if (unlikely(flvmask & ~SEG6_LOCAL_FLV8986_SUPP_OPS)) {
>  		pr_warn_once("seg6local: invalid RFC8986 flavors\n");
>  		goto drop;
> @@ -919,8 +963,8 @@ static int input_action_end(struct sk_buff *skb, struct seg6_local_lwt *slwt)
>  	if (!fops)
>  		return input_action_end_core(skb, slwt);
>  
> -	/* check for the presence of NEXT-C-SID since it applies first */
> -	if (seg6_next_csid_enabled(fops))
> +	/* NEXT-C-SID is evaluated first, when configured */
> +	if (seg6_use_next_csid(skb, finfo))
>  		return end_next_csid_core(skb, slwt);
>  
>  	/* the specific processing function to be performed on the packet
> -- 
> 2.43.0
> 

Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>

Thanks
Hangbin

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net-next 5/5] selftests: seg6: add tests for PSP with a consumed SRH
  2026-10-11 19:23 ` [PATCH net-next 5/5] selftests: seg6: add tests for PSP with a consumed SRH Andrea Mayer
@ 2026-10-12  8:19   ` Hangbin Liu
  0 siblings, 0 replies; 11+ messages in thread
From: Hangbin Liu @ 2026-10-12  8:19 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman, netdev, linux-kernel, linux-kselftest,
	Shuah Khan, Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano

On Sun, Oct 11, 2026 at 09:23:10PM +0200, Andrea Mayer wrote:
> Extend srv6_end_flavors_test.sh with tests for the SRv6 End behavior
> with the PSP flavor, alone and together with NEXT-C-SID, on packets that
> carry a consumed SRH in front of the SRH to process.
> 
> Each test sends a ping along an existing SRv6 Policy, and a router on
> the path inserts an extra SRH in front of the Policy's SRH. An End
> behavior on another router consumes the extra SRH, and the router
> connected to the host must then remove only the Policy's SRH. A test
> passes if the ping succeeds.
> 
> These tests set seg6_enabled to 1 on the hosts, which must accept the
> extra SRH, and set it back to 0 at the end. PSP itself is checked
> by the other PSP tests, which run with seg6_enabled set to 0.
> 
> Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
> ---
>  .../selftests/net/srv6_end_flavors_test.sh    | 144 +++++++++++++++++-
>  1 file changed, 142 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/testing/selftests/net/srv6_end_flavors_test.sh b/tools/testing/selftests/net/srv6_end_flavors_test.sh
> index baa1b09a1aab..b5dbf53a7f23 100755
> --- a/tools/testing/selftests/net/srv6_end_flavors_test.sh
> +++ b/tools/testing/selftests/net/srv6_end_flavors_test.sh
> @@ -22,8 +22,7 @@
>  # flavors will be supported in the kernel.
>  #
>  # The purpose of the PSP flavor consists in instructing the penultimate node
> -# listed in the SRv6 policy to remove (i.e. pop) the outermost SRH from the IPv6
> -# header.
> +# listed in the SRv6 policy to remove (i.e. pop) the SRH from the IPv6 header.
>  # A PSP enabled SRv6 End behavior instance processes the SRH by:
>  #  - decrementing the Segment Left (SL) value from 1 to 0;
>  #  - copying the last SID from the SID List into the IPv6 Destination Address
> @@ -258,6 +257,60 @@
>  # the hosts). The loopback address of a host is reached only through the
>  # router connected to that host: the ping succeeds only if the SRH is removed
>  # by that router.
> +#
> +# Traffic with a consumed SRH
> +# ---------------------------
> +#
> +# A packet can carry more than one SRH. The SRv6 End behavior skips an SRH with
> +# SL=0 and processes the next header [1].
> +#
> +# The traffic of this section reuses the Policies (i.a), (i.b), (i.c) and (i.d).
> +# A router on the path inserts an extra SRH in front of the Policy's SRH, and
> +# another router then consumes the extra SRH.
> +#
> +# The Policy (i.a) has SID List=fcff:3::e,fcff:4::ef1,fcff:2::ef1,cafe::2. A
> +# packet from hs-1 to hs-2 goes as follows:
> +#
> +#  - rt-1 applies the Policy and sends the packet to rt-3:
> +#      IPv6 DA=fcff:3::e | Policy's SRH, SL=3 | Payload
> +#
> +#  - rt-3 (End) processes the Policy's SRH and sends the packet to rt-4:
> +#      IPv6 DA=fcff:4::ef1 | Policy's SRH, SL=2 | Payload
> +#
> +#  - rt-4 (End with PSP and SL>1, acting as End) processes the Policy's SRH.
> +#    The new DA is fcff:2::ef1:
> +#      IPv6 DA=fcff:2::ef1 | Policy's SRH, SL=1 | Payload
> +#    On rt-4, the route added by the test for fcff:2::ef1 then inserts the
> +#    extra SRH, with SID List=fcff:3::e,fcff:2::ef1, and the packet goes back to
> +#    rt-3:
> +#      IPv6 DA=fcff:3::e | extra SRH, SL=1 | Policy's SRH, SL=1 | Payload
> +#
> +#  - rt-3 (End) consumes the extra SRH and sets the DA back to fcff:2::ef1:
> +#      IPv6 DA=fcff:2::ef1 | extra SRH, SL=0 | Policy's SRH, SL=1 | Payload
> +#
> +#  - rt-2 (End with PSP) skips the extra SRH, processes the Policy's SRH and
> +#    removes it:
> +#      IPv6 DA=cafe::2 | extra SRH, SL=0 | Payload
> +#
> +# The extra SRH reaches hs-2, which skips it as its SL is 0. The other
> +# Policies work in the same way:
> +#
> +#   (i.b) hs-2 -> hs-1: on the packets with DA=fcff:1::ef1, rt-2 inserts the
> +#         extra SRH with SID List=fcff:3::e,fcff:1::ef1, and rt-3 consumes it.
> +#   (i.c) hs-1 -> hs-2: on the packets with DA=fcbb:0:02a1::, rt-4 inserts the
> +#         extra SRH with SID List=fcff:3::e,fcbb:0:02a1::, and rt-3 consumes it.
> +#   (i.d) hs-2 -> hs-1: on the packets with DA=fcbb:0:01a1::, rt-3 inserts the
> +#         extra SRH with SID List=fcff:4::e,fcbb:0:01a1::, and rt-4 consumes it.
> +#
> +# The Policy (i.b) has no router between rt-2 and rt-1. For this reason, rt-2
> +# applies the Policy, inserts the extra SRH and sends the packet to rt-3:
> +#      IPv6 DA=fcff:3::e | extra SRH, SL=1 | Policy's SRH, SL=1 | Payload
> +# rt-3 consumes the extra SRH, and rt-1 removes the Policy's SRH.
> +#
> +# The hosts need seg6_enabled set to 1 to accept the extra SRH, and it is set
> +# back to 0 at the end. These tests only check that the ping succeeds: PSP
> +# itself is checked by the PSP flavor and NEXT-C-SID,PSP tests, which run with
> +# seg6_enabled set to 0.
>  
>  # shellcheck source=lib.sh
>  source lib.sh
> @@ -967,6 +1020,92 @@ host_srv6_end_flv_next_csid_psp_tests()
>  	check_and_log_hs_lo_addr_connectivity 2 1 "${END_CSID_PSP_FUNC}"
>  }
>  
> +# On a router, add a route for a SID with seg6 encap in inline mode. The packets
> +# that the router forwards to that SID get an extra SRH with the End SID of the
> +# router that consumes it.
> +# args:
> +#  $1 - router on which the route is added
> +#  $2 - SID of the route
> +#  $3 - router with the SRv6 End behavior that consumes the extra SRH
> +setup_rt_consumed_srh()
> +{
> +	local rt="$1"
> +	local sid="$2"
> +	local end_rt="$3"
> +	local nsname
> +
> +	nsname="$(get_rtname "${rt}")"
> +
> +	ip -netns "${nsname}" -6 route \
> +		add "${sid}" table "${LOCALSID_TABLE_ID}" \
> +		encap seg6 mode inline \
> +		segs "${LOCATOR_SERVICE}:${end_rt}::${END_FUNC}" \
> +		dev "${DUMMY_DEVNAME}"
> +}
> +
> +cleanup_rt_consumed_srh()
> +{
> +	local rt="$1"
> +	local sid="$2"
> +	local nsname
> +
> +	nsname="$(get_rtname "${rt}")"
> +
> +	ip -netns "${nsname}" -6 route \
> +		del "${sid}" table "${LOCALSID_TABLE_ID}"
> +}
> +
> +set_hs_seg6_enabled()
> +{
> +	local val="$1"
> +	local hsname
> +	local hs
> +
> +	for hs in ${HOSTS}; do
> +		hsname="$(get_hsname "${hs}")"
> +
> +		ip netns exec "${hsname}" \
> +			sysctl -wq net.ipv6.conf.all.seg6_enabled="${val}"
> +		ip netns exec "${hsname}" \
> +			sysctl -wq net.ipv6.conf.veth0.seg6_enabled="${val}"
> +	done
> +}
> +
> +host_srv6_end_flv_consumed_srh_tests()
> +{
> +	local sid
> +
> +	log_section "SRv6 connectivity test hosts (h1 <-> h2, consumed SRH)"
> +
> +	set_hs_seg6_enabled 1
> +
> +	# Policy (i.a): rt-4 inserts the extra SRH consumed by rt-3
> +	sid="${LOCATOR_SERVICE}:2::${END_PSP_FUNC}"
> +	setup_rt_consumed_srh 4 "${sid}" 3
> +	check_and_log_hs_connectivity 1 2
> +	cleanup_rt_consumed_srh 4 "${sid}"
> +
> +	# Policy (i.b): rt-2 inserts the extra SRH consumed by rt-3
> +	sid="${LOCATOR_SERVICE}:1::${END_PSP_FUNC}"
> +	setup_rt_consumed_srh 2 "${sid}" 3
> +	check_and_log_hs_connectivity 2 1
> +	cleanup_rt_consumed_srh 2 "${sid}"
> +
> +	# Policy (i.c): rt-4 inserts the extra SRH consumed by rt-3
> +	sid="$(build_csid_container 2 "${END_CSID_PSP_FUNC}")"
> +	setup_rt_consumed_srh 4 "${sid}" 3
> +	check_and_log_hs_lo_addr_connectivity 1 2 "${END_CSID_PSP_FUNC}"
> +	cleanup_rt_consumed_srh 4 "${sid}"
> +
> +	# Policy (i.d): rt-3 inserts the extra SRH consumed by rt-4
> +	sid="$(build_csid_container 1 "${END_CSID_PSP_FUNC}")"
> +	setup_rt_consumed_srh 3 "${sid}" 4
> +	check_and_log_hs_lo_addr_connectivity 2 1 "${END_CSID_PSP_FUNC}"
> +	cleanup_rt_consumed_srh 3 "${sid}"
> +
> +	set_hs_seg6_enabled 0
> +}
> +
>  test_iproute2_supp_or_ksft_skip()
>  {
>  	local flavor="$1"
> @@ -1071,5 +1210,6 @@ router_tests
>  host2gateway_tests
>  host_srv6_end_flv_psp_tests
>  host_srv6_end_flv_next_csid_psp_tests
> +host_srv6_end_flv_consumed_srh_tests
>  
>  print_log_test_results
> -- 
> 2.43.0
> 

Tested-by: Hangbin Liu <liuhangbin@kylinos.cn>
Reviewed-by: Hangbin Liu <liuhangbin@kylinos.cn>

Thanks
Hangbin

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH net-next 2/5] seg6: handle a consumed SRH in SRv6 End with the PSP flavor
  2026-10-11 19:23 ` [PATCH net-next 2/5] seg6: handle a consumed SRH in SRv6 End with the PSP flavor Andrea Mayer
@ 2026-10-12  9:28   ` Hangbin Liu
  0 siblings, 0 replies; 11+ messages in thread
From: Hangbin Liu @ 2026-10-12  9:28 UTC (permalink / raw)
  To: Andrea Mayer
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	David Ahern, Simon Horman, netdev, linux-kernel, linux-kselftest,
	Shuah Khan, Justin Iurman, Nicolas Dichtel, Ahmed Abdelsalam,
	Stefano Salsano

Hi Andrea,
On Sun, Oct 11, 2026 at 09:23:07PM +0200, Andrea Mayer wrote:
> With the seg6 inline mode, a packet can carry more than one SRH. The
> SRHs with Segments Left 0 are considered consumed SRHs, and they can
> come before the SRH to process (Segments Left > 0), as in this packet:
> 
>   +------+----------------------+----------------------+---------+
>   | IPv6 | SRH, Segments Left 0 | SRH, Segments Left 1 | payload |
>   +------+----------------------+----------------------+---------+
> 
> End without flavors skips the consumed SRH and processes the next
> one [1]. With the PSP flavor, End should do the same. When the SRH to
> process arrives with Segments Left 1, as in the diagram, End with PSP
> should then also remove it [2]. However, End with PSP alone currently
> looks only at the first routing header of the packet, finds Segments
> Left 0 there, and drops the packet.
> 
> Make End with PSP alone skip the consumed SRHs, and any other routing
> header with Segments Left 0, and process the SRH that follows them. If
> there is no SRH to process, the packet is dropped as before. When the
> SRH to process arrives with Segments Left 1, End with PSP now removes
> it even if consumed SRHs come before it.
> 
> Found by manual code inspection and reproduced in a VM without kernel
> changes or error injection. A following commit adds tests for this case
> to srv6_end_flavors_test.sh. Without this change, the new tests with a
> consumed SRH fail for End with PSP alone. With this series, all tests
> pass and KASAN reports no error.
> 
> [1] - https://datatracker.ietf.org/doc/html/rfc8986#section-4.1
> [2] - https://datatracker.ietf.org/doc/html/rfc8986#section-4.16.1.2
> 
> Fixes: bdf3c0b9c10b ("seg6: add PSP flavor support for SRv6 End behavior")
> Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
> ---
>  net/ipv6/seg6_local.c | 29 +++++++++++++++++++++++++----
>  1 file changed, 25 insertions(+), 4 deletions(-)
> 
> diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
> index da8225591fe3..26cd4facbe36 100644
> --- a/net/ipv6/seg6_local.c
> +++ b/net/ipv6/seg6_local.c
> @@ -775,11 +775,14 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
>  		skb_set_transport_header(skb, thoff);
>  
>  	iph = ipv6_hdr(skb);
> -	if (iph->nexthdr == NEXTHDR_ROUTING) {
> +	if (srhoff == sizeof(*iph)) {
>  		iph->nexthdr = srh_nexthdr;
>  	} else {
>  		/* we must look for the extension header (EXTH, for short) that
> -		 * immediately precedes the SRH we have just removed.
> +		 * immediately precedes the SRH we have just removed, i.e. the
> +		 * EXTH that ends at srhoff. We find it by its position and not
> +		 * by its nexthdr, since another routing header (e.g. an SRH
> +		 * with SL = 0) may come before the removed SRH.
>  		 * Then, we update the value of the EXTH nexthdr with the one
>  		 * contained in the SRH nexthdr.
>  		 */
> @@ -807,7 +810,7 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
>  				break;
>  			}
>  
> -			if (hp->nexthdr == NEXTHDR_ROUTING) {
> +			if (off == srhoff) {
>  				hp->nexthdr = srh_nexthdr;
>  				break;
>  			}
> @@ -823,6 +826,24 @@ static bool seg6_pop_srh(struct sk_buff *skb, int srhoff)
>  	return true;
>  }
>  
> +/* look up the SRH to be processed by the RFC8986 flavors. As End does, a
> + * routing header with SL = 0 is skipped (e.g. an SRH already consumed).
> + * This function returns NULL when no valid SRH is found.
> + */
> +static struct ipv6_sr_hdr *seg6_flv8986_get_srh(struct sk_buff *skb)
> +{
> +	struct ipv6_sr_hdr *srh;
> +
> +	srh = seg6_get_srh(skb, IP6_FH_F_SKIP_RH);
> +	if (srh)
> +		return srh;
> +
> +	/* we take the first routing header without skipping it. In this way,
> +	 * seg6_get_srh_pktinfo() reports SL = 0 and not a missing SRH.
> +	 */
> +	return seg6_get_srh(skb, 0);
> +}
> +
>  /* process the packet on the basis of the RFC8986 flavors set for the given
>   * SRv6 End behavior instance.
>   */
> @@ -837,7 +858,7 @@ static int end_flv8986_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
>  	__u32 flvmask;
>  	int srhoff;
>  
> -	srh = seg6_get_srh(skb, 0);
> +	srh = seg6_flv8986_get_srh(skb);

Hmm, here we always try skip the SL = 0 SRH when multi SRH exists. What if
we want to add USP flavor support in future? Then we will not able to remove
the first SRH which SL = 0, right? e.g.

   +------+----------------------+----------------------+---------+
   | IPv6 | SRH, Segments Left 0 | SRH, Segments Left 2 | payload |
   +------+----------------------+----------------------+---------+

Thanks
Hangbin

>  	srhoff = srh ? ((unsigned char *)srh - skb->data) : 0;
>  	pinfo = seg6_get_srh_pktinfo(srh);
>  #ifdef CONFIG_IPV6_SEG6_HMAC
> -- 
> 2.43.0
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-10-12  9:28 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-11 19:23 [PATCH net-next 0/5] seg6: fixes for the PSP flavor of SRv6 End Andrea Mayer
2026-10-11 19:23 ` [PATCH net-next 1/5] seg6: handle a Fragment or AH header before the SRH consistently in PSP Andrea Mayer
2026-10-12  7:59   ` Hangbin Liu
2026-10-11 19:23 ` [PATCH net-next 2/5] seg6: handle a consumed SRH in SRv6 End with the PSP flavor Andrea Mayer
2026-10-12  9:28   ` Hangbin Liu
2026-10-11 19:23 ` [PATCH net-next 3/5] seg6: apply the PSP flavor together with NEXT-C-SID in SRv6 End Andrea Mayer
2026-10-12  8:17   ` Hangbin Liu
2026-10-11 19:23 ` [PATCH net-next 4/5] selftests: seg6: add tests for PSP together with NEXT-C-SID Andrea Mayer
2026-10-12  7:54   ` Hangbin Liu
2026-10-11 19:23 ` [PATCH net-next 5/5] selftests: seg6: add tests for PSP with a consumed SRH Andrea Mayer
2026-10-12  8:19   ` Hangbin Liu

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®