[PATCH net-next v2 1/4] selftests: net: test IPV6_FL_A_RENEW

Marcelo Mendes Spessoto Junior <[email protected]> Mon, 3 Aug 2026 23:59:07 -0300
Newsgroups org.kernel.vger.linux-kselftest,org.kernel.vger.linux-kernel,org.kernel.vger.netdev
Message-ID <[email protected]>
RENEW was the only flow label action without selftests coverage.

Assert renew returns no error on correct usage and fails for labels
that do not exist.

Based on the previously implemented EXCL share test, that demonstrates
that a new flow label with same label can be created after the linger
period, use renew to show that the flow label can last longer and
block a new flow label creation after the previous linger time. This
test, however, demands sleep during execution, and should be placed as
a conditional test under the -l option.

The addition of expect_fail_errno helper is necessary to assert the
corresponding error when a function can fail on multiple ways.

Signed-off-by: Marcelo Mendes Spessoto Junior <[email protected]>
---
 .../selftests/net/ipv6_flowlabel_mgr.c        | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/tools/testing/selftests/net/ipv6_flowlabel_mgr.c b/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
index af95b48acea9..01fab414895c 100644
--- a/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
+++ b/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
@@ -27,6 +27,7 @@
 
 /* from net/ipv6/ip6_flowlabel.c */
 #define FL_MIN_LINGER		6
+#define FL_MAX_LINGER	150
 
 #define explain(x)							\
 	do { if (cfg_verbose) fprintf(stderr, "       " x "\n"); } while (0)
@@ -42,6 +43,18 @@
 #define expect_pass(x)	__expect(x)
 #define expect_fail(x)	__expect(!(x))
 
+#define expect_fail_errno(x, e)						\
+	do {								\
+		int __exp = (e);					\
+		int __ret = (x);					\
+		int __err = errno;					\
+		if (__ret && __err == __exp)				\
+			fprintf(stderr, "[OK]   " #x "\n");		\
+		else							\
+			error(1, 0, "[ERR]  " #x " (line %d): expected errno %d, got %d", \
+			      __LINE__, __exp, __err);			\
+	} while (0)
+
 static bool cfg_long_running;
 static bool cfg_verbose;
 
@@ -71,6 +84,17 @@ static int flowlabel_put(int fd, uint32_t label)
 	return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
 }
 
+static int flowlabel_renew(int fd, uint32_t label, uint16_t linger)
+{
+	struct in6_flowlabel_req req = {
+		.flr_action = IPV6_FL_A_RENEW,
+		.flr_label = htonl(label),
+		.flr_linger = linger,
+	};
+
+	return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
+}
+
 static void run_tests(int fd)
 {
 	int wstatus;
@@ -160,6 +184,26 @@ static void run_tests(int fd)
 		error(1, errno, "wait");
 	if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0)
 		error(1, errno, "wait: unexpected child result");
+
+	explain("It is not possible to renew a label that does not exist");
+	expect_fail_errno(flowlabel_renew(fd, 5, 2 * (FL_MIN_LINGER * 2 + 1)), ESRCH);
+
+	explain("Create a label for basic renew validation");
+	expect_pass(flowlabel_get(fd, 5, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));
+	explain("Check if renew does not return errors for existing and valid label");
+	expect_pass(flowlabel_renew(fd, 5, 2 * (FL_MIN_LINGER * 2 + 1)));
+
+	if (cfg_long_running) {
+		explain("create a new label with FL_MIN_LINGER linger time");
+		expect_pass(flowlabel_get(fd, 6, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE));
+		explain("renew the label to increase its linger time and put it");
+		expect_pass(flowlabel_renew(fd, 6, 2 * (FL_MIN_LINGER * 2 + 1)));
+		expect_pass(flowlabel_put(fd, 6));
+		sleep(FL_MIN_LINGER * 2 + 1);
+		explain("The label cannot be created because the new linger time is not over yet");
+		expect_fail_errno(flowlabel_get(fd, 6, IPV6_FL_S_ANY, IPV6_FL_F_CREATE), EPERM);
+	}
+
 }
 
 static void parse_opts(int argc, char **argv)
-- 
2.55.0