All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jakub Kicinski <kuba@kernel.org>
To: davem@davemloft.net
Cc: netdev@vger.kernel.org, edumazet@google.com, pabeni@redhat.com,
	andrew+netdev@lunn.ch, horms@kernel.org, donald.hunter@gmail.com,
	liuhangbin@gmail.com, matttbe@kernel.org,
	Jakub Kicinski <kuba@kernel.org>
Subject: [PATCH net-next v2 04/10] tools: ynl: convert rt-link sample to selftest
Date: Fri,  6 Mar 2026 19:36:24 -0800	[thread overview]
Message-ID: <20260307033630.1396085-5-kuba@kernel.org> (raw)
In-Reply-To: <20260307033630.1396085-1-kuba@kernel.org>

Convert rt-link.c to use kselftest_harness.h with FIXTURE/TEST_F.
Move rt-link from BINS to TEST_GEN_PROGS.

Output:

  TAP version 13
  1..3
  # Starting 3 tests from 1 test cases.
  #  RUN           rt_link.dump ...
  #   1:          lo: mtu 65536
  #   2:          sit0: mtu  1480  kind sit
  #            OK  rt_link.dump
  ok 1 rt_link.dump
  #  RUN           rt_link.netkit ...
  #   4:          nk1: mtu  1500  kind netkit    primary 1  policy blackhole
  #            OK  rt_link.netkit
  ok 2 rt_link.netkit
  #  RUN           rt_link.netkit_err_msg ...
  #            OK  rt_link.netkit_err_msg
  ok 3 rt_link.netkit_err_msg
  # PASSED: 3 / 3 tests passed.
  # Totals: pass:3 fail:0 xfail:0 xpass:0 skip:0 error:0

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/tests/Makefile  |   2 +-
 tools/net/ynl/tests/rt-link.c | 196 +++++++++++++++++++---------------
 tools/net/ynl/tests/config    |   1 +
 3 files changed, 111 insertions(+), 88 deletions(-)

diff --git a/tools/net/ynl/tests/Makefile b/tools/net/ynl/tests/Makefile
index df9d37c8b2a4..08d1146d91ce 100644
--- a/tools/net/ynl/tests/Makefile
+++ b/tools/net/ynl/tests/Makefile
@@ -21,13 +21,13 @@ TEST_PROGS := \
 TEST_GEN_PROGS := \
 	netdev \
 	ovs \
+	rt-link \
 # end of TEST_GEN_PROGS
 
 BINS := \
 	devlink \
 	ethtool \
 	rt-addr \
-	rt-link \
 	rt-route \
 	tc \
 	tc-filter-add \
diff --git a/tools/net/ynl/tests/rt-link.c b/tools/net/ynl/tests/rt-link.c
index acdd4b4a0f74..ef619ce6143f 100644
--- a/tools/net/ynl/tests/rt-link.c
+++ b/tools/net/ynl/tests/rt-link.c
@@ -7,16 +7,21 @@
 #include <arpa/inet.h>
 #include <net/if.h>
 
+#include <kselftest_harness.h>
+
 #include "rt-link-user.h"
 
-static void rt_link_print(struct rt_link_getlink_rsp *r)
+static void rt_link_print(struct __test_metadata *_metadata,
+			  struct rt_link_getlink_rsp *r)
 {
 	unsigned int i;
 
-	printf("%3d: ", r->_hdr.ifi_index);
+	EXPECT_TRUE((bool)r->_hdr.ifi_index);
+	ksft_print_msg("%3d: ", r->_hdr.ifi_index);
 
+	EXPECT_TRUE((bool)r->_len.ifname);
 	if (r->_len.ifname)
-		printf("%16s: ", r->ifname);
+		printf("%6s: ", r->ifname);
 
 	if (r->_present.mtu)
 		printf("mtu %5d  ", r->mtu);
@@ -50,7 +55,7 @@ static void rt_link_print(struct rt_link_getlink_rsp *r)
 	printf("\n");
 }
 
-static int rt_link_create_netkit(struct ynl_sock *ys)
+static int netkit_create(struct ynl_sock *ys)
 {
 	struct rt_link_getlink_ntf *ntf_gl;
 	struct rt_link_newlink_req *req;
@@ -58,49 +63,24 @@ static int rt_link_create_netkit(struct ynl_sock *ys)
 	int ret;
 
 	req = rt_link_newlink_req_alloc();
-	if (!req) {
-		fprintf(stderr, "Can't alloc req\n");
+	if (!req)
 		return -1;
-	}
 
-	/* rtnetlink doesn't provide info about the created object.
-	 * It expects us to set the ECHO flag and the dig the info out
-	 * of the notifications...
-	 */
 	rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO);
