https://github.com/thom311/libnl/issues/448
https://github.com/thom311/libnl/commit/f680f27d61be1de3f4a0e50c7158c1cd0d6df585
https://github.com/thom311/libnl/commit/1ac4b3216501574e7621618477d91b8fab13164a

From f680f27d61be1de3f4a0e50c7158c1cd0d6df585 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thom311@gmail.com>
Date: Tue, 23 Dec 2025 21:31:06 +0100
Subject: [PATCH] tests: add and use _nltst_skip_eopnotsupp() helper

---
 tests/cksuite-all-netns.c |  3 +--
 tests/cksuite-route-nh.c  |  4 +---
 tests/nl-test-util.c      | 11 +++++++++++
 tests/nl-test-util.h      |  4 ++++
 4 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/tests/cksuite-all-netns.c b/tests/cksuite-all-netns.c
index ff6fd6576..4714db268 100644
--- a/tests/cksuite-all-netns.c
+++ b/tests/cksuite-all-netns.c
@@ -273,8 +273,7 @@ START_TEST(test_create_iface)
 	}
 
 	r = rtnl_link_add(sk, link, NLM_F_CREATE);
-	if (r == -NLE_OPNOTSUPP) {
-		/* Hm, no kernel module? Skip the test. */
+	if (_nltst_skip_eopnotsupp(r)) {
 		_nltst_assert_link_not_exists(IFNAME);
 		IFNAME = NULL;
 		return;
diff --git a/tests/cksuite-route-nh.c b/tests/cksuite-route-nh.c
index d31cecf3c..e05c94df1 100644
--- a/tests/cksuite-route-nh.c
+++ b/tests/cksuite-route-nh.c
@@ -1054,10 +1054,8 @@ START_TEST(test_kernel_roundtrip_encap_ila)
 	ck_assert_int_eq(rtnl_nh_set_oif(nh, (uint32_t)ifindex_dummy), 0);
 	ck_assert_int_eq(rtnl_nh_set_family(nh, AF_INET6), 0);
 	ret = rtnl_nh_add(sk, nh, NLM_F_CREATE);
-	if (ret == -NLE_OPNOTSUPP) {
-		/* ila module is not loaded - skipping */
+	if (_nltst_skip_eopnotsupp(ret))
 		return;
-	}
 	ck_assert_int_eq(ret, 0);
 
 	ck_assert_int_eq(rtnl_nh_alloc_cache(sk, AF_UNSPEC, &cache), 0);
diff --git a/tests/nl-test-util.c b/tests/nl-test-util.c
index 51c04c69f..75bb54035 100644
--- a/tests/nl-test-util.c
+++ b/tests/nl-test-util.c
@@ -838,6 +838,17 @@ bool _nltst_skip_no_iproute2(const char *msg)
 
 /*****************************************************************************/
 
+bool _nltst_skip_eopnotsupp(int err)
+{
+	if (err != -NLE_OPNOTSUPP)
+		return false;
+
+	printf("skip test after operation failed with NLE_OPNOTSUPP. This indicates missing kernel support");
+	return true;
+}
+
+/*****************************************************************************/
+
 void _nltst_add_dummy_and_up(struct nl_sock *sk, const char *ifname,
 			     int *out_ifindex)
 {
diff --git a/tests/nl-test-util.h b/tests/nl-test-util.h
index ecae8856a..a2c0e3b3f 100644
--- a/tests/nl-test-util.h
+++ b/tests/nl-test-util.h
@@ -449,6 +449,10 @@ bool _nltst_skip_no_iproute2(const char *msg);
 
 /*****************************************************************************/
 
+bool _nltst_skip_eopnotsupp(int err);
+
+/*****************************************************************************/
+
 typedef struct {
 	int addr_family;
 	int ifindex;

From 1ac4b3216501574e7621618477d91b8fab13164a Mon Sep 17 00:00:00 2001
From: Thomas Haller <thom311@gmail.com>
Date: Tue, 23 Dec 2025 21:35:06 +0100
Subject: [PATCH] tests: skip various tests when kernel returns EOPNOTSUPP
 (NLE_OPNOTSUPP)

https://github.com/thom311/libnl/issues/448
---
 tests/cksuite-link-ip6tnl.c   |  2 ++
 tests/cksuite-route-nexthop.c |  6 +++++-
 tests/cksuite-route-nh.c      | 21 ++++++++++++++++++---
 3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/tests/cksuite-link-ip6tnl.c b/tests/cksuite-link-ip6tnl.c
index ea785b864..c5dc35341 100644
--- a/tests/cksuite-link-ip6tnl.c
+++ b/tests/cksuite-link-ip6tnl.c
@@ -97,6 +97,8 @@ START_TEST(test_kernel_roundtrip_all)
 	 * This tests the netlink-message construction.
 	 */
 	r = rtnl_link_add(sk, link, NLM_F_CREATE);
+	if (_nltst_skip_eopnotsupp(r))
+		return;
 	ck_assert_int_eq(r, 0);
 
 	/* Now, query it and check whether all the attributes passed.
diff --git a/tests/cksuite-route-nexthop.c b/tests/cksuite-route-nexthop.c
index 34fc1d3b3..971a580bd 100644
--- a/tests/cksuite-route-nexthop.c
+++ b/tests/cksuite-route-nexthop.c
@@ -416,6 +416,7 @@ START_TEST(test_kernel_route_roundtrip_nh_mpls_encap_v4)
 	struct rtnl_nh_encap *encap2;
 	struct rtnl_nexthop *nh = NULL;
 	int ifindex_dummy;
+	int r;
 
 	if (_nltst_skip_no_netns())
 		return;
@@ -447,7 +448,10 @@ START_TEST(test_kernel_route_roundtrip_nh_mpls_encap_v4)
 	ck_assert_int_eq(rtnl_route_nh_set_encap(nh, encap2), 0);
 	rtnl_route_add_nexthop(route, nh);
 
-	ck_assert_int_eq(rtnl_route_add(sk, route, NLM_F_CREATE), 0);
+	r = rtnl_route_add(sk, route, NLM_F_CREATE);
+	if (_nltst_skip_eopnotsupp(r))
+		return;
+	ck_assert_int_eq(r, 0);
 
 	/* Retrieve the route back by its prefix and validate MPLS encap on nexthop */
 	ck_assert_int_eq(nltst_route_get_by_dst(sk, dst, &got), 0);
diff --git a/tests/cksuite-route-nh.c b/tests/cksuite-route-nh.c
index e05c94df1..b6ab8dc1e 100644
--- a/tests/cksuite-route-nh.c
+++ b/tests/cksuite-route-nh.c
@@ -91,6 +91,7 @@ START_TEST(test_kernel_roundtrip_encap_mpls)
 	_nl_auto_nl_addr struct nl_addr *labels = NULL;
 	struct rtnl_nh_encap *encap = NULL;
 	int ifindex_dummy;
+	int r;
 
 	if (_nltst_skip_no_netns())
 		return;
@@ -127,7 +128,11 @@ START_TEST(test_kernel_roundtrip_encap_mpls)
 	ck_assert_int_eq(rtnl_nh_add(sk, nh, NLM_F_CREATE), -NLE_INVAL);
 
 	ck_assert_int_eq(rtnl_nh_set_family(nh, AF_INET), 0);
-	ck_assert_int_eq(rtnl_nh_add(sk, nh, NLM_F_CREATE), 0);
+
+	r = rtnl_nh_add(sk, nh, NLM_F_CREATE);
+	if (_nltst_skip_eopnotsupp(r))
+		return;
+	ck_assert_int_eq(r, 0);
 
 	/* Query and verify */
 	ck_assert_int_eq(rtnl_nh_alloc_cache(sk, AF_UNSPEC, &cache), 0);
@@ -944,6 +949,7 @@ START_TEST(test_kernel_roundtrip_encap_ip6)
 	_nl_auto_rtnl_nh_encap struct rtnl_nh_encap *encap = NULL;
 	uint16_t flags;
 	int ifindex_dummy;
+	int r;
 
 	if (_nltst_skip_no_netns())
 		return;
@@ -980,7 +986,11 @@ START_TEST(test_kernel_roundtrip_encap_ip6)
 	/* Set required attributes and add */
 	ck_assert_int_eq(rtnl_nh_set_oif(nh, (uint32_t)ifindex_dummy), 0);
 	ck_assert_int_eq(rtnl_nh_set_family(nh, AF_INET6), 0);
-	ck_assert_int_eq(rtnl_nh_add(sk, nh, NLM_F_CREATE), 0);
+
+	r = rtnl_nh_add(sk, nh, NLM_F_CREATE);
+	if (_nltst_skip_eopnotsupp(r))
+		return;
+	ck_assert_int_eq(r, 0);
 
 	/* Query and verify */
 	ck_assert_int_eq(rtnl_nh_alloc_cache(sk, AF_UNSPEC, &cache), 0);
@@ -1097,6 +1107,7 @@ START_TEST(test_kernel_roundtrip_encap_ip)
 	_nl_auto_rtnl_nh_encap struct rtnl_nh_encap *encap = NULL;
 	int ifindex_dummy;
 	uint64_t id = 0;
+	int r;
 
 	if (_nltst_skip_no_netns())
 		return;
@@ -1132,7 +1143,11 @@ START_TEST(test_kernel_roundtrip_encap_ip)
 	/* Set required attributes and add */
 	ck_assert_int_eq(rtnl_nh_set_oif(nh, (uint32_t)ifindex_dummy), 0);
 	ck_assert_int_eq(rtnl_nh_set_family(nh, AF_INET), 0);
-	ck_assert_int_eq(rtnl_nh_add(sk, nh, NLM_F_CREATE), 0);
+
+	r = rtnl_nh_add(sk, nh, NLM_F_CREATE);
+	if (_nltst_skip_eopnotsupp(r))
+		return;
+	ck_assert_int_eq(r, 0);
 
 	/* Query and verify */
 	ck_assert_int_eq(rtnl_nh_alloc_cache(sk, AF_UNSPEC, &cache), 0);
