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