-
 	rt_link_newlink_req_set_linkinfo_kind(req, "netkit");
-
-	/* Test error messages */
-	rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10);
-	ret = rt_link_newlink(ys, req);
-	if (ret) {
-		printf("Testing error message for policy being bad:\n\t%s\n", ys->err.msg);
-	} else {
-		fprintf(stderr,	"Warning: unexpected success creating netkit with bad attrs\n");
-		goto created;
-	}
-
 	rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP);
 
 	ret = rt_link_newlink(ys, req);
-created:
 	rt_link_newlink_req_free(req);
-	if (ret) {
-		fprintf(stderr, "YNL: %s\n", ys->err.msg);
+	if (ret)
 		return -1;
-	}
 
-	if (!ynl_has_ntf(ys)) {
-		fprintf(stderr,
-			"Warning: interface created but received no notification, won't delete the interface\n");
+	if (!ynl_has_ntf(ys))
 		return 0;
-	}
 
 	ntf = ynl_ntf_dequeue(ys);
-	if (ntf->cmd !=	RTM_NEWLINK) {
-		fprintf(stderr,
-			"Warning: unexpected notification type, won't delete the interface\n");
+	if (!ntf || ntf->cmd != RTM_NEWLINK) {
+		ynl_ntf_free(ntf);
 		return 0;
 	}
 	ntf_gl = (void *)ntf;
@@ -110,75 +90,117 @@ static int rt_link_create_netkit(struct ynl_sock *ys)
 	return ret;
 }
 
-static void rt_link_del(struct ynl_sock *ys, int ifindex)
+static void netkit_delete(struct __test_metadata *_metadata,
+			  struct ynl_sock *ys, int ifindex)
 {
 	struct rt_link_dellink_req *req;
 
 	req = rt_link_dellink_req_alloc();
-	if (!req) {
-		fprintf(stderr, "Can't alloc req\n");
-		return;
-	}
+	ASSERT_NE(NULL, req);
 
 	req->_hdr.ifi_index = ifindex;
-	if (rt_link_dellink(ys, req))
-		fprintf(stderr, "YNL: %s\n", ys->err.msg);
-	else
-		fprintf(stderr,
-			"Trying to delete a Netkit interface (ifindex %d)\n",
-			ifindex);
-
+	EXPECT_EQ(0, rt_link_dellink(ys, req));
 	rt_link_dellink_req_free(req);
 }
 
-int main(int argc, char **argv)
+FIXTURE(rt_link)
+{
+	struct ynl_sock *ys;
+};
+
+FIXTURE_SETUP(rt_link)
+{
+	struct ynl_error yerr;
+
+	self->ys = ynl_sock_create(&ynl_rt_link_family, &yerr);
+	ASSERT_NE(NULL, self->ys) {
+		TH_LOG("failed to create rt-link socket: %s", yerr.msg);
+	}
+}
+
+FIXTURE_TEARDOWN(rt_link)
+{
+	ynl_sock_destroy(self->ys);
+}
+
+TEST_F(rt_link, dump)
 {
 	struct rt_link_getlink_req_dump *req;
 	struct rt_link_getlink_list *rsp;
-	struct ynl_error yerr;
-	struct ynl_sock *ys;
-	int created = 0;
-
-	ys = ynl_sock_create(&ynl_rt_link_family, &yerr);
-	if (!ys) {
-		fprintf(stderr, "YNL: %s\n", yerr.msg);
-		return 1;
-	}
-
-	if (argc > 1) {
-		fprintf(stderr, "Trying to create a Netkit interface\n");
-		created = rt_link_create_netkit(ys);
-		if (created < 0)
-			goto err_destroy;
-	}
 
 	req = rt_link_getlink_req_dump_alloc();
-	if (!req)
-		goto err_del_ifc;
-
-	rsp = rt_link_getlink_dump(ys, req);
+	ASSERT_NE(NULL, req);
+	rsp = rt_link_getlink_dump(self->ys, req);
 	rt_link_getlink_req_dump_free(req);
-	if (!rsp)
-		goto err_close;
+	ASSERT_NE(NULL, rsp) {
+		TH_LOG("dump failed: %s", self->ys->err.msg);
+	}
+	ASSERT_FALSE(ynl_dump_empty(rsp));
 
-	if (ynl_dump_empty(rsp))
-		fprintf(stderr, "Error: no links reported\n");
 	ynl_dump_foreach(rsp, link)
-		rt_link_print(link);
+		rt_link_print(_metadata, link);
+
 	rt_link_getlink_list_free(rsp);
-
-	if (created)
-		rt_link_del(ys, created);
-
-	ynl_sock_destroy(ys);
-	return 0;
-
-err_close:
-	fprintf(stderr, "YNL: %s\n", ys->err.msg);
-err_del_ifc:
-	if (created)
-		rt_link_del(ys, created);
-err_destroy:
-	ynl_sock_destroy(ys);
-	return 2;
 }
