[PATCH iproute2-next 1/2] seg6: add support for lookup attribute in SRv6 encap routes
From: Andrea Mayer <andrea.mayer@uniroma2.it>
Date: 2026-07-12 02:13:42
Subsystem:
the rest · Maintainer:
Linus Torvalds
Add support for the new optional "lookup" attribute for seg6 encap
routes. It selects the FIB table for the post-encap SID route lookup
and accepts a table number or a table name.
Examples:
# SID route installed in the underlay table 500
ip -6 route add fc00::100/128 via fd00::1 dev veth0 table 500
# encap route in vrf-100; the first SID is looked up in table 500
ip -6 route add cafe::1/128 vrf vrf-100 \
encap seg6 mode encap segs fc00::100 lookup 500 dev veth0
# or if the SID is already handled by the main table
ip -6 route add cafe::1/128 vrf vrf-100 \
encap seg6 mode encap segs fc00::100 lookup main dev veth0
When the attribute is omitted, the post-encap SID route lookup behaves
as before, using the current routing context (e.g. the tables selected
according to the routing policy database).
Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
---
ip/iproute.c | 1 +
ip/iproute_lwtunnel.c | 22 +++++++++++++++++++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/ip/iproute.c b/ip/iproute.c
index 5b9e7ac1..1ce71f78 100644
--- a/ip/iproute.c
+++ b/ip/iproute.c@@ -101,6 +101,7 @@ static void usage(void) "ENCAPTYPE := [ mpls | ip | ip6 | seg6 | seg6local | rpl | ioam6 | xfrm ]\n" "ENCAPHDR := [ MPLSLABEL | SEG6HDR | SEG6LOCAL | IOAM6HDR | XFRMINFO ]\n" "SEG6HDR := [ mode SEGMODE ] segs ADDR1,ADDRi,ADDRn [hmac HMACKEYID] [cleanup]\n" + " [ lookup TABLEID ]\n" "SEGMODE := [ encap | encap.red | inline | l2encap | l2encap.red ]\n" "SEG6LOCAL := action ACTION [ OPTIONS ] [ count ]\n" "ACTION := { End | End.X | End.T | End.DX2 | End.DX6 | End.DX4 |\n"
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
index 00b4f756..9a1e747c 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c@@ -256,6 +256,7 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap) { struct rtattr *tb[SEG6_IPTUNNEL_MAX+1]; struct seg6_iptunnel_encap *tuninfo; + SPRINT_BUF(b1); parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
@@ -274,6 +275,12 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap) } print_srh(fp, tuninfo->srh); + + if (tb[SEG6_IPTUNNEL_TABLE]) { + print_string(PRINT_ANY, "lookup", "lookup %s ", + rtnl_rttable_n2a(rta_getattr_u32(tb[SEG6_IPTUNNEL_TABLE]), + b1, sizeof(b1))); + } } static void print_rpl_srh(FILE *fp, struct ipv6_rpl_sr_hdr *srh)
@@ -955,7 +962,7 @@ static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap) static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { - int mode_ok = 0, segs_ok = 0, hmac_ok = 0; + int mode_ok = 0, segs_ok = 0, hmac_ok = 0, lookup_ok = 0; struct seg6_iptunnel_encap *tuninfo = NULL; struct ipv6_sr_hdr *srh; char **argv = *argvp;
@@ -963,6 +970,7 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, bool tunsrc = false; inet_prefix saddr; int argc = *argcp; + __u32 lookup = 0; int encap = -1; __u32 hmac = 0; int ret = -1;
@@ -1006,6 +1014,13 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, if (hmac_ok++) duparg2("hmac", *argv); get_u32(&hmac, *argv, 0); + } else if (strcmp(*argv, "lookup") == 0) { + NEXT_ARG(); + if (lookup_ok++) + duparg2("lookup", *argv); + /* note that table 0 is considered an invalid value */ + if (rtnl_rttable_a2n(&lookup, *argv) || !lookup) + invarg("\"lookup\" value is invalid\n", *argv); } else { break; }
@@ -1036,6 +1051,11 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, goto out; } + if (lookup) { + if (rta_addattr32(rta, len, SEG6_IPTUNNEL_TABLE, lookup)) + goto out; + } + *argcp = argc + 1; *argvp = argv - 1; ret = 0;
--
2.20.1