xref: /linux/tools/net/ynl/tests/netdev.c (revision 9b29afa1166088ca4e8223857508f2a19d88b58b)
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