]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - tools/testing/selftests/bpf/test_align.c
Merge tag 'driver-core-4.13-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / tools / testing / selftests / bpf / test_align.c
1 #include <asm/types.h>
2 #include <linux/types.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <stddef.h>
10 #include <stdbool.h>
11
12 #include <sys/resource.h>
13
14 #include <linux/unistd.h>
15 #include <linux/filter.h>
16 #include <linux/bpf_perf_event.h>
17 #include <linux/bpf.h>
18
19 #include <bpf/bpf.h>
20
21 #include "../../../include/linux/filter.h"
22
23 #ifndef ARRAY_SIZE
24 # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
25 #endif
26
27 #define MAX_INSNS       512
28 #define MAX_MATCHES     16
29
30 struct bpf_align_test {
31         const char *descr;
32         struct bpf_insn insns[MAX_INSNS];
33         enum {
34                 UNDEF,
35                 ACCEPT,
36                 REJECT
37         } result;
38         enum bpf_prog_type prog_type;
39         const char *matches[MAX_MATCHES];
40 };
41
42 static struct bpf_align_test tests[] = {
43         {
44                 .descr = "mov",
45                 .insns = {
46                         BPF_MOV64_IMM(BPF_REG_3, 2),
47                         BPF_MOV64_IMM(BPF_REG_3, 4),
48                         BPF_MOV64_IMM(BPF_REG_3, 8),
49                         BPF_MOV64_IMM(BPF_REG_3, 16),
50                         BPF_MOV64_IMM(BPF_REG_3, 32),
51                         BPF_MOV64_IMM(BPF_REG_0, 0),
52                         BPF_EXIT_INSN(),
53                 },
54                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
55                 .matches = {
56                         "1: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
57                         "2: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
58                         "3: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
59                         "4: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
60                         "5: R1=ctx R3=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
61                 },
62         },
63         {
64                 .descr = "shift",
65                 .insns = {
66                         BPF_MOV64_IMM(BPF_REG_3, 1),
67                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
68                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
69                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
70                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
71                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_3, 4),
72                         BPF_MOV64_IMM(BPF_REG_4, 32),
73                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
74                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
75                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
76                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
77                         BPF_MOV64_IMM(BPF_REG_0, 0),
78                         BPF_EXIT_INSN(),
79                 },
80                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
81                 .matches = {
82                         "1: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
83                         "2: R1=ctx R3=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
84                         "3: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
85                         "4: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
86                         "5: R1=ctx R3=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
87                         "6: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R10=fp",
88                         "7: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm32,min_value=32,max_value=32,min_align=32 R10=fp",
89                         "8: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm16,min_value=16,max_value=16,min_align=16 R10=fp",
90                         "9: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
91                         "10: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
92                         "11: R1=ctx R3=imm1,min_value=1,max_value=1,min_align=1 R4=imm2,min_value=2,max_value=2,min_align=2 R10=fp",
93                 },
94         },
95         {
96                 .descr = "addsub",
97                 .insns = {
98                         BPF_MOV64_IMM(BPF_REG_3, 4),
99                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 4),
100                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, 2),
101                         BPF_MOV64_IMM(BPF_REG_4, 8),
102                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
103                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 2),
104                         BPF_MOV64_IMM(BPF_REG_0, 0),
105                         BPF_EXIT_INSN(),
106                 },
107                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
108                 .matches = {
109                         "1: R1=ctx R3=imm4,min_value=4,max_value=4,min_align=4 R10=fp",
110                         "2: R1=ctx R3=imm8,min_value=8,max_value=8,min_align=4 R10=fp",
111                         "3: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R10=fp",
112                         "4: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm8,min_value=8,max_value=8,min_align=8 R10=fp",
113                         "5: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm12,min_value=12,max_value=12,min_align=4 R10=fp",
114                         "6: R1=ctx R3=imm10,min_value=10,max_value=10,min_align=2 R4=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
115                 },
116         },
117         {
118                 .descr = "mul",
119                 .insns = {
120                         BPF_MOV64_IMM(BPF_REG_3, 7),
121                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 1),
122                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 2),
123                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_3, 4),
124                         BPF_MOV64_IMM(BPF_REG_0, 0),
125                         BPF_EXIT_INSN(),
126                 },
127                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
128                 .matches = {
129                         "1: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
130                         "2: R1=ctx R3=imm7,min_value=7,max_value=7,min_align=1 R10=fp",
131                         "3: R1=ctx R3=imm14,min_value=14,max_value=14,min_align=2 R10=fp",
132                         "4: R1=ctx R3=imm56,min_value=56,max_value=56,min_align=4 R10=fp",
133                 },
134         },
135
136 #define PREP_PKT_POINTERS \
137         BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \
138                     offsetof(struct __sk_buff, data)), \
139         BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \
140                     offsetof(struct __sk_buff, data_end))
141
142 #define LOAD_UNKNOWN(DST_REG) \
143         PREP_PKT_POINTERS, \
144         BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), \
145         BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), \
146         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_0, 1), \
147         BPF_EXIT_INSN(), \
148         BPF_LDX_MEM(BPF_B, DST_REG, BPF_REG_2, 0)
149
150         {
151                 .descr = "unknown shift",
152                 .insns = {
153                         LOAD_UNKNOWN(BPF_REG_3),
154                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
155                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
156                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
157                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_3, 1),
158                         LOAD_UNKNOWN(BPF_REG_4),
159                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_4, 5),
160                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
161                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
162                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
163                         BPF_ALU64_IMM(BPF_RSH, BPF_REG_4, 1),
164                         BPF_MOV64_IMM(BPF_REG_0, 0),
165                         BPF_EXIT_INSN(),
166                 },
167                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
168                 .matches = {
169                         "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
170                         "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv55,min_align=2 R10=fp",
171                         "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv54,min_align=4 R10=fp",
172                         "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv53,min_align=8 R10=fp",
173                         "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv52,min_align=16 R10=fp",
174                         "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv56 R10=fp",
175                         "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv51,min_align=32 R10=fp",
176                         "20: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv52,min_align=16 R10=fp",
177                         "21: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv53,min_align=8 R10=fp",
178                         "22: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv54,min_align=4 R10=fp",
179                         "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv55,min_align=2 R10=fp",
180                 },
181         },
182         {
183                 .descr = "unknown mul",
184                 .insns = {
185                         LOAD_UNKNOWN(BPF_REG_3),
186                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
187                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 1),
188                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
189                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
190                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
191                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 4),
192                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_3),
193                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 8),
194                         BPF_ALU64_IMM(BPF_MUL, BPF_REG_4, 2),
195                         BPF_MOV64_IMM(BPF_REG_0, 0),
196                         BPF_EXIT_INSN(),
197                 },
198                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
199                 .matches = {
200                         "7: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R10=fp",
201                         "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
202                         "9: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv55,min_align=1 R10=fp",
203                         "10: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
204                         "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv54,min_align=2 R10=fp",
205                         "12: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
206                         "13: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv53,min_align=4 R10=fp",
207                         "14: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv56 R10=fp",
208                         "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv52,min_align=8 R10=fp",
209                         "16: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=inv56 R4=inv50,min_align=8 R10=fp"
210                 },
211         },
212         {
213                 .descr = "packet const offset",
214                 .insns = {
215                         PREP_PKT_POINTERS,
216                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
217
218                         BPF_MOV64_IMM(BPF_REG_0, 0),
219
220                         /* Skip over ethernet header.  */
221                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
222                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
223                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
224                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
225                         BPF_EXIT_INSN(),
226
227                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 0),
228                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 1),
229                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 2),
230                         BPF_LDX_MEM(BPF_B, BPF_REG_4, BPF_REG_5, 3),
231                         BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 0),
232                         BPF_LDX_MEM(BPF_H, BPF_REG_4, BPF_REG_5, 2),
233                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
234
235                         BPF_MOV64_IMM(BPF_REG_0, 0),
236                         BPF_EXIT_INSN(),
237                 },
238                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
239                 .matches = {
240                         "4: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=0,r=0) R10=fp",
241                         "5: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R5=pkt(id=0,off=14,r=0) R10=fp",
242                         "6: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=0) R3=pkt_end R4=pkt(id=0,off=14,r=0) R5=pkt(id=0,off=14,r=0) R10=fp",
243                         "10: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv56 R5=pkt(id=0,off=14,r=18) R10=fp",
244                         "14: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
245                         "15: R0=imm0,min_value=0,max_value=0,min_align=2147483648 R1=ctx R2=pkt(id=0,off=0,r=18) R3=pkt_end R4=inv48 R5=pkt(id=0,off=14,r=18) R10=fp",
246                 },
247         },
248         {
249                 .descr = "packet variable offset",
250                 .insns = {
251                         LOAD_UNKNOWN(BPF_REG_6),
252                         BPF_ALU64_IMM(BPF_LSH, BPF_REG_6, 2),
253
254                         /* First, add a constant to the R5 packet pointer,
255                          * then a variable with a known alignment.
256                          */
257                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
258                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
259                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
260                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
261                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
262                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
263                         BPF_EXIT_INSN(),
264                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
265
266                         /* Now, test in the other direction.  Adding first
267                          * the variable offset to R5, then the constant.
268                          */
269                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
270                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
271                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
272                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
273                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
274                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
275                         BPF_EXIT_INSN(),
276                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
277
278                         /* Test multiple accumulations of unknown values
279                          * into a packet pointer.
280                          */
281                         BPF_MOV64_REG(BPF_REG_5, BPF_REG_2),
282                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 14),
283                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
284                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_5, 4),
285                         BPF_ALU64_REG(BPF_ADD, BPF_REG_5, BPF_REG_6),
286                         BPF_MOV64_REG(BPF_REG_4, BPF_REG_5),
287                         BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 4),
288                         BPF_JMP_REG(BPF_JGE, BPF_REG_3, BPF_REG_4, 1),
289                         BPF_EXIT_INSN(),
290                         BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_5, 0),
291
292                         BPF_MOV64_IMM(BPF_REG_0, 0),
293                         BPF_EXIT_INSN(),
294                 },
295                 .prog_type = BPF_PROG_TYPE_SCHED_CLS,
296                 .matches = {
297                         /* Calculated offset in R6 has unknown value, but known
298                          * alignment of 4.
299                          */
300                         "8: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R6=inv54,min_align=4 R10=fp",
301
302                         /* Offset is added to packet pointer R5, resulting in known
303                          * auxiliary alignment and offset.
304                          */
305                         "11: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R5=pkt(id=1,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
306
307                         /* At the time the word size load is performed from R5,
308                          * it's total offset is NET_IP_ALIGN + reg->off (0) +
309                          * reg->aux_off (14) which is 16.  Then the variable
310                          * offset is considered using reg->aux_off_align which
311                          * is 4 and meets the load's requirements.
312                          */
313                         "15: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=1,off=4,r=4),aux_off=14,aux_off_align=4 R5=pkt(id=1,off=0,r=4),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
314
315
316                         /* Variable offset is added to R5 packet pointer,
317                          * resulting in auxiliary alignment of 4.
318                          */
319                         "18: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=0,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
320
321                         /* Constant offset is added to R5, resulting in
322                          * reg->off of 14.
323                          */
324                         "19: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off=14,aux_off_align=4 R5=pkt(id=2,off=14,r=0),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
325
326                         /* At the time the word size load is performed from R5,
327                          * it's total offset is NET_IP_ALIGN + reg->off (14) which
328                          * is 16.  Then the variable offset is considered using
329                          * reg->aux_off_align which is 4 and meets the load's
330                          * requirements.
331                          */
332                         "23: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=2,off=18,r=18),aux_off_align=4 R5=pkt(id=2,off=14,r=18),aux_off_align=4 R6=inv54,min_align=4 R10=fp",
333
334                         /* Constant offset is added to R5 packet pointer,
335                          * resulting in reg->off value of 14.
336                          */
337                         "26: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=0,off=14,r=8) R6=inv54,min_align=4 R10=fp",
338                         /* Variable offset is added to R5, resulting in an
339                          * auxiliary offset of 14, and an auxiliary alignment of 4.
340                          */
341                         "27: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=0,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
342                         /* Constant is added to R5 again, setting reg->off to 4. */
343                         "28: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=3,off=4,r=0),aux_off=14,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
344                         /* And once more we add a variable, which causes an accumulation
345                          * of reg->off into reg->aux_off_align, with resulting value of
346                          * 18.  The auxiliary alignment stays at 4.
347                          */
348                         "29: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=inv,aux_off_align=4 R5=pkt(id=4,off=0,r=0),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
349                         /* At the time the word size load is performed from R5,
350                          * it's total offset is NET_IP_ALIGN + reg->off (0) +
351                          * reg->aux_off (18) which is 20.  Then the variable offset
352                          * is considered using reg->aux_off_align which is 4 and meets
353                          * the load's requirements.
354                          */
355                         "33: R0=pkt(id=0,off=8,r=8) R1=ctx R2=pkt(id=0,off=0,r=8) R3=pkt_end R4=pkt(id=4,off=4,r=4),aux_off=18,aux_off_align=4 R5=pkt(id=4,off=0,r=4),aux_off=18,aux_off_align=4 R6=inv54,min_align=4 R10=fp",
356                 },
357         },
358 };
359
360 static int probe_filter_length(const struct bpf_insn *fp)
361 {
362         int len;
363
364         for (len = MAX_INSNS - 1; len > 0; --len)
365                 if (fp[len].code != 0 || fp[len].imm != 0)
366                         break;
367         return len + 1;
368 }
369
370 static char bpf_vlog[32768];
371
372 static int do_test_single(struct bpf_align_test *test)
373 {
374         struct bpf_insn *prog = test->insns;
375         int prog_type = test->prog_type;
376         int prog_len, i;
377         int fd_prog;
378         int ret;
379
380         prog_len = probe_filter_length(prog);
381         fd_prog = bpf_verify_program(prog_type ? : BPF_PROG_TYPE_SOCKET_FILTER,
382                                      prog, prog_len, 1, "GPL", 0,
383                                      bpf_vlog, sizeof(bpf_vlog), 2);
384         if (fd_prog < 0) {
385                 printf("Failed to load program.\n");
386                 printf("%s", bpf_vlog);
387                 ret = 1;
388         } else {
389                 ret = 0;
390                 for (i = 0; i < MAX_MATCHES; i++) {
391                         const char *t, *m = test->matches[i];
392
393                         if (!m)
394                                 break;
395                         t = strstr(bpf_vlog, m);
396                         if (!t) {
397                                 printf("Failed to find match: %s\n", m);
398                                 ret = 1;
399                                 printf("%s", bpf_vlog);
400                                 break;
401                         }
402                 }
403                 close(fd_prog);
404         }
405         return ret;
406 }
407
408 static int do_test(unsigned int from, unsigned int to)
409 {
410         int all_pass = 0;
411         int all_fail = 0;
412         unsigned int i;
413
414         for (i = from; i < to; i++) {
415                 struct bpf_align_test *test = &tests[i];
416                 int fail;
417
418                 printf("Test %3d: %s ... ",
419                        i, test->descr);
420                 fail = do_test_single(test);
421                 if (fail) {
422                         all_fail++;
423                         printf("FAIL\n");
424                 } else {
425                         all_pass++;
426                         printf("PASS\n");
427                 }
428         }
429         printf("Results: %d pass %d fail\n",
430                all_pass, all_fail);
431         return all_fail ? EXIT_FAILURE : EXIT_SUCCESS;
432 }
433
434 int main(int argc, char **argv)
435 {
436         unsigned int from = 0, to = ARRAY_SIZE(tests);
437         struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
438
439         setrlimit(RLIMIT_MEMLOCK, &rinf);
440
441         if (argc == 3) {
442                 unsigned int l = atoi(argv[argc - 2]);
443                 unsigned int u = atoi(argv[argc - 1]);
444
445                 if (l < to && u < to) {
446                         from = l;
447                         to   = u + 1;
448                 }
449         } else if (argc == 2) {
450                 unsigned int t = atoi(argv[argc - 1]);
451
452                 if (t < to) {
453                         from = t;
454                         to   = t + 1;
455                 }
456         }
457         return do_test(from, to);
458 }