public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Donald Hunter <donald.hunter@gmail.com>
To: Jakub Kicinski <kuba@kernel.org>
Cc: davem@davemloft.net,  netdev@vger.kernel.org,
	 edumazet@google.com, pabeni@redhat.com,  andrew+netdev@lunn.ch,
	 horms@kernel.org, liuhangbin@gmail.com,  matttbe@kernel.org
Subject: Re: [PATCH net-next 04/10] tools: ynl: convert rt-link sample to selftest
Date: Fri, 06 Mar 2026 14:29:09 +0000	[thread overview]
Message-ID: <m2y0k5ghfu.fsf@gmail.com> (raw)
In-Reply-To: <20260306020901.524105-5-kuba@kernel.org>

Jakub Kicinski <kuba@kernel.org> writes:

> 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 | 192 +++++++++++++++++++---------------
>  tools/net/ynl/tests/config    |   1 +
>  3 files changed, 108 insertions(+), 87 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..a55f7523dbe8 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,115 @@ 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");
> +	if (!req)
>  		return;
> -	}
>  
>  	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);
> +	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();

I see there's error handling for *_alloc() in helper functions but
not in tests. Is that intentional?

> +	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();
> +	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

  reply	other threads:[~2026-03-06 14:29 UTC|newest]

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

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=m2y0k5ghfu.fsf@gmail.com \
    --to=donald.hunter@gmail.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox