// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ #define _GNU_SOURCE #include <sched.h> #include <linux/socket.h> #include <linux/tls.h> #include <net/if.h> #include "test_progs.h" #include "cgroup_helpers.h" #include "network_helpers.h" #include "setget_sockopt.skel.h" #define CG_NAME "/setget-sockopt-test" static const char addr4_str[] = "127.0.0.1"; static const char addr6_str[] = "::1"; static struct setget_sockopt *skel; static int cg_fd; static int create_netns(void) { if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns")) return -1; if (!ASSERT_OK(system("ip link set dev lo up"), "set lo up")) return -1; if (!ASSERT_OK(system("ip link add dev binddevtest1 type veth peer name binddevtest2"), "add veth")) return -1; if (!ASSERT_OK(system("ip link set dev binddevtest1 up"), "bring veth up")) return -1; return 0; } static void test_tcp(int family) { struct setget_sockopt__bss *bss = skel->bss; int sfd, cfd; 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; cfd = connect_to_fd(sfd, 0); if (!ASSERT_GE(cfd, 0, "connect_to_fd_server")) { close(sfd); return; } close(sfd); 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"); } static void test_udp(int family) { struct setget_sockopt__bss *bss = skel->bss; int sfd; memset(bss, 0, sizeof(*bss)); sfd = start_server(family, SOCK_DGRAM, family == AF_INET6 ? addr6_str : addr4_str, 0, 0); if (!ASSERT_GE(sfd, 0, "start_server")) return; close(sfd); ASSERT_GE(bss->nr_socket_post_create, 1, "nr_socket_post_create"); 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); if (cg_fd < 0) return; if (create_netns()) goto done; skel = setget_sockopt__open(); if (!ASSERT_OK_PTR(skel, "open skel")) goto done; strcpy(skel->rodata->veth, "binddevtest1"); skel->rodata->veth_ifindex = if_nametoindex("binddevtest1"); if (!ASSERT_GT(skel->rodata->veth_ifindex, 0, "if_nametoindex")) goto done; if (!ASSERT_OK(setget_sockopt__load(skel), "load skel")) goto done; skel->links.skops_sockopt = bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd); if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup")) goto done; skel->links.socket_post_create = bpf_program__attach_cgroup(skel->progs.socket_post_create, cg_fd); if (!ASSERT_OK_PTR(skel->links.socket_post_create, "attach_cgroup")) goto done; test_tcp(AF_INET6); 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); close(cg_fd); }