tools: ynl: convert ovs sample to selftest

Convert ovs.c to produce KTAP output with kselftest_harness.
The single "crud" test creates a new OVS datapath, fetches it back
by name, then dumps all datapaths verifying the new one appears.

IIRC I added this test because ovs is a genetlink family but
has a family-specific fixed header.

  TAP version 13
  1..1
  # Starting 1 tests from 1 test cases.
  #  RUN           ovs.crud ...
  # get:
  # ynl-test(3): pid:0 cache:256
  # dump:
  # ynl-test(3): pid:0 cache:256
  #            OK  ovs.crud
  ok 1 ovs.crud
  # PASSED: 1 / 1 tests passed.
  # Totals: pass:1 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-4-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-03-06 19:36:23 -08:00
parent 285804d63f
commit 7e3effbc76
3 changed files with 91 additions and 41 deletions

View File

@@ -20,12 +20,12 @@ TEST_PROGS := \
TEST_GEN_PROGS := \
netdev \
ovs \
# end of TEST_GEN_PROGS
BINS := \
devlink \
ethtool \
ovs \
rt-addr \
rt-link \
rt-route \
@@ -34,6 +34,7 @@ BINS := \
# end of BINS
CFLAGS_netdev:=$(CFLAGS_netdev) $(CFLAGS_rt-link)
CFLAGS_ovs:=$(CFLAGS_ovs_datapath)
CFLAGS_tc-filter-add:=$(CFLAGS_tc)
include $(wildcard *.d)

View File

@@ -3,4 +3,5 @@ CONFIG_INET_DIAG=y
CONFIG_IPV6=y
CONFIG_NET_NS=y
CONFIG_NETDEVSIM=m
CONFIG_OPENVSWITCH=m
CONFIG_VETH=m

View File

@@ -4,57 +4,105 @@
#include <ynl.h>
#include <kselftest_harness.h>
#include "ovs_datapath-user.h"
int main(int argc, char **argv)
static void ovs_print_datapath(struct __test_metadata *_metadata,
struct ovs_datapath_get_rsp *dp)
{
EXPECT_TRUE((bool)dp->_len.name);
if (!dp->_len.name)
return;
EXPECT_TRUE((bool)dp->_hdr.dp_ifindex);
ksft_print_msg("%s(%d): pid:%u cache:%u\n",
dp->name, dp->_hdr.dp_ifindex,
dp->upcall_pid, dp->masks_cache_size);
}
FIXTURE(ovs)
{
struct ynl_sock *ys;
char *dp_name;
};
FIXTURE_SETUP(ovs)
{
self->ys = ynl_sock_create(&ynl_ovs_datapath_family, NULL);
ASSERT_NE(NULL, self->ys)
TH_LOG("failed to create OVS datapath socket");
}
FIXTURE_TEARDOWN(ovs)
{
if (self->dp_name) {
struct ovs_datapath_del_req *req;
req = ovs_datapath_del_req_alloc();
if (req) {
ovs_datapath_del_req_set_name(req, self->dp_name);
ovs_datapath_del(self->ys, req);
ovs_datapath_del_req_free(req);
}
}
ynl_sock_destroy(self->ys);
}
TEST_F(ovs, crud)
{
struct ovs_datapath_get_req_dump *dreq;
struct ovs_datapath_new_req *new_req;
struct ovs_datapath_get_list *dps;
struct ovs_datapath_get_rsp *dp;
struct ovs_datapath_get_req *req;
bool found = false;
int err;
ys = ynl_sock_create(&ynl_ovs_datapath_family, NULL);
if (!ys)
return 1;
new_req = ovs_datapath_new_req_alloc();
ASSERT_NE(NULL, new_req);
ovs_datapath_new_req_set_upcall_pid(new_req, 1);
ovs_datapath_new_req_set_name(new_req, "ynl-test");
if (argc > 1) {
struct ovs_datapath_new_req *req;
err = ovs_datapath_new(self->ys, new_req);
ovs_datapath_new_req_free(new_req);
ASSERT_EQ(0, err) {
TH_LOG("new failed: %s", self->ys->err.msg);
}
self->dp_name = "ynl-test";
req = ovs_datapath_new_req_alloc();
if (!req)
goto err_close;
ksft_print_msg("get:\n");
req = ovs_datapath_get_req_alloc();
ASSERT_NE(NULL, req);
ovs_datapath_get_req_set_name(req, "ynl-test");
ovs_datapath_new_req_set_upcall_pid(req, 1);
ovs_datapath_new_req_set_name(req, argv[1]);
err = ovs_datapath_new(ys, req);
ovs_datapath_new_req_free(req);
if (err)
goto err_close;
} else {
struct ovs_datapath_get_req_dump *req;
struct ovs_datapath_get_list *dps;
printf("Dump:\n");
req = ovs_datapath_get_req_dump_alloc();
dps = ovs_datapath_get_dump(ys, req);
ovs_datapath_get_req_dump_free(req);
if (!dps)
goto err_close;
ynl_dump_foreach(dps, dp) {
printf(" %s(%d): pid:%u cache:%u\n",
dp->name, dp->_hdr.dp_ifindex,
dp->upcall_pid, dp->masks_cache_size);
}
ovs_datapath_get_list_free(dps);
dp = ovs_datapath_get(self->ys, req);
ovs_datapath_get_req_free(req);
ASSERT_NE(NULL, dp) {
TH_LOG("get failed: %s", self->ys->err.msg);
}
ynl_sock_destroy(ys);
ovs_print_datapath(_metadata, dp);
EXPECT_STREQ("ynl-test", dp->name);
ovs_datapath_get_rsp_free(dp);
return 0;
ksft_print_msg("dump:\n");
dreq = ovs_datapath_get_req_dump_alloc();
ASSERT_NE(NULL, dreq);
err_close:
fprintf(stderr, "YNL (%d): %s\n", ys->err.code, ys->err.msg);
ynl_sock_destroy(ys);
return 2;
dps = ovs_datapath_get_dump(self->ys, dreq);
ovs_datapath_get_req_dump_free(dreq);
ASSERT_NE(NULL, dps) {
TH_LOG("dump failed: %s", self->ys->err.msg);
}
ynl_dump_foreach(dps, d) {
ovs_print_datapath(_metadata, d);
if (d->name && !strcmp(d->name, "ynl-test"))
found = true;
}
ovs_datapath_get_list_free(dps);
EXPECT_TRUE(found);
}
TEST_HARNESS_MAIN