brintos

brintos / linux-shallow public Read only

0
0
Text · 10.2 KiB · 6dd4318 Raw
421 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) Meta Platforms, Inc. and affiliates. */3 4#include "vmlinux.h"5#include "bpf_tracing_net.h"6#include <bpf/bpf_core_read.h>7#include <bpf/bpf_helpers.h>8#include <bpf/bpf_tracing.h>9#include "bpf_misc.h"10 11extern unsigned long CONFIG_HZ __kconfig;12 13const volatile char veth[IFNAMSIZ];14const volatile int veth_ifindex;15 16int nr_listen;17int nr_passive;18int nr_active;19int nr_connect;20int nr_binddev;21int nr_socket_post_create;22int nr_fin_wait1;23 24struct sockopt_test {25	int opt;26	int new;27	int restore;28	int expected;29	int tcp_expected;30	unsigned int flip:1;31};32 33static const char not_exist_cc[] = "not_exist";34static const char cubic_cc[] = "cubic";35static const char reno_cc[] = "reno";36 37static const struct sockopt_test sol_socket_tests[] = {38	{ .opt = SO_REUSEADDR, .flip = 1, },39	{ .opt = SO_SNDBUF, .new = 8123, .expected = 8123 * 2, },40	{ .opt = SO_RCVBUF, .new = 8123, .expected = 8123 * 2, },41	{ .opt = SO_KEEPALIVE, .flip = 1, },42	{ .opt = SO_PRIORITY, .new = 0xeb9f, .expected = 0xeb9f, },43	{ .opt = SO_REUSEPORT, .flip = 1, },44	{ .opt = SO_RCVLOWAT, .new = 8123, .expected = 8123, },45	{ .opt = SO_MARK, .new = 0xeb9f, .expected = 0xeb9f, },46	{ .opt = SO_MAX_PACING_RATE, .new = 0xeb9f, .expected = 0xeb9f, },47	{ .opt = SO_TXREHASH, .flip = 1, },48	{ .opt = 0, },49};50 51static const struct sockopt_test sol_tcp_tests[] = {52	{ .opt = TCP_NODELAY, .flip = 1, },53	{ .opt = TCP_KEEPIDLE, .new = 123, .expected = 123, .restore = 321, },54	{ .opt = TCP_KEEPINTVL, .new = 123, .expected = 123, .restore = 321, },55	{ .opt = TCP_KEEPCNT, .new = 123, .expected = 123, .restore = 124, },56	{ .opt = TCP_SYNCNT, .new = 123, .expected = 123, .restore = 124, },57	{ .opt = TCP_WINDOW_CLAMP, .new = 8123, .expected = 8123, .restore = 8124, },58	{ .opt = TCP_CONGESTION, },59	{ .opt = TCP_THIN_LINEAR_TIMEOUTS, .flip = 1, },60	{ .opt = TCP_USER_TIMEOUT, .new = 123400, .expected = 123400, },61	{ .opt = TCP_NOTSENT_LOWAT, .new = 1314, .expected = 1314, },62	{ .opt = TCP_BPF_SOCK_OPS_CB_FLAGS, .new = BPF_SOCK_OPS_ALL_CB_FLAGS,63	  .expected = BPF_SOCK_OPS_ALL_CB_FLAGS, },64	{ .opt = 0, },65};66 67static const struct sockopt_test sol_ip_tests[] = {68	{ .opt = IP_TOS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },69	{ .opt = 0, },70};71 72static const struct sockopt_test sol_ipv6_tests[] = {73	{ .opt = IPV6_TCLASS, .new = 0xe1, .expected = 0xe1, .tcp_expected = 0xe0, },74	{ .opt = IPV6_AUTOFLOWLABEL, .flip = 1, },75	{ .opt = 0, },76};77 78struct loop_ctx {79	void *ctx;80	struct sock *sk;81};82 83static int bpf_test_sockopt_flip(void *ctx, struct sock *sk,84				 const struct sockopt_test *t,85				 int level)86{87	int old, tmp, new, opt = t->opt;88 89	opt = t->opt;90 91	if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)))92		return 1;93	/* kernel initialized txrehash to 255 */94	if (level == SOL_SOCKET && opt == SO_TXREHASH && old != 0 && old != 1)95		old = 1;96 97	new = !old;98	if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))99		return 1;100	if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||101	    tmp != new)102		return 1;103 104	if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))105		return 1;106 107	return 0;108}109 110static int bpf_test_sockopt_int(void *ctx, struct sock *sk,111				const struct sockopt_test *t,112				int level)113{114	int old, tmp, new, expected, opt;115 116	opt = t->opt;117	new = t->new;118	if (sk->sk_type == SOCK_STREAM && t->tcp_expected)119		expected = t->tcp_expected;120	else121		expected = t->expected;122 123	if (bpf_getsockopt(ctx, level, opt, &old, sizeof(old)) ||124	    old == new)125		return 1;126 127	if (bpf_setsockopt(ctx, level, opt, &new, sizeof(new)))128		return 1;129	if (bpf_getsockopt(ctx, level, opt, &tmp, sizeof(tmp)) ||130	    tmp != expected)131		return 1;132 133	if (t->restore)134		old = t->restore;135	if (bpf_setsockopt(ctx, level, opt, &old, sizeof(old)))136		return 1;137 138	return 0;139}140 141static int bpf_test_socket_sockopt(__u32 i, struct loop_ctx *lc)142{143	const struct sockopt_test *t;144 145	if (i >= ARRAY_SIZE(sol_socket_tests))146		return 1;147 148	t = &sol_socket_tests[i];149	if (!t->opt)150		return 1;151 152	if (t->flip)153		return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, SOL_SOCKET);154 155	return bpf_test_sockopt_int(lc->ctx, lc->sk, t, SOL_SOCKET);156}157 158static int bpf_test_ip_sockopt(__u32 i, struct loop_ctx *lc)159{160	const struct sockopt_test *t;161 162	if (i >= ARRAY_SIZE(sol_ip_tests))163		return 1;164 165	t = &sol_ip_tests[i];166	if (!t->opt)167		return 1;168 169	if (t->flip)170		return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IP);171 172	return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IP);173}174 175static int bpf_test_ipv6_sockopt(__u32 i, struct loop_ctx *lc)176{177	const struct sockopt_test *t;178 179	if (i >= ARRAY_SIZE(sol_ipv6_tests))180		return 1;181 182	t = &sol_ipv6_tests[i];183	if (!t->opt)184		return 1;185 186	if (t->flip)187		return bpf_test_sockopt_flip(lc->ctx, lc->sk, t, IPPROTO_IPV6);188 189	return bpf_test_sockopt_int(lc->ctx, lc->sk, t, IPPROTO_IPV6);190}191 192static int bpf_test_tcp_sockopt(__u32 i, struct loop_ctx *lc)193{194	const struct sockopt_test *t;195	struct sock *sk;196	void *ctx;197 198	if (i >= ARRAY_SIZE(sol_tcp_tests))199		return 1;200 201	t = &sol_tcp_tests[i];202	if (!t->opt)203		return 1;204 205	ctx = lc->ctx;206	sk = lc->sk;207 208	if (t->opt == TCP_CONGESTION) {209		char old_cc[16], tmp_cc[16];210		const char *new_cc;211		int new_cc_len;212 213		if (!bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION,214				    (void *)not_exist_cc, sizeof(not_exist_cc)))215			return 1;216		if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))217			return 1;218		if (!bpf_strncmp(old_cc, sizeof(old_cc), cubic_cc)) {219			new_cc = reno_cc;220			new_cc_len = sizeof(reno_cc);221		} else {222			new_cc = cubic_cc;223			new_cc_len = sizeof(cubic_cc);224		}225		if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, (void *)new_cc,226				   new_cc_len))227			return 1;228		if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, tmp_cc, sizeof(tmp_cc)))229			return 1;230		if (bpf_strncmp(tmp_cc, sizeof(tmp_cc), new_cc))231			return 1;232		if (bpf_setsockopt(ctx, IPPROTO_TCP, TCP_CONGESTION, old_cc, sizeof(old_cc)))233			return 1;234		return 0;235	}236 237	if (t->flip)238		return bpf_test_sockopt_flip(ctx, sk, t, IPPROTO_TCP);239 240	return bpf_test_sockopt_int(ctx, sk, t, IPPROTO_TCP);241}242 243static int bpf_test_sockopt(void *ctx, struct sock *sk)244{245	struct loop_ctx lc = { .ctx = ctx, .sk = sk, };246	__u16 family, proto;247	int n;248 249	family = sk->sk_family;250	proto = sk->sk_protocol;251 252	n = bpf_loop(ARRAY_SIZE(sol_socket_tests), bpf_test_socket_sockopt, &lc, 0);253	if (n != ARRAY_SIZE(sol_socket_tests))254		return -1;255 256	if (proto == IPPROTO_TCP) {257		n = bpf_loop(ARRAY_SIZE(sol_tcp_tests), bpf_test_tcp_sockopt, &lc, 0);258		if (n != ARRAY_SIZE(sol_tcp_tests))259			return -1;260	}261 262	if (family == AF_INET) {263		n = bpf_loop(ARRAY_SIZE(sol_ip_tests), bpf_test_ip_sockopt, &lc, 0);264		if (n != ARRAY_SIZE(sol_ip_tests))265			return -1;266	} else {267		n = bpf_loop(ARRAY_SIZE(sol_ipv6_tests), bpf_test_ipv6_sockopt, &lc, 0);268		if (n != ARRAY_SIZE(sol_ipv6_tests))269			return -1;270	}271 272	return 0;273}274 275static int binddev_test(void *ctx)276{277	const char empty_ifname[] = "";278	int ifindex, zero = 0;279 280	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,281			   (void *)veth, sizeof(veth)))282		return -1;283	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,284			   &ifindex, sizeof(int)) ||285	    ifindex != veth_ifindex)286		return -1;287 288	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,289			   (void *)empty_ifname, sizeof(empty_ifname)))290		return -1;291	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,292			   &ifindex, sizeof(int)) ||293	    ifindex != 0)294		return -1;295 296	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,297			   (void *)&veth_ifindex, sizeof(int)))298		return -1;299	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,300			   &ifindex, sizeof(int)) ||301	    ifindex != veth_ifindex)302		return -1;303 304	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,305			   &zero, sizeof(int)))306		return -1;307	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,308			   &ifindex, sizeof(int)) ||309	    ifindex != 0)310		return -1;311 312	return 0;313}314 315static int test_tcp_maxseg(void *ctx, struct sock *sk)316{317	int val = 1314, tmp;318 319	if (sk->sk_state != TCP_ESTABLISHED)320		return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG,321				      &val, sizeof(val));322 323	if (bpf_getsockopt(ctx, IPPROTO_TCP, TCP_MAXSEG, &tmp, sizeof(tmp)) ||324	    tmp > val)325		return -1;326 327	return 0;328}329 330static int test_tcp_saved_syn(void *ctx, struct sock *sk)331{332	__u8 saved_syn[20];333	int one = 1;334 335	if (sk->sk_state == TCP_LISTEN)336		return bpf_setsockopt(ctx, IPPROTO_TCP, TCP_SAVE_SYN,337				      &one, sizeof(one));338 339	return bpf_getsockopt(ctx, IPPROTO_TCP, TCP_SAVED_SYN,340			      saved_syn, sizeof(saved_syn));341}342 343SEC("lsm_cgroup/socket_post_create")344int BPF_PROG(socket_post_create, struct socket *sock, int family,345	     int type, int protocol, int kern)346{347	struct sock *sk = sock->sk;348 349	if (!sk)350		return 1;351 352	nr_socket_post_create += !bpf_test_sockopt(sk, sk);353	nr_binddev += !binddev_test(sk);354 355	return 1;356}357 358SEC("cgroup/getsockopt")359int _getsockopt(struct bpf_sockopt *ctx)360{361	struct bpf_sock *sk = ctx->sk;362	int *optval = ctx->optval;363	struct tcp_sock *tp;364 365	if (!sk || ctx->level != SOL_TCP || ctx->optname != TCP_BPF_SOCK_OPS_CB_FLAGS)366		return 1;367 368	tp = bpf_core_cast(sk, struct tcp_sock);369	if (ctx->optval + sizeof(int) <= ctx->optval_end) {370		*optval = tp->bpf_sock_ops_cb_flags;371		ctx->retval = 0;372	}373	return 1;374}375 376SEC("sockops")377int skops_sockopt(struct bpf_sock_ops *skops)378{379	struct bpf_sock *bpf_sk = skops->sk;380	struct sock *sk;381	int flags;382 383	if (!bpf_sk)384		return 1;385 386	sk = (struct sock *)bpf_skc_to_tcp_sock(bpf_sk);387	if (!sk)388		return 1;389 390	switch (skops->op) {391	case BPF_SOCK_OPS_TCP_LISTEN_CB:392		nr_listen += !(bpf_test_sockopt(skops, sk) ||393			       test_tcp_maxseg(skops, sk) ||394			       test_tcp_saved_syn(skops, sk));395		break;396	case BPF_SOCK_OPS_TCP_CONNECT_CB:397		nr_connect += !(bpf_test_sockopt(skops, sk) ||398				test_tcp_maxseg(skops, sk));399		break;400	case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:401		nr_active += !(bpf_test_sockopt(skops, sk) ||402			       test_tcp_maxseg(skops, sk));403		break;404	case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:405		nr_passive += !(bpf_test_sockopt(skops, sk) ||406				test_tcp_maxseg(skops, sk) ||407				test_tcp_saved_syn(skops, sk));408		flags = skops->bpf_sock_ops_cb_flags | BPF_SOCK_OPS_STATE_CB_FLAG;409		bpf_setsockopt(skops, SOL_TCP, TCP_BPF_SOCK_OPS_CB_FLAGS, &flags, sizeof(flags));410		break;411	case BPF_SOCK_OPS_STATE_CB:412		if (skops->args[1] == BPF_TCP_CLOSE_WAIT)413			nr_fin_wait1 += !bpf_test_sockopt(skops, sk);414		break;415	}416 417	return 1;418}419 420char _license[] SEC("license") = "GPL";421