Commit d0b3d2d7 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'selftests/bpf: Migrate test_tcpbpf_user to be a part of test_progs'



Alexander Duyck says:

====================
Move the test functionality from test_tcpbpf_user into the test_progs
framework so that it will be run any time the test_progs framework is run.
This will help to prevent future test escapes as the individual tests, such
as test_tcpbpf_user, are less likely to be run by developers and CI
tests.

As a part of moving it over the series goes through and updates the code to
make use of the existing APIs included in the test_progs framework. This is
meant to simplify and streamline the test code and avoid duplication of
effort.

v2: Dropped test_tcpbpf_user from .gitignore
    Replaced CHECK_FAIL calls with CHECK calls
    Minimized changes in patch 1 when moving the file
    Updated stg mail command line to display renames in submission
    Added shutdown logic to end of run_test function to guarantee close
    Added patch that replaces the two maps with use of global variables
v3: Left err at -1 while we are performing send/recv calls w/ data
    Drop extra labels from test_tcpbpf_user in favor of keeping err label
    Dropped redundant zero init for tcpbpf_globals result and key
    Dropped replacing of "printf(" with "fprintf(stderr, "
    Fixed error in use of ASSERT_OK_PTR which was skipping of run_test
    Replaced "{ 0 }" with "{}" in init of global in test_tcpbpf_kern.c
    Added "Acked-by" from Martin KaiFai Lau and Andrii Nakryiko
====================

Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 8aaeed81 21b5177e
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -8,7 +8,6 @@ FEATURE-DUMP.libbpf
fixdep
test_dev_cgroup
/test_progs*
test_tcpbpf_user
test_verifier_log
feature
test_sock
+1 −2
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ LDLIBS += -lcap -lelf -lz -lrt -lpthread

# Order correspond to 'make run_tests' order
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
	test_verifier_log test_dev_cgroup test_tcpbpf_user \
	test_verifier_log test_dev_cgroup \
	test_sock test_sockmap get_cgroup_id_user test_socket_cookie \
	test_cgroup_storage \
	test_netcnt test_tcpnotify_user test_sysctl \
@@ -163,7 +163,6 @@ $(OUTPUT)/test_sock: cgroup_helpers.c
$(OUTPUT)/test_sock_addr: cgroup_helpers.c
$(OUTPUT)/test_socket_cookie: cgroup_helpers.c
$(OUTPUT)/test_sockmap: cgroup_helpers.c
$(OUTPUT)/test_tcpbpf_user: cgroup_helpers.c
$(OUTPUT)/test_tcpnotify_user: cgroup_helpers.c trace_helpers.c
$(OUTPUT)/get_cgroup_id_user: cgroup_helpers.c
$(OUTPUT)/test_cgroup_storage: cgroup_helpers.c
+141 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <test_progs.h>
#include <network_helpers.h>

#include "test_tcpbpf.h"
#include "test_tcpbpf_kern.skel.h"

#define LO_ADDR6 "::1"
#define CG_NAME "/tcpbpf-user-test"

static __u32 duration;

static void verify_result(struct tcpbpf_globals *result)
{
	__u32 expected_events = ((1 << BPF_SOCK_OPS_TIMEOUT_INIT) |
				 (1 << BPF_SOCK_OPS_RWND_INIT) |
				 (1 << BPF_SOCK_OPS_TCP_CONNECT_CB) |
				 (1 << BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB) |
				 (1 << BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB) |
				 (1 << BPF_SOCK_OPS_NEEDS_ECN) |
				 (1 << BPF_SOCK_OPS_STATE_CB) |
				 (1 << BPF_SOCK_OPS_TCP_LISTEN_CB));

	/* check global map */
	CHECK(expected_events != result->event_map, "event_map",
	      "unexpected event_map: actual 0x%08x != expected 0x%08x\n",
	      result->event_map, expected_events);

	ASSERT_EQ(result->bytes_received, 501, "bytes_received");
	ASSERT_EQ(result->bytes_acked, 1002, "bytes_acked");
	ASSERT_EQ(result->data_segs_in, 1, "data_segs_in");
	ASSERT_EQ(result->data_segs_out, 1, "data_segs_out");
	ASSERT_EQ(result->bad_cb_test_rv, 0x80, "bad_cb_test_rv");
	ASSERT_EQ(result->good_cb_test_rv, 0, "good_cb_test_rv");
	ASSERT_EQ(result->num_listen, 1, "num_listen");

	/* 3 comes from one listening socket + both ends of the connection */
	ASSERT_EQ(result->num_close_events, 3, "num_close_events");

	/* check setsockopt for SAVE_SYN */
	ASSERT_EQ(result->tcp_save_syn, 0, "tcp_save_syn");

	/* check getsockopt for SAVED_SYN */
	ASSERT_EQ(result->tcp_saved_syn, 1, "tcp_saved_syn");
}

