xref: /linux/tools/net/ynl/tests/rt-link.c (revision 91a4855d6c03e770e42f17c798a36a3c46e63de2)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <stdio.h>
3 #include <string.h>
4 
5 #include <ynl.h>
6 
7 #include <arpa/inet.h>
8 #include <net/if.h>
9 
10 #include <kselftest_harness.h>
11 
12 #include "rt-link-user.h"
13 
14 static void rt_link_print(struct __test_metadata *_metadata,
15 			  struct rt_link_getlink_rsp *r)
16 {
17 	unsigned int i;
18 
19 	EXPECT_TRUE((bool)r->_hdr.ifi_index);
20 	ksft_print_msg("%3d: ", r->_hdr.ifi_index);
21 
22 	EXPECT_TRUE((bool)r->_len.ifname);
23 	if (r->_len.ifname)
24 		printf("%6s: ", r->ifname);
25 
26 	if (r->_present.mtu)
27 		printf("mtu %5d  ", r->mtu);
28 
29 	if (r->linkinfo._len.kind)
30 		printf("kind %-8s  ", r->linkinfo.kind);
31 	else
32 		printf("     %8s  ", "");
33 
34 	if (r->prop_list._count.alt_ifname) {
35 		printf("altname ");
36 		for (i = 0; i < r->prop_list._count.alt_ifname; i++)
37 			printf("%s ", r->prop_list.alt_ifname[i]->str);
38 		printf(" ");
39 	}
40 
41 	if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) {
42 		struct rt_link_linkinfo_netkit_attrs *netkit;
43 		const char *name;
44 
45 		netkit = &r->linkinfo.data.netkit;
46 		printf("primary %d  ", netkit->primary);
47 
48 		name = NULL;
49 		if (netkit->_present.policy)
50 			name = rt_link_netkit_policy_str(netkit->policy);
51 		if (name)
52 			printf("policy %s  ", name);
53 	}
54 
55 	printf("\n");
56 }
57 
58 static int netkit_create(struct ynl_sock *ys)
59 {
60 	struct rt_link_getlink_ntf *ntf_gl;
61 	struct rt_link_newlink_req *req;
62 	struct ynl_ntf_base_type *ntf;
63 	int ret;
64 
65 	req = rt_link_newlink_req_alloc();
66 	if (!req)
67 		return -1;
68 
69 	rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO);
70 	rt_link_newlink_req_set_linkinfo_kind(req, "netkit");
71 	rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP);
72 
73 	ret = rt_link_newlink(ys, req);
74 	rt_link_newlink_req_free(req);
75 	if (ret)
76 		return -1;
77 
78 	if (!ynl_has_ntf(ys))
79 		return 0;
80 
81 	ntf = ynl_ntf_dequeue(ys);
82 	if (!ntf || ntf->cmd != RTM_NEWLINK) {
83 		ynl_ntf_free(ntf);
84 		return 0;
85 	}
86 	ntf_gl = (void *)ntf;
87 	ret = ntf_gl->obj._hdr.ifi_index;
88 	ynl_ntf_free(ntf);
89 
90 	return ret;
91 }
92 
93 static void netkit_delete(struct __test_metadata *_metadata,
94 			  struct ynl_sock *ys, int ifindex)
95 {
96 	struct rt_link_dellink_req *req;
97 
98 	req = rt_link_dellink_req_alloc();
99 	ASSERT_NE(NULL, req);
100 
101 	req->_hdr.ifi_index = ifindex;
102 	EXPECT_EQ(0, rt_link_dellink(ys, req));
103 	rt_link_dellink_req_free(req);
104 }
105 
106 FIXTURE(rt_link)
107 {
108 	struct ynl_sock *ys;
109 };
110 
111 FIXTURE_SETUP(rt_link)
112 {
113 	struct ynl_error yerr;
114 
115 	self->ys = ynl_sock_create(&ynl_rt_link_family, &yerr);
116 	ASSERT_NE(NULL, self->ys) {
117 		TH_LOG("failed to create rt-link socket: %s", yerr.msg);
118 	}
119 }
120 
121 FIXTURE_TEARDOWN(rt_link)
122 {
123 	ynl_sock_destroy(self->ys);
124 }
125 
126 TEST_F(rt_link, dump)
127 {
128 	struct rt_link_getlink_req_dump *req;
129 	struct rt_link_getlink_list *rsp;
130 
131 	req = rt_link_getlink_req_dump_alloc();
132 	ASSERT_NE(NULL, req);
133 	rsp = rt_link_getlink_dump(self->ys, req);
134 	rt_link_getlink_req_dump_free(req);
135 	ASSERT_NE(NULL, rsp) {
136 		TH_LOG("dump failed: %s", self->ys->err.msg);
137 	}
138 	ASSERT_FALSE(ynl_dump_empty(rsp));
139 
140 	ynl_dump_foreach(rsp, link)
141 		rt_link_print(_metadata, link);
142 
143 	rt_link_getlink_list_free(rsp);
144 }
145 
146 TEST_F(rt_link, netkit)
147 {
148 	struct rt_link_getlink_req_dump *dreq;
149 	struct rt_link_getlink_list *rsp;
150 	bool found = false;
151 	int netkit_ifindex;
152 
153 	/* Create netkit with valid policy */
154 	netkit_ifindex = netkit_create(self->ys);
155 	ASSERT_GT(netkit_ifindex, 0)
156 		TH_LOG("failed to create netkit: %s", self->ys->err.msg);
157 
158 	/* Verify it appears in a dump */
159 	dreq = rt_link_getlink_req_dump_alloc();
160 	ASSERT_NE(NULL, dreq);
161 	rsp = rt_link_getlink_dump(self->ys, dreq);
162 	rt_link_getlink_req_dump_free(dreq);
163 	ASSERT_NE(NULL, rsp) {
164 		TH_LOG("dump failed: %s", self->ys->err.msg);
165 	}
166 
167 	ynl_dump_foreach(rsp, link) {
168 		if (link->_hdr.ifi_index == netkit_ifindex) {
169 			rt_link_print(_metadata, link);
170 			found = true;
171 		}
172 	}
173 	rt_link_getlink_list_free(rsp);
174 	EXPECT_TRUE(found);
175 
176 	netkit_delete(_metadata, self->ys, netkit_ifindex);
177 }
178 
179 TEST_F(rt_link, netkit_err_msg)
180 {
181 	struct rt_link_newlink_req *req;
182 	int ret;
183 
184 	/* Test creating netkit with bad policy - should fail */
185 	req = rt_link_newlink_req_alloc();
186 	ASSERT_NE(NULL, req);
187 	rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE);
188 	rt_link_newlink_req_set_linkinfo_kind(req, "netkit");
189 	rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10);
190 
191 	ret = rt_link_newlink(self->ys, req);
192 	rt_link_newlink_req_free(req);
193 	EXPECT_NE(0, ret) {
194 		TH_LOG("creating netkit with bad policy should fail");
195 	}
196 
197 	/* Expect:
198 	 * Kernel error: 'Provided default xmit policy not supported' (bad attribute: .linkinfo.data(netkit).policy)
199 	 */
200 	EXPECT_NE(NULL, strstr(self->ys->err.msg, "bad attribute: .linkinfo.data(netkit).policy")) {
201 		TH_LOG("expected extack msg not found: %s",
202 		       self->ys->err.msg);
203 	}
204 }
205 
206 TEST_HARNESS_MAIN
207