summaryrefslogtreecommitdiff
path: root/tools/net/ynl/tests/rt-link.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/net/ynl/tests/rt-link.c')
-rw-r--r--tools/net/ynl/tests/rt-link.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/tools/net/ynl/tests/rt-link.c b/tools/net/ynl/tests/rt-link.c
new file mode 100644
index 000000000000..ef619ce6143f
--- /dev/null
+++ b/tools/net/ynl/tests/rt-link.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <stdio.h>
+#include <string.h>
+
+#include <ynl.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <kselftest_harness.h>
+
+#include "rt-link-user.h"
+
+static void rt_link_print(struct __test_metadata *_metadata,
+ struct rt_link_getlink_rsp *r)
+{
+ unsigned int i;
+
+ 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("%6s: ", r->ifname);
+
+ if (r->_present.mtu)
+ printf("mtu %5d ", r->mtu);
+
+ if (r->linkinfo._len.kind)
+ printf("kind %-8s ", r->linkinfo.kind);
+ else
+ printf(" %8s ", "");
+
+ if (r->prop_list._count.alt_ifname) {
+ printf("altname ");
+ for (i = 0; i < r->prop_list._count.alt_ifname; i++)
+ printf("%s ", r->prop_list.alt_ifname[i]->str);
+ printf(" ");
+ }
+
+ if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) {
+ struct rt_link_linkinfo_netkit_attrs *netkit;
+ const char *name;
+
+ netkit = &r->linkinfo.data.netkit;
+ printf("primary %d ", netkit->primary);
+
+ name = NULL;
+ if (netkit->_present.policy)
+ name = rt_link_netkit_policy_str(netkit->policy);
+ if (name)
+ printf("policy %s ", name);
+ }
+
+ printf("\n");
+}
+
+static int netkit_create(struct ynl_sock *ys)
+{
+ struct rt_link_getlink_ntf *ntf_gl;
+ struct rt_link_newlink_req *req;
+ struct ynl_ntf_base_type *ntf;
+ int ret;
+
+ req = rt_link_newlink_req_alloc();
+ if (!req)
+ return -1;
+
+ rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO);
+ rt_link_newlink_req_set_linkinfo_kind(req, "netkit");
+ rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP);
+
+ ret = rt_link_newlink(ys, req);
+ rt_link_newlink_req_free(req);
+ if (ret)
+ return -1;
+
+ if (!ynl_has_ntf(ys))
+ return 0;
+
+ ntf = ynl_ntf_dequeue(ys);
+ if (!ntf || ntf->cmd != RTM_NEWLINK) {
+ ynl_ntf_free(ntf);
+ return 0;
+ }
+ ntf_gl = (void *)ntf;
+ ret = ntf_gl->obj._hdr.ifi_index;
+ ynl_ntf_free(ntf);
+
+ return ret;
+}
+
+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();
+ ASSERT_NE(NULL, req);
+
+ req->_hdr.ifi_index = ifindex;
+ EXPECT_EQ(0, rt_link_dellink(ys, req));
+ rt_link_dellink_req_free(req);
+}
+
+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;
+
+ 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);
+ ASSERT_NE(NULL, rsp) {
+ TH_LOG("dump failed: %s", self->ys->err.msg);
+ }
+ ASSERT_FALSE(ynl_dump_empty(rsp));
+
+ ynl_dump_foreach(rsp, link)
+ rt_link_print(_metadata, link);
+
+ rt_link_getlink_list_free(rsp);
+}
+
+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