// SPDX-License-Identifier: GPL-2.0 #include #include #include #include #include #include #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