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