Commit 0164776a authored by Martin KaFai Lau's avatar Martin KaFai Lau
Browse files

Merge branch 'Enable bpf_setsockopt() on ktls enabled sockets.'

Kui-Feng Lee says:

====================

This patchset implements a change to bpf_setsockopt() which allows
ktls enabled sockets to be used with the SOL_TCP level. This is
necessary as when ktls is enabled, it changes the function pointer of
setsockopt of the socket, which bpf_setsockopt() checks in order to
make sure that the socket is a TCP socket. Checking sk_protocol
instead of the function pointer will ensure that bpf_setsockopt() with
the SOL_TCP level still works on sockets with ktls enabled.

The major differences form v2 are:
 - Add a read() call to make sure that the FIN has arrived.
 - Remove the dependency on other test's header.

The major differences from v1 are:
 - Test with a IPv6 connect as well.
 - Use ASSERT_OK()

v2: https://lore.kernel.org/bpf/20230124181220.2871611-1-kuifeng@meta.com/
v1: https://lore.kernel.org/bpf/20230121025716.3039933-1-kuifeng@meta.com/


====================

Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
parents a5f6b9d5 d1246f93
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5204,7 +5204,7 @@ static int sol_tcp_sockopt(struct sock *sk, int optname,
			   char *optval, int *optlen,
			   bool getopt)
{
	if (sk->sk_prot->setsockopt != tcp_setsockopt)
	if (sk->sk_protocol != IPPROTO_TCP)
		return -EINVAL;

	switch (optname) {
+73 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#define _GNU_SOURCE
#include <sched.h>
#include <linux/socket.h>
#include <linux/tls.h>
#include <net/if.h>

#include "test_progs.h"
@@ -83,6 +84,76 @@ static void test_udp(int family)
	ASSERT_EQ(bss->nr_binddev, 1, "nr_bind");
}

static void test_ktls(int family)
{
	struct tls12_crypto_info_aes_gcm_128 aes128;
	struct setget_sockopt__bss *bss = skel->bss;
	int cfd = -1, sfd = -1, fd = -1, ret;
	char buf;

	memset(bss, 0, sizeof(*bss));

	sfd = start_server(family, SOCK_STREAM,
			   family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
	if (!ASSERT_GE(sfd, 0, "start_server"))
		return;
	fd = connect_to_fd(sfd, 0);
	if (!ASSERT_GE(fd, 0, "connect_to_fd"))
		goto err_out;

	cfd = accept(sfd, NULL, 0);
	if (!ASSERT_GE(cfd, 0, "accept"))
		goto err_out;

	close(sfd);
	sfd = -1;

	/* Setup KTLS */
	ret = setsockopt(fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
	if (!ASSERT_OK(ret, "setsockopt"))
		goto err_out;
	ret = setsockopt(cfd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls"));
	if (!ASSERT_OK(ret, "setsockopt"))
		goto err_out;

	memset(&aes128, 0, sizeof(aes128));
	aes128.info.version = TLS_1_2_VERSION;
	aes128.info.cipher_type = TLS_CIPHER_AES_GCM_128;

	ret = setsockopt(fd, SOL_TLS, TLS_TX, &aes128, sizeof(aes128));
	if (!ASSERT_OK(ret, "setsockopt"))
		goto err_out;

	ret = setsockopt(cfd, SOL_TLS, TLS_RX, &aes128, sizeof(aes128));
	if (!ASSERT_OK(ret, "setsockopt"))
		goto err_out;

	/* KTLS is enabled */

	close(fd);
	/* At this point, the cfd socket is at the CLOSE_WAIT state
	 * and still run TLS protocol.  The test for
	 * BPF_TCP_CLOSE_WAIT should be run at this point.
	 */
	ret = read(cfd, &buf, sizeof(buf));
	ASSERT_EQ(ret, 0, "read");
	close(cfd);

	ASSERT_EQ(bss->nr_listen, 1, "nr_listen");
	ASSERT_EQ(bss->nr_connect, 1, "nr_connect");
	ASSERT_EQ(bss->nr_active, 1, "nr_active");
	ASSERT_EQ(bss->nr_passive, 1, "nr_passive");
	ASSERT_EQ(bss->nr_socket_post_create, 2, "nr_socket_post_create");
	ASSERT_EQ(bss->nr_binddev, 2, "nr_bind");
	ASSERT_EQ(bss->nr_fin_wait1, 1, "nr_fin_wait1");
	return;

err_out:
	close(fd);
	close(cfd);
	close(sfd);
}

void test_setget_sockopt(void)
{
	cg_fd = test__join_cgroup(CG_NAME);
@@ -118,6 +189,8 @@ void test_setget_sockopt(void)
	test_tcp(AF_INET);
	test_udp(AF_INET6);
	test_udp(AF_INET);
	test_ktls(AF_INET6);
	test_ktls(AF_INET);

done:
	setget_sockopt__destroy(skel);
+8 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ int nr_active;
int nr_connect;
int nr_binddev;
int nr_socket_post_create;
int nr_fin_wait1;

struct sockopt_test {
	int opt;
@@ -386,6 +387,13 @@ int skops_sockopt(struct bpf_sock_ops *skops)
		nr_passive += !(bpf_test_sockopt(skops, sk) ||
				test_tcp_maxseg(skops, sk) ||
				test_tcp_saved_syn(skops, sk));
		bpf_sock_ops_cb_flags_set(skops,
					  skops->bpf_sock_ops_cb_flags |
					  BPF_SOCK_OPS_STATE_CB_FLAG);
		break;
	case BPF_SOCK_OPS_STATE_CB:
		if (skops->args[1] == BPF_TCP_CLOSE_WAIT)
			nr_fin_wait1 += !bpf_test_sockopt(skops, sk);
		break;
	}