1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdio.h> 3 #include <string.h> 4 5 #include <ynl.h> 6 7 #include <net/if.h> 8 9 #include <kselftest_harness.h> 10 11 #include "netdev-user.h" 12 #include "rt-link-user.h" 13 14 static void netdev_print_device(struct __test_metadata *_metadata, 15 struct netdev_dev_get_rsp *d, unsigned int op) 16 { 17 char ifname[IF_NAMESIZE]; 18 const char *name; 19 20 EXPECT_TRUE((bool)d->_present.ifindex); 21 if (!d->_present.ifindex) 22 return; 23 24 name = if_indextoname(d->ifindex, ifname); 25 EXPECT_TRUE((bool)name); 26 if (name) 27 ksft_print_msg("%8s[%d]\t", name, d->ifindex); 28 else 29 ksft_print_msg("[%d]\t", d->ifindex); 30 31 EXPECT_TRUE((bool)d->_present.xdp_features); 32 if (!d->_present.xdp_features) 33 return; 34 35 printf("xdp-features (%llx):", d->xdp_features); 36 for (int i = 0; d->xdp_features >= 1U << i; i++) { 37 if (d->xdp_features & (1U << i)) 38 printf(" %s", netdev_xdp_act_str(1 << i)); 39 } 40 41 printf(" xdp-rx-metadata-features (%llx):", 42 d->xdp_rx_metadata_features); 43 for (int i = 0; d->xdp_rx_metadata_features >= 1U << i; i++) { 44 if (d->xdp_rx_metadata_features & (1U << i)) 45 printf(" %s", 46 netdev_xdp_rx_metadata_str(1 << i)); 47 } 48 49 printf(" xsk-features (%llx):", d->xsk_features); 50 for (int i = 0; d->xsk_features >= 1U << i; i++) { 51 if (d->xsk_features & (1U << i)) 52 printf(" %s", netdev_xsk_flags_str(1 << i)); 53 } 54 55 printf(" xdp-zc-max-segs=%u", d->xdp_zc_max_segs); 56 57 name = netdev_op_str(op); 58 if (name) 59 printf(" (ntf: %s)", name); 60 printf("\n"); 61 } 62 63 static int veth_create(struct ynl_sock *ys_link) 64 { 65 struct rt_link_getlink_ntf *ntf_gl; 66 struct rt_link_newlink_req *req; 67 struct ynl_ntf_base_type *ntf; 68 int ret; 69 70 req = rt_link_newlink_req_alloc(); 71 if (!req) 72 return -1; 73 74 rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); 75 rt_link_newlink_req_set_linkinfo_kind(req, "veth"); 76 77 ret = rt_link_newlink(ys_link, req); 78 rt_link_newlink_req_free(req); 79 if (ret) 80 return -1; 81 82 if (!ynl_has_ntf(ys_link)) 83 return 0; 84 85 ntf = ynl_ntf_dequeue(ys_link); 86 if (!ntf || ntf->cmd != RTM_NEWLINK) { 87 ynl_ntf_free(ntf); 88 return 0; 89 } 90 ntf_gl = (void *)ntf; 91 ret = ntf_gl->obj._hdr.ifi_index; 92 ynl_ntf_free(ntf); 93 94 return ret; 95 } 96 97 static void veth_delete(struct __test_metadata *_metadata, 98 struct ynl_sock *ys_link, int ifindex) 99 { 100 struct rt_link_dellink_req *req; 101 102 req = rt_link_dellink_req_alloc(); 103 ASSERT_NE(NULL, req); 104 105 req->_hdr.ifi_index = ifindex; 106 EXPECT_EQ(0, rt_link_dellink(ys_link, req)); 107 rt_link_dellink_req_free(req); 108 } 109 110 FIXTURE(netdev) 111 { 112 struct ynl_sock *ys; 113 struct ynl_sock *ys_link; 114 }; 115 116 FIXTURE_SETUP(netdev) 117 { 118 struct ynl_error yerr; 119 120 self->ys = ynl_sock_create(&ynl_netdev_family, &yerr); 121 ASSERT_NE(NULL, self->ys) { 122 TH_LOG("Failed to create YNL netdev socket: %s", yerr.msg); 123 } 124 } 125 126 FIXTURE_TEARDOWN(netdev) 127 { 128 if (self->ys_link) 129 ynl_sock_destroy(self->ys_link); 130 ynl_sock_destroy(self->ys); 131 } 132 133 TEST_F(netdev, dump) 134 { 135 struct netdev_dev_get_list *devs; 136 137 devs = netdev_dev_get_dump(self->ys); 138 ASSERT_NE(NULL, devs) { 139 TH_LOG("dump failed: %s", self->ys->err.msg); 140 } 141 142 if (ynl_dump_empty(devs)) { 143 netdev_dev_get_list_free(devs); 144 SKIP(return, "no entries in dump"); 145 } 146 147 ynl_dump_foreach(devs, d) 148 netdev_print_device(_metadata, d, 0); 149 150 netdev_dev_get_list_free(devs); 151 } 152 153 TEST_F(netdev, get) 154 { 155 struct netdev_dev_get_list *devs; 156 struct netdev_dev_get_req *req; 157 struct netdev_dev_get_rsp *dev; 158 int ifindex = 0; 159 160 devs = netdev_dev_get_dump(self->ys); 161 ASSERT_NE(NULL, devs) { 162 TH_LOG("dump failed: %s", self->ys->err.msg); 163 } 164 165 ynl_dump_foreach(devs, d) { 166 if (d->_present.ifindex) { 167 ifindex = d->ifindex; 168 break; 169 } 170 } 171 netdev_dev_get_list_free(devs); 172 173 if (!ifindex) 174 SKIP(return, "no device to query"); 175 176 req = netdev_dev_get_req_alloc(); 177 ASSERT_NE(NULL, req); 178 netdev_dev_get_req_set_ifindex(req, ifindex); 179 180 dev = netdev_dev_get(self->ys, req); 181 netdev_dev_get_req_free(req); 182 ASSERT_NE(NULL, dev) { 183 TH_LOG("dev_get failed: %s", self->ys->err.msg); 184 } 185 186 netdev_print_device(_metadata, dev, 0); 187 netdev_dev_get_rsp_free(dev); 188 } 189 190 TEST_F(netdev, ntf_check) 191 { 192 struct ynl_ntf_base_type *ntf; 193 int veth_ifindex; 194 bool received; 195 int ret; 196 197 ret = ynl_subscribe(self->ys, "mgmt"); 198 ASSERT_EQ(0, ret) { 199 TH_LOG("subscribe failed: %s", self->ys->err.msg); 200 } 201 202 self->ys_link = ynl_sock_create(&ynl_rt_link_family, NULL); 203 ASSERT_NE(NULL, self->ys_link) 204 TH_LOG("failed to create rt-link socket"); 205 206 veth_ifindex = veth_create(self->ys_link); 207 ASSERT_GT(veth_ifindex, 0) 208 TH_LOG("failed to create veth"); 209 210 ynl_ntf_check(self->ys); 211 212 ntf = ynl_ntf_dequeue(self->ys); 213 received = ntf; 214 if (ntf) { 215 netdev_print_device(_metadata, 216 (struct netdev_dev_get_rsp *)&ntf->data, 217 ntf->cmd); 218 ynl_ntf_free(ntf); 219 } 220 221 /* Drain any remaining notifications */ 222 while ((ntf = ynl_ntf_dequeue(self->ys))) 223 ynl_ntf_free(ntf); 224 225 veth_delete(_metadata, self->ys_link, veth_ifindex); 226 227 ASSERT_TRUE(received) 228 TH_LOG("no notification received"); 229 } 230 231 TEST_HARNESS_MAIN 232