xref: /linux/tools/testing/selftests/net/netlink-dumps.c (revision 2eff01ee2881becc9daaa0d53477ec202136b1f4)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <sys/socket.h>
9 #include <sys/stat.h>
10 #include <sys/syscall.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 
14 #include <linux/genetlink.h>
15 #include <linux/neighbour.h>
16 #include <linux/netdevice.h>
17 #include <linux/netlink.h>
18 #include <linux/mqueue.h>
19 #include <linux/rtnetlink.h>
20 
21 #include "../kselftest_harness.h"
22 
23 #include <ynl.h>
24 
25 struct ext_ack {
26 	int err;
27 
28 	__u32 attr_offs;
29 	__u32 miss_type;
30 	__u32 miss_nest;
31 	const char *str;
32 };
33 
34 /* 0: no done, 1: done found, 2: extack found, -1: error */
35 static int nl_get_extack(char *buf, size_t n, struct ext_ack *ea)
36 {
37 	const struct nlmsghdr *nlh;
38 	const struct nlattr *attr;
39 	ssize_t rem;
40 
41 	for (rem = n; rem > 0; NLMSG_NEXT(nlh, rem)) {
42 		nlh = (struct nlmsghdr *)&buf[n - rem];
43 		if (!NLMSG_OK(nlh, rem))
44 			return -1;
45 
46 		if (nlh->nlmsg_type != NLMSG_DONE)
47 			continue;
48 
49 		ea->err = -*(int *)NLMSG_DATA(nlh);
50 
51 		if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
52 			return 1;
53 
54 		ynl_attr_for_each(attr, nlh, sizeof(int)) {
55 			switch (ynl_attr_type(attr)) {
56 			case NLMSGERR_ATTR_OFFS:
57 				ea->attr_offs = ynl_attr_get_u32(attr);
58 				break;
59 			case NLMSGERR_ATTR_MISS_TYPE:
60 				ea->miss_type = ynl_attr_get_u32(attr);
61 				break;
62 			case NLMSGERR_ATTR_MISS_NEST:
63 				ea->miss_nest = ynl_attr_get_u32(attr);
64 				break;
65 			case NLMSGERR_ATTR_MSG:
66 				ea->str = ynl_attr_get_str(attr);
67 				break;
68 			}
69 		}
70 
71 		return 2;
72 	}
73 
74 	return 0;
75 }
76 
77 static const struct {
78 	struct nlmsghdr nlhdr;
79 	struct ndmsg ndm;
80 	struct nlattr ahdr;
81 	__u32 val;
82 } dump_neigh_bad = {
83 	.nlhdr = {
84 		.nlmsg_len	= sizeof(dump_neigh_bad),
85 		.nlmsg_type	= RTM_GETNEIGH,
86 		.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
87 		.nlmsg_seq	= 1,
88 	},
89 	.ndm = {
90 		.ndm_family	= 123,
91 	},
92 	.ahdr = {
93 		.nla_len	= 4 + 4,
94 		.nla_type	= NDA_FLAGS_EXT,
95 	},
96 	.val = -1, // should fail MASK validation
97 };
98 
99 TEST(dump_extack)
100 {
101 	int netlink_sock;
102 	char buf[8192];
103 	int one = 1;
104 	int i, cnt;
105 	ssize_t n;
106 
107 	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
108 	ASSERT_GE(netlink_sock, 0);
109 
110 	n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_CAP_ACK,
111 		       &one, sizeof(one));
112 	ASSERT_EQ(n, 0);
113 	n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_EXT_ACK,
114 		       &one, sizeof(one));
115 	ASSERT_EQ(n, 0);
116 	n = setsockopt(netlink_sock, SOL_NETLINK, NETLINK_GET_STRICT_CHK,
117 		       &one, sizeof(one));
118 	ASSERT_EQ(n, 0);
119 
120 	/* Dump so many times we fill up the buffer */
121 	cnt = 64;
122 	for (i = 0; i < cnt; i++) {
123 		n = send(netlink_sock, &dump_neigh_bad,
124 			 sizeof(dump_neigh_bad), 0);
125 		ASSERT_EQ(n, sizeof(dump_neigh_bad));
126 	}
127 
128 	/* Read out the ENOBUFS */
129 	n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
130 	EXPECT_EQ(n, -1);
131 	EXPECT_EQ(errno, ENOBUFS);
132 
133 	for (i = 0; i < cnt; i++) {
134 		struct ext_ack ea = {};
135 
136 		n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
137 		if (n < 0) {
138 			ASSERT_GE(i, 10);
139 			break;
140 		}
141 		ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));
142 
143 		EXPECT_EQ(nl_get_extack(buf, n, &ea), 2);
144 		EXPECT_EQ(ea.attr_offs,
145 			  sizeof(struct nlmsghdr) + sizeof(struct ndmsg));
146 	}
147 }
148 
149 static const struct {
150 	struct nlmsghdr nlhdr;
151 	struct genlmsghdr genlhdr;
152 	struct nlattr ahdr;
153 	__u16 val;
154 	__u16 pad;
155 } dump_policies = {
156 	.nlhdr = {
157 		.nlmsg_len	= sizeof(dump_policies),
158 		.nlmsg_type	= GENL_ID_CTRL,
159 		.nlmsg_flags	= NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
160 		.nlmsg_seq	= 1,
161 	},
162 	.genlhdr = {
163 		.cmd		= CTRL_CMD_GETPOLICY,
164 		.version	= 2,
165 	},
166 	.ahdr = {
167 		.nla_len	= 6,
168 		.nla_type	= CTRL_ATTR_FAMILY_ID,
169 	},
170 	.val = GENL_ID_CTRL,
171 	.pad = 0,
172 };
173 
174 // Sanity check for the test itself, make sure the dump doesn't fit in one msg
175 TEST(test_sanity)
176 {
177 	int netlink_sock;
178 	char buf[8192];
179 	ssize_t n;
180 
181 	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
182 	ASSERT_GE(netlink_sock, 0);
183 
184 	n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
185 	ASSERT_EQ(n, sizeof(dump_policies));
186 
187 	n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
188 	ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));
189 
190 	n = recv(netlink_sock, buf, sizeof(buf), MSG_DONTWAIT);
191 	ASSERT_GE(n, (ssize_t)sizeof(struct nlmsghdr));
192 
193 	close(netlink_sock);
194 }
195 
196 TEST(close_in_progress)
197 {
198 	int netlink_sock;
199 	ssize_t n;
200 
201 	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
202 	ASSERT_GE(netlink_sock, 0);
203 
204 	n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
205 	ASSERT_EQ(n, sizeof(dump_policies));
206 
207 	close(netlink_sock);
208 }
209 
210 TEST(close_with_ref)
211 {
212 	char cookie[NOTIFY_COOKIE_LEN] = {};
213 	int netlink_sock, mq_fd;
214 	struct sigevent sigev;
215 	ssize_t n;
216 
217 	netlink_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
218 	ASSERT_GE(netlink_sock, 0);
219 
220 	n = send(netlink_sock, &dump_policies, sizeof(dump_policies), 0);
221 	ASSERT_EQ(n, sizeof(dump_policies));
222 
223 	mq_fd = syscall(__NR_mq_open, "sed", O_CREAT | O_WRONLY, 0600, 0);
224 	ASSERT_GE(mq_fd, 0);
225 
226 	memset(&sigev, 0, sizeof(sigev));
227 	sigev.sigev_notify		= SIGEV_THREAD;
228 	sigev.sigev_value.sival_ptr	= cookie;
229 	sigev.sigev_signo		= netlink_sock;
230 
231 	syscall(__NR_mq_notify, mq_fd, &sigev);
232 
233 	close(netlink_sock);
234 
235 	// give mqueue time to fire
236 	usleep(100 * 1000);
237 }
238 
239 TEST_HARNESS_MAIN
240