Commit 5e85c6bb authored by Andrii Nakryiko's avatar Andrii Nakryiko Committed by Daniel Borkmann
Browse files

selftests/bpf: Add variable-length data concatenation pattern test



Add selftest that validates variable-length data reading and concatentation
with one big shared data array. This is a common pattern in production use for
monitoring and tracing applications, that potentially can read a lot of data,
but overall read much less. Such pattern allows to determine precisely what
amount of data needs to be sent over perfbuf/ringbuf and maximize efficiency.

Signed-off-by: default avatarAndrii Nakryiko <andriin@fb.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20200623032224.4020118-2-andriin@fb.com
parent bdb7b79b
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */

#include <test_progs.h>
#include <time.h>
#include "test_varlen.skel.h"

#define CHECK_VAL(got, exp) \
	CHECK((got) != (exp), "check", "got %ld != exp %ld\n", \
	      (long)(got), (long)(exp))

void test_varlen(void)
{
	int duration = 0, err;
	struct test_varlen* skel;
	struct test_varlen__bss *bss;
	struct test_varlen__data *data;
	const char str1[] = "Hello, ";
	const char str2[] = "World!";
	const char exp_str[] = "Hello, \0World!\0";
	const int size1 = sizeof(str1);
	const int size2 = sizeof(str2);

	skel = test_varlen__open_and_load();
	if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
		return;
	bss = skel->bss;
	data = skel->data;

	err = test_varlen__attach(skel);
	if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
		goto cleanup;

	bss->test_pid = getpid();

	/* trigger everything */
	memcpy(bss->buf_in1, str1, size1);
	memcpy(bss->buf_in2, str2, size2);
	bss->capture = true;
	usleep(1);
	bss->capture = false;

	CHECK_VAL(bss->payload1_len1, size1);
	CHECK_VAL(bss->payload1_len2, size2);
	CHECK_VAL(bss->total1, size1 + size2);
	CHECK(memcmp(bss->payload1, exp_str, size1 + size2), "content_check",
	      "doesn't match!");

	CHECK_VAL(data->payload2_len1, size1);
	CHECK_VAL(data->payload2_len2, size2);
	CHECK_VAL(data->total2, size1 + size2);
	CHECK(memcmp(data->payload2, exp_str, size1 + size2), "content_check",
	      "doesn't match!");
cleanup:
	test_varlen__destroy(skel);
}
+96 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2020 Facebook */

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>

#define MAX_LEN 256

char buf_in1[MAX_LEN] = {};
char buf_in2[MAX_LEN] = {};

int test_pid = 0;
bool capture = false;

/* .bss */
long payload1_len1 = 0;
long payload1_len2 = 0;
long total1 = 0;
char payload1[MAX_LEN + MAX_LEN] = {};

/* .data */
int payload2_len1 = -1;
int payload2_len2 = -1;
int total2 = -1;
char payload2[MAX_LEN + MAX_LEN] = { 1 };

SEC("raw_tp/sys_enter")
int handler64(void *regs)
{
	int pid = bpf_get_current_pid_tgid() >> 32;
	void *payload = payload1;
	u64 len;

	/* ignore irrelevant invocations */
	if (test_pid != pid || !capture)
		return 0;

	len = bpf_probe_read_kernel_str(payload, MAX_LEN, &buf_in1[0]);
	if (len <= MAX_LEN) {
		payload += len;
		payload1_len1 = len;
	}

	len = bpf_probe_read_kernel_str(payload, MAX_LEN, &buf_in2[0]);
	if (len <= MAX_LEN) {
		payload += len;
		payload1_len2 = len;
	}

	total1 = payload - (void *)payload1;

	return 0;
}

SEC("tp_btf/sys_enter")
int handler32(void *regs)
{
	int pid = bpf_get_current_pid_tgid() >> 32;
	void *payload = payload2;
	u32 len;

	/* ignore irrelevant invocations */
	if (test_pid != pid || !capture)
		return 0;

	len = bpf_probe_read_kernel_str(payload, MAX_LEN, &buf_in1[0]);
	if (len <= MAX_LEN) {
		payload += len;
		payload2_len1 = len;
	}

	len = bpf_probe_read_kernel_str(payload, MAX_LEN, &buf_in2[0]);
	if (len <= MAX_LEN) {
		payload += len;
		payload2_len2 = len;
	}

	total2 = payload - (void *)payload2;

	return 0;
}

SEC("tp_btf/sys_exit")
int handler_exit(void *regs)
{
	long bla;

	if (bpf_probe_read_kernel(&bla, sizeof(bla), 0))
		return 1;
	else
		return 0;
}

char LICENSE[] SEC("license") = "GPL";