1e0aa0c61SJakub Kicinski // SPDX-License-Identifier: GPL-2.0 2e0aa0c61SJakub Kicinski #include <stdio.h> 3e0aa0c61SJakub Kicinski #include <string.h> 4e0aa0c61SJakub Kicinski 5e0aa0c61SJakub Kicinski #include <ynl.h> 6e0aa0c61SJakub Kicinski 7e0aa0c61SJakub Kicinski #include <arpa/inet.h> 8e0aa0c61SJakub Kicinski #include <net/if.h> 9e0aa0c61SJakub Kicinski 10*5c320678SJakub Kicinski #include <kselftest_harness.h> 11*5c320678SJakub Kicinski 12e0aa0c61SJakub Kicinski #include "rt-link-user.h" 13e0aa0c61SJakub Kicinski 14*5c320678SJakub Kicinski static void rt_link_print(struct __test_metadata *_metadata, 15*5c320678SJakub Kicinski struct rt_link_getlink_rsp *r) 16e0aa0c61SJakub Kicinski { 17e0aa0c61SJakub Kicinski unsigned int i; 18e0aa0c61SJakub Kicinski 19*5c320678SJakub Kicinski EXPECT_TRUE((bool)r->_hdr.ifi_index); 20*5c320678SJakub Kicinski ksft_print_msg("%3d: ", r->_hdr.ifi_index); 21e0aa0c61SJakub Kicinski 22*5c320678SJakub Kicinski EXPECT_TRUE((bool)r->_len.ifname); 23e0aa0c61SJakub Kicinski if (r->_len.ifname) 24*5c320678SJakub Kicinski printf("%6s: ", r->ifname); 25e0aa0c61SJakub Kicinski 26e0aa0c61SJakub Kicinski if (r->_present.mtu) 27e0aa0c61SJakub Kicinski printf("mtu %5d ", r->mtu); 28e0aa0c61SJakub Kicinski 29e0aa0c61SJakub Kicinski if (r->linkinfo._len.kind) 30e0aa0c61SJakub Kicinski printf("kind %-8s ", r->linkinfo.kind); 31e0aa0c61SJakub Kicinski else 32e0aa0c61SJakub Kicinski printf(" %8s ", ""); 33e0aa0c61SJakub Kicinski 34e0aa0c61SJakub Kicinski if (r->prop_list._count.alt_ifname) { 35e0aa0c61SJakub Kicinski printf("altname "); 36e0aa0c61SJakub Kicinski for (i = 0; i < r->prop_list._count.alt_ifname; i++) 37e0aa0c61SJakub Kicinski printf("%s ", r->prop_list.alt_ifname[i]->str); 38e0aa0c61SJakub Kicinski printf(" "); 39e0aa0c61SJakub Kicinski } 40e0aa0c61SJakub Kicinski 41e0aa0c61SJakub Kicinski if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) { 42e0aa0c61SJakub Kicinski struct rt_link_linkinfo_netkit_attrs *netkit; 43e0aa0c61SJakub Kicinski const char *name; 44e0aa0c61SJakub Kicinski 45e0aa0c61SJakub Kicinski netkit = &r->linkinfo.data.netkit; 46e0aa0c61SJakub Kicinski printf("primary %d ", netkit->primary); 47e0aa0c61SJakub Kicinski 48e0aa0c61SJakub Kicinski name = NULL; 49e0aa0c61SJakub Kicinski if (netkit->_present.policy) 50e0aa0c61SJakub Kicinski name = rt_link_netkit_policy_str(netkit->policy); 51e0aa0c61SJakub Kicinski if (name) 52e0aa0c61SJakub Kicinski printf("policy %s ", name); 53e0aa0c61SJakub Kicinski } 54e0aa0c61SJakub Kicinski 55e0aa0c61SJakub Kicinski printf("\n"); 56e0aa0c61SJakub Kicinski } 57e0aa0c61SJakub Kicinski 58*5c320678SJakub Kicinski static int netkit_create(struct ynl_sock *ys) 59e0aa0c61SJakub Kicinski { 60e0aa0c61SJakub Kicinski struct rt_link_getlink_ntf *ntf_gl; 61e0aa0c61SJakub Kicinski struct rt_link_newlink_req *req; 62e0aa0c61SJakub Kicinski struct ynl_ntf_base_type *ntf; 63e0aa0c61SJakub Kicinski int ret; 64e0aa0c61SJakub Kicinski 65e0aa0c61SJakub Kicinski req = rt_link_newlink_req_alloc(); 66*5c320678SJakub Kicinski if (!req) 67e0aa0c61SJakub Kicinski return -1; 68e0aa0c61SJakub Kicinski 69e0aa0c61SJakub Kicinski rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); 70e0aa0c61SJakub Kicinski rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); 71e0aa0c61SJakub Kicinski rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP); 72e0aa0c61SJakub Kicinski 73e0aa0c61SJakub Kicinski ret = rt_link_newlink(ys, req); 74e0aa0c61SJakub Kicinski rt_link_newlink_req_free(req); 75*5c320678SJakub Kicinski if (ret) 76e0aa0c61SJakub Kicinski return -1; 77e0aa0c61SJakub Kicinski 78*5c320678SJakub Kicinski if (!ynl_has_ntf(ys)) 79e0aa0c61SJakub Kicinski return 0; 80e0aa0c61SJakub Kicinski 81e0aa0c61SJakub Kicinski ntf = ynl_ntf_dequeue(ys); 82*5c320678SJakub Kicinski if (!ntf || ntf->cmd != RTM_NEWLINK) { 83*5c320678SJakub Kicinski ynl_ntf_free(ntf); 84e0aa0c61SJakub Kicinski return 0; 85e0aa0c61SJakub Kicinski } 86e0aa0c61SJakub Kicinski ntf_gl = (void *)ntf; 87e0aa0c61SJakub Kicinski ret = ntf_gl->obj._hdr.ifi_index; 88e0aa0c61SJakub Kicinski ynl_ntf_free(ntf); 89e0aa0c61SJakub Kicinski 90e0aa0c61SJakub Kicinski return ret; 91e0aa0c61SJakub Kicinski } 92e0aa0c61SJakub Kicinski 93*5c320678SJakub Kicinski static void netkit_delete(struct __test_metadata *_metadata, 94*5c320678SJakub Kicinski struct ynl_sock *ys, int ifindex) 95e0aa0c61SJakub Kicinski { 96e0aa0c61SJakub Kicinski struct rt_link_dellink_req *req; 97e0aa0c61SJakub Kicinski 98e0aa0c61SJakub Kicinski req = rt_link_dellink_req_alloc(); 99*5c320678SJakub Kicinski ASSERT_NE(NULL, req); 100e0aa0c61SJakub Kicinski 101e0aa0c61SJakub Kicinski req->_hdr.ifi_index = ifindex; 102*5c320678SJakub Kicinski EXPECT_EQ(0, rt_link_dellink(ys, req)); 103e0aa0c61SJakub Kicinski rt_link_dellink_req_free(req); 104e0aa0c61SJakub Kicinski } 105e0aa0c61SJakub Kicinski 106*5c320678SJakub Kicinski FIXTURE(rt_link) 107*5c320678SJakub Kicinski { 108*5c320678SJakub Kicinski struct ynl_sock *ys; 109*5c320678SJakub Kicinski }; 110*5c320678SJakub Kicinski 111*5c320678SJakub Kicinski FIXTURE_SETUP(rt_link) 112*5c320678SJakub Kicinski { 113*5c320678SJakub Kicinski struct ynl_error yerr; 114*5c320678SJakub Kicinski 115*5c320678SJakub Kicinski self->ys = ynl_sock_create(&ynl_rt_link_family, &yerr); 116*5c320678SJakub Kicinski ASSERT_NE(NULL, self->ys) { 117*5c320678SJakub Kicinski TH_LOG("failed to create rt-link socket: %s", yerr.msg); 118*5c320678SJakub Kicinski } 119*5c320678SJakub Kicinski } 120*5c320678SJakub Kicinski 121*5c320678SJakub Kicinski FIXTURE_TEARDOWN(rt_link) 122*5c320678SJakub Kicinski { 123*5c320678SJakub Kicinski ynl_sock_destroy(self->ys); 124*5c320678SJakub Kicinski } 125*5c320678SJakub Kicinski 126*5c320678SJakub Kicinski TEST_F(rt_link, dump) 127e0aa0c61SJakub Kicinski { 128e0aa0c61SJakub Kicinski struct rt_link_getlink_req_dump *req; 129e0aa0c61SJakub Kicinski struct rt_link_getlink_list *rsp; 130e0aa0c61SJakub Kicinski 131e0aa0c61SJakub Kicinski req = rt_link_getlink_req_dump_alloc(); 132*5c320678SJakub Kicinski ASSERT_NE(NULL, req); 133*5c320678SJakub Kicinski rsp = rt_link_getlink_dump(self->ys, req); 134e0aa0c61SJakub Kicinski rt_link_getlink_req_dump_free(req); 135*5c320678SJakub Kicinski ASSERT_NE(NULL, rsp) { 136*5c320678SJakub Kicinski TH_LOG("dump failed: %s", self->ys->err.msg); 137e0aa0c61SJakub Kicinski } 138*5c320678SJakub Kicinski ASSERT_FALSE(ynl_dump_empty(rsp)); 139*5c320678SJakub Kicinski 140*5c320678SJakub Kicinski ynl_dump_foreach(rsp, link) 141*5c320678SJakub Kicinski rt_link_print(_metadata, link); 142*5c320678SJakub Kicinski 143*5c320678SJakub Kicinski rt_link_getlink_list_free(rsp); 144*5c320678SJakub Kicinski } 145*5c320678SJakub Kicinski 146*5c320678SJakub Kicinski TEST_F(rt_link, netkit) 147*5c320678SJakub Kicinski { 148*5c320678SJakub Kicinski struct rt_link_getlink_req_dump *dreq; 149*5c320678SJakub Kicinski struct rt_link_getlink_list *rsp; 150*5c320678SJakub Kicinski bool found = false; 151*5c320678SJakub Kicinski int netkit_ifindex; 152*5c320678SJakub Kicinski 153*5c320678SJakub Kicinski /* Create netkit with valid policy */ 154*5c320678SJakub Kicinski netkit_ifindex = netkit_create(self->ys); 155*5c320678SJakub Kicinski ASSERT_GT(netkit_ifindex, 0) 156*5c320678SJakub Kicinski TH_LOG("failed to create netkit: %s", self->ys->err.msg); 157*5c320678SJakub Kicinski 158*5c320678SJakub Kicinski /* Verify it appears in a dump */ 159*5c320678SJakub Kicinski dreq = rt_link_getlink_req_dump_alloc(); 160*5c320678SJakub Kicinski ASSERT_NE(NULL, dreq); 161*5c320678SJakub Kicinski rsp = rt_link_getlink_dump(self->ys, dreq); 162*5c320678SJakub Kicinski rt_link_getlink_req_dump_free(dreq); 163*5c320678SJakub Kicinski ASSERT_NE(NULL, rsp) { 164*5c320678SJakub Kicinski TH_LOG("dump failed: %s", self->ys->err.msg); 165*5c320678SJakub Kicinski } 166*5c320678SJakub Kicinski 167*5c320678SJakub Kicinski ynl_dump_foreach(rsp, link) { 168*5c320678SJakub Kicinski if (link->_hdr.ifi_index == netkit_ifindex) { 169*5c320678SJakub Kicinski rt_link_print(_metadata, link); 170*5c320678SJakub Kicinski found = true; 171*5c320678SJakub Kicinski } 172*5c320678SJakub Kicinski } 173*5c320678SJakub Kicinski rt_link_getlink_list_free(rsp); 174*5c320678SJakub Kicinski EXPECT_TRUE(found); 175*5c320678SJakub Kicinski 176*5c320678SJakub Kicinski netkit_delete(_metadata, self->ys, netkit_ifindex); 177*5c320678SJakub Kicinski } 178*5c320678SJakub Kicinski 179*5c320678SJakub Kicinski TEST_F(rt_link, netkit_err_msg) 180*5c320678SJakub Kicinski { 181*5c320678SJakub Kicinski struct rt_link_newlink_req *req; 182*5c320678SJakub Kicinski int ret; 183*5c320678SJakub Kicinski 184*5c320678SJakub Kicinski /* Test creating netkit with bad policy - should fail */ 185*5c320678SJakub Kicinski req = rt_link_newlink_req_alloc(); 186*5c320678SJakub Kicinski ASSERT_NE(NULL, req); 187*5c320678SJakub Kicinski rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE); 188*5c320678SJakub Kicinski rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); 189*5c320678SJakub Kicinski rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10); 190*5c320678SJakub Kicinski 191*5c320678SJakub Kicinski ret = rt_link_newlink(self->ys, req); 192*5c320678SJakub Kicinski rt_link_newlink_req_free(req); 193*5c320678SJakub Kicinski EXPECT_NE(0, ret) { 194*5c320678SJakub Kicinski TH_LOG("creating netkit with bad policy should fail"); 195*5c320678SJakub Kicinski } 196*5c320678SJakub Kicinski 197*5c320678SJakub Kicinski /* Expect: 198*5c320678SJakub Kicinski * Kernel error: 'Provided default xmit policy not supported' (bad attribute: .linkinfo.data(netkit).policy) 199*5c320678SJakub Kicinski */ 200*5c320678SJakub Kicinski EXPECT_NE(NULL, strstr(self->ys->err.msg, "bad attribute: .linkinfo.data(netkit).policy")) { 201*5c320678SJakub Kicinski TH_LOG("expected extack msg not found: %s", 202*5c320678SJakub Kicinski self->ys->err.msg); 203*5c320678SJakub Kicinski } 204*5c320678SJakub Kicinski } 205*5c320678SJakub Kicinski 206*5c320678SJakub Kicinski TEST_HARNESS_MAIN 207