brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · d2ca32f Raw
345 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2020, Tessares SA. */3/* Copyright (c) 2022, SUSE. */4 5#include <linux/const.h>6#include <netinet/in.h>7#include <test_progs.h>8#include "cgroup_helpers.h"9#include "network_helpers.h"10#include "mptcp_sock.skel.h"11#include "mptcpify.skel.h"12 13#define NS_TEST "mptcp_ns"14 15#ifndef IPPROTO_MPTCP16#define IPPROTO_MPTCP 26217#endif18 19#ifndef SOL_MPTCP20#define SOL_MPTCP 28421#endif22#ifndef MPTCP_INFO23#define MPTCP_INFO		124#endif25#ifndef MPTCP_INFO_FLAG_FALLBACK26#define MPTCP_INFO_FLAG_FALLBACK		_BITUL(0)27#endif28#ifndef MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED29#define MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED	_BITUL(1)30#endif31 32#ifndef TCP_CA_NAME_MAX33#define TCP_CA_NAME_MAX	1634#endif35 36struct __mptcp_info {37	__u8	mptcpi_subflows;38	__u8	mptcpi_add_addr_signal;39	__u8	mptcpi_add_addr_accepted;40	__u8	mptcpi_subflows_max;41	__u8	mptcpi_add_addr_signal_max;42	__u8	mptcpi_add_addr_accepted_max;43	__u32	mptcpi_flags;44	__u32	mptcpi_token;45	__u64	mptcpi_write_seq;46	__u64	mptcpi_snd_una;47	__u64	mptcpi_rcv_nxt;48	__u8	mptcpi_local_addr_used;49	__u8	mptcpi_local_addr_max;50	__u8	mptcpi_csum_enabled;51	__u32	mptcpi_retransmits;52	__u64	mptcpi_bytes_retrans;53	__u64	mptcpi_bytes_sent;54	__u64	mptcpi_bytes_received;55	__u64	mptcpi_bytes_acked;56};57 58struct mptcp_storage {59	__u32 invoked;60	__u32 is_mptcp;61	struct sock *sk;62	__u32 token;63	struct sock *first;64	char ca_name[TCP_CA_NAME_MAX];65};66 67static struct nstoken *create_netns(void)68{69	SYS(fail, "ip netns add %s", NS_TEST);70	SYS(fail, "ip -net %s link set dev lo up", NS_TEST);71 72	return open_netns(NS_TEST);73fail:74	return NULL;75}76 77static void cleanup_netns(struct nstoken *nstoken)78{79	if (nstoken)80		close_netns(nstoken);81 82	SYS_NOFAIL("ip netns del %s", NS_TEST);83}84 85static int start_mptcp_server(int family, const char *addr_str, __u16 port,86			      int timeout_ms)87{88	struct network_helper_opts opts = {89		.timeout_ms	= timeout_ms,90		.proto		= IPPROTO_MPTCP,91	};92 93	return start_server_str(family, SOCK_STREAM, addr_str, port, &opts);94}95 96static int verify_tsk(int map_fd, int client_fd)97{98	int err, cfd = client_fd;99	struct mptcp_storage val;100 101	err = bpf_map_lookup_elem(map_fd, &cfd, &val);102	if (!ASSERT_OK(err, "bpf_map_lookup_elem"))103		return err;104 105	if (!ASSERT_EQ(val.invoked, 1, "unexpected invoked count"))106		err++;107 108	if (!ASSERT_EQ(val.is_mptcp, 0, "unexpected is_mptcp"))109		err++;110 111	return err;112}113 114static void get_msk_ca_name(char ca_name[])115{116	size_t len;117	int fd;118 119	fd = open("/proc/sys/net/ipv4/tcp_congestion_control", O_RDONLY);120	if (!ASSERT_GE(fd, 0, "failed to open tcp_congestion_control"))121		return;122 123	len = read(fd, ca_name, TCP_CA_NAME_MAX);124	if (!ASSERT_GT(len, 0, "failed to read ca_name"))125		goto err;126 127	if (len > 0 && ca_name[len - 1] == '\n')128		ca_name[len - 1] = '\0';129 130err:131	close(fd);132}133 134static int verify_msk(int map_fd, int client_fd, __u32 token)135{136	char ca_name[TCP_CA_NAME_MAX];137	int err, cfd = client_fd;138	struct mptcp_storage val;139 140	if (!ASSERT_GT(token, 0, "invalid token"))141		return -1;142 143	get_msk_ca_name(ca_name);144 145	err = bpf_map_lookup_elem(map_fd, &cfd, &val);146	if (!ASSERT_OK(err, "bpf_map_lookup_elem"))147		return err;148 149	if (!ASSERT_EQ(val.invoked, 1, "unexpected invoked count"))150		err++;151 152	if (!ASSERT_EQ(val.is_mptcp, 1, "unexpected is_mptcp"))153		err++;154 155	if (!ASSERT_EQ(val.token, token, "unexpected token"))156		err++;157 158	if (!ASSERT_EQ(val.first, val.sk, "unexpected first"))159		err++;160 161	if (!ASSERT_STRNEQ(val.ca_name, ca_name, TCP_CA_NAME_MAX, "unexpected ca_name"))162		err++;163 164	return err;165}166 167static int run_test(int cgroup_fd, int server_fd, bool is_mptcp)168{169	int client_fd, prog_fd, map_fd, err;170	struct mptcp_sock *sock_skel;171 172	sock_skel = mptcp_sock__open_and_load();173	if (!ASSERT_OK_PTR(sock_skel, "skel_open_load"))174		return libbpf_get_error(sock_skel);175 176	err = mptcp_sock__attach(sock_skel);177	if (!ASSERT_OK(err, "skel_attach"))178		goto out;179 180	prog_fd = bpf_program__fd(sock_skel->progs._sockops);181	map_fd = bpf_map__fd(sock_skel->maps.socket_storage_map);182	err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);183	if (!ASSERT_OK(err, "bpf_prog_attach"))184		goto out;185 186	client_fd = connect_to_fd(server_fd, 0);187	if (!ASSERT_GE(client_fd, 0, "connect to fd")) {188		err = -EIO;189		goto out;190	}191 192	err += is_mptcp ? verify_msk(map_fd, client_fd, sock_skel->bss->token) :193			  verify_tsk(map_fd, client_fd);194 195	close(client_fd);196 197out:198	mptcp_sock__destroy(sock_skel);199	return err;200}201 202static void test_base(void)203{204	struct nstoken *nstoken = NULL;205	int server_fd, cgroup_fd;206 207	cgroup_fd = test__join_cgroup("/mptcp");208	if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup"))209		return;210 211	nstoken = create_netns();212	if (!ASSERT_OK_PTR(nstoken, "create_netns"))213		goto fail;214 215	/* without MPTCP */216	server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);217	if (!ASSERT_GE(server_fd, 0, "start_server"))218		goto with_mptcp;219 220	ASSERT_OK(run_test(cgroup_fd, server_fd, false), "run_test tcp");221 222	close(server_fd);223 224with_mptcp:225	/* with MPTCP */226	server_fd = start_mptcp_server(AF_INET, NULL, 0, 0);227	if (!ASSERT_GE(server_fd, 0, "start_mptcp_server"))228		goto fail;229 230	ASSERT_OK(run_test(cgroup_fd, server_fd, true), "run_test mptcp");231 232	close(server_fd);233 234fail:235	cleanup_netns(nstoken);236	close(cgroup_fd);237}238 239static void send_byte(int fd)240{241	char b = 0x55;242 243	ASSERT_EQ(write(fd, &b, sizeof(b)), 1, "send single byte");244}245 246static int verify_mptcpify(int server_fd, int client_fd)247{248	struct __mptcp_info info;249	socklen_t optlen;250	int protocol;251	int err = 0;252 253	optlen = sizeof(protocol);254	if (!ASSERT_OK(getsockopt(server_fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &optlen),255		       "getsockopt(SOL_PROTOCOL)"))256		return -1;257 258	if (!ASSERT_EQ(protocol, IPPROTO_MPTCP, "protocol isn't MPTCP"))259		err++;260 261	optlen = sizeof(info);262	if (!ASSERT_OK(getsockopt(client_fd, SOL_MPTCP, MPTCP_INFO, &info, &optlen),263		       "getsockopt(MPTCP_INFO)"))264		return -1;265 266	if (!ASSERT_GE(info.mptcpi_flags, 0, "unexpected mptcpi_flags"))267		err++;268	if (!ASSERT_FALSE(info.mptcpi_flags & MPTCP_INFO_FLAG_FALLBACK,269			  "MPTCP fallback"))270		err++;271	if (!ASSERT_TRUE(info.mptcpi_flags & MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED,272			 "no remote key received"))273		err++;274 275	return err;276}277 278static int run_mptcpify(int cgroup_fd)279{280	int server_fd, client_fd, err = 0;281	struct mptcpify *mptcpify_skel;282 283	mptcpify_skel = mptcpify__open_and_load();284	if (!ASSERT_OK_PTR(mptcpify_skel, "skel_open_load"))285		return libbpf_get_error(mptcpify_skel);286 287	mptcpify_skel->bss->pid = getpid();288 289	err = mptcpify__attach(mptcpify_skel);290	if (!ASSERT_OK(err, "skel_attach"))291		goto out;292 293	/* without MPTCP */294	server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);295	if (!ASSERT_GE(server_fd, 0, "start_server")) {296		err = -EIO;297		goto out;298	}299 300	client_fd = connect_to_fd(server_fd, 0);301	if (!ASSERT_GE(client_fd, 0, "connect to fd")) {302		err = -EIO;303		goto close_server;304	}305 306	send_byte(client_fd);307 308	err = verify_mptcpify(server_fd, client_fd);309 310	close(client_fd);311close_server:312	close(server_fd);313out:314	mptcpify__destroy(mptcpify_skel);315	return err;316}317 318static void test_mptcpify(void)319{320	struct nstoken *nstoken = NULL;321	int cgroup_fd;322 323	cgroup_fd = test__join_cgroup("/mptcpify");324	if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup"))325		return;326 327	nstoken = create_netns();328	if (!ASSERT_OK_PTR(nstoken, "create_netns"))329		goto fail;330 331	ASSERT_OK(run_mptcpify(cgroup_fd), "run_mptcpify");332 333fail:334	cleanup_netns(nstoken);335	close(cgroup_fd);336}337 338void test_mptcp(void)339{340	if (test__start_subtest("base"))341		test_base();342	if (test__start_subtest("mptcpify"))343		test_mptcpify();344}345