xref: /openbmc/linux/tools/testing/selftests/bpf/prog_tests/sockopt_sk.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
19a365e67SStanislav Fomichev // SPDX-License-Identifier: GPL-2.0
29a365e67SStanislav Fomichev #include <test_progs.h>
39a365e67SStanislav Fomichev #include "cgroup_helpers.h"
49a365e67SStanislav Fomichev 
59cacf81fSStanislav Fomichev #include <linux/tcp.h>
6833d67ecSStanislav Fomichev #include <linux/netlink.h>
7cad99cceSYauheni Kaliuta #include "sockopt_sk.skel.h"
89cacf81fSStanislav Fomichev 
99cacf81fSStanislav Fomichev #ifndef SOL_TCP
109cacf81fSStanislav Fomichev #define SOL_TCP IPPROTO_TCP
119cacf81fSStanislav Fomichev #endif
129cacf81fSStanislav Fomichev 
139a365e67SStanislav Fomichev #define SOL_CUSTOM			0xdeadbeef
149a365e67SStanislav Fomichev 
getsetsockopt(void)159a365e67SStanislav Fomichev static int getsetsockopt(void)
169a365e67SStanislav Fomichev {
179a365e67SStanislav Fomichev 	int fd, err;
189a365e67SStanislav Fomichev 	union {
199a365e67SStanislav Fomichev 		char u8[4];
209a365e67SStanislav Fomichev 		__u32 u32;
219a365e67SStanislav Fomichev 		char cc[16]; /* TCP_CA_NAME_MAX */
229cacf81fSStanislav Fomichev 		struct tcp_zerocopy_receive zc;
239a365e67SStanislav Fomichev 	} buf = {};
249a365e67SStanislav Fomichev 	socklen_t optlen;
25a0cb12b0SStanislav Fomichev 	char *big_buf = NULL;
269a365e67SStanislav Fomichev 
279a365e67SStanislav Fomichev 	fd = socket(AF_INET, SOCK_STREAM, 0);
289a365e67SStanislav Fomichev 	if (fd < 0) {
299a365e67SStanislav Fomichev 		log_err("Failed to create socket");
309a365e67SStanislav Fomichev 		return -1;
319a365e67SStanislav Fomichev 	}
329a365e67SStanislav Fomichev 
339a365e67SStanislav Fomichev 	/* IP_TOS - BPF bypass */
349a365e67SStanislav Fomichev 
35a0cb12b0SStanislav Fomichev 	optlen = getpagesize() * 2;
36a0cb12b0SStanislav Fomichev 	big_buf = calloc(1, optlen);
37a0cb12b0SStanislav Fomichev 	if (!big_buf) {
38a0cb12b0SStanislav Fomichev 		log_err("Couldn't allocate two pages");
39a0cb12b0SStanislav Fomichev 		goto err;
40a0cb12b0SStanislav Fomichev 	}
41a0cb12b0SStanislav Fomichev 
42a0cb12b0SStanislav Fomichev 	*(int *)big_buf = 0x08;
43a0cb12b0SStanislav Fomichev 	err = setsockopt(fd, SOL_IP, IP_TOS, big_buf, optlen);
449a365e67SStanislav Fomichev 	if (err) {
459a365e67SStanislav Fomichev 		log_err("Failed to call setsockopt(IP_TOS)");
469a365e67SStanislav Fomichev 		goto err;
479a365e67SStanislav Fomichev 	}
489a365e67SStanislav Fomichev 
49a0cb12b0SStanislav Fomichev 	memset(big_buf, 0, optlen);
509a365e67SStanislav Fomichev 	optlen = 1;
51a0cb12b0SStanislav Fomichev 	err = getsockopt(fd, SOL_IP, IP_TOS, big_buf, &optlen);
529a365e67SStanislav Fomichev 	if (err) {
539a365e67SStanislav Fomichev 		log_err("Failed to call getsockopt(IP_TOS)");
549a365e67SStanislav Fomichev 		goto err;
559a365e67SStanislav Fomichev 	}
569a365e67SStanislav Fomichev 
57fec47bbcSIlya Leoshkevich 	if (*big_buf != 0x08) {
58a0cb12b0SStanislav Fomichev 		log_err("Unexpected getsockopt(IP_TOS) optval 0x%x != 0x08",
59fec47bbcSIlya Leoshkevich 			(int)*big_buf);
609a365e67SStanislav Fomichev 		goto err;
619a365e67SStanislav Fomichev 	}
629a365e67SStanislav Fomichev 
639a365e67SStanislav Fomichev 	/* IP_TTL - EPERM */
649a365e67SStanislav Fomichev 
659a365e67SStanislav Fomichev 	buf.u8[0] = 1;
669a365e67SStanislav Fomichev 	err = setsockopt(fd, SOL_IP, IP_TTL, &buf, 1);
679a365e67SStanislav Fomichev 	if (!err || errno != EPERM) {
689a365e67SStanislav Fomichev 		log_err("Unexpected success from setsockopt(IP_TTL)");
699a365e67SStanislav Fomichev 		goto err;
709a365e67SStanislav Fomichev 	}
719a365e67SStanislav Fomichev 
729a365e67SStanislav Fomichev 	/* SOL_CUSTOM - handled by BPF */
739a365e67SStanislav Fomichev 
749a365e67SStanislav Fomichev 	buf.u8[0] = 0x01;
759a365e67SStanislav Fomichev 	err = setsockopt(fd, SOL_CUSTOM, 0, &buf, 1);
769a365e67SStanislav Fomichev 	if (err) {
779a365e67SStanislav Fomichev 		log_err("Failed to call setsockopt");
789a365e67SStanislav Fomichev 		goto err;
799a365e67SStanislav Fomichev 	}
809a365e67SStanislav Fomichev 
819a365e67SStanislav Fomichev 	buf.u32 = 0x00;
829a365e67SStanislav Fomichev 	optlen = 4;
839a365e67SStanislav Fomichev 	err = getsockopt(fd, SOL_CUSTOM, 0, &buf, &optlen);
849a365e67SStanislav Fomichev 	if (err) {
859a365e67SStanislav Fomichev 		log_err("Failed to call getsockopt");
869a365e67SStanislav Fomichev 		goto err;
879a365e67SStanislav Fomichev 	}
889a365e67SStanislav Fomichev 
899a365e67SStanislav Fomichev 	if (optlen != 1) {
909a365e67SStanislav Fomichev 		log_err("Unexpected optlen %d != 1", optlen);
919a365e67SStanislav Fomichev 		goto err;
929a365e67SStanislav Fomichev 	}
939a365e67SStanislav Fomichev 	if (buf.u8[0] != 0x01) {
949a365e67SStanislav Fomichev 		log_err("Unexpected buf[0] 0x%02x != 0x01", buf.u8[0]);
959a365e67SStanislav Fomichev 		goto err;
969a365e67SStanislav Fomichev 	}
979a365e67SStanislav Fomichev 
98a0cb12b0SStanislav Fomichev 	/* IP_FREEBIND - BPF can't access optval past PAGE_SIZE */
99a0cb12b0SStanislav Fomichev 
100a0cb12b0SStanislav Fomichev 	optlen = getpagesize() * 2;
101a0cb12b0SStanislav Fomichev 	memset(big_buf, 0, optlen);
102a0cb12b0SStanislav Fomichev 
103a0cb12b0SStanislav Fomichev 	err = setsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, optlen);
104a0cb12b0SStanislav Fomichev 	if (err != 0) {
105a0cb12b0SStanislav Fomichev 		log_err("Failed to call setsockopt, ret=%d", err);
106a0cb12b0SStanislav Fomichev 		goto err;
107a0cb12b0SStanislav Fomichev 	}
108a0cb12b0SStanislav Fomichev 
109a0cb12b0SStanislav Fomichev 	err = getsockopt(fd, SOL_IP, IP_FREEBIND, big_buf, &optlen);
110a0cb12b0SStanislav Fomichev 	if (err != 0) {
111a0cb12b0SStanislav Fomichev 		log_err("Failed to call getsockopt, ret=%d", err);
112a0cb12b0SStanislav Fomichev 		goto err;
113a0cb12b0SStanislav Fomichev 	}
114a0cb12b0SStanislav Fomichev 
115a0cb12b0SStanislav Fomichev 	if (optlen != 1 || *(__u8 *)big_buf != 0x55) {
116a0cb12b0SStanislav Fomichev 		log_err("Unexpected IP_FREEBIND getsockopt, optlen=%d, optval=0x%x",
117a0cb12b0SStanislav Fomichev 			optlen, *(__u8 *)big_buf);
118a0cb12b0SStanislav Fomichev 	}
119a0cb12b0SStanislav Fomichev 
1209a365e67SStanislav Fomichev 	/* SO_SNDBUF is overwritten */
1219a365e67SStanislav Fomichev 
1229a365e67SStanislav Fomichev 	buf.u32 = 0x01010101;
1239a365e67SStanislav Fomichev 	err = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, 4);
1249a365e67SStanislav Fomichev 	if (err) {
1259a365e67SStanislav Fomichev 		log_err("Failed to call setsockopt(SO_SNDBUF)");
1269a365e67SStanislav Fomichev 		goto err;
1279a365e67SStanislav Fomichev 	}
1289a365e67SStanislav Fomichev 
1299a365e67SStanislav Fomichev 	buf.u32 = 0x00;
1309a365e67SStanislav Fomichev 	optlen = 4;
1319a365e67SStanislav Fomichev 	err = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf, &optlen);
1329a365e67SStanislav Fomichev 	if (err) {
1339a365e67SStanislav Fomichev 		log_err("Failed to call getsockopt(SO_SNDBUF)");
1349a365e67SStanislav Fomichev 		goto err;
1359a365e67SStanislav Fomichev 	}
1369a365e67SStanislav Fomichev 
1379a365e67SStanislav Fomichev 	if (buf.u32 != 0x55AA*2) {
1389a365e67SStanislav Fomichev 		log_err("Unexpected getsockopt(SO_SNDBUF) 0x%x != 0x55AA*2",
1399a365e67SStanislav Fomichev 			buf.u32);
1409a365e67SStanislav Fomichev 		goto err;
1419a365e67SStanislav Fomichev 	}
1429a365e67SStanislav Fomichev 
1439a365e67SStanislav Fomichev 	/* TCP_CONGESTION can extend the string */
1449a365e67SStanislav Fomichev 
1459a365e67SStanislav Fomichev 	strcpy(buf.cc, "nv");
1469a365e67SStanislav Fomichev 	err = setsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, strlen("nv"));
1479a365e67SStanislav Fomichev 	if (err) {
1489a365e67SStanislav Fomichev 		log_err("Failed to call setsockopt(TCP_CONGESTION)");
1499a365e67SStanislav Fomichev 		goto err;
1509a365e67SStanislav Fomichev 	}
1519a365e67SStanislav Fomichev 
1529a365e67SStanislav Fomichev 
1539a365e67SStanislav Fomichev 	optlen = sizeof(buf.cc);
1549a365e67SStanislav Fomichev 	err = getsockopt(fd, SOL_TCP, TCP_CONGESTION, &buf, &optlen);
1559a365e67SStanislav Fomichev 	if (err) {
1569a365e67SStanislav Fomichev 		log_err("Failed to call getsockopt(TCP_CONGESTION)");
1579a365e67SStanislav Fomichev 		goto err;
1589a365e67SStanislav Fomichev 	}
1599a365e67SStanislav Fomichev 
1609a365e67SStanislav Fomichev 	if (strcmp(buf.cc, "cubic") != 0) {
1619a365e67SStanislav Fomichev 		log_err("Unexpected getsockopt(TCP_CONGESTION) %s != %s",
1629a365e67SStanislav Fomichev 			buf.cc, "cubic");
1639a365e67SStanislav Fomichev 		goto err;
1649a365e67SStanislav Fomichev 	}
1659a365e67SStanislav Fomichev 
1669cacf81fSStanislav Fomichev 	/* TCP_ZEROCOPY_RECEIVE triggers */
1679cacf81fSStanislav Fomichev 	memset(&buf, 0, sizeof(buf));
1689cacf81fSStanislav Fomichev 	optlen = sizeof(buf.zc);
1699cacf81fSStanislav Fomichev 	err = getsockopt(fd, SOL_TCP, TCP_ZEROCOPY_RECEIVE, &buf, &optlen);
1709cacf81fSStanislav Fomichev 	if (err) {
1719cacf81fSStanislav Fomichev 		log_err("Unexpected getsockopt(TCP_ZEROCOPY_RECEIVE) err=%d errno=%d",
1729cacf81fSStanislav Fomichev 			err, errno);
1739cacf81fSStanislav Fomichev 		goto err;
1749cacf81fSStanislav Fomichev 	}
1759cacf81fSStanislav Fomichev 
1769cacf81fSStanislav Fomichev 	memset(&buf, 0, sizeof(buf));
1771080ef5cSYiFei Zhu 	buf.zc.address = 12345; /* Not page aligned. Rejected by tcp_zerocopy_receive() */
1789cacf81fSStanislav Fomichev 	optlen = sizeof(buf.zc);
1799cacf81fSStanislav Fomichev 	errno = 0;
1809cacf81fSStanislav Fomichev 	err = getsockopt(fd, SOL_TCP, TCP_ZEROCOPY_RECEIVE, &buf, &optlen);
1811080ef5cSYiFei Zhu 	if (errno != EINVAL) {
1829cacf81fSStanislav Fomichev 		log_err("Unexpected getsockopt(TCP_ZEROCOPY_RECEIVE) err=%d errno=%d",
1839cacf81fSStanislav Fomichev 			err, errno);
1849cacf81fSStanislav Fomichev 		goto err;
1859cacf81fSStanislav Fomichev 	}
1869cacf81fSStanislav Fomichev 
187833d67ecSStanislav Fomichev 	/* optval=NULL case is handled correctly */
188833d67ecSStanislav Fomichev 
189833d67ecSStanislav Fomichev 	close(fd);
190833d67ecSStanislav Fomichev 	fd = socket(AF_NETLINK, SOCK_RAW, 0);
191833d67ecSStanislav Fomichev 	if (fd < 0) {
192833d67ecSStanislav Fomichev 		log_err("Failed to create AF_NETLINK socket");
193833d67ecSStanislav Fomichev 		return -1;
194833d67ecSStanislav Fomichev 	}
195833d67ecSStanislav Fomichev 
196833d67ecSStanislav Fomichev 	buf.u32 = 1;
197833d67ecSStanislav Fomichev 	optlen = sizeof(__u32);
198833d67ecSStanislav Fomichev 	err = setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &buf, optlen);
199833d67ecSStanislav Fomichev 	if (err) {
200833d67ecSStanislav Fomichev 		log_err("Unexpected getsockopt(NETLINK_ADD_MEMBERSHIP) err=%d errno=%d",
201833d67ecSStanislav Fomichev 			err, errno);
202833d67ecSStanislav Fomichev 		goto err;
203833d67ecSStanislav Fomichev 	}
204833d67ecSStanislav Fomichev 
205833d67ecSStanislav Fomichev 	optlen = 0;
206833d67ecSStanislav Fomichev 	err = getsockopt(fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &optlen);
207833d67ecSStanislav Fomichev 	if (err) {
208833d67ecSStanislav Fomichev 		log_err("Unexpected getsockopt(NETLINK_LIST_MEMBERSHIPS) err=%d errno=%d",
209833d67ecSStanislav Fomichev 			err, errno);
210833d67ecSStanislav Fomichev 		goto err;
211833d67ecSStanislav Fomichev 	}
212*69844e33SYonghong Song 	ASSERT_EQ(optlen, 8, "Unexpected NETLINK_LIST_MEMBERSHIPS value");
213833d67ecSStanislav Fomichev 
214a0cb12b0SStanislav Fomichev 	free(big_buf);
2159a365e67SStanislav Fomichev 	close(fd);
2169a365e67SStanislav Fomichev 	return 0;
2179a365e67SStanislav Fomichev err:
218a0cb12b0SStanislav Fomichev 	free(big_buf);
2199a365e67SStanislav Fomichev 	close(fd);
2209a365e67SStanislav Fomichev 	return -1;
2219a365e67SStanislav Fomichev }
2229a365e67SStanislav Fomichev 
run_test(int cgroup_fd)2239a365e67SStanislav Fomichev static void run_test(int cgroup_fd)
2249a365e67SStanislav Fomichev {
225cad99cceSYauheni Kaliuta 	struct sockopt_sk *skel;
2269a365e67SStanislav Fomichev 
227cad99cceSYauheni Kaliuta 	skel = sockopt_sk__open_and_load();
228cad99cceSYauheni Kaliuta 	if (!ASSERT_OK_PTR(skel, "skel_load"))
229cad99cceSYauheni Kaliuta 		goto cleanup;
2309a365e67SStanislav Fomichev 
231361d3202SYauheni Kaliuta 	skel->bss->page_size = getpagesize();
232361d3202SYauheni Kaliuta 
233cad99cceSYauheni Kaliuta 	skel->links._setsockopt =
234cad99cceSYauheni Kaliuta 		bpf_program__attach_cgroup(skel->progs._setsockopt, cgroup_fd);
235cad99cceSYauheni Kaliuta 	if (!ASSERT_OK_PTR(skel->links._setsockopt, "setsockopt_link"))
236cad99cceSYauheni Kaliuta 		goto cleanup;
2379a365e67SStanislav Fomichev 
238cad99cceSYauheni Kaliuta 	skel->links._getsockopt =
239cad99cceSYauheni Kaliuta 		bpf_program__attach_cgroup(skel->progs._getsockopt, cgroup_fd);
240cad99cceSYauheni Kaliuta 	if (!ASSERT_OK_PTR(skel->links._getsockopt, "getsockopt_link"))
241cad99cceSYauheni Kaliuta 		goto cleanup;
2429a365e67SStanislav Fomichev 
243cad99cceSYauheni Kaliuta 	ASSERT_OK(getsetsockopt(), "getsetsockopt");
2449a365e67SStanislav Fomichev 
245cad99cceSYauheni Kaliuta cleanup:
246cad99cceSYauheni Kaliuta 	sockopt_sk__destroy(skel);
2479a365e67SStanislav Fomichev }
2489a365e67SStanislav Fomichev 
test_sockopt_sk(void)2499a365e67SStanislav Fomichev void test_sockopt_sk(void)
2509a365e67SStanislav Fomichev {
2519a365e67SStanislav Fomichev 	int cgroup_fd;
2529a365e67SStanislav Fomichev 
2539a365e67SStanislav Fomichev 	cgroup_fd = test__join_cgroup("/sockopt_sk");
254f19708dfSWang Yufen 	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /sockopt_sk"))
2559a365e67SStanislav Fomichev 		return;
2569a365e67SStanislav Fomichev 
2579a365e67SStanislav Fomichev 	run_test(cgroup_fd);
2589a365e67SStanislav Fomichev 	close(cgroup_fd);
2599a365e67SStanislav Fomichev }
260