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: Martin KaFai Lau <martin.lau@kernel.org>
This commit is contained in:
Martin KaFai Lau 2023-01-25 14:49:12 -08:00
commit 0164776a2c
3 changed files with 82 additions and 1 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;
}