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