mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next 0/2] net: ipv6: seg6: extack messages for lwtunnel setup
@ 2026-09-18 15:35 Gabriel Goller
  2026-09-18 15:35 ` [PATCH net-next 1/2] net: ipv6: seg6: report lwtunnel setup errors via extack Gabriel Goller
  2026-09-18 15:35 ` [PATCH net-next 2/2] selftests: seg6: check extack messages on SRv6 lwtunnel setup Gabriel Goller
  0 siblings, 2 replies; 4+ messages in thread
From: Gabriel Goller @ 2026-09-18 15:35 UTC (permalink / raw)
  To: Andrea Mayer, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Shuah Khan
  Cc: netdev, linux-kernel, linux-kselftest

seg6_build_state() rejects invalid lwtunnel configurations with a bare -EINVAL,
so "ip route add ... encap seg6 ..." always reports "Invalid argument".

Patch 1 attaches an extack message to each of them.

Patch 2 adds a ksft/ynl selftest that hits some rejection paths and checks the
error messages.

Gabriel Goller (2):
  net: ipv6: seg6: report lwtunnel setup errors via extack
  selftests: seg6: check extack messages on SRv6 lwtunnel setup

 net/ipv6/seg6_iptunnel.c                      |  25 ++-
 tools/testing/selftests/net/Makefile          |   1 +
 .../selftests/net/srv6_iptunnel_extack.py     | 168 ++++++++++++++++++
 3 files changed, 189 insertions(+), 5 deletions(-)
 create mode 100755 tools/testing/selftests/net/srv6_iptunnel_extack.py


base-commit: 4bb9710c6a68d35207f123aef55dcd50e7195ec5
-- 
2.47.3



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

* [PATCH net-next 1/2] net: ipv6: seg6: report lwtunnel setup errors via extack
  2026-09-18 15:35 [PATCH net-next 0/2] net: ipv6: seg6: extack messages for lwtunnel setup Gabriel Goller
@ 2026-09-18 15:35 ` Gabriel Goller
  2026-09-18 15:35 ` [PATCH net-next 2/2] selftests: seg6: check extack messages on SRv6 lwtunnel setup Gabriel Goller
  1 sibling, 0 replies; 4+ messages in thread
From: Gabriel Goller @ 2026-09-18 15:35 UTC (permalink / raw)
  To: Andrea Mayer, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Shuah Khan
  Cc: netdev, linux-kernel, linux-kselftest

seg6_build_state() rejected invalid configurations with a generic
-EINVAL, so "ip route add ... encap seg6 ..." always reported "Invalid
argument".

Attach an extack message to each of them. The checks themselves and
their return values are unchanged.

Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
---
 net/ipv6/seg6_iptunnel.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
index 61c6a27bf202..e7f75970e26e 100644
--- a/net/ipv6/seg6_iptunnel.c
+++ b/net/ipv6/seg6_iptunnel.c
@@ -756,8 +756,12 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
 	struct seg6_lwt *slwt;
 	int err;
 
-	if (family != AF_INET && family != AF_INET6)
+	if (family != AF_INET && family != AF_INET6) {
+		NL_SET_ERR_MSG(
+			extack,
+			"unsupported address family for SRv6 encapsulation");
 		return -EINVAL;
+	}
 
 	err = nla_parse_nested_deprecated(tb, SEG6_IPTUNNEL_MAX, nla,
 					  seg6_iptunnel_policy, extack);
@@ -765,8 +769,10 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
 	if (err < 0)
 		return err;
 
-	if (!tb[SEG6_IPTUNNEL_SRH])
+	if (!tb[SEG6_IPTUNNEL_SRH]) {
+		NL_SET_ERR_MSG(extack, "missing SRv6 SRH attribute");
 		return -EINVAL;
+	}
 
 	tuninfo = nla_data(tb[SEG6_IPTUNNEL_SRH]);
 	tuninfo_len = nla_len(tb[SEG6_IPTUNNEL_SRH]);
@@ -776,13 +782,18 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
 	 */
 	min_size = sizeof(*tuninfo) + sizeof(struct ipv6_sr_hdr) +
 		   sizeof(struct in6_addr);
