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