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