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