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