tools/testing/selftests/bpf/prog_tests/sockmap_strp.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/bpf/prog_tests/sockmap_strp.c
Extension
.c
Size
13247 bytes
Lines
455
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
#include <error.h>
#include <netinet/tcp.h>
#include <test_progs.h>
#include "sockmap_helpers.h"
#include "test_skmsg_load_helpers.skel.h"
#include "test_sockmap_strp.skel.h"

#define STRP_PKT_HEAD_LEN 4
#define STRP_PKT_BODY_LEN 6
#define STRP_PKT_FULL_LEN (STRP_PKT_HEAD_LEN + STRP_PKT_BODY_LEN)

static const char packet[STRP_PKT_FULL_LEN] = "head+body\0";
static const int test_packet_num = 100;

/* Current implementation of tcp_bpf_recvmsg_parser() invokes data_ready
 * with sk held if an skb exists in sk_receive_queue. Then for the
 * data_ready implementation of strparser, it will delay the read
 * operation if sk is held and EAGAIN is returned.
 */
static int sockmap_strp_consume_pre_data(int p)
{
	int recvd;
	bool retried = false;
	char rcv[10];

retry:
	errno = 0;
	recvd = recv_timeout(p, rcv, sizeof(rcv), 0, 1);
	if (recvd < 0 && errno == EAGAIN && retried == false) {
		/* On the first call, EAGAIN will certainly be returned.
		 * A 1-second wait is enough for the workqueue to finish.
		 */
		sleep(1);
		retried = true;
		goto retry;
	}

	if (!ASSERT_EQ(recvd, STRP_PKT_FULL_LEN, "recv error or truncated data") ||
	    !ASSERT_OK(memcmp(packet, rcv, STRP_PKT_FULL_LEN),
				"data mismatch"))
		return -1;
	return 0;
}

static struct test_sockmap_strp *sockmap_strp_init(int *out_map, bool pass,
						   bool need_parser)
{
	struct test_sockmap_strp *strp = NULL;
	int verdict, parser;
	int err;

	strp = test_sockmap_strp__open_and_load();
	*out_map = bpf_map__fd(strp->maps.sock_map);

	if (need_parser)
		parser = bpf_program__fd(strp->progs.prog_skb_parser_partial);
	else
		parser = bpf_program__fd(strp->progs.prog_skb_parser);

	if (pass)
		verdict = bpf_program__fd(strp->progs.prog_skb_verdict_pass);
	else
		verdict = bpf_program__fd(strp->progs.prog_skb_verdict);

	err = bpf_prog_attach(parser, *out_map, BPF_SK_SKB_STREAM_PARSER, 0);
	if (!ASSERT_OK(err, "bpf_prog_attach stream parser"))
		goto err;

	err = bpf_prog_attach(verdict, *out_map, BPF_SK_SKB_STREAM_VERDICT, 0);
	if (!ASSERT_OK(err, "bpf_prog_attach stream verdict"))
		goto err;

	return strp;
err:
	test_sockmap_strp__destroy(strp);
	return NULL;
}

/* Dispatch packets to different socket by packet size:
 *
 *                      ------  ------
 *                     | pkt4 || pkt1 |... > remote socket
 *  ------ ------     / ------  ------
 * | pkt8 | pkt7 |...
 *  ------ ------     \ ------  ------
 *                     | pkt3 || pkt2 |... > local socket
 *                      ------  ------
 */
static void test_sockmap_strp_dispatch_pkt(int family, int sotype)

Annotation

Implementation Notes