Revisiting Segment Routing IPv6 (SRv6) with VyOS
At the beginning of 2024, I looked at configuring a very basic SRv6 L3VPN service using VyOS. During that effort, I ran into a critical caveat in which CE traffic was not being forwarded until locally sourced traffic on each PE was transmitted.
Issue
The trace below demonstrates a sequence of CE1 sourced ICMP echo packets
destined for CE5. We can see that they were encapsulated in an SRv6 packet by
noting the destination prefix as the End.DT46
SID on PE4 (2001:db8:4:aaa:65::
):
|
|
Each of these packet’s routing process attempts a lookup on table 101
(VRF1).
However, no route to 2001:db8:4:aaa:65::
exists within the VRF table. The
result is the behavior I noted in a previous post.
The packet is silently dropped at this stage with a
IP_INNOROUTES
error: network unreachable
indicating no route to the destination can be
found.
Unfortunately VyOS does not include the appropriate tracing options out of the box. The above traces were obtained by compiling a custom kernel with the appropriate tracing options enabled.
Once running, the following trace options were performed:
|
|
This behavior was not something I experienced when attempting a similar configuration on a vanilla Debian installation. Here is the result of that trace performing the same lookup:
|
|
This highlighted a difference between the route lookup behavior between VyOS and
Linux in general. Linux utilizes a form of
policy based routing
(ip rules
) to determine the priority of which tables to consult in a first
match exit strategy.
From a generic Debian installation out of the box, this policy appears as:
|
|
On VyOS there is a difference most notably after l3mdev-table
(VRF) lookups:
|
|
VyOS does modify
this behavior on the creation of VRFs. When the lookup is performed, no route is
found at priority 1000
. The very next result at 2000
drops the packet with
an unreachable error if no match was found previously. I suspect this rule
serves to prevent VRF isolated traffic from errantly resolving a next-hop in
another table as doing so would allow traffic to “leak” out of a contained
environment.
However in our case, this statement is preventing SRv6 encapsulated L3VPN
traffic from being able to recurse the main
table in order to forward traffic
appropriately.
In my opinion, the SRv6 encapsulation and routing behavior should not be
in conflict with these priorities. I suspect this discovered routing
behavior should be classified as a bug in seg6
within the kernel itself.
The VRF route appears as:
|
|
This route has all of the elements to correctly identify the SR instructions,
next-hop, and outbound interface. I believe that the resulting SRv6 packet
should simply follow the predetermined routing table forwarding
instruction: via inet6 fe80::5201:ff:fe04:0 dev eth0
.
Workaround
In order to work around this behavior we need to modify the route lookup policy. Fortunately, VyOS includes local route policy as a standard configuration feature.
Here we can simply short circuit the routing behavior to perform a lookup differently under specific circumstances. A working policy in this case needs to:
- Match the SRv6 source address of the PE.
- Match the SRv6 destination prefix.
- Instruct the lookup to be performed on the
main
table. - Match the above conditions before following the normal lookup process.
We can use the following configuration to achieve this:
PE2
|
|
PE4
|
|
Result
The above configuration modifies the ip -6 rule
table as:
|
|
In order of priority, the rules are matched and route caching is performed.
Our CE traffic within the VRF is encapsulated in SRv6 and the resulting
lookup will be from 2001:db8:2:ffff::2
with an IPv6 destination
within: 2001:db8:4::/48
. It will now match the first rule (priority 500
) and
be forced to perform a lookup using the main
table instead of the VRF’s.
It is important to note that I very specifically match the SRv6 encapsulation
source address (loopback) to avoid introducing any other undesired traffic flow
leaking across tables. Any other transit SRv6 traffic is already in the
main
table and not effected by this change.