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