brintos

brintos / linux-shallow public Read only

0
0
Text · 13.7 KiB · 56685fc Raw
564 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2020 Facebook */3 4#define _GNU_SOURCE5#include <sched.h>6#include <stdio.h>7#include <stdlib.h>8#include <sys/socket.h>9#include <linux/compiler.h>10 11#include "test_progs.h"12#include "cgroup_helpers.h"13#include "network_helpers.h"14#include "test_tcp_hdr_options.h"15#include "test_tcp_hdr_options.skel.h"16#include "test_misc_tcp_hdr_options.skel.h"17 18#define LO_ADDR6 "::1"19#define CG_NAME "/tcpbpf-hdr-opt-test"20 21static struct bpf_test_option exp_passive_estab_in;22static struct bpf_test_option exp_active_estab_in;23static struct bpf_test_option exp_passive_fin_in;24static struct bpf_test_option exp_active_fin_in;25static struct hdr_stg exp_passive_hdr_stg;26static struct hdr_stg exp_active_hdr_stg = { .active = true, };27 28static struct test_misc_tcp_hdr_options *misc_skel;29static struct test_tcp_hdr_options *skel;30static int lport_linum_map_fd;31static int hdr_stg_map_fd;32static __u32 duration;33static int cg_fd;34 35struct sk_fds {36	int srv_fd;37	int passive_fd;38	int active_fd;39	int passive_lport;40	int active_lport;41};42 43static int create_netns(void)44{45	if (!ASSERT_OK(unshare(CLONE_NEWNET), "create netns"))46		return -1;47 48	if (!ASSERT_OK(system("ip link set dev lo up"), "run ip cmd"))49		return -1;50 51	return 0;52}53 54static void print_hdr_stg(const struct hdr_stg *hdr_stg, const char *prefix)55{56	fprintf(stderr, "%s{active:%u, resend_syn:%u, syncookie:%u, fastopen:%u}\n",57		prefix ? : "", hdr_stg->active, hdr_stg->resend_syn,58		hdr_stg->syncookie, hdr_stg->fastopen);59}60 61static void print_option(const struct bpf_test_option *opt, const char *prefix)62{63	fprintf(stderr, "%s{flags:0x%x, max_delack_ms:%u, rand:0x%x}\n",64		prefix ? : "", opt->flags, opt->max_delack_ms, opt->rand);65}66 67static void sk_fds_close(struct sk_fds *sk_fds)68{69	close(sk_fds->srv_fd);70	close(sk_fds->passive_fd);71	close(sk_fds->active_fd);72}73 74static int sk_fds_shutdown(struct sk_fds *sk_fds)75{76	int ret, abyte;77 78	shutdown(sk_fds->active_fd, SHUT_WR);79	ret = read(sk_fds->passive_fd, &abyte, sizeof(abyte));80	if (!ASSERT_EQ(ret, 0, "read-after-shutdown(passive_fd):"))81		return -1;82 83	shutdown(sk_fds->passive_fd, SHUT_WR);84	ret = read(sk_fds->active_fd, &abyte, sizeof(abyte));85	if (!ASSERT_EQ(ret, 0, "read-after-shutdown(active_fd):"))86		return -1;87 88	return 0;89}90 91static int sk_fds_connect(struct sk_fds *sk_fds, bool fast_open)92{93	const char fast[] = "FAST!!!";94	struct sockaddr_in6 addr6;95	socklen_t len;96 97	sk_fds->srv_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0);98	if (!ASSERT_NEQ(sk_fds->srv_fd, -1, "start_server"))99		goto error;100 101	if (fast_open)102		sk_fds->active_fd = fastopen_connect(sk_fds->srv_fd, fast,103						     sizeof(fast), 0);104	else105		sk_fds->active_fd = connect_to_fd(sk_fds->srv_fd, 0);106 107	if (!ASSERT_NEQ(sk_fds->active_fd, -1, "")) {108		close(sk_fds->srv_fd);109		goto error;110	}111 112	len = sizeof(addr6);113	if (!ASSERT_OK(getsockname(sk_fds->srv_fd, (struct sockaddr *)&addr6,114				   &len), "getsockname(srv_fd)"))115		goto error_close;116	sk_fds->passive_lport = ntohs(addr6.sin6_port);117 118	len = sizeof(addr6);119	if (!ASSERT_OK(getsockname(sk_fds->active_fd, (struct sockaddr *)&addr6,120				   &len), "getsockname(active_fd)"))121		goto error_close;122	sk_fds->active_lport = ntohs(addr6.sin6_port);123 124	sk_fds->passive_fd = accept(sk_fds->srv_fd, NULL, 0);125	if (!ASSERT_NEQ(sk_fds->passive_fd, -1, "accept(srv_fd)"))126		goto error_close;127 128	if (fast_open) {129		char bytes_in[sizeof(fast)];130		int ret;131 132		ret = read(sk_fds->passive_fd, bytes_in, sizeof(bytes_in));133		if (!ASSERT_EQ(ret, sizeof(fast), "read fastopen syn data")) {134			close(sk_fds->passive_fd);135			goto error_close;136		}137	}138 139	return 0;140 141error_close:142	close(sk_fds->active_fd);143	close(sk_fds->srv_fd);144 145error:146	memset(sk_fds, -1, sizeof(*sk_fds));147	return -1;148}149 150static int check_hdr_opt(const struct bpf_test_option *exp,151			 const struct bpf_test_option *act,152			 const char *hdr_desc)153{154	if (!ASSERT_EQ(memcmp(exp, act, sizeof(*exp)), 0, hdr_desc)) {155		print_option(exp, "expected: ");156		print_option(act, "  actual: ");157		return -1;158	}159 160	return 0;161}162 163static int check_hdr_stg(const struct hdr_stg *exp, int fd,164			 const char *stg_desc)165{166	struct hdr_stg act;167 168	if (!ASSERT_OK(bpf_map_lookup_elem(hdr_stg_map_fd, &fd, &act),169		  "map_lookup(hdr_stg_map_fd)"))170		return -1;171 172	if (!ASSERT_EQ(memcmp(exp, &act, sizeof(*exp)), 0, stg_desc)) {173		print_hdr_stg(exp, "expected: ");174		print_hdr_stg(&act, "  actual: ");175		return -1;176	}177 178	return 0;179}180 181static int check_error_linum(const struct sk_fds *sk_fds)182{183	unsigned int nr_errors = 0;184	struct linum_err linum_err;185	int lport;186 187	lport = sk_fds->passive_lport;188	if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {189		fprintf(stderr,190			"bpf prog error out at lport:passive(%d), linum:%u err:%d\n",191			lport, linum_err.linum, linum_err.err);192		nr_errors++;193	}194 195	lport = sk_fds->active_lport;196	if (!bpf_map_lookup_elem(lport_linum_map_fd, &lport, &linum_err)) {197		fprintf(stderr,198			"bpf prog error out at lport:active(%d), linum:%u err:%d\n",199			lport, linum_err.linum, linum_err.err);200		nr_errors++;201	}202 203	return nr_errors;204}205 206static void check_hdr_and_close_fds(struct sk_fds *sk_fds)207{208	const __u32 expected_inherit_cb_flags =209		BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG |210		BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG |211		BPF_SOCK_OPS_STATE_CB_FLAG;212 213	if (sk_fds_shutdown(sk_fds))214		goto check_linum;215 216	if (!ASSERT_EQ(expected_inherit_cb_flags, skel->bss->inherit_cb_flags,217		       "inherit_cb_flags"))218		goto check_linum;219 220	if (check_hdr_stg(&exp_passive_hdr_stg, sk_fds->passive_fd,221			  "passive_hdr_stg"))222		goto check_linum;223 224	if (check_hdr_stg(&exp_active_hdr_stg, sk_fds->active_fd,225			  "active_hdr_stg"))226		goto check_linum;227 228	if (check_hdr_opt(&exp_passive_estab_in, &skel->bss->passive_estab_in,229			  "passive_estab_in"))230		goto check_linum;231 232	if (check_hdr_opt(&exp_active_estab_in, &skel->bss->active_estab_in,233			  "active_estab_in"))234		goto check_linum;235 236	if (check_hdr_opt(&exp_passive_fin_in, &skel->bss->passive_fin_in,237			  "passive_fin_in"))238		goto check_linum;239 240	check_hdr_opt(&exp_active_fin_in, &skel->bss->active_fin_in,241		      "active_fin_in");242 243check_linum:244	ASSERT_FALSE(check_error_linum(sk_fds), "check_error_linum");245	sk_fds_close(sk_fds);246}247 248static void prepare_out(void)249{250	skel->bss->active_syn_out = exp_passive_estab_in;251	skel->bss->passive_synack_out = exp_active_estab_in;252 253	skel->bss->active_fin_out = exp_passive_fin_in;254	skel->bss->passive_fin_out = exp_active_fin_in;255}256 257static void reset_test(void)258{259	size_t optsize = sizeof(struct bpf_test_option);260	int lport, err;261 262	memset(&skel->bss->passive_synack_out, 0, optsize);263	memset(&skel->bss->passive_fin_out, 0, optsize);264 265	memset(&skel->bss->passive_estab_in, 0, optsize);266	memset(&skel->bss->passive_fin_in, 0, optsize);267 268	memset(&skel->bss->active_syn_out, 0, optsize);269	memset(&skel->bss->active_fin_out, 0, optsize);270 271	memset(&skel->bss->active_estab_in, 0, optsize);272	memset(&skel->bss->active_fin_in, 0, optsize);273 274	skel->bss->inherit_cb_flags = 0;275 276	skel->data->test_kind = TCPOPT_EXP;277	skel->data->test_magic = 0xeB9F;278 279	memset(&exp_passive_estab_in, 0, optsize);280	memset(&exp_active_estab_in, 0, optsize);281	memset(&exp_passive_fin_in, 0, optsize);282	memset(&exp_active_fin_in, 0, optsize);283 284	memset(&exp_passive_hdr_stg, 0, sizeof(exp_passive_hdr_stg));285	memset(&exp_active_hdr_stg, 0, sizeof(exp_active_hdr_stg));286	exp_active_hdr_stg.active = true;287 288	err = bpf_map_get_next_key(lport_linum_map_fd, NULL, &lport);289	while (!err) {290		bpf_map_delete_elem(lport_linum_map_fd, &lport);291		err = bpf_map_get_next_key(lport_linum_map_fd, &lport, &lport);292	}293}294 295static void fastopen_estab(void)296{297	struct bpf_link *link;298	struct sk_fds sk_fds;299 300	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);301	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);302 303	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;304	exp_passive_estab_in.rand = 0xfa;305	exp_passive_estab_in.max_delack_ms = 11;306 307	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;308	exp_active_estab_in.rand = 0xce;309	exp_active_estab_in.max_delack_ms = 22;310 311	exp_passive_hdr_stg.fastopen = true;312 313	prepare_out();314 315	/* Allow fastopen without fastopen cookie */316	if (write_sysctl("/proc/sys/net/ipv4/tcp_fastopen", "1543"))317		return;318 319	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);320	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))321		return;322 323	if (sk_fds_connect(&sk_fds, true)) {324		bpf_link__destroy(link);325		return;326	}327 328	check_hdr_and_close_fds(&sk_fds);329	bpf_link__destroy(link);330}331 332static void syncookie_estab(void)333{334	struct bpf_link *link;335	struct sk_fds sk_fds;336 337	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);338	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);339 340	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;341	exp_passive_estab_in.rand = 0xfa;342	exp_passive_estab_in.max_delack_ms = 11;343 344	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS |345					OPTION_F_RESEND;346	exp_active_estab_in.rand = 0xce;347	exp_active_estab_in.max_delack_ms = 22;348 349	exp_passive_hdr_stg.syncookie = true;350	exp_active_hdr_stg.resend_syn = true;351 352	prepare_out();353 354	/* Clear the RESEND to ensure the bpf prog can learn355	 * want_cookie and set the RESEND by itself.356	 */357	skel->bss->passive_synack_out.flags &= ~OPTION_F_RESEND;358 359	/* Enforce syncookie mode */360	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))361		return;362 363	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);364	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))365		return;366 367	if (sk_fds_connect(&sk_fds, false)) {368		bpf_link__destroy(link);369		return;370	}371 372	check_hdr_and_close_fds(&sk_fds);373	bpf_link__destroy(link);374}375 376static void fin(void)377{378	struct bpf_link *link;379	struct sk_fds sk_fds;380 381	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);382	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);383 384	exp_passive_fin_in.flags = OPTION_F_RAND;385	exp_passive_fin_in.rand = 0xfa;386 387	exp_active_fin_in.flags = OPTION_F_RAND;388	exp_active_fin_in.rand = 0xce;389 390	prepare_out();391 392	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))393		return;394 395	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);396	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))397		return;398 399	if (sk_fds_connect(&sk_fds, false)) {400		bpf_link__destroy(link);401		return;402	}403 404	check_hdr_and_close_fds(&sk_fds);405	bpf_link__destroy(link);406}407 408static void __simple_estab(bool exprm)409{410	struct bpf_link *link;411	struct sk_fds sk_fds;412 413	hdr_stg_map_fd = bpf_map__fd(skel->maps.hdr_stg_map);414	lport_linum_map_fd = bpf_map__fd(skel->maps.lport_linum_map);415 416	exp_passive_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;417	exp_passive_estab_in.rand = 0xfa;418	exp_passive_estab_in.max_delack_ms = 11;419 420	exp_active_estab_in.flags = OPTION_F_RAND | OPTION_F_MAX_DELACK_MS;421	exp_active_estab_in.rand = 0xce;422	exp_active_estab_in.max_delack_ms = 22;423 424	prepare_out();425 426	if (!exprm) {427		skel->data->test_kind = 0xB9;428		skel->data->test_magic = 0;429	}430 431	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))432		return;433 434	link = bpf_program__attach_cgroup(skel->progs.estab, cg_fd);435	if (!ASSERT_OK_PTR(link, "attach_cgroup(estab)"))436		return;437 438	if (sk_fds_connect(&sk_fds, false)) {439		bpf_link__destroy(link);440		return;441	}442 443	check_hdr_and_close_fds(&sk_fds);444	bpf_link__destroy(link);445}446 447static void no_exprm_estab(void)448{449	__simple_estab(false);450}451 452static void simple_estab(void)453{454	__simple_estab(true);455}456 457static void misc(void)458{459	const char send_msg[] = "MISC!!!";460	char recv_msg[sizeof(send_msg)];461	const unsigned int nr_data = 2;462	struct bpf_link *link;463	struct sk_fds sk_fds;464	int i, ret;465 466	lport_linum_map_fd = bpf_map__fd(misc_skel->maps.lport_linum_map);467 468	if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))469		return;470 471	link = bpf_program__attach_cgroup(misc_skel->progs.misc_estab, cg_fd);472	if (!ASSERT_OK_PTR(link, "attach_cgroup(misc_estab)"))473		return;474 475	if (sk_fds_connect(&sk_fds, false)) {476		bpf_link__destroy(link);477		return;478	}479 480	for (i = 0; i < nr_data; i++) {481		/* MSG_EOR to ensure skb will not be combined */482		ret = send(sk_fds.active_fd, send_msg, sizeof(send_msg),483			   MSG_EOR);484		if (!ASSERT_EQ(ret, sizeof(send_msg), "send(msg)"))485			goto check_linum;486 487		ret = read(sk_fds.passive_fd, recv_msg, sizeof(recv_msg));488		if (!ASSERT_EQ(ret, sizeof(send_msg), "read(msg)"))489			goto check_linum;490	}491 492	if (sk_fds_shutdown(&sk_fds))493		goto check_linum;494 495	ASSERT_EQ(misc_skel->bss->nr_syn, 1, "unexpected nr_syn");496 497	ASSERT_EQ(misc_skel->bss->nr_data, nr_data, "unexpected nr_data");498 499	/* The last ACK may have been delayed, so it is either 1 or 2. */500	CHECK(misc_skel->bss->nr_pure_ack != 1 &&501	      misc_skel->bss->nr_pure_ack != 2,502	      "unexpected nr_pure_ack",503	      "expected (1 or 2) != actual (%u)\n",504		misc_skel->bss->nr_pure_ack);505 506	ASSERT_EQ(misc_skel->bss->nr_fin, 1, "unexpected nr_fin");507 508	ASSERT_EQ(misc_skel->bss->nr_hwtstamp, 0, "nr_hwtstamp");509 510check_linum:511	ASSERT_FALSE(check_error_linum(&sk_fds), "check_error_linum");512	sk_fds_close(&sk_fds);513	bpf_link__destroy(link);514}515 516struct test {517	const char *desc;518	void (*run)(void);519};520 521#define DEF_TEST(name) { #name, name }522static struct test tests[] = {523	DEF_TEST(simple_estab),524	DEF_TEST(no_exprm_estab),525	DEF_TEST(syncookie_estab),526	DEF_TEST(fastopen_estab),527	DEF_TEST(fin),528	DEF_TEST(misc),529};530 531void test_tcp_hdr_options(void)532{533	int i;534 535	skel = test_tcp_hdr_options__open_and_load();536	if (!ASSERT_OK_PTR(skel, "open and load skel"))537		return;538 539	misc_skel = test_misc_tcp_hdr_options__open_and_load();540	if (!ASSERT_OK_PTR(misc_skel, "open and load misc test skel"))541		goto skel_destroy;542 543	cg_fd = test__join_cgroup(CG_NAME);544	if (!ASSERT_GE(cg_fd, 0, "join_cgroup"))545		goto skel_destroy;546 547	for (i = 0; i < ARRAY_SIZE(tests); i++) {548		if (!test__start_subtest(tests[i].desc))549			continue;550 551		if (create_netns())552			break;553 554		tests[i].run();555 556		reset_test();557	}558 559	close(cg_fd);560skel_destroy:561	test_misc_tcp_hdr_options__destroy(misc_skel);562	test_tcp_hdr_options__destroy(skel);563}564