Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) Meta Platforms, Inc. and affiliates. */
  3
  4#define _GNU_SOURCE
  5#include <sched.h>
  6#include <linux/socket.h>
  7#include <linux/tls.h>
  8#include <net/if.h>
  9
 10#include "test_progs.h"
 11#include "cgroup_helpers.h"
 12#include "network_helpers.h"
 13
 14#include "setget_sockopt.skel.h"
 15
 16#define CG_NAME "/setget-sockopt-test"
 17
 18static const char addr4_str[] = "127.0.0.1";
 19static const char addr6_str[] = "::1";
 20static struct setget_sockopt *skel;
 21static int cg_fd;
 22
 23static int create_netns(void)
 24{
 25	if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))
 26		return -1;
 27
 28	if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up"))
 29		return -1;
 30
 31	if (!ASSERT_OK(system("ip link add dev binddevtest1 type veth peer name binddevtest2"),
 32		       "add veth"))
 33		return -1;
 34
 35	if (!ASSERT_OK(system("ip link set dev binddevtest1 up"),
 36		       "bring veth up"))
 37		return -1;
 38
 39	return 0;
 40}
 41
 42static void test_tcp(int family)
 43{
 44	struct setget_sockopt__bss *bss = skel->bss;
 45	int sfd, cfd;
 46
 47	memset(bss, 0, sizeof(*bss));
 48
 49	sfd = start_server(family, SOCK_STREAM,
 50			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
 51	if (!ASSERT_GE(sfd, 0, "start_server"))
 52		return;
 53
 54	cfd = connect_to_fd(sfd, 0);
 55	if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) {
 56		close(sfd);
 57		return;
 58	}
 59	close(sfd);
 60	close(cfd);
 61
 62	ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
 63	ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
 64	ASSERT_EQ(bss->nr_active, 1, "nr_active");
 65	ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
 66	ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
 67	ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
 68}
 69
 70static void test_udp(int family)
 71{
 72	struct setget_sockopt__bss *bss = skel->bss;
 73	int sfd;
 74
 75	memset(bss, 0, sizeof(*bss));
 76
 77	sfd = start_server(family, SOCK_DGRAM,
 78			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
 79	if (!ASSERT_GE(sfd, 0, "start_server"))
 80		return;
 81	close(sfd);
 82
 83	ASSERT_GE(bss->nr_socket_post_create, 1, "nr_socket_post_create");
 84	ASSERT_EQ(bss->nr_binddev, 1, "nr_bind");
 85}
 86
 87static void test_ktls(int family)
 88{
 89	struct tls12_crypto_info_aes_gcm_128 aes128;
 90	struct setget_sockopt__bss *bss = skel->bss;
 91	int cfd = -1, sfd = -1, fd = -1, ret;
 92	char buf;
 93
 94	memset(bss, 0, sizeof(*bss));
 95
 96	sfd = start_server(family, SOCK_STREAM,
 97			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
 98	if (!ASSERT_GE(sfd, 0, "start_server"))
 99		return;
100	fd = connect_to_fd(sfd, 0);
101	if (!ASSERT_GE(fd, 0, "connect_to_fd"))
102		goto err_out;
103
104	cfd = accept(sfd, NULL, 0);
105	if (!ASSERT_GE(cfd, 0, "accept"))
106		goto err_out;
107
108	close(sfd);
109	sfd = -1;
110
111	/* Setup KTLS */
112	ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
113	if (!ASSERT_OK(ret, "setsockopt"))
114		goto err_out;
115	ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
116	if (!ASSERT_OK(ret, "setsockopt"))
117		goto err_out;
118
119	memset(&aes128, 0, sizeof(aes128));
120	aes128.info.version = TLS_1_2_VERSION;
121	aes128.info.cipher_type = TLS_CIPHER_AES_GCM_128;
122
123	ret = setsockopt(fd, SOL_TLS, TLS_TX, &aes128, sizeof(aes128));
124	if (!ASSERT_OK(ret, "setsockopt"))
125		goto err_out;
126
127	ret = setsockopt(cfd, SOL_TLS, TLS_RX, &aes128, sizeof(aes128));
128	if (!ASSERT_OK(ret, "setsockopt"))
129		goto err_out;
130
131	/* KTLS is enabled */
132
133	close(fd);
134	/* At this point, the cfd socket is at the CLOSE_WAIT state
135	 * and still run TLS protocol.  The test for
136	 * BPF_TCP_CLOSE_WAIT should be run at this point.
137	 */
138	ret = read(cfd, &buf, sizeof(buf));
139	ASSERT_EQ(ret, 0, "read");
140	close(cfd);
141
142	ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
143	ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
144	ASSERT_EQ(bss->nr_active, 1, "nr_active");
145	ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
146	ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
147	ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
148	ASSERT_EQ(bss->nr_fin_wait1, 1, "nr_fin_wait1");
149	return;
150
151err_out:
152	close(fd);
153	close(cfd);
154	close(sfd);
155}
156
157static void test_nonstandard_opt(int family)
158{
159	struct setget_sockopt__bss *bss = skel->bss;
160	struct bpf_link *getsockopt_link = NULL;
161	int sfd = -1, fd = -1, cfd = -1, flags;
162	socklen_t flagslen = sizeof(flags);
163
164	memset(bss, 0, sizeof(*bss));
165
166	sfd = start_server(family, SOCK_STREAM,
167			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
168	if (!ASSERT_GE(sfd, 0, "start_server"))
169		return;
170
171	fd = connect_to_fd(sfd, 0);
172	if (!ASSERT_GE(fd, 0, "connect_to_fd_server"))
173		goto err_out;
174
175	/* cgroup/getsockopt prog will intercept getsockopt() below and
176	 * retrieve the tcp socket bpf_sock_ops_cb_flags value for the
177	 * accept()ed socket; this was set earlier in the passive established
178	 * callback for the accept()ed socket via bpf_setsockopt().
179	 */
180	getsockopt_link = bpf_program__attach_cgroup(skel->progs._getsockopt, cg_fd);
181	if (!ASSERT_OK_PTR(getsockopt_link, "getsockopt prog"))
182		goto err_out;
183
184	cfd = accept(sfd, NULL, 0);
185	if (!ASSERT_GE(cfd, 0, "accept"))
186		goto err_out;
187
188	if (!ASSERT_OK(getsockopt(cfd, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, &flagslen),
189		       "getsockopt_flags"))
190		goto err_out;
191	ASSERT_EQ(flags & BPF_SOCK_OPS_STATE_CB_FLAG, BPF_SOCK_OPS_STATE_CB_FLAG,
192		  "cb_flags_set");
193err_out:
194	close(sfd);
195	if (fd != -1)
196		close(fd);
197	if (cfd != -1)
198		close(cfd);
199	bpf_link__destroy(getsockopt_link);
200}
201
202void test_setget_sockopt(void)
203{
204	cg_fd = test__join_cgroup(CG_NAME);
205	if (cg_fd < 0)
206		return;
207
208	if (create_netns())
209		goto done;
210
211	skel = setget_sockopt__open();
212	if (!ASSERT_OK_PTR(skel, "open skel"))
213		goto done;
214
215	strcpy(skel->rodata->veth, "binddevtest1");
216	skel->rodata->veth_ifindex = if_nametoindex("binddevtest1");
217	if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex"))
218		goto done;
219
220	if (!ASSERT_OK(setget_sockopt__load(skel), "load skel"))
221		goto done;
222
223	skel->links.skops_sockopt =
224		bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd);
225	if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup"))
226		goto done;
227
228	skel->links.socket_post_create =
229		bpf_program__attach_cgroup(skel->progs.socket_post_create, cg_fd);
230	if (!ASSERT_OK_PTR(skel->links.socket_post_create, "attach_cgroup"))
231		goto done;
232
233	test_tcp(AF_INET6);
234	test_tcp(AF_INET);
235	test_udp(AF_INET6);
236	test_udp(AF_INET);
237	test_ktls(AF_INET6);
238	test_ktls(AF_INET);
239	test_nonstandard_opt(AF_INET);
240	test_nonstandard_opt(AF_INET6);
241
242done:
243	setget_sockopt__destroy(skel);
244	close(cg_fd);
245}