]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tools: ynl: convert rt-link sample to selftest
authorJakub Kicinski <kuba@kernel.org>
Sat, 7 Mar 2026 03:36:24 +0000 (19:36 -0800)
committerJakub Kicinski <kuba@kernel.org>
Tue, 10 Mar 2026 00:02:26 +0000 (17:02 -0700)
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

Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
Tested-by: Donald Hunter <donald.hunter@gmail.com>
Link: https://patch.msgid.link/20260307033630.1396085-5-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
tools/net/ynl/tests/Makefile
tools/net/ynl/tests/config
tools/net/ynl/tests/rt-link.c

index df9d37c8b2a4428018e0a9c15294affde85dab81..08d1146d91ce356898e11191fdef2bc7746ba334 100644 (file)
@@ -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 \
index 357b34611da4a55408fbef16961ece8d48c0bfde..b4c58d86a6c26d8f8c02415bd1d4fe1971ff1eef 100644 (file)
@@ -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
index acdd4b4a0f7433ec8b0394513b798d2c4345a33b..ef619ce6143f3f7919cbdeac6d25b4e67126fbd4 100644 (file)
@@ -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 @@ created:
        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 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;
-       }
+FIXTURE_SETUP(rt_link)
+{
+       struct ynl_error yerr;
 
-       if (argc > 1) {
-               fprintf(stderr, "Trying to create a Netkit interface\n");
-               created = rt_link_create_netkit(ys);
-               if (created < 0)
-                       goto err_destroy;
+       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);
        }
+}
 
-       req = rt_link_getlink_req_dump_alloc();
-       if (!req)
-               goto err_del_ifc;
+FIXTURE_TEARDOWN(rt_link)
+{
+       ynl_sock_destroy(self->ys);
+}
 
-       rsp = rt_link_getlink_dump(ys, req);
+TEST_F(rt_link, dump)
+{
+       struct rt_link_getlink_req_dump *req;
+       struct rt_link_getlink_list *rsp;
+
+       req = rt_link_getlink_req_dump_alloc();
+       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);
+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_sock_destroy(ys);
-       return 0;
+       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);
 
-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;
+       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