File Index
Files and directories
Sign in
FILE

test_tag.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/test_tag.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#include <stdint.h>
  3#include <stdio.h>
  4#include <stdlib.h>
  5#include <ctype.h>
  6#include <time.h>
  7#include <errno.h>
  8#include <unistd.h>
  9#include <string.h>
 10#include <sched.h>
 11#include <limits.h>
 12#include <assert.h>
 13
 14#include <sys/socket.h>
 15
 16#include <linux/filter.h>
 17#include <linux/bpf.h>
 18#include <linux/if_alg.h>
 19
 20#include <bpf/bpf.h>
 21
 22#include "../../../include/linux/filter.h"
 23#include "testing_helpers.h"
 24
 25static struct bpf_insn prog[BPF_MAXINSNS];
 26
 27static void bpf_gen_imm_prog(unsigned int insns, int fd_map)
 28{
 29	int i;
 30
 31	srand(time(NULL));
 32	for (i = 0; i < insns; i++)
 33		prog[i] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, rand());
 34	prog[i - 1] = BPF_EXIT_INSN();
 35}
 36
 37static void bpf_gen_map_prog(unsigned int insns, int fd_map)
 38{
 39	int i, j = 0;
 40
 41	for (i = 0; i + 1 < insns; i += 2) {
 42		struct bpf_insn tmp[] = {
 43			BPF_LD_MAP_FD(j++ % BPF_REG_10, fd_map)
 44		};
 45
 46		memcpy(&prog[i], tmp, sizeof(tmp));
 47	}
 48	if (insns % 2 == 0)
 49		prog[insns - 2] = BPF_ALU64_IMM(BPF_MOV, i % BPF_REG_10, 42);
 50	prog[insns - 1] = BPF_EXIT_INSN();
 51}
 52
 53static int bpf_try_load_prog(int insns, int fd_map,
 54			     void (*bpf_filler)(unsigned int insns,
 55						int fd_map))
 56{
 57	int fd_prog;
 58
 59	bpf_filler(insns, fd_map);
 60	fd_prog = bpf_test_load_program(BPF_PROG_TYPE_SCHED_CLS, prog, insns, "", 0,
 61				   NULL, 0);
 62	assert(fd_prog > 0);
 63	if (fd_map > 0)
 64		bpf_filler(insns, 0);
 65	return fd_prog;
 66}
 67
 68static int __hex2bin(char ch)
 69{
 70	if ((ch >= '0') && (ch <= '9'))
 71		return ch - '0';
 72	ch = tolower(ch);
 73	if ((ch >= 'a') && (ch <= 'f'))
 74		return ch - 'a' + 10;
 75	return -1;
 76}
 77
 78static int hex2bin(uint8_t *dst, const char *src, size_t count)
 79{
 80	while (count--) {
 81		int hi = __hex2bin(*src++);
 82		int lo = __hex2bin(*src++);
 83
 84		if ((hi < 0) || (lo < 0))
 85			return -1;
 86		*dst++ = (hi << 4) | lo;
 87	}
 88	return 0;
 89}
 90
 91static void tag_from_fdinfo(int fd_prog, uint8_t *tag, uint32_t len)
 92{
 93	const int prefix_len = sizeof("prog_tag:\t") - 1;
 94	char buff[256];
 95	int ret = -1;
 96	FILE *fp;
 97
 98	snprintf(buff, sizeof(buff), "/proc/%d/fdinfo/%d", getpid(),
 99		 fd_prog);
100	fp = fopen(buff, "r");
101	assert(fp);
102
103	while (fgets(buff, sizeof(buff), fp)) {
104		if (strncmp(buff, "prog_tag:\t", prefix_len))
105			continue;
106		ret = hex2bin(tag, buff + prefix_len, len);
107		break;
108	}
109
110	fclose(fp);
111	assert(!ret);
112}
113
114static void tag_from_alg(int insns, uint8_t *tag, uint32_t len)
115{
116	static const struct sockaddr_alg alg = {
117		.salg_family	= AF_ALG,
118		.salg_type	= "hash",
119		.salg_name	= "sha256",
120	};
121	int fd_base, fd_alg, ret;
122	ssize_t size;
123
124	fd_base = socket(AF_ALG, SOCK_SEQPACKET, 0);
125	assert(fd_base > 0);
126
127	ret = bind(fd_base, (struct sockaddr *)&alg, sizeof(alg));
128	assert(!ret);
129
130	fd_alg = accept(fd_base, NULL, 0);
131	assert(fd_alg > 0);
132
133	insns *= sizeof(struct bpf_insn);
134	size = write(fd_alg, prog, insns);
135	assert(size == insns);
136
137	size = read(fd_alg, tag, len);
138	assert(size == len);
139
140	close(fd_alg);
141	close(fd_base);
142}
143
144static void tag_dump(const char *prefix, uint8_t *tag, uint32_t len)
145{
146	int i;
147
148	printf("%s", prefix);
149	for (i = 0; i < len; i++)
150		printf("%02x", tag[i]);
151	printf("\n");
152}
153
154static void tag_exit_report(int insns, int fd_map, uint8_t *ftag,
155			    uint8_t *atag, uint32_t len)
156{
157	printf("Program tag mismatch for %d insns%s!\n", insns,
158	       fd_map < 0 ? "" : " with map");
159
160	tag_dump("  fdinfo result: ", ftag, len);
161	tag_dump("  af_alg result: ", atag, len);
162	exit(1);
163}
164
165static void do_test(uint32_t *tests, int start_insns, int fd_map,
166		    void (*bpf_filler)(unsigned int insns, int fd))
167{
168	int i, fd_prog;
169
170	for (i = start_insns; i <= BPF_MAXINSNS; i++) {
171		uint8_t ftag[8], atag[sizeof(ftag)];
172
173		fd_prog = bpf_try_load_prog(i, fd_map, bpf_filler);
174		tag_from_fdinfo(fd_prog, ftag, sizeof(ftag));
175		tag_from_alg(i, atag, sizeof(atag));
176		if (memcmp(ftag, atag, sizeof(ftag)))
177			tag_exit_report(i, fd_map, ftag, atag, sizeof(ftag));
178
179		close(fd_prog);
180		sched_yield();
181		(*tests)++;
182	}
183}
184
185int main(void)
186{
187	LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_NO_PREALLOC);
188	uint32_t tests = 0;
189	int i, fd_map;
190
191	/* Use libbpf 1.0 API mode */
192	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
193
194	fd_map = bpf_map_create(BPF_MAP_TYPE_HASH, NULL, sizeof(int),
195				sizeof(int), 1, &opts);
196	assert(fd_map > 0);
197
198	for (i = 0; i < 5; i++) {
199		do_test(&tests, 2, -1,     bpf_gen_imm_prog);
200		do_test(&tests, 3, fd_map, bpf_gen_map_prog);
201	}
202
203	printf("test_tag: OK (%u tests)\n", tests);
204	close(fd_map);
205	return 0;
206}
~/ Read-only file preview.