| 1 | |
| 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 |
|
| 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
|