flowtop: Replace single linked list by list_head from list.h
[netsniff-ng.git] / bpf_parser.y
blob3008fd509d49cd6b636e9fe7fd22dcc996890a4c
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
7 */
9 /* yaac-func-prefix: yy */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdbool.h>
16 #include <signal.h>
17 #include <stdint.h>
18 #include <errno.h>
19 #include <libgen.h>
20 #include <linux/filter.h>
22 #include "bpf.h"
23 #include "str.h"
24 #include "xmalloc.h"
25 #include "bpf_parser.tab.h"
26 #include "built_in.h"
27 #include "die.h"
28 #include "cpp.h"
30 static int curr_instr = 0;
32 static struct sock_filter out[BPF_MAXINSNS];
34 static char *labels[BPF_MAXINSNS];
35 static char *labels_jt[BPF_MAXINSNS];
36 static char *labels_jf[BPF_MAXINSNS];
37 static char *labels_k[BPF_MAXINSNS];
39 #define YYERROR_VERBOSE 0
40 #define YYDEBUG 0
41 #define YYENABLE_NLS 1
42 #define YYLTYPE_IS_TRIVIAL 1
43 #define ENABLE_NLS 1
45 extern FILE *yyin;
46 extern int yylex(void);
47 extern void yyerror(const char *);
48 extern int yylineno;
49 extern char *yytext;
51 static inline void check_max_instr(void)
53 if (curr_instr >= BPF_MAXINSNS)
54 panic("Exceeded maximal number of instructions!\n");
57 static inline void set_curr_instr(uint16_t code, uint8_t jt, uint8_t jf, uint32_t k)
59 check_max_instr();
61 out[curr_instr].code = code;
62 out[curr_instr].jt = jt;
63 out[curr_instr].jf = jf;
64 out[curr_instr].k = k;
66 curr_instr++;
69 static inline void set_curr_label(char *label)
71 check_max_instr();
73 labels[curr_instr] = label;
76 #define JTL 1
77 #define JFL 2
78 #define JKL 3
80 static inline void set_jmp_label(char *label, int which)
82 check_max_instr();
84 switch (which) {
85 case JTL:
86 labels_jt[curr_instr] = label;
87 break;
88 case JFL:
89 labels_jf[curr_instr] = label;
90 break;
91 case JKL:
92 labels_k[curr_instr] = label;
93 break;
94 default:
95 bug();
99 static int find_intr_offset_or_panic(char *label_to_search)
101 int i, max = curr_instr, ret = -ENOENT;
103 bug_on(!label_to_search);
105 for (i = 0; i < max; ++i) {
106 if (labels[i] != NULL) {
107 /* Both are \0-terminated! */
108 if (!strcmp(label_to_search, labels[i])) {
109 ret = i;
110 break;
115 if (ret == -ENOENT)
116 panic("No such label!\n");
118 return ret;
123 %union {
124 char *label;
125 long int number;
128 %token OP_LDB OP_LDH OP_LD OP_LDX OP_ST OP_STX OP_JMP OP_JEQ OP_JGT OP_JGE
129 %token OP_JSET OP_ADD OP_SUB OP_MUL OP_DIV OP_AND OP_OR OP_XOR OP_LSH OP_RSH
130 %token OP_RET OP_TAX OP_TXA OP_LDXB OP_MOD OP_NEG OP_JNEQ OP_JLT OP_JLE OP_LDI
131 %token OP_LDXI
133 %token K_PKT_LEN K_PROTO K_TYPE K_NLATTR K_NLATTR_NEST K_MARK K_QUEUE K_HATYPE
134 %token K_RXHASH K_CPU K_IFIDX K_VLANT K_VLANP K_POFF
136 %token ':' ',' '[' ']' '(' ')' 'x' 'a' '+' 'M' '*' '&' '#' '%'
138 %token number label
140 %type <number> number
141 %type <label> label
145 prog
146 : line
147 | prog line
150 line
151 : instr
152 | labelled_instr
155 labelled_instr
156 : labelled instr
159 instr
160 : ldb
161 | ldh
162 | ld
163 | ldi
164 | ldx
165 | ldxi
166 | st
167 | stx
168 | jmp
169 | jeq
170 | jneq
171 | jlt
172 | jle
173 | jgt
174 | jge
175 | jset
176 | add
177 | sub
178 | mul
179 | div
180 | mod
181 | neg
182 | and
183 | or
184 | xor
185 | lsh
186 | rsh
187 | ret
188 | tax
189 | txa
192 labelled
193 : label ':' { set_curr_label($1); }
197 : OP_LDB '[' 'x' '+' number ']' {
198 set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $5); }
199 | OP_LDB '[' '%' 'x' '+' number ']' {
200 set_curr_instr(BPF_LD | BPF_B | BPF_IND, 0, 0, $6); }
201 | OP_LDB '[' number ']' {
202 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0, $3); }
203 | OP_LDB K_PROTO {
204 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
205 SKF_AD_OFF + SKF_AD_PROTOCOL); }
206 | OP_LDB K_TYPE {
207 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
208 SKF_AD_OFF + SKF_AD_PKTTYPE); }
209 | OP_LDB K_IFIDX {
210 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
211 SKF_AD_OFF + SKF_AD_IFINDEX); }
212 | OP_LDB K_NLATTR {
213 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
214 SKF_AD_OFF + SKF_AD_NLATTR); }
215 | OP_LDB K_NLATTR_NEST {
216 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
217 SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
218 | OP_LDB K_MARK {
219 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
220 SKF_AD_OFF + SKF_AD_MARK); }
221 | OP_LDB K_QUEUE {
222 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
223 SKF_AD_OFF + SKF_AD_QUEUE); }
224 | OP_LDB K_HATYPE {
225 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
226 SKF_AD_OFF + SKF_AD_HATYPE); }
227 | OP_LDB K_RXHASH {
228 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
229 SKF_AD_OFF + SKF_AD_RXHASH); }
230 | OP_LDB K_CPU {
231 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
232 SKF_AD_OFF + SKF_AD_CPU); }
233 | OP_LDB K_VLANT {
234 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
235 SKF_AD_OFF + SKF_AD_VLAN_TAG); }
236 | OP_LDB K_VLANP {
237 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
238 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
239 | OP_LDB K_POFF {
240 set_curr_instr(BPF_LD | BPF_B | BPF_ABS, 0, 0,
241 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
245 : OP_LDH '[' 'x' '+' number ']' {
246 set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $5); }
247 | OP_LDH '[' '%' 'x' '+' number ']' {
248 set_curr_instr(BPF_LD | BPF_H | BPF_IND, 0, 0, $6); }
249 | OP_LDH '[' number ']' {
250 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0, $3); }
251 | OP_LDH K_PROTO {
252 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
253 SKF_AD_OFF + SKF_AD_PROTOCOL); }
254 | OP_LDH K_TYPE {
255 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
256 SKF_AD_OFF + SKF_AD_PKTTYPE); }
257 | OP_LDH K_IFIDX {
258 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
259 SKF_AD_OFF + SKF_AD_IFINDEX); }
260 | OP_LDH K_NLATTR {
261 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
262 SKF_AD_OFF + SKF_AD_NLATTR); }
263 | OP_LDH K_NLATTR_NEST {
264 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
265 SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
266 | OP_LDH K_MARK {
267 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
268 SKF_AD_OFF + SKF_AD_MARK); }
269 | OP_LDH K_QUEUE {
270 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
271 SKF_AD_OFF + SKF_AD_QUEUE); }
272 | OP_LDH K_HATYPE {
273 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
274 SKF_AD_OFF + SKF_AD_HATYPE); }
275 | OP_LDH K_RXHASH {
276 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
277 SKF_AD_OFF + SKF_AD_RXHASH); }
278 | OP_LDH K_CPU {
279 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
280 SKF_AD_OFF + SKF_AD_CPU); }
281 | OP_LDH K_VLANT {
282 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
283 SKF_AD_OFF + SKF_AD_VLAN_TAG); }
284 | OP_LDH K_VLANP {
285 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
286 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
287 | OP_LDH K_POFF {
288 set_curr_instr(BPF_LD | BPF_H | BPF_ABS, 0, 0,
289 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
293 : OP_LDI '#' number {
294 set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
295 | OP_LDI number {
296 set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $2); }
300 : OP_LD '#' number {
301 set_curr_instr(BPF_LD | BPF_IMM, 0, 0, $3); }
302 | OP_LD K_PKT_LEN {
303 set_curr_instr(BPF_LD | BPF_W | BPF_LEN, 0, 0, 0); }
304 | OP_LD K_PROTO {
305 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
306 SKF_AD_OFF + SKF_AD_PROTOCOL); }
307 | OP_LD K_TYPE {
308 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
309 SKF_AD_OFF + SKF_AD_PKTTYPE); }
310 | OP_LD K_IFIDX {
311 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
312 SKF_AD_OFF + SKF_AD_IFINDEX); }
313 | OP_LD K_NLATTR {
314 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
315 SKF_AD_OFF + SKF_AD_NLATTR); }
316 | OP_LD K_NLATTR_NEST {
317 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
318 SKF_AD_OFF + SKF_AD_NLATTR_NEST); }
319 | OP_LD K_MARK {
320 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
321 SKF_AD_OFF + SKF_AD_MARK); }
322 | OP_LD K_QUEUE {
323 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
324 SKF_AD_OFF + SKF_AD_QUEUE); }
325 | OP_LD K_HATYPE {
326 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
327 SKF_AD_OFF + SKF_AD_HATYPE); }
328 | OP_LD K_RXHASH {
329 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
330 SKF_AD_OFF + SKF_AD_RXHASH); }
331 | OP_LD K_CPU {
332 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
333 SKF_AD_OFF + SKF_AD_CPU); }
334 | OP_LD K_VLANT {
335 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
336 SKF_AD_OFF + SKF_AD_VLAN_TAG); }
337 | OP_LD K_VLANP {
338 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
339 SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT); }
340 | OP_LD K_POFF {
341 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0,
342 SKF_AD_OFF + SKF_AD_PAY_OFFSET); }
343 | OP_LD 'M' '[' number ']' {
344 set_curr_instr(BPF_LD | BPF_MEM, 0, 0, $4); }
345 | OP_LD '[' 'x' '+' number ']' {
346 set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $5); }
347 | OP_LD '[' '%' 'x' '+' number ']' {
348 set_curr_instr(BPF_LD | BPF_W | BPF_IND, 0, 0, $6); }
349 | OP_LD '[' number ']' {
350 set_curr_instr(BPF_LD | BPF_W | BPF_ABS, 0, 0, $3); }
353 ldxi
354 : OP_LDXI '#' number {
355 set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
356 | OP_LDXI number {
357 set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $2); }
361 : OP_LDX '#' number {
362 set_curr_instr(BPF_LDX | BPF_IMM, 0, 0, $3); }
363 | OP_LDX K_PKT_LEN {
364 set_curr_instr(BPF_LDX | BPF_W | BPF_LEN, 0, 0, 0); }
365 | OP_LDX 'M' '[' number ']' {
366 set_curr_instr(BPF_LDX | BPF_MEM, 0, 0, $4); }
367 | OP_LDXB number '*' '(' '[' number ']' '&' number ')' {
368 if ($2 != 4 || $9 != 0xf) {
369 panic("ldxb offset not supported!\n");
370 } else {
371 set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
372 | OP_LDX number '*' '(' '[' number ']' '&' number ')' {
373 if ($2 != 4 || $9 != 0xf) {
374 panic("ldxb offset not supported!\n");
375 } else {
376 set_curr_instr(BPF_LDX | BPF_MSH | BPF_B, 0, 0, $6); } }
380 : OP_ST 'M' '[' number ']' {
381 set_curr_instr(BPF_ST, 0, 0, $4); }
385 : OP_STX 'M' '[' number ']' {
386 set_curr_instr(BPF_STX, 0, 0, $4); }
390 : OP_JMP label {
391 set_jmp_label($2, JKL);
392 set_curr_instr(BPF_JMP | BPF_JA, 0, 0, 0); }
396 : OP_JEQ '#' number ',' label ',' label {
397 set_jmp_label($5, JTL);
398 set_jmp_label($7, JFL);
399 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
400 | OP_JEQ 'x' ',' label ',' label {
401 set_jmp_label($4, JTL);
402 set_jmp_label($6, JFL);
403 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
404 | OP_JEQ '%' 'x' ',' label ',' label {
405 set_jmp_label($5, JTL);
406 set_jmp_label($7, JFL);
407 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
408 | OP_JEQ '#' number ',' label {
409 set_jmp_label($5, JTL);
410 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
411 | OP_JEQ 'x' ',' label {
412 set_jmp_label($4, JTL);
413 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
414 | OP_JEQ '%' 'x' ',' label {
415 set_jmp_label($5, JTL);
416 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
419 jneq
420 : OP_JNEQ '#' number ',' label {
421 set_jmp_label($5, JFL);
422 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_K, 0, 0, $3); }
423 | OP_JNEQ 'x' ',' label {
424 set_jmp_label($4, JFL);
425 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
426 | OP_JNEQ '%' 'x' ',' label {
427 set_jmp_label($5, JFL);
428 set_curr_instr(BPF_JMP | BPF_JEQ | BPF_X, 0, 0, 0); }
432 : OP_JLT '#' number ',' label {
433 set_jmp_label($5, JFL);
434 set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
435 | OP_JLT 'x' ',' label {
436 set_jmp_label($4, JFL);
437 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
438 | OP_JLT '%' 'x' ',' label {
439 set_jmp_label($5, JFL);
440 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
444 : OP_JLE '#' number ',' label {
445 set_jmp_label($5, JFL);
446 set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
447 | OP_JLE 'x' ',' label {
448 set_jmp_label($4, JFL);
449 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
450 | OP_JLE '%' 'x' ',' label {
451 set_jmp_label($5, JFL);
452 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
456 : OP_JGT '#' number ',' label ',' label {
457 set_jmp_label($5, JTL);
458 set_jmp_label($7, JFL);
459 set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
460 | OP_JGT 'x' ',' label ',' label {
461 set_jmp_label($4, JTL);
462 set_jmp_label($6, JFL);
463 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
464 | OP_JGT '%' 'x' ',' label ',' label {
465 set_jmp_label($5, JTL);
466 set_jmp_label($7, JFL);
467 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
468 | OP_JGT '#' number ',' label {
469 set_jmp_label($5, JTL);
470 set_curr_instr(BPF_JMP | BPF_JGT | BPF_K, 0, 0, $3); }
471 | OP_JGT 'x' ',' label {
472 set_jmp_label($4, JTL);
473 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
474 | OP_JGT '%' 'x' ',' label {
475 set_jmp_label($5, JTL);
476 set_curr_instr(BPF_JMP | BPF_JGT | BPF_X, 0, 0, 0); }
480 : OP_JGE '#' number ',' label ',' label {
481 set_jmp_label($5, JTL);
482 set_jmp_label($7, JFL);
483 set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
484 | OP_JGE 'x' ',' label ',' label {
485 set_jmp_label($4, JTL);
486 set_jmp_label($6, JFL);
487 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
488 | OP_JGE '%' 'x' ',' label ',' label {
489 set_jmp_label($5, JTL);
490 set_jmp_label($7, JFL);
491 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
492 | OP_JGE '#' number ',' label {
493 set_jmp_label($5, JTL);
494 set_curr_instr(BPF_JMP | BPF_JGE | BPF_K, 0, 0, $3); }
495 | OP_JGE 'x' ',' label {
496 set_jmp_label($4, JTL);
497 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
498 | OP_JGE '%' 'x' ',' label {
499 set_jmp_label($5, JTL);
500 set_curr_instr(BPF_JMP | BPF_JGE | BPF_X, 0, 0, 0); }
503 jset
504 : OP_JSET '#' number ',' label ',' label {
505 set_jmp_label($5, JTL);
506 set_jmp_label($7, JFL);
507 set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
508 | OP_JSET 'x' ',' label ',' label {
509 set_jmp_label($4, JTL);
510 set_jmp_label($6, JFL);
511 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
512 | OP_JSET '%' 'x' ',' label ',' label {
513 set_jmp_label($5, JTL);
514 set_jmp_label($7, JFL);
515 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
516 | OP_JSET '#' number ',' label {
517 set_jmp_label($5, JTL);
518 set_curr_instr(BPF_JMP | BPF_JSET | BPF_K, 0, 0, $3); }
519 | OP_JSET 'x' ',' label {
520 set_jmp_label($4, JTL);
521 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
522 | OP_JSET '%' 'x' ',' label {
523 set_jmp_label($5, JTL);
524 set_curr_instr(BPF_JMP | BPF_JSET | BPF_X, 0, 0, 0); }
528 : OP_ADD '#' number {
529 set_curr_instr(BPF_ALU | BPF_ADD | BPF_K, 0, 0, $3); }
530 | OP_ADD 'x' {
531 set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
532 | OP_ADD '%' 'x' {
533 set_curr_instr(BPF_ALU | BPF_ADD | BPF_X, 0, 0, 0); }
537 : OP_SUB '#' number {
538 set_curr_instr(BPF_ALU | BPF_SUB | BPF_K, 0, 0, $3); }
539 | OP_SUB 'x' {
540 set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
541 | OP_SUB '%' 'x' {
542 set_curr_instr(BPF_ALU | BPF_SUB | BPF_X, 0, 0, 0); }
546 : OP_MUL '#' number {
547 set_curr_instr(BPF_ALU | BPF_MUL | BPF_K, 0, 0, $3); }
548 | OP_MUL 'x' {
549 set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
550 | OP_MUL '%' 'x' {
551 set_curr_instr(BPF_ALU | BPF_MUL | BPF_X, 0, 0, 0); }
555 : OP_DIV '#' number {
556 set_curr_instr(BPF_ALU | BPF_DIV | BPF_K, 0, 0, $3); }
557 | OP_DIV 'x' {
558 set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
559 | OP_DIV '%' 'x' {
560 set_curr_instr(BPF_ALU | BPF_DIV | BPF_X, 0, 0, 0); }
564 : OP_MOD '#' number {
565 set_curr_instr(BPF_ALU | BPF_MOD | BPF_K, 0, 0, $3); }
566 | OP_MOD 'x' {
567 set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
568 | OP_MOD '%' 'x' {
569 set_curr_instr(BPF_ALU | BPF_MOD | BPF_X, 0, 0, 0); }
573 : OP_NEG {
574 set_curr_instr(BPF_ALU | BPF_NEG, 0, 0, 0); }
578 : OP_AND '#' number {
579 set_curr_instr(BPF_ALU | BPF_AND | BPF_K, 0, 0, $3); }
580 | OP_AND 'x' {
581 set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
582 | OP_AND '%' 'x' {
583 set_curr_instr(BPF_ALU | BPF_AND | BPF_X, 0, 0, 0); }
587 : OP_OR '#' number {
588 set_curr_instr(BPF_ALU | BPF_OR | BPF_K, 0, 0, $3); }
589 | OP_OR 'x' {
590 set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
591 | OP_OR '%' 'x' {
592 set_curr_instr(BPF_ALU | BPF_OR | BPF_X, 0, 0, 0); }
596 : OP_XOR '#' number {
597 set_curr_instr(BPF_ALU | BPF_XOR | BPF_K, 0, 0, $3); }
598 | OP_XOR 'x' {
599 set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
600 | OP_XOR '%' 'x' {
601 set_curr_instr(BPF_ALU | BPF_XOR | BPF_X, 0, 0, 0); }
605 : OP_LSH '#' number {
606 set_curr_instr(BPF_ALU | BPF_LSH | BPF_K, 0, 0, $3); }
607 | OP_LSH 'x' {
608 set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
609 | OP_LSH '%' 'x' {
610 set_curr_instr(BPF_ALU | BPF_LSH | BPF_X, 0, 0, 0); }
614 : OP_RSH '#' number {
615 set_curr_instr(BPF_ALU | BPF_RSH | BPF_K, 0, 0, $3); }
616 | OP_RSH 'x' {
617 set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
618 | OP_RSH '%' 'x' {
619 set_curr_instr(BPF_ALU | BPF_RSH | BPF_X, 0, 0, 0); }
623 : OP_RET 'a' {
624 set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
625 | OP_RET '%' 'a' {
626 set_curr_instr(BPF_RET | BPF_A, 0, 0, 0); }
627 | OP_RET 'x' {
628 set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
629 | OP_RET '%' 'x' {
630 set_curr_instr(BPF_RET | BPF_X, 0, 0, 0); }
631 | OP_RET '#' number {
632 set_curr_instr(BPF_RET | BPF_K, 0, 0, $3); }
636 : OP_TAX {
637 set_curr_instr(BPF_MISC | BPF_TAX, 0, 0, 0); }
641 : OP_TXA {
642 set_curr_instr(BPF_MISC | BPF_TXA, 0, 0, 0); }
647 static void stage_1_inline(void)
649 yyparse();
652 static void stage_2_label_reduce(void)
654 int i, max = curr_instr, off;
656 /* 1. reduce k jumps */
657 for (i = 0; i < max; ++i) {
658 if (labels_k[i] != NULL) {
659 off = find_intr_offset_or_panic(labels_k[i]);
660 out[i].k = (uint32_t) (off - i - 1);
664 /* 1. reduce jt jumps */
665 for (i = 0; i < max; ++i) {
666 if (labels_jt[i] != NULL) {
667 off = find_intr_offset_or_panic(labels_jt[i]);
668 out[i].jt = (uint8_t) (off - i -1);
672 /* 1. reduce jf jumps */
673 for (i = 0; i < max; ++i) {
674 if (labels_jf[i] != NULL) {
675 off = find_intr_offset_or_panic(labels_jf[i]);
676 out[i].jf = (uint8_t) (off - i - 1);
681 static void pretty_printer_c(const struct sock_fprog *prog)
683 int i;
685 for (i = 0; i < prog->len; ++i) {
686 printf("{ 0x%x, %u, %u, 0x%08x },\n",
687 prog->filter[i].code, prog->filter[i].jt,
688 prog->filter[i].jf, prog->filter[i].k);
692 static void pretty_printer_xt_bpf(const struct sock_fprog *prog)
694 int i;
696 printf("%d,", prog->len);
697 for (i = 0; i < prog->len; ++i) {
698 printf("%u %u %u %u,",
699 prog->filter[i].code, prog->filter[i].jt,
700 prog->filter[i].jf, prog->filter[i].k);
703 fflush(stdout);
706 static void pretty_printer_tcpdump(const struct sock_fprog *prog)
708 int i;
710 for (i = 0; i < prog->len; ++i) {
711 printf("%u %u %u %u\n",
712 prog->filter[i].code, prog->filter[i].jt,
713 prog->filter[i].jf, prog->filter[i].k);
717 static void pretty_printer(const struct sock_fprog *prog, int format)
719 switch (format) {
720 case 0:
721 pretty_printer_c(prog);
722 break;
723 case 1:
724 pretty_printer_xt_bpf(prog);
725 break;
726 case 2:
727 pretty_printer_tcpdump(prog);
728 break;
729 default:
730 bug();
734 int compile_filter(char *file, bool verbose, int bypass, int format,
735 bool invoke_cpp, char *const cpp_argv[])
737 int i;
738 struct sock_fprog res;
739 char tmp_file[128];
740 int ret = 0;
742 memset(tmp_file, 0, sizeof(tmp_file));
744 if (invoke_cpp) {
745 ret = cpp_exec(file, tmp_file, sizeof(tmp_file), cpp_argv);
746 if (ret) {
747 fprintf(stderr, "Failed to invoke C preprocessor!\n");
748 goto exit;
751 file = tmp_file;
754 if (!strncmp("-", file, strlen("-")))
755 yyin = stdin;
756 else
757 yyin = fopen(file, "r");
758 if (!yyin)
759 panic("Cannot open file!\n");
761 memset(out, 0, sizeof(out));
762 memset(labels, 0, sizeof(labels));
763 memset(labels_jf, 0, sizeof(labels_jf));
764 memset(labels_jt, 0, sizeof(labels_jt));
765 memset(labels_k, 0, sizeof(labels_k));
767 stage_1_inline();
768 stage_2_label_reduce();
770 res.filter = out;
771 res.len = curr_instr;
773 if (verbose) {
774 printf("Generated program:\n");
775 bpf_dump_all(&res);
778 if (!bypass) {
779 if (verbose) {
780 printf("Validating: ");
781 fflush(stdout);
784 if (__bpf_validate(&res) == 0) {
785 if (verbose)
786 printf("Semantic error! BPF validation failed!\n");
787 else {
788 printf("Semantic error! BPF validation failed! "
789 "Try -V for debugging output!\n");
790 ret = 1;
791 goto exit;
793 } else if (verbose) {
794 printf("is runnable!\n");
798 if (verbose)
799 printf("Result:\n");
801 pretty_printer(&res, format);
803 for (i = 0; i < res.len; ++i) {
804 free(labels[i]);
805 free(labels_jt[i]);
806 free(labels_jf[i]);
807 free(labels_k[i]);
810 if (yyin && yyin != stdin)
811 fclose(yyin);
813 exit:
814 if (invoke_cpp)
815 unlink(tmp_file);
817 return ret;
820 void yyerror(const char *err)
822 panic("Syntax error at line %d: %s! %s!\n",
823 yylineno, yytext, err);