+
+TEST_F(rt_link, netkit)
+{
+	struct rt_link_getlink_req_dump *dreq;
+	struct rt_link_getlink_list *rsp;
+	bool found = false;
+	int netkit_ifindex;
+
+	/* Create netkit with valid policy */
+	netkit_ifindex = netkit_create(self->ys);
+	ASSERT_GT(netkit_ifindex, 0)
+		TH_LOG("failed to create netkit: %s", self->ys->err.msg);
+
+	/* Verify it appears in a dump */
+	dreq = rt_link_getlink_req_dump_alloc();
+	ASSERT_NE(NULL, dreq);
+	rsp = rt_link_getlink_dump(self->ys, dreq);
+	rt_link_getlink_req_dump_free(dreq);
+	ASSERT_NE(NULL, rsp) {
+		TH_LOG("dump failed: %s", self->ys->err.msg);
+	}
+
+	ynl_dump_foreach(rsp, link) {
+		if (link->_hdr.ifi_index == netkit_ifindex) {
+			rt_link_print(_metadata, link);
+			found = true;
+		}
+	}
+	rt_link_getlink_list_free(rsp);
+	EXPECT_TRUE(found);
+
+	netkit_delete(_metadata, self->ys, netkit_ifindex);
+}
+
+TEST_F(rt_link, netkit_err_msg)
+{
+	struct rt_link_newlink_req *req;
+	int ret;
+
+	/* Test creating netkit with bad policy - should fail */
+	req = rt_link_newlink_req_alloc();
+	ASSERT_NE(NULL, req);
+	rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE);
+	rt_link_newlink_req_set_linkinfo_kind(req, "netkit");
+	rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10);
+
+	ret = rt_link_newlink(self->ys, req);
+	rt_link_newlink_req_free(req);
+	EXPECT_NE(0, ret) {
+		TH_LOG("creating netkit with bad policy should fail");
+	}
+
+	/* Expect:
+	 * Kernel error: 'Provided default xmit policy not supported' (bad attribute: .linkinfo.data(netkit).policy)
+	 */
+	EXPECT_NE(NULL, strstr(self->ys->err.msg, "bad attribute: .linkinfo.data(netkit).policy")) {
+		TH_LOG("expected extack msg not found: %s",
+		       self->ys->err.msg);
+	}
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/net/ynl/tests/config b/tools/net/ynl/tests/config
index 357b34611da4..b4c58d86a6c2 100644
--- a/tools/net/ynl/tests/config
+++ b/tools/net/ynl/tests/config
@@ -3,5 +3,6 @@ CONFIG_INET_DIAG=y
 CONFIG_IPV6=y
 CONFIG_NET_NS=y
 CONFIG_NETDEVSIM=m
+CONFIG_NETKIT=y
 CONFIG_OPENVSWITCH=m
 CONFIG_VETH=m
-- 
2.53.0


  parent reply	other threads:[~2026-03-07  3:36 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-07  3:36 [PATCH net-next v2 00/10] tools: ynl: convert samples into selftests Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 01/10] tools: ynl: move samples to tests Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 02/10] tools: ynl: convert netdev sample to selftest Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 03/10] tools: ynl: convert ovs " Jakub Kicinski
2026-03-07  3:36 ` Jakub Kicinski [this message]
2026-03-07  3:36 ` [PATCH net-next v2 05/10] tools: ynl: convert tc and tc-filter-add samples " Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 06/10] tools: ynl: add netdevsim wrapper library for YNL tests Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 07/10] tools: ynl: convert devlink sample to selftest Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 08/10] tools: ynl: convert ethtool " Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 09/10] tools: ynl: convert rt-addr " Jakub Kicinski
2026-03-07  3:36 ` [PATCH net-next v2 10/10] tools: ynl: convert rt-route " Jakub Kicinski
2026-03-08 17:23 ` [PATCH net-next v2 00/10] tools: ynl: convert samples into selftests Donald Hunter
2026-03-10  0:10 ` patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260307033630.1396085-5-kuba@kernel.org \
    --to=kuba@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=donald.hunter@gmail.com \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=liuhangbin@gmail.com \
    --cc=matttbe@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.