-	if (tuninfo_len < min_size)
+	if (tuninfo_len < min_size) {
+		NL_SET_ERR_MSG(extack, "truncated SRv6 SRH attribute");
 		return -EINVAL;
+	}
 
 	switch (tuninfo->mode) {
 	case SEG6_IPTUN_MODE_INLINE:
-		if (family != AF_INET6)
+		if (family != AF_INET6) {
+			NL_SET_ERR_MSG(extack,
+				       "inline mode requires an IPv6 route");
 			return -EINVAL;
+		}
 
 		if (tb[SEG6_IPTUNNEL_SRC]) {
 			NL_SET_ERR_MSG(extack, "incompatible mode for tunsrc");
@@ -798,12 +809,16 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
 	case SEG6_IPTUN_MODE_L2ENCAP_RED:
 		break;
 	default:
+		NL_SET_ERR_MSG(extack, "invalid SRv6 encapsulation mode");
 		return -EINVAL;
 	}
 
 	/* verify that SRH is consistent */
-	if (!seg6_validate_srh(tuninfo->srh, tuninfo_len - sizeof(*tuninfo), false))
+	if (!seg6_validate_srh(tuninfo->srh, tuninfo_len - sizeof(*tuninfo),
+			       false)) {
+		NL_SET_ERR_MSG(extack, "invalid SRv6 segment routing header");
 		return -EINVAL;
+	}
 
 	newts = lwtunnel_state_alloc(tuninfo_len + sizeof(*slwt));
 	if (!newts)
-- 
2.47.3



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

* [PATCH net-next 2/2] selftests: seg6: check extack messages on SRv6 lwtunnel setup
  2026-09-18 15:35 [PATCH net-next 0/2] net: ipv6: seg6: extack messages for lwtunnel setup Gabriel Goller
  2026-09-18 15:35 ` [PATCH net-next 1/2] net: ipv6: seg6: report lwtunnel setup errors via extack Gabriel Goller
@ 2026-09-18 15:35 ` Gabriel Goller
  2026-09-18 22:02   ` Jakub Kicinski
  1 sibling, 1 reply; 4+ messages in thread
From: Gabriel Goller @ 2026-09-18 15:35 UTC (permalink / raw)
  To: Andrea Mayer, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Shuah Khan
  Cc: netdev, linux-kernel, linux-kselftest

Add a ksft/ynl test that shoves invalid RTA_ENCAP payloads to
RTM_NEWROUTE and asserts both the errno and the extack message are
correct.Also verify that the rejected route was not installed.

Signed-off-by: Gabriel Goller <g.goller@proxmox.com>
---
 tools/testing/selftests/net/Makefile          |   1 +
 .../selftests/net/srv6_iptunnel_extack.py     | 168 ++++++++++++++++++
 2 files changed, 169 insertions(+)
 create mode 100755 tools/testing/selftests/net/srv6_iptunnel_extack.py

diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index 3ee3378f8b26..45639f46b003 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -101,6 +101,7 @@ TEST_PROGS := \
 	srv6_hencap_red_l3vpn_test.sh \
 	srv6_hl2encap_red_l2vpn_test.sh \
 	srv6_iptunnel_cache.sh \
+	srv6_iptunnel_extack.py \
 	stress_reuseport_listen.sh \
 	tcp_ecmp_failover.sh \
 	tcp_fastopen_backup_key.sh \
diff --git a/tools/testing/selftests/net/srv6_iptunnel_extack.py b/tools/testing/selftests/net/srv6_iptunnel_extack.py
new file mode 100755
index 000000000000..77e708a08c3e
--- /dev/null
+++ b/tools/testing/selftests/net/srv6_iptunnel_extack.py
@@ -0,0 +1,168 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0
+#
+# author: Gabriel Goller <g.goller@proxmox.com>
+
+"""Exercise SRv6 tunnel validation with invalid netlink attributes."""
+
+import errno
+import os
+import socket
+import struct
+from contextlib import contextmanager
+
+from lib.py import KsftNamedVariant, KsftSkipEx, Netlink, NetNS, NetNSEnter
+from lib.py import NlError, RtnlRouteFamily, ip, ksft_eq, ksft_exit, ksft_raises
+from lib.py import ksft_run, ksft_variants
+
+
+LWTUNNEL_ENCAP_SEG6 = 5
+SEG6_IPTUNNEL_SRH = 1
+SEG6_IPTUNNEL_SRC = 2
+SEG6_IPTUNNEL_TABLE = 3
+SEG6_IPTUN_MODE_INLINE = 0
+SEG6_IPTUN_MODE_ENCAP = 1
+SEG6_IPTUN_MODE_L2ENCAP = 2
+SEG6_IPTUN_MODE_ENCAP_RED = 3
+SEG6_IPTUN_MODE_L2ENCAP_RED = 4
+
+
+def encap(mode=SEG6_IPTUN_MODE_ENCAP, hdrlen=2, routing_type=4):
+    # seg6_iptunnel_encap followed by an SRH containing one segment.
+    srh = struct.pack('!BBBBBBH', 0, hdrlen, routing_type, 0, 0, 0, 0)
+    srh += socket.inet_pton(socket.AF_INET6, '2001:db8::1')
+    return struct.pack('=i', mode) + srh
+
+
+def nlattr(attr_type, payload):
+    length = 4 + len(payload)
+    return (struct.pack('=HH', length, attr_type) + payload +
+            bytes(-length % 4))
+
+
+def route(family, oif, payload, tunsrc=None, table=None):
+    attrs = b''
+    if payload is not None:
+        attrs += nlattr(SEG6_IPTUNNEL_SRH, payload)
+    if tunsrc is not None:
+        attrs += nlattr(SEG6_IPTUNNEL_SRC,
+                        socket.inet_pton(socket.AF_INET6, tunsrc))
+    if table is not None:
+        attrs += nlattr(SEG6_IPTUNNEL_TABLE, struct.pack('=I', table))
+
+    return {
+        'rtm-family': family,
+        'rtm-dst-len': 32 if family == socket.AF_INET else 128,
+        'rtm-table': 254,
+        'rtm-protocol': 4,  # RTPROT_STATIC
+        'rtm-type': 1,  # RTN_UNICAST
+        'dst': '192.0.2.1' if family == socket.AF_INET else '2001:db8:1::1',
+        'oif': oif,
+        'encap-type': LWTUNNEL_ENCAP_SEG6,
+        'encap': attrs,
+    }
+
+
+def add_route(rtnl, attrs):
+    rtnl.newroute(attrs.copy(),
+                  flags=[Netlink.NLM_F_CREATE, Netlink.NLM_F_EXCL])
+
+
+def matching_routes(rtnl, attrs):
+    routes = rtnl.getroute({'rtm-family': attrs['rtm-family']}, dump=True)
+    return [entry for entry in routes
+            if entry.get('dst') == attrs['dst'] and
+            entry['rtm-table'] == attrs['rtm-table']]
+
+
+@contextmanager
+def setup():
+    if os.geteuid() != 0:
+        raise KsftSkipEx('Root privileges are required')
+
+    with NetNS() as ns, NetNSEnter(str(ns)):
+        ip('link set lo up')
+        oif = socket.if_nametoindex('lo')
+        rtnl = RtnlRouteFamily()
+        try:
+            # Probe with a valid route so missing SRv6 support is a skip,
+            # whereas missing diagnostics remain a test failure.
+            probe = route(socket.AF_INET6, oif, encap())
+            try:
+                add_route(rtnl, probe)
+            except NlError as error:
+                if error.error == errno.EOPNOTSUPP:
+                    raise KsftSkipEx('SRv6 tunnels are not supported') from error
+                raise
+            rtnl.delroute(probe.copy())
+            yield rtnl, oif
+        finally:
+            rtnl.close()
+
+
+# (name, SRH payload, extra encap attributes, expected extack message)
+INVALID = [
+    ('missing_srh', None, {}, 'missing SRv6 SRH attribute'),
+    ('empty_srh', b'', {}, 'truncated SRv6 SRH attribute'),
+    ('short_srh', encap()[:-1], {}, 'truncated SRv6 SRH attribute'),
+    ('invalid_mode', encap(mode=255), {}, 'invalid SRv6 encapsulation mode'),
+    ('invalid_type', encap(routing_type=0), {},
+     'invalid SRv6 segment routing header'),
+    ('invalid_length', encap(hdrlen=4), {},
+     'invalid SRv6 segment routing header'),
+    ('invalid_tunsrc', encap(), {'tunsrc': '::'}, 'invalid tunsrc address'),
+    ('invalid_table', encap(), {'table': 0}, 'invalid lookup table'),
+]
+
+
+@ksft_variants([
+    KsftNamedVariant(f'{name}_{af_name}', family, payload, extra, message)
+    for name, payload, extra, message in INVALID
+    for af_name, family in [('ipv4', socket.AF_INET), ('ipv6', socket.AF_INET6)]
+] + [KsftNamedVariant('inline_ipv4', socket.AF_INET,
+                      encap(mode=SEG6_IPTUN_MODE_INLINE), {},
+                      'inline mode requires an IPv6 route'),
+     # Inline mode rejects a non-IPv6 route before it looks at tunsrc,
+     # so only IPv6 reaches the tunsrc check.
+     KsftNamedVariant('inline_tunsrc_ipv6', socket.AF_INET6,
+                      encap(mode=SEG6_IPTUN_MODE_INLINE),
+                      {'tunsrc': '2001:db8::2'},
+                      'incompatible mode for tunsrc')])
+def invalid_config(family, payload, extra, message):
+    with setup() as (rtnl, oif):
+        attrs = route(family, oif, payload, **extra)
+        with ksft_raises(NlError) as caught:
+            add_route(rtnl, attrs)
+        ksft_eq(matching_routes(rtnl, attrs), [], 'Rejected route was installed')
+        if caught.exception is None:
+            return
+        ksft_eq(caught.exception.error, errno.EINVAL)
+        ksft_eq((caught.exception.nl_msg.extack or {}).get('msg'), message)
+
+
+@ksft_variants([
+    KsftNamedVariant(f'{name}_{af_name}', family, mode)
+    for name, mode in [('inline', SEG6_IPTUN_MODE_INLINE),
+                       ('encap', SEG6_IPTUN_MODE_ENCAP),
+                       ('l2encap', SEG6_IPTUN_MODE_L2ENCAP),
+                       ('encap_red', SEG6_IPTUN_MODE_ENCAP_RED),
+                       ('l2encap_red', SEG6_IPTUN_MODE_L2ENCAP_RED)]
+    for af_name, family in [('ipv4', socket.AF_INET), ('ipv6', socket.AF_INET6)]
+    if mode != SEG6_IPTUN_MODE_INLINE or family == socket.AF_INET6
+])
+def valid_config(family, mode):
+    with setup() as (rtnl, oif):
+        attrs = route(family, oif, encap(mode=mode))
+        add_route(rtnl, attrs)
+        routes = matching_routes(rtnl, attrs)
+        ksft_eq(len(routes), 1)
+        if routes:
+            ksft_eq(routes[0].get('encap-type'), LWTUNNEL_ENCAP_SEG6)
+            ksft_eq(routes[0].get('encap'), attrs['encap'])
+            rtnl.delroute(attrs.copy())
+            ksft_eq(matching_routes(rtnl, attrs), [])
+
+
+if __name__ == '__main__':
+    ksft_run([invalid_config, valid_config])
+    ksft_exit()
-- 
2.47.3



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

* Re: [PATCH net-next 2/2] selftests: seg6: check extack messages on SRv6 lwtunnel setup
  2026-09-18 15:35 ` [PATCH net-next 2/2] selftests: seg6: check extack messages on SRv6 lwtunnel setup Gabriel Goller
@ 2026-09-18 22:02   ` Jakub Kicinski
  0 siblings, 0 replies; 4+ messages in thread
From: Jakub Kicinski @ 2026-09-18 22:02 UTC (permalink / raw)
  To: Gabriel Goller
  Cc: Andrea Mayer, David S . Miller, Eric Dumazet, Paolo Abeni,
	Simon Horman, Shuah Khan, netdev, linux-kernel, linux-kselftest

On Fri, 18 Sep 2026 17:35:16 +0200 Gabriel Goller wrote:
> Add a ksft/ynl test that shoves invalid RTA_ENCAP payloads to
> RTM_NEWROUTE and asserts both the errno and the extack message are
> correct.

Please be judicious when adding tests.

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

end of thread, other threads:[~2026-09-18 22:02 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18 15:35 [PATCH net-next 0/2] net: ipv6: seg6: extack messages for lwtunnel setup Gabriel Goller
2026-09-18 15:35 ` [PATCH net-next 1/2] net: ipv6: seg6: report lwtunnel setup errors via extack Gabriel Goller
2026-09-18 15:35 ` [PATCH net-next 2/2] selftests: seg6: check extack messages on SRv6 lwtunnel setup Gabriel Goller
2026-09-18 22:02   ` Jakub Kicinski

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®