Subject: [PATCH net-next v2 07/10] tools: ynl: convert devlink sample to selftest

From: Jakub Kicinski <[email-masked]>
Date: Fri, 6 Mar 2026 19:36:27 -0800

Convert devlink.c to use kselftest_harness.h with FIXTURE/TEST_F.
Move devlink from BINS to TEST_GEN_FILES in the Makefile since
it's invoked via the devlink.sh wrapper which sets up netdevsim.

Output:

  TAP version 13
  1..2
  # Starting 2 tests from 1 test cases.
  #  RUN           devlink.dump ...
  # netdevsim/netdevsim1337
  #            OK  devlink.dump
  ok 1 devlink.dump
  #  RUN           devlink.info ...
  # netdevsim/netdevsim1337:
  #   driver: netdevsim
  #   running fw:
  #     fw.mgmt: 10.20.30
  #            OK  devlink.info
  ok 2 devlink.info
  # PASSED: 2 / 2 tests passed.
  # Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0

Signed-off-by: Jakub Kicinski <[email-masked]>
---
 tools/net/ynl/tests/Makefile   |  16 ++++--
 tools/net/ynl/tests/devlink.c  | 100 +++++++++++++++++++++++----------
 tools/net/ynl/tests/devlink.sh |   5 ++
 3 files changed, 85 insertions(+), 36 deletions(-)
 create mode 100755 tools/net/ynl/tests/devlink.sh

diff --git a/tools/net/ynl/tests/Makefile b/tools/net/ynl/tests/Makefile
index a329de031add..14d399a70f10 100644
--- a/tools/net/ynl/tests/Makefile
+++ b/tools/net/ynl/tests/Makefile
@@ -14,6 +14,7 @@ endif
 LDLIBS=../lib/ynl.a ../generated/protos.a
 
 TEST_PROGS := \
+	devlink.sh \
 	test_ynl_cli.sh \
 	test_ynl_ethtool.sh \
 # end of TEST_PROGS
@@ -25,8 +26,11 @@ TEST_GEN_PROGS := \
 	tc \
 # end of TEST_GEN_PROGS
 
-BINS := \
+TEST_GEN_FILES := \
 	devlink \
+# end of TEST_GEN_FILES
+
+BINS := \
 	ethtool \
 	rt-addr \
 	rt-route \
@@ -41,7 +45,7 @@ include $(wildcard *.d)
 
 INSTALL_PATH ?= $(DESTDIR)/usr/share/kselftest
 
-all: $(TEST_GEN_PROGS) $(BINS)
+all: $(TEST_GEN_PROGS) $(TEST_GEN_FILES) $(BINS)
 
 ../lib/ynl.a:
 	@$(MAKE) -C ../lib
@@ -49,7 +53,7 @@ all: $(TEST_GEN_PROGS) $(BINS)
  ../generated/protos.a:
 	@$(MAKE) -C ../generated
 
-$(TEST_GEN_PROGS) $(BINS): %: %.c ../lib/ynl.a ../generated/protos.a
+$(TEST_GEN_PROGS) $(TEST_GEN_FILES) $(BINS): %: %.c ../lib/ynl.a ../generated/protos.a
 	@echo -e '\tCC test $@'
 	@$(COMPILE.c) $(CFLAGS_$@) $@.c -o $@.o
 	@$(LINK.c) $@.o -o $@  $(LDLIBS)
@@ -59,7 +63,7 @@ $(TEST_GEN_PROGS) $(BINS): %: %.c ../lib/ynl.a ../generated/protos.a
 		./$$test; \
 	done
 
-install: $(TEST_GEN_PROGS) $(BINS)
+install: $(TEST_GEN_PROGS) $(TEST_GEN_FILES) $(BINS)
 	@mkdir -p $(INSTALL_PATH)/ynl
 	@cp ../../../testing/selftests/kselftest/ktap_helpers.sh $(INSTALL_PATH)/
 	@for test in $(TEST_PROGS); do \
@@ -73,7 +77,7 @@ install: $(TEST_GEN_PROGS) $(BINS)
 	@for file in $(TEST_FILES); do \
 		cp $$file $(INSTALL_PATH)/ynl/$$file; \
 	done
-	@for bin in $(TEST_GEN_PROGS) $(BINS); do \
+	@for bin in $(TEST_GEN_PROGS) $(TEST_GEN_FILES) $(BINS); do \
 		cp $$bin $(INSTALL_PATH)/ynl/$$bin; \
 	done
 	@for test in $(TEST_PROGS) $(TEST_GEN_PROGS); do \
@@ -84,7 +88,7 @@ install: $(TEST_GEN_PROGS) $(BINS)
 	rm -f *.o *.d *~
 
 distclean: clean
-	rm -f $(TEST_GEN_PROGS) $(BINS)
+	rm -f $(TEST_GEN_PROGS) $(TEST_GEN_FILES) $(BINS)
 
 .PHONY: all install clean distclean run_tests
 .DEFAULT_GOAL=all
diff --git a/tools/net/ynl/tests/devlink.c b/tools/net/ynl/tests/devlink.c
index ac9dfb01f280..2e668bb15af1 100644
--- a/tools/net/ynl/tests/devlink.c
+++ b/tools/net/ynl/tests/devlink.c
@@ -4,58 +4,98 @@
 
 #include <ynl.h>
 
+#include <kselftest_harness.h>
+
 #include "devlink-user.h"
 
-int main(int argc, char **argv)
+FIXTURE(devlink)
+{
+	struct ynl_sock *ys;
+};
+
+FIXTURE_SETUP(devlink)
+{
+	self->ys = ynl_sock_create(&ynl_devlink_family, NULL);
+	ASSERT_NE(NULL, self->ys)
+		TH_LOG("failed to create devlink socket");
+}
+
+FIXTURE_TEARDOWN(devlink)
+{
+	ynl_sock_destroy(self->ys);
+}
+
+TEST_F(devlink, dump)
 {
 	struct devlink_get_list *devs;
-	struct ynl_sock *ys;
 
-	ys = ynl_sock_create(&ynl_devlink_family, NULL);
-	if (!ys)
-		return 1;
+	devs = devlink_get_dump(self->ys);
+	ASSERT_NE(NULL, devs) {
+		TH_LOG("dump failed: %s", self->ys->err.msg);
+	}
 
-	devs = devlink_get_dump(ys);
-	if (!devs)
-		goto err_close;
+	if (ynl_dump_empty(devs)) {
+		devlink_get_list_free(devs);
+		SKIP(return, "no entries in dump");
+	}
+
+	ynl_dump_foreach(devs, d) {
+		EXPECT_TRUE((bool)d->_len.bus_name);
+		EXPECT_TRUE((bool)d->_len.dev_name);
+		ksft_print_msg("%s/%s\n", d->bus_name, d->dev_name);
+	}
+
+	devlink_get_list_free(devs);
+}
+
+TEST_F(devlink, info)
+{
+	struct devlink_get_list *devs;
+
+	devs = devlink_get_dump(self->ys);
+	ASSERT_NE(NULL, devs) {
+		TH_LOG("dump failed: %s", self->ys->err.msg);
+	}
+
+	if (ynl_dump_empty(devs)) {
+		devlink_get_list_free(devs);
+		SKIP(return, "no devices to query");
+	}
 
 	ynl_dump_foreach(devs, d) {
 		struct devlink_info_get_req *info_req;
 		struct devlink_info_get_rsp *info_rsp;
-		unsigned i;
+		unsigned int i;
 
-		printf("%s/%s:\n", d->bus_name, d->dev_name);
+		EXPECT_TRUE((bool)d->_len.bus_name);
+		EXPECT_TRUE((bool)d->_len.dev_name);
+		ksft_print_msg("%s/%s:\n", d->bus_name, d->dev_name);
 
 		info_req = devlink_info_get_req_alloc();
+		ASSERT_NE(NULL, info_req);
 		devlink_info_get_req_set_bus_name(info_req, d->bus_name);
 		devlink_info_get_req_set_dev_name(info_req, d->dev_name);
 
-		info_rsp = devlink_info_get(ys, info_req);
+		info_rsp = devlink_info_get(self->ys, info_req);
 		devlink_info_get_req_free(info_req);
-		if (!info_rsp)
-			goto err_free_devs;
+		ASSERT_NE(NULL, info_rsp) {
+			devlink_get_list_free(devs);
+			TH_LOG("info_get failed: %s", self->ys->err.msg);
+		}
 
+		EXPECT_TRUE((bool)info_rsp->_len.info_driver_name);
 		if (info_rsp->_len.info_driver_name)
-			printf("    driver: %s\n", info_rsp->info_driver_name);
+			ksft_print_msg("  driver: %s\n",
+				       info_rsp->info_driver_name);
 		if (info_rsp->_count.info_version_running)
-			printf("    running fw:\n");
+			ksft_print_msg("  running fw:\n");
 		for (i = 0; i < info_rsp->_count.info_version_running; i++)
-			printf("        %s: %s\n",
-			       info_rsp->info_version_running[i].info_version_name,
-			       info_rsp->info_version_running[i].info_version_value);
-		printf("    ...\n");
+			ksft_print_msg("    %s: %s\n",
+				       info_rsp->info_version_running[i].info_version_name,
+				       info_rsp->info_version_running[i].info_version_value);
 		devlink_info_get_rsp_free(info_rsp);
 	}
 	devlink_get_list_free(devs);
-
-	ynl_sock_destroy(ys);
-
-	return 0;
-
-err_free_devs:
-	devlink_get_list_free(devs);
-err_close:
-	fprintf(stderr, "YNL: %s\n", ys->err.msg);
-	ynl_sock_destroy(ys);
-	return 2;
 }
+
+TEST_HARNESS_MAIN
diff --git a/tools/net/ynl/tests/devlink.sh b/tools/net/ynl/tests/devlink.sh
new file mode 100755
index 000000000000..a684c749aa5e
--- /dev/null
+++ b/tools/net/ynl/tests/devlink.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+source "$(dirname "$(realpath "$0")")/ynl_nsim_lib.sh"
+nsim_setup
+"$(dirname "$(realpath "$0")")/devlink"
-- 
2.53.0