static void run_test(struct tcpbpf_globals *result)
{
	int listen_fd = -1, cli_fd = -1, accept_fd = -1;
	char buf[1000];
	int err = -1;
	int i, rv;

	listen_fd = start_server(AF_INET6, SOCK_STREAM, LO_ADDR6, 0, 0);
	if (CHECK(listen_fd == -1, "start_server", "listen_fd:%d errno:%d\n",
		  listen_fd, errno))
		goto done;

	cli_fd = connect_to_fd(listen_fd, 0);
	if (CHECK(cli_fd == -1, "connect_to_fd(listen_fd)",
		  "cli_fd:%d errno:%d\n", cli_fd, errno))
		goto done;

	accept_fd = accept(listen_fd, NULL, NULL);
	if (CHECK(accept_fd == -1, "accept(listen_fd)",
		  "accept_fd:%d errno:%d\n", accept_fd, errno))
		goto done;

	/* Send 1000B of '+'s from cli_fd -> accept_fd */
	for (i = 0; i < 1000; i++)
		buf[i] = '+';

	rv = send(cli_fd, buf, 1000, 0);
	if (CHECK(rv != 1000, "send(cli_fd)", "rv:%d errno:%d\n", rv, errno))
		goto done;

	rv = recv(accept_fd, buf, 1000, 0);
	if (CHECK(rv != 1000, "recv(accept_fd)", "rv:%d errno:%d\n", rv, errno))
		goto done;

	/* Send 500B of '.'s from accept_fd ->cli_fd */
	for (i = 0; i < 500; i++)
		buf[i] = '.';

	rv = send(accept_fd, buf, 500, 0);
	if (CHECK(rv != 500, "send(accept_fd)", "rv:%d errno:%d\n", rv, errno))
		goto done;

	rv = recv(cli_fd, buf, 500, 0);
	if (CHECK(rv != 500, "recv(cli_fd)", "rv:%d errno:%d\n", rv, errno))
		goto done;

	/*
	 * shutdown accept first to guarantee correct ordering for
	 * bytes_received and bytes_acked when we go to verify the results.
	 */
	shutdown(accept_fd, SHUT_WR);
	err = recv(cli_fd, buf, 1, 0);
	if (CHECK(err, "recv(cli_fd) for fin", "err:%d errno:%d\n", err, errno))
		goto done;

	shutdown(cli_fd, SHUT_WR);
	err = recv(accept_fd, buf, 1, 0);
	CHECK(err, "recv(accept_fd) for fin", "err:%d errno:%d\n", err, errno);
done:
	if (accept_fd != -1)
		close(accept_fd);
	if (cli_fd != -1)
		close(cli_fd);
	if (listen_fd != -1)
		close(listen_fd);

	if (!err)
		verify_result(result);
}

void test_tcpbpf_user(void)
{
	struct test_tcpbpf_kern *skel;
	int cg_fd = -1;

	skel = test_tcpbpf_kern__open_and_load();
	if (CHECK(!skel, "open and load skel", "failed"))
		return;

	cg_fd = test__join_cgroup(CG_NAME);
	if (CHECK(cg_fd < 0, "test__join_cgroup(" CG_NAME ")",
		  "cg_fd:%d errno:%d", cg_fd, errno))
		goto err;

	skel->links.bpf_testcb = bpf_program__attach_cgroup(skel->progs.bpf_testcb, cg_fd);
	if (!ASSERT_OK_PTR(skel->links.bpf_testcb, "attach_cgroup(bpf_testcb)"))
		goto err;

	run_test(&skel->bss->global);

err:
	if (cg_fd != -1)
		close(cg_fd);
	test_tcpbpf_kern__destroy(skel);
}
+13 −73
Original line number Diff line number Diff line
@@ -14,40 +14,7 @@
#include <bpf/bpf_endian.h>
#include "test_tcpbpf.h"

struct {
	__uint(type, BPF_MAP_TYPE_ARRAY);
	__uint(max_entries, 4);
	__type(key, __u32);
	__type(value, struct tcpbpf_globals);
} global_map SEC(".maps");

struct {
	__uint(type, BPF_MAP_TYPE_ARRAY);
	__uint(max_entries, 2);
	__type(key, __u32);
	__type(value, int);
} sockopt_results SEC(".maps");

static inline void update_event_map(int event)
{
	__u32 key = 0;
	struct tcpbpf_globals g, *gp;

	gp = bpf_map_lookup_elem(&global_map, &key);
	if (gp == NULL) {
		struct tcpbpf_globals g = {0};

		g.event_map |= (1 << event);
		bpf_map_update_elem(&global_map, &key, &g,
			    BPF_ANY);
	} else {
		g = *gp;
		g.event_map |= (1 << event);
		bpf_map_update_elem(&global_map, &key, &g,
			    BPF_ANY);
	}
}

struct tcpbpf_globals global = {};
int _version SEC("version") = 1;

SEC("sockops")
@@ -105,29 +72,15 @@ int bpf_testcb(struct bpf_sock_ops *skops)

	op = (int) skops->op;

	update_event_map(op);
	global.event_map |= (1 << op);

	switch (op) {
	case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
		/* Test failure to set largest cb flag (assumes not defined) */
		bad_call_rv = bpf_sock_ops_cb_flags_set(skops, 0x80);
		global.bad_cb_test_rv = bpf_sock_ops_cb_flags_set(skops, 0x80);
		/* Set callback */
		good_call_rv = bpf_sock_ops_cb_flags_set(skops,
		global.good_cb_test_rv = bpf_sock_ops_cb_flags_set(skops,
						 BPF_SOCK_OPS_STATE_CB_FLAG);
		/* Update results */
		{
			__u32 key = 0;
			struct tcpbpf_globals g, *gp;

			gp = bpf_map_lookup_elem(&global_map, &key);
			if (!gp)
				break;
			g = *gp;
			g.bad_cb_test_rv = bad_call_rv;
			g.good_cb_test_rv = good_call_rv;
			bpf_map_update_elem(&global_map, &key, &g,
					    BPF_ANY);
		}
		break;
	case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
		skops->sk_txhash = 0x12345f;
@@ -143,10 +96,8 @@ int bpf_testcb(struct bpf_sock_ops *skops)

				thdr = (struct tcphdr *)(header + offset);
				v = thdr->syn;
				__u32 key = 1;

				bpf_map_update_elem(&sockopt_results, &key, &v,
						    BPF_ANY);
				global.tcp_saved_syn = v;
			}
		}
		break;
@@ -156,25 +107,16 @@ int bpf_testcb(struct bpf_sock_ops *skops)
		break;
	case BPF_SOCK_OPS_STATE_CB:
		if (skops->args[1] == BPF_TCP_CLOSE) {
			__u32 key = 0;
			struct tcpbpf_globals g, *gp;

			gp = bpf_map_lookup_elem(&global_map, &key);
			if (!gp)
				break;
			g = *gp;
			if (skops->args[0] == BPF_TCP_LISTEN) {
				g.num_listen++;
				global.num_listen++;
			} else {
				g.total_retrans = skops->total_retrans;
				g.data_segs_in = skops->data_segs_in;
				g.data_segs_out = skops->data_segs_out;
				g.bytes_received = skops->bytes_received;
				g.bytes_acked = skops->bytes_acked;
				global.total_retrans = skops->total_retrans;
				global.data_segs_in = skops->data_segs_in;
				global.data_segs_out = skops->data_segs_out;
				global.bytes_received = skops->bytes_received;
				global.bytes_acked = skops->bytes_acked;
			}
			g.num_close_events++;
			bpf_map_update_elem(&global_map, &key, &g,
					    BPF_ANY);
			global.num_close_events++;
		}
		break;
	case BPF_SOCK_OPS_TCP_LISTEN_CB:
@@ -182,9 +124,7 @@ int bpf_testcb(struct bpf_sock_ops *skops)
		v = bpf_setsockopt(skops, IPPROTO_TCP, TCP_SAVE_SYN,
				   &save_syn, sizeof(save_syn));
		/* Update global map w/ result of setsock opt */
		__u32 key = 0;

		bpf_map_update_elem(&sockopt_results, &key, &v, BPF_ANY);
		global.tcp_save_syn = v;
		break;
	default:
		rv = -1;
+0 −50
Original line number Diff line number Diff line
#!/usr/bin/env python3
#
# SPDX-License-Identifier: GPL-2.0
#

import sys, os, os.path, getopt
import socket, time
import subprocess
import select

def read(sock, n):
    buf = b''
    while len(buf) < n:
        rem = n - len(buf)
        try: s = sock.recv(rem)
        except (socket.error) as e: return b''
        buf += s
    return buf

def send(sock, s):
    total = len(s)
    count = 0
    while count < total:
        try: n = sock.send(s)
        except (socket.error) as e: n = 0
        if n == 0:
            return count;
        count += n
    return count


serverPort = int(sys.argv[1])

# create active socket
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
try:
    sock.connect(('::1', serverPort))
except socket.error as e:
    sys.exit(1)

buf = b''
n = 0
while n < 1000:
    buf += b'+'
    n += 1

sock.settimeout(1);
n = send(sock, buf)
n = read(sock, 500)
sys.exit(0)
Loading