[Bug ?] Packet with End.X segment not correctly forwarded to nexthop

From: Anthony Doeraene <hidden>
Date: 2026-06-19 13:25:14

Hello,

I am currently experimenting with SRv6 and VRFs, and I found some weird 
interactions between the two.

For the context, I need routers to have multiple VRFs, with each VRF 
having different routes to reach destinations.
Our routers not only send packets to a specific nexthop, but also 
specify the VRF that the nexthop
should use to forward these packets.
To achieve this goal, routes in these VRFs push two segments: a local 
End.X segment, and a End.DT46 segment.
Due to some implementation constraints, I want to have a single End.DT46 
segment shared by
all routers in the network.

Once packets are encapsulated by the VRF, the packet is sent in the main 
table to do a lookup for the nexthop.
As the End.DT46 segment is shared between routers and can not be used to 
learn the nexthop, I decided to
use an End.X segment to specify it.

However, what I observe in this scenario is that End.X segment 
processing function is never called, resulting
in the packet not being sent to the correct nexthop.

I am wondering if this is an expected behavior (i.e. a node should never 
push a local segment), or if it is a real bug ?

I am not well versed into the implementation details of SRv6 in the 
kernel, but I'm suspecting that this "bug" comes
from the fact that seg6_output_core calls dst_output, which does not 
allow an SRv6 segment function to be called.

A minimal example is given below, which creates two namespaces (r1, r2)  
and allows to reproduce this behavior.
(tested on a kernel compiled on virtme-ng from commit 
e771677c937da5808f7b6c1f0e4a97ec1a84f8a8)

Thank you in advance for the help and thanks for the SRv6 support on Linux,
Doeraene Anthony

File setup.sh
# Topology under test:
#
#                    fc00::1:1       fc00::1:2
# fc00::1 [ r1 ] ------------------------- [ r2 ] fc00::2
#
# Description:
# ============
#
# Each node has an additional VRF, which it can use to provide different
# routing decisions based on arbitrary rules (e.g. QoS aware forwarding)
# Routes in this VRF will encapsulate the packets and push segments to
# specify the nexthop (End.X) and the VRF the nexthop should use
# (End.DT46). The same End.DT46 segment is shared by all nodes
#
# Problem:
# ========
#
# Once segments are pushed, the End.X segment is never applied. As a
# result, the segment is not popped from the SL, and the packet is sent
# on an incorrect interface.
#
# Forwarding steps:
# =================
#
# - R1 sends the packet to fc00::2 in its VRF `myvrf`
# - This VRF encapsulates the packet and add two segments:
#   1) End.X segment to force the transmission of the packet on r1-r2
#   2) End.DT46 segment allowing r2 to know which VRF it should use
#      to forward the packet.
# - After encapsulation, r1 does a lookup in its main table for the
#   End.X segment, but does not pop the segment. The packet is thus
#   sent incorrectly on the dummy interface
#
# Running the example (with sudo):
# ====================
#
# 1) Start the topology
#
# bash setup.sh
#
# 2) Start pinging (leave in the background)
#
# ip netns exec r1 ping -I fc00::1 fc00::2
#
# 3) Check with tcpdump. We should see packets on r1-r2, and should not
#    see any packet on dum0
#
# ip netns exec r1 tcpdump -i dum0 -n
# ip netns exec r1 tcpdump -i r1-r2 -n


if [ -z "$(lsmod | grep vrf)" ]; then
     echo "Run modprobe vrf"
     exit 1
fi

nodes="r1 r2"
vrftable=10
localsid=90

# Create nodes
for node in $nodes; do
     ip netns add $node
     ip -n $node link set lo up
done

# Create loopback addresses
ip -n r1 addr add fc00::1 dev lo
ip -n r2 addr add fc00::2 dev lo

# Create links
ip link add r1-r2 type veth peer name r2-r1

ip link set r1-r2 netns r1
ip link set r2-r1 netns r2

ip -n r1 link set r1-r2 up
ip -n r2 link set r2-r1 up

# Configure IPs
ip -n r1 addr add dev r1-r2 fc00::1:1/112
ip -n r2 addr add dev r2-r1 fc00::1:2/112

# Add default routes
ip -n r1 -6 route add default via fc00::1:2
ip -n r2 -6 route add default via fc00::1:1


# Configure sysctls
for node in $nodes; do
     ip netns exec $node sysctl -w net.ipv6.conf.all.forwarding=1
     ip netns exec $node sysctl -w net.ipv6.conf.all.seg6_enabled=1
     ip netns exec $node sysctl -w net.vrf.strict_mode=1

     for itf in $(ip netns exec $node ls /sys/class/net); do
         ip netns exec $node sysctl net.ipv6.conf.$itf.seg6_enabled=1
     done
done

for node in $nodes; do
     # Create a dummy interface for End.X segments
     ip -n $node link add dum0 type dummy
     ip -n $node link set dum0 up

     # Create VRF
     ip -n $node link add myvrf type vrf table $vrftable
     ip -n $node link set dev myvrf up
done

# Create SID table route
ip -n r1 -6 rule add to fc00:1::/32 lookup $localsid prio 998
ip -n r1 -6 rule add to fc00:ffff::/32 lookup $localsid prio 999
ip -n r2 -6 rule add to fc00:2::/32 lookup $localsid prio 998
ip -n r2 -6 rule add to fc00:ffff::/32 lookup $localsid prio 999

# Create the DT46 segment associated with the VRF
ip -n r1 route add table $localsid fc00:ffff:: \
     encap seg6local \
     action End.DT46 vrftable $vrftable dev myvrf
ip -n r2 route add table $localsid fc00:ffff:: \
     encap seg6local \
     action End.DT46 vrftable $vrftable dev myvrf

# Create the End.X segment
ip -n r1 route add table $localsid fc00:1:2:: \
     encap seg6local action End.X nh6 fc00::1:2 oif r1-r2 dev dum0
ip -n r2 route add table $localsid fc00:2:1:: \
     encap seg6local action End.X nh6 fc00::1:1 oif r2-r1 dev dum0

# Setup routes (main table)
ip -n r1 route add fc00::2 dev myvrf

# Setup routes (VRF). R1 push an End.X into End.DT46 segment
ip -n r1 route add fc00::2 encap seg6 \
     mode encap \
     segs fc00:1:2::,fc00:ffff:: \
     dev r1-r2 via fc00::1:2 \
     table 10
  
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help