iof-bird-daemon / filter / config.Y @ 04632fd7
History | View | Annotate | Download (24.5 KB)
1 |
/* |
---|---|
2 |
* BIRD - filters |
3 |
* |
4 |
* Copyright 1998--2000 Pavel Machek |
5 |
* |
6 |
* Can be freely distributed and used under the terms of the GNU GPL. |
7 |
* |
8 |
FIXME: priority of ! should be lower |
9 |
*/ |
10 |
|
11 |
CF_HDR |
12 |
|
13 |
CF_DEFINES |
14 |
|
15 |
#define P(a,b) ((a << 8) | b) |
16 |
|
17 |
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } |
18 |
static inline u32 pair_a(u32 p) { return p >> 16; } |
19 |
static inline u32 pair_b(u32 p) { return p & 0xFFFF; } |
20 |
|
21 |
|
22 |
/* |
23 |
* Sets and their items are during parsing handled as lists, linked |
24 |
* through left ptr. The first item in a list also contains a pointer |
25 |
* to the last item in a list (right ptr). For convenience, even items |
26 |
* are handled as one-item lists. Lists are merged by f_merge_items(). |
27 |
*/ |
28 |
static int |
29 |
f_valid_set_type(int type) |
30 |
{ |
31 |
switch (type) |
32 |
{ |
33 |
case T_INT: |
34 |
case T_PAIR: |
35 |
case T_QUAD: |
36 |
case T_ENUM: |
37 |
case T_IP: |
38 |
case T_EC: |
39 |
return 1; |
40 |
|
41 |
default: |
42 |
return 0; |
43 |
} |
44 |
} |
45 |
|
46 |
static inline struct f_tree * |
47 |
f_new_item(struct f_val from, struct f_val to) |
48 |
{ |
49 |
struct f_tree *t = f_new_tree(); |
50 |
t->right = t; |
51 |
t->from = from; |
52 |
t->to = to; |
53 |
return t; |
54 |
} |
55 |
|
56 |
static inline struct f_tree * |
57 |
f_merge_items(struct f_tree *a, struct f_tree *b) |
58 |
{ |
59 |
if (!a) return b; |
60 |
a->right->left = b; |
61 |
a->right = b->right; |
62 |
b->right = NULL; |
63 |
return a; |
64 |
} |
65 |
|
66 |
static inline struct f_tree * |
67 |
f_new_pair_item(int fa, int ta, int fb, int tb) |
68 |
{ |
69 |
struct f_tree *t = f_new_tree(); |
70 |
t->right = t; |
71 |
t->from.type = t->to.type = T_PAIR; |
72 |
t->from.val.i = pair(fa, fb); |
73 |
t->to.val.i = pair(ta, tb); |
74 |
return t; |
75 |
} |
76 |
|
77 |
static inline struct f_tree * |
78 |
f_new_pair_set(int fa, int ta, int fb, int tb) |
79 |
{ |
80 |
struct f_tree *lst = NULL; |
81 |
int i; |
82 |
|
83 |
if ((fa == ta) || ((fb == 0) && (tb == 0xFFFF))) |
84 |
return f_new_pair_item(fa, ta, fb, tb); |
85 |
|
86 |
if ((ta < fa) || (tb < fb)) |
87 |
cf_error( "From value cannot be higher that To value in pair sets"); |
88 |
|
89 |
for (i = fa; i <= ta; i++) |
90 |
lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb)); |
91 |
|
92 |
return lst; |
93 |
} |
94 |
|
95 |
#define EC_ALL 0xFFFFFFFF |
96 |
|
97 |
static struct f_tree * |
98 |
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt) |
99 |
{ |
100 |
u64 fm, to; |
101 |
|
102 |
if (ipv4_used || (key >= 0x10000)) { |
103 |
check_u16(vf); |
104 |
if (vt == EC_ALL) |
105 |
vt = 0xFFFF; |
106 |
else |
107 |
check_u16(vt); |
108 |
} |
109 |
|
110 |
if (kind == EC_GENERIC) { |
111 |
fm = ec_generic(key, vf); |
112 |
to = ec_generic(key, vt); |
113 |
} |
114 |
else if (ipv4_used) { |
115 |
fm = ec_ip4(kind, key, vf); |
116 |
to = ec_ip4(kind, key, vt); |
117 |
} |
118 |
else if (key < 0x10000) { |
119 |
fm = ec_as2(kind, key, vf); |
120 |
to = ec_as2(kind, key, vt); |
121 |
} |
122 |
else { |
123 |
fm = ec_as4(kind, key, vf); |
124 |
to = ec_as4(kind, key, vt); |
125 |
} |
126 |
|
127 |
struct f_tree *t = f_new_tree(); |
128 |
t->right = t; |
129 |
t->from.type = t->to.type = T_EC; |
130 |
t->from.val.ec = fm; |
131 |
t->to.val.ec = to; |
132 |
return t; |
133 |
} |
134 |
|
135 |
static inline struct f_inst * |
136 |
f_generate_empty(struct f_inst *dyn) |
137 |
{ |
138 |
struct f_inst *e = f_new_inst(); |
139 |
e->code = 'E'; |
140 |
|
141 |
switch (dyn->aux & EAF_TYPE_MASK) { |
142 |
case EAF_TYPE_AS_PATH: |
143 |
e->aux = T_PATH; |
144 |
break; |
145 |
case EAF_TYPE_INT_SET: |
146 |
e->aux = T_CLIST; |
147 |
break; |
148 |
case EAF_TYPE_EC_SET: |
149 |
e->aux = T_ECLIST; |
150 |
break; |
151 |
default: |
152 |
cf_error("Can't empty that attribute"); |
153 |
} |
154 |
|
155 |
dyn->code = P('e','S'); |
156 |
dyn->a1.p = e; |
157 |
return dyn; |
158 |
} |
159 |
|
160 |
|
161 |
static inline struct f_inst * |
162 |
f_generate_dpair(struct f_inst *t1, struct f_inst *t2) |
163 |
{ |
164 |
struct f_inst *rv; |
165 |
|
166 |
if ((t1->code == 'c') && (t2->code == 'c')) { |
167 |
if ((t1->aux != T_INT) || (t2->aux != T_INT)) |
168 |
cf_error( "Can't operate with value of non-integer type in pair constructor"); |
169 |
|
170 |
check_u16(t1->a2.i); |
171 |
check_u16(t2->a2.i); |
172 |
|
173 |
rv = f_new_inst(); |
174 |
rv->code = 'c'; |
175 |
rv->aux = T_PAIR; |
176 |
rv->a2.i = pair(t1->a2.i, t2->a2.i); |
177 |
} |
178 |
else { |
179 |
rv = f_new_inst(); |
180 |
rv->code = P('m', 'p'); |
181 |
rv->a1.p = t1; |
182 |
rv->a2.p = t2; |
183 |
} |
184 |
|
185 |
return rv; |
186 |
} |
187 |
|
188 |
static inline struct f_inst * |
189 |
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv) |
190 |
{ |
191 |
struct f_inst *rv; |
192 |
int c1 = 0, c2 = 0, ipv4_used = 0; |
193 |
u32 key = 0, val2 = 0; |
194 |
|
195 |
if (tk->code == 'c') { |
196 |
c1 = 1; |
197 |
|
198 |
if (tk->aux == T_INT) { |
199 |
ipv4_used = 0; key = tk->a2.i; |
200 |
} |
201 |
else if (tk->aux == T_QUAD) { |
202 |
ipv4_used = 1; key = tk->a2.i; |
203 |
} |
204 |
else |
205 |
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); |
206 |
} |
207 |
|
208 |
/* IP->Quad implicit conversion */ |
209 |
else if (tk->code == 'C') { |
210 |
c1 = 1; |
211 |
struct f_val *val = tk->a1.p; |
212 |
|
213 |
if (val->type == T_INT) { |
214 |
ipv4_used = 0; key = val->val.i; |
215 |
} |
216 |
else if (val->type == T_QUAD) { |
217 |
ipv4_used = 1; key = val->val.i; |
218 |
} |
219 |
else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) { |
220 |
ipv4_used = 1; key = ipa_to_u32(val->val.ip); |
221 |
} |
222 |
else |
223 |
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); |
224 |
} |
225 |
|
226 |
if (tv->code == 'c') { |
227 |
if (tv->aux != T_INT) |
228 |
cf_error("Can't operate with value of non-integer type in EC constructor"); |
229 |
c2 = 1; |
230 |
val2 = tv->a2.i; |
231 |
} |
232 |
|
233 |
if (c1 && c2) { |
234 |
u64 ec; |
235 |
|
236 |
if (kind == EC_GENERIC) { |
237 |
ec = ec_generic(key, val2); |
238 |
} |
239 |
else if (ipv4_used) { |
240 |
check_u16(val2); |
241 |
ec = ec_ip4(kind, key, val2); |
242 |
} |
243 |
else if (key < 0x10000) { |
244 |
ec = ec_as2(kind, key, val2); |
245 |
} |
246 |
else { |
247 |
check_u16(val2); |
248 |
ec = ec_as4(kind, key, val2); |
249 |
} |
250 |
|
251 |
NEW_F_VAL; |
252 |
rv = f_new_inst(); |
253 |
rv->code = 'C'; |
254 |
rv->a1.p = val; |
255 |
val->type = T_EC; |
256 |
val->val.ec = ec; |
257 |
} |
258 |
else { |
259 |
rv = f_new_inst(); |
260 |
rv->code = P('m','c'); |
261 |
rv->aux = kind; |
262 |
rv->a1.p = tk; |
263 |
rv->a2.p = tv; |
264 |
} |
265 |
|
266 |
return rv; |
267 |
} |
268 |
|
269 |
|
270 |
|
271 |
CF_DECLS |
272 |
|
273 |
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, |
274 |
ACCEPT, REJECT, ERROR, QUITBIRD, |
275 |
INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, |
276 |
SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, |
277 |
IF, THEN, ELSE, CASE, |
278 |
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, |
279 |
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX, |
280 |
PREFERENCE, |
281 |
LEN, |
282 |
DEFINED, |
283 |
ADD, DELETE, CONTAINS, RESET, |
284 |
PREPEND, FIRST, LAST, MATCH, |
285 |
EMPTY, |
286 |
FILTER, WHERE, EVAL) |
287 |
|
288 |
%nonassoc THEN |
289 |
%nonassoc ELSE |
290 |
|
291 |
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr |
292 |
%type <f> filter filter_body where_filter |
293 |
%type <i> type break_command pair_expr ec_kind |
294 |
%type <i32> pair_atom ec_expr |
295 |
%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body |
296 |
%type <trie> fprefix_set |
297 |
%type <v> set_atom switch_atom fipa |
298 |
%type <px> fprefix |
299 |
%type <s> decls declsn one_decl function_params |
300 |
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2 |
301 |
|
302 |
CF_GRAMMAR |
303 |
|
304 |
CF_ADDTO(conf, filter_def) |
305 |
filter_def: |
306 |
FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); } |
307 |
filter_body { |
308 |
$2->def = $4; |
309 |
$4->name = $2->name; |
310 |
DBG( "We have new filter defined (%s)\n", $2->name ); |
311 |
cf_pop_scope(); |
312 |
} |
313 |
; |
314 |
|
315 |
CF_ADDTO(conf, filter_eval) |
316 |
filter_eval: |
317 |
EVAL term { f_eval_int($2); } |
318 |
; |
319 |
|
320 |
type: |
321 |
INT { $$ = T_INT; } |
322 |
| BOOL { $$ = T_BOOL; } |
323 |
| IP { $$ = T_IP; } |
324 |
| PREFIX { $$ = T_NET; } |
325 |
| PAIR { $$ = T_PAIR; } |
326 |
| QUAD { $$ = T_QUAD; } |
327 |
| EC { $$ = T_EC; } |
328 |
| STRING { $$ = T_STRING; } |
329 |
| BGPMASK { $$ = T_PATH_MASK; } |
330 |
| BGPPATH { $$ = T_PATH; } |
331 |
| CLIST { $$ = T_CLIST; } |
332 |
| ECLIST { $$ = T_ECLIST; } |
333 |
| type SET { |
334 |
switch ($1) { |
335 |
case T_INT: |
336 |
case T_PAIR: |
337 |
case T_QUAD: |
338 |
case T_EC: |
339 |
case T_IP: |
340 |
$$ = T_SET; |
341 |
break; |
342 |
|
343 |
case T_NET: |
344 |
$$ = T_PREFIX_SET; |
345 |
break; |
346 |
|
347 |
default: |
348 |
cf_error( "You can't create sets of this type." ); |
349 |
} |
350 |
} |
351 |
; |
352 |
|
353 |
one_decl: |
354 |
type SYM { |
355 |
struct f_val * val = cfg_alloc(sizeof(struct f_val)); |
356 |
val->type = T_VOID; |
357 |
$2 = cf_define_symbol($2, SYM_VARIABLE | $1, val); |
358 |
DBG( "New variable %s type %x\n", $2->name, $1 ); |
359 |
$2->aux2 = NULL; |
360 |
$$=$2; |
361 |
} |
362 |
; |
363 |
|
364 |
/* Decls with ';' at the end */ |
365 |
decls: /* EMPTY */ { $$ = NULL; } |
366 |
| one_decl ';' decls { |
367 |
$$ = $1; |
368 |
$$->aux2 = $3; |
369 |
} |
370 |
; |
371 |
|
372 |
/* Declarations that have no ';' at the end. */ |
373 |
declsn: one_decl { $$ = $1; } |
374 |
| one_decl ';' declsn { |
375 |
$$ = $1; |
376 |
$$->aux2 = $3; |
377 |
} |
378 |
; |
379 |
|
380 |
filter_body: |
381 |
function_body { |
382 |
struct filter *f = cfg_alloc(sizeof(struct filter)); |
383 |
f->name = NULL; |
384 |
f->root = $1; |
385 |
$$ = f; |
386 |
} |
387 |
; |
388 |
|
389 |
filter: |
390 |
SYM { |
391 |
if ($1->class != SYM_FILTER) cf_error("No such filter."); |
392 |
$$ = $1->def; |
393 |
} |
394 |
| filter_body |
395 |
; |
396 |
|
397 |
where_filter: |
398 |
WHERE term { |
399 |
/* Construct 'IF term THEN ACCEPT; REJECT;' */ |
400 |
struct filter *f = cfg_alloc(sizeof(struct filter)); |
401 |
struct f_inst *i, *acc, *rej; |
402 |
acc = f_new_inst(); /* ACCEPT */ |
403 |
acc->code = P('p',','); |
404 |
acc->a1.p = NULL; |
405 |
acc->a2.i = F_ACCEPT; |
406 |
rej = f_new_inst(); /* REJECT */ |
407 |
rej->code = P('p',','); |
408 |
rej->a1.p = NULL; |
409 |
rej->a2.i = F_REJECT; |
410 |
i = f_new_inst(); /* IF */ |
411 |
i->code = '?'; |
412 |
i->a1.p = $2; |
413 |
i->a2.p = acc; |
414 |
i->next = rej; |
415 |
f->name = NULL; |
416 |
f->root = i; |
417 |
$$ = f; |
418 |
} |
419 |
; |
420 |
|
421 |
function_params: |
422 |
'(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; } |
423 |
| '(' ')' { $$=NULL; } |
424 |
; |
425 |
|
426 |
function_body: |
427 |
decls '{' cmds '}' { |
428 |
if ($1) { |
429 |
/* Prepend instruction to clear local variables */ |
430 |
$$ = f_new_inst(); |
431 |
$$->code = P('c','v'); |
432 |
$$->a1.p = $1; |
433 |
$$->next = $3; |
434 |
} else |
435 |
$$ = $3; |
436 |
} |
437 |
; |
438 |
|
439 |
CF_ADDTO(conf, function_def) |
440 |
function_def: |
441 |
FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name ); |
442 |
$2 = cf_define_symbol($2, SYM_FUNCTION, NULL); |
443 |
cf_push_scope($2); |
444 |
} function_params function_body { |
445 |
$2->def = $5; |
446 |
$2->aux2 = $4; |
447 |
DBG("Hmm, we've got one function here - %s\n", $2->name); |
448 |
cf_pop_scope(); |
449 |
} |
450 |
; |
451 |
|
452 |
/* Programs */ |
453 |
|
454 |
/* Hack: $$ of cmds_int is the last node. |
455 |
$$->next of cmds_int is temporary used for the first node */ |
456 |
|
457 |
cmds: /* EMPTY */ { $$ = NULL; } |
458 |
| cmds_int { $$ = $1->next; $1->next = NULL; } |
459 |
; |
460 |
|
461 |
cmds_int: cmd { $$ = $1; $1->next = $1; } |
462 |
| cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; } |
463 |
; |
464 |
|
465 |
block: |
466 |
cmd { |
467 |
$$=$1; |
468 |
} |
469 |
| '{' cmds '}' { |
470 |
$$=$2; |
471 |
} |
472 |
; |
473 |
|
474 |
/* |
475 |
* Complex types, their bison value is struct f_val |
476 |
*/ |
477 |
fipa: |
478 |
IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); } |
479 |
| IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); } |
480 |
; |
481 |
|
482 |
|
483 |
|
484 |
/* |
485 |
* Set constants. They are also used in switch cases. We use separate |
486 |
* nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...) |
487 |
* to elude a collision between symbol (in expr) in set_atom and symbol |
488 |
* as a function call in switch case cmds. |
489 |
*/ |
490 |
|
491 |
set_atom: |
492 |
NUM { $$.type = T_INT; $$.val.i = $1; } |
493 |
| fipa { $$ = $1; } |
494 |
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } |
495 |
| '(' term ')' { |
496 |
$$ = f_eval($2, cfg_mem); |
497 |
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type"); |
498 |
} |
499 |
| SYM { |
500 |
if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name); |
501 |
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name); |
502 |
$$ = *(struct f_val *)($1->def); |
503 |
} |
504 |
; |
505 |
|
506 |
switch_atom: |
507 |
NUM { $$.type = T_INT; $$.val.i = $1; } |
508 |
| '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); } |
509 |
| fipa { $$ = $1; } |
510 |
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } |
511 |
; |
512 |
|
513 |
pair_expr: |
514 |
term { $$ = f_eval_int($1); check_u16($$); } |
515 |
|
516 |
pair_atom: |
517 |
pair_expr { $$ = pair($1, $1); } |
518 |
| pair_expr DDOT pair_expr { $$ = pair($1, $3); } |
519 |
| '*' { $$ = 0xFFFF; } |
520 |
; |
521 |
|
522 |
pair_item: |
523 |
'(' pair_atom ',' pair_atom ')' { |
524 |
$$ = f_new_pair_set(pair_a($2), pair_b($2), pair_a($4), pair_b($4)); |
525 |
} |
526 |
| '(' pair_atom ',' pair_atom ')' DDOT '(' pair_expr ',' pair_expr ')' { |
527 |
/* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */ |
528 |
if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4))) |
529 |
cf_error("syntax error"); |
530 |
$$ = f_new_pair_item(pair_b($2), $8, pair_b($4), $10); |
531 |
} |
532 |
; |
533 |
|
534 |
ec_expr: |
535 |
term { $$ = f_eval_int($1); } |
536 |
|
537 |
ec_kind: |
538 |
RT { $$ = EC_RT; } |
539 |
| RO { $$ = EC_RO; } |
540 |
| UNKNOWN NUM { $$ = $2; } |
541 |
| GENERIC { $$ = EC_GENERIC; } |
542 |
; |
543 |
|
544 |
ec_item: |
545 |
'(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); } |
546 |
| '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); } |
547 |
| '(' ec_kind ',' ec_expr ',' '*' ')' { $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); } |
548 |
; |
549 |
|
550 |
set_item: |
551 |
pair_item |
552 |
| ec_item |
553 |
| set_atom { $$ = f_new_item($1, $1); } |
554 |
| set_atom DDOT set_atom { $$ = f_new_item($1, $3); } |
555 |
; |
556 |
|
557 |
switch_item: |
558 |
pair_item |
559 |
| ec_item |
560 |
| switch_atom { $$ = f_new_item($1, $1); } |
561 |
| switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); } |
562 |
; |
563 |
|
564 |
set_items: |
565 |
set_item |
566 |
| set_items ',' set_item { $$ = f_merge_items($1, $3); } |
567 |
; |
568 |
|
569 |
switch_items: |
570 |
switch_item |
571 |
| switch_items ',' switch_item { $$ = f_merge_items($1, $3); } |
572 |
; |
573 |
|
574 |
fprefix: |
575 |
net_ip_ { $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; } |
576 |
| net_ip_ '+' { $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; } |
577 |
| net_ip_ '-' { $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; } |
578 |
| net_ip_ '{' NUM ',' NUM '}' { |
579 |
$$.net = $1; $$.lo = $3; $$.hi = $5; |
580 |
if ((0 > $3) || ($3 > $5) || ($5 > net_max_prefix_length[$1.type])) |
581 |
cf_error("Invalid prefix pattern range: {%d, %d}", $3, $5); |
582 |
} |
583 |
; |
584 |
|
585 |
fprefix_set: |
586 |
fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); } |
587 |
| fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); } |
588 |
; |
589 |
|
590 |
switch_body: /* EMPTY */ { $$ = NULL; } |
591 |
| switch_body switch_items ':' cmds { |
592 |
/* Fill data fields */ |
593 |
struct f_tree *t; |
594 |
for (t = $2; t; t = t->left) |
595 |
t->data = $4; |
596 |
$$ = f_merge_items($1, $2); |
597 |
} |
598 |
| switch_body ELSECOL cmds { |
599 |
struct f_tree *t = f_new_tree(); |
600 |
t->from.type = t->to.type = T_VOID; |
601 |
t->right = t; |
602 |
t->data = $3; |
603 |
$$ = f_merge_items($1, t); |
604 |
} |
605 |
; |
606 |
|
607 |
/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */ |
608 |
|
609 |
bgp_path_expr: |
610 |
symbol { $$ = $1; } |
611 |
| '(' term ')' { $$ = $2; } |
612 |
; |
613 |
|
614 |
bgp_path: |
615 |
PO bgp_path_tail1 PC { $$ = $2; } |
616 |
| '/' bgp_path_tail2 '/' { $$ = $2; } |
617 |
; |
618 |
|
619 |
bgp_path_tail1: |
620 |
NUM bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } |
621 |
| '*' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val = 0; } |
622 |
| '?' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; $$->val = 0; } |
623 |
| bgp_path_expr bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; } |
624 |
| { $$ = NULL; } |
625 |
; |
626 |
|
627 |
bgp_path_tail2: |
628 |
NUM bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } |
629 |
| '?' bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val = 0; } |
630 |
| { $$ = NULL; } |
631 |
; |
632 |
|
633 |
constant: |
634 |
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; } |
635 |
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; } |
636 |
| FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; } |
637 |
| TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; } |
638 |
| fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } |
639 |
| net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; } |
640 |
| '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); } |
641 |
| '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; } |
642 |
| ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } |
643 |
| bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; } |
644 |
; |
645 |
|
646 |
constructor: |
647 |
'(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } |
648 |
| '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } |
649 |
; |
650 |
|
651 |
|
652 |
/* |
653 |
* Maybe there are no dynamic attributes defined by protocols. |
654 |
* For such cases, we force the dynamic_attr list to contain |
655 |
* at least an invalid token, so it is syntantically correct. |
656 |
*/ |
657 |
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; }) |
658 |
|
659 |
rtadot: /* EMPTY, we are not permitted RTA. prefix */ |
660 |
; |
661 |
|
662 |
function_call: |
663 |
SYM '(' var_list ')' { |
664 |
struct symbol *sym; |
665 |
struct f_inst *inst = $3; |
666 |
if ($1->class != SYM_FUNCTION) |
667 |
cf_error("You can't call something which is not a function. Really."); |
668 |
DBG("You are calling function %s\n", $1->name); |
669 |
$$ = f_new_inst(); |
670 |
$$->code = P('c','a'); |
671 |
$$->a1.p = inst; |
672 |
$$->a2.p = $1->def; |
673 |
sym = $1->aux2; |
674 |
while (sym || inst) { |
675 |
if (!sym || !inst) |
676 |
cf_error("Wrong number of arguments for function %s.", $1->name); |
677 |
DBG( "You should pass parameter called %s\n", sym->name); |
678 |
inst->a1.p = sym; |
679 |
sym = sym->aux2; |
680 |
inst = inst->next; |
681 |
} |
682 |
} |
683 |
; |
684 |
|
685 |
symbol: |
686 |
SYM { |
687 |
$$ = f_new_inst(); |
688 |
|
689 |
switch ($1->class & 0xff00) { |
690 |
case SYM_CONSTANT: $$->code = 'C'; break; |
691 |
case SYM_VARIABLE: $$->code = 'V'; break; |
692 |
default: cf_error("%s: variable expected.", $1->name); |
693 |
} |
694 |
|
695 |
$$->a1.p = $1->def; |
696 |
$$->a2.p = $1->name; |
697 |
} |
698 |
|
699 |
static_attr: |
700 |
FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; } |
701 |
| GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; } |
702 |
| NET { $$ = f_new_inst(); $$->aux = T_NET; $$->a2.i = SA_NET; } |
703 |
| PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; } |
704 |
| SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; } |
705 |
| SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; } |
706 |
| CAST { $$ = f_new_inst(); $$->aux = T_ENUM_RTC; $$->a2.i = SA_CAST; } |
707 |
| DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; } |
708 |
| IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; } |
709 |
| IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; } |
710 |
; |
711 |
|
712 |
term: |
713 |
'(' term ')' { $$ = $2; } |
714 |
| term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; } |
715 |
| term '-' term { $$ = f_new_inst(); $$->code = '-'; $$->a1.p = $1; $$->a2.p = $3; } |
716 |
| term '*' term { $$ = f_new_inst(); $$->code = '*'; $$->a1.p = $1; $$->a2.p = $3; } |
717 |
| term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; } |
718 |
| term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; } |
719 |
| term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; } |
720 |
| term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; } |
721 |
| term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; } |
722 |
| term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; } |
723 |
| term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; } |
724 |
| term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; } |
725 |
| term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; } |
726 |
| term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; } |
727 |
| '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; } |
728 |
| DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; } |
729 |
|
730 |
| symbol { $$ = $1; } |
731 |
| constant { $$ = $1; } |
732 |
| constructor { $$ = $1; } |
733 |
|
734 |
| PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; } |
735 |
|
736 |
| rtadot static_attr { $$ = $2; $$->code = 'a'; } |
737 |
|
738 |
| rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); } |
739 |
|
740 |
| term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; } |
741 |
| term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; } |
742 |
| term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } |
743 |
| term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; } |
744 |
| term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; } |
745 |
|
746 |
/* Communities */ |
747 |
/* This causes one shift/reduce conflict |
748 |
| rtadot dynamic_attr '.' ADD '(' term ')' { } |
749 |
| rtadot dynamic_attr '.' DELETE '(' term ')' { } |
750 |
| rtadot dynamic_attr '.' CONTAINS '(' term ')' { } |
751 |
| rtadot dynamic_attr '.' RESET{ } |
752 |
*/ |
753 |
|
754 |
| '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } |
755 |
| '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; } |
756 |
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; } |
757 |
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } |
758 |
| ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } |
759 |
| DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } |
760 |
| FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; } |
761 |
|
762 |
/* |
763 |
| ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); } |
764 |
| ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } |
765 |
*/ |
766 |
|
767 |
/* | term '.' LEN { $$->code = P('P','l'); } */ |
768 |
|
769 |
/* function_call is inlined here */ |
770 |
| SYM '(' var_list ')' { |
771 |
struct symbol *sym; |
772 |
struct f_inst *inst = $3; |
773 |
if ($1->class != SYM_FUNCTION) |
774 |
cf_error("You can't call something which is not a function. Really."); |
775 |
DBG("You are calling function %s\n", $1->name); |
776 |
$$ = f_new_inst(); |
777 |
$$->code = P('c','a'); |
778 |
$$->a1.p = inst; |
779 |
$$->a2.p = $1->def; |
780 |
sym = $1->aux2; |
781 |
while (sym || inst) { |
782 |
if (!sym || !inst) |
783 |
cf_error("Wrong number of arguments for function %s.", $1->name); |
784 |
DBG( "You should pass parameter called %s\n", sym->name); |
785 |
inst->a1.p = sym; |
786 |
sym = sym->aux2; |
787 |
inst = inst->next; |
788 |
} |
789 |
} |
790 |
; |
791 |
|
792 |
break_command: |
793 |
QUITBIRD { $$ = F_QUITBIRD; } |
794 |
| ACCEPT { $$ = F_ACCEPT; } |
795 |
| REJECT { $$ = F_REJECT; } |
796 |
| ERROR { $$ = F_ERROR; } |
797 |
| PRINT { $$ = F_NOP; } |
798 |
| PRINTN { $$ = F_NONL; } |
799 |
; |
800 |
|
801 |
print_one: |
802 |
term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; } |
803 |
; |
804 |
|
805 |
print_list: /* EMPTY */ { $$ = NULL; } |
806 |
| print_one { $$ = $1; } |
807 |
| print_one ',' print_list { |
808 |
if ($1) { |
809 |
$1->next = $3; |
810 |
$$ = $1; |
811 |
} else $$ = $3; |
812 |
} |
813 |
; |
814 |
|
815 |
var_listn: term { |
816 |
$$ = f_new_inst(); |
817 |
$$->code = 's'; |
818 |
$$->a1.p = NULL; |
819 |
$$->a2.p = $1; |
820 |
$$->next = NULL; |
821 |
} |
822 |
| term ',' var_listn { |
823 |
$$ = f_new_inst(); |
824 |
$$->code = 's'; |
825 |
$$->a1.p = NULL; |
826 |
$$->a2.p = $1; |
827 |
$$->next = $3; |
828 |
} |
829 |
; |
830 |
|
831 |
var_list: /* EMPTY */ { $$ = NULL; } |
832 |
| var_listn { $$ = $1; } |
833 |
; |
834 |
|
835 |
cmd: |
836 |
IF term THEN block { |
837 |
$$ = f_new_inst(); |
838 |
$$->code = '?'; |
839 |
$$->a1.p = $2; |
840 |
$$->a2.p = $4; |
841 |
} |
842 |
| IF term THEN block ELSE block { |
843 |
struct f_inst *i = f_new_inst(); |
844 |
i->code = '?'; |
845 |
i->a1.p = $2; |
846 |
i->a2.p = $4; |
847 |
$$ = f_new_inst(); |
848 |
$$->code = '?'; |
849 |
$$->a1.p = i; |
850 |
$$->a2.p = $6; |
851 |
} |
852 |
| SYM '=' term ';' { |
853 |
$$ = f_new_inst(); |
854 |
DBG( "Ook, we'll set value\n" ); |
855 |
if (($1->class & ~T_MASK) != SYM_VARIABLE) |
856 |
cf_error( "You may set only variables." ); |
857 |
$$->code = 's'; |
858 |
$$->a1.p = $1; |
859 |
$$->a2.p = $3; |
860 |
} |
861 |
| RETURN term ';' { |
862 |
$$ = f_new_inst(); |
863 |
DBG( "Ook, we'll return the value\n" ); |
864 |
$$->code = 'r'; |
865 |
$$->a1.p = $2; |
866 |
} |
867 |
| rtadot dynamic_attr '=' term ';' { |
868 |
$$ = $2; |
869 |
$$->code = P('e','S'); |
870 |
$$->a1.p = $4; |
871 |
} |
872 |
| rtadot static_attr '=' term ';' { |
873 |
$$ = $2; |
874 |
if (!$$->a1.i) |
875 |
cf_error( "This static attribute is read-only."); |
876 |
$$->code = P('a','S'); |
877 |
$$->a1.p = $4; |
878 |
} |
879 |
| PREFERENCE '=' term ';' { |
880 |
$$ = f_new_inst(); |
881 |
$$->code = P('P','S'); |
882 |
$$->a1.p = $3; |
883 |
} |
884 |
| UNSET '(' rtadot dynamic_attr ')' ';' { |
885 |
$$ = $4; |
886 |
$$->aux = EAF_TYPE_UNDEF | EAF_TEMP; |
887 |
$$->code = P('e','S'); |
888 |
$$->a1.p = NULL; |
889 |
} |
890 |
| break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; } |
891 |
| function_call ';' { $$ = $1; } |
892 |
| CASE term '{' switch_body '}' { |
893 |
$$ = f_new_inst(); |
894 |
$$->code = P('S','W'); |
895 |
$$->a1.p = $2; |
896 |
$$->a2.p = build_tree( $4 ); |
897 |
} |
898 |
|
899 |
|
900 |
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } |
901 |
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); } |
902 |
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); } |
903 |
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); } |
904 |
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); } |
905 |
; |
906 |
|
907 |
CF_END |