]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/config.Y
As usuall, most important info was missing.
[thirdparty/bird.git] / filter / config.Y
CommitLineData
b9d70dc8
PM
1/*
2 * BIRD - filters
3 *
6542ece9 4 * Copyright 1998,1999 Pavel Machek
b9d70dc8
PM
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
c9f8c1a8 7 *
f4536657 8 FIXME (nonurgent): define keyword
2d496d20 9 FIXME (for BGP): whole system of paths, path ~ string, path.prepend(), path.originate
c9f8c1a8 10 FIXME: create community lists
60d7d10e 11 FIXME: IP addresses in ipv6
0a06a9b8
PM
12
13
14(1) Cesty
15
16 AS paths budtez interne reprezentovany stejne jako v BGP (viz RFC 1771),
17to znamena jako posloupnost segmentu, z nichz kazdy je budto posloupnost nebo
18mnozina cisel ASu. Na cestach nadefinuji nasledujici operace:
19
20 - zformatovani do stringu
21 - append dalsiho AS k ceste
22
23Filtry by mely podporovat:
24
25 - operator pridani AS k ceste
26 - matchovani na pritomnost podposloupnosti v ceste (pricemz vyskytne-li
27 se tam mnozina, tak si ji lze predstavit prerovnanou v libovolnem
28 poradi)
29 - operator zjisteni delky cesty (pro vypocet metrik)
30
31Byl bych rad, kdyby se samotne matchovaci funkce objevily v proto/bgp/attrs.c.
32
33
34(2) Community-listy
35
36Community list budiz interne reprezentovan jako posloupnost 32-bitovych cisel.
37
38Filtry by se mely na communities divat jako na usporadane dvojice 16-bitovych
39cisel (prvni je cislo AS, ktery community definoval, druhe pak community ID
40v ramci AS) a melo by byt mozne definovat si konstanty typu community.
41K dispozici by mely byt nasledujici operace:
42
43 - zjisteni pritomnosti community v listu
44 - pridani community do listu
45 - odebrani community z listu
46 - zresetovani listu
47
48Pro operace na cestach i na community listech by se mela pouzivat `teckova'
49notace pouzita v mem puvodnim navrhu syntaxe.
50
51
52(3) Zmeny v semantice dynamickych atributu
53
54Aby se nemusely neustale kopirovat seznamy atributu, rad bych provedl jeste
55jednu zmenu v tom, jak filtry nakladaji s atributy (pevne doufam, ze posledni,
56ale uznavam, ze u te predchozi jsem to take tvrdil): Funkci f_run budiz
57pridan jeste jeden parametr, ktery prepina mezi dvema mody:
58
59 (a) [incoming filter mode] Jako nyni.
60
61 (b) [outgoing filter mode] Pokud se hleda atribut, hleda se nejdrive
62 v tmp_attrs a pokud to selze, tak v rta->attrs. Pokud se nastavuje,
63 dava se _vzdy_ do tmp_attrs.
64
65Diky tomu filtry pri exportu routes nebudou vubec muset modifikovat rta a
66protokoly, ktere v import_control potrebuji nastavovat i non-temporary
67atributy, je budou moci pridat do tmp_attrs, aniz by sahly na rta.
68
69
b9d70dc8
PM
70 */
71
72CF_HDR
73
2d496d20
PM
74#define P(a,b) ((a<<8) | b)
75
b9d70dc8
PM
76CF_DECLS
77
e4a73dbf 78CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
ba921648
PM
79 ACCEPT, REJECT, ERROR, QUITBIRD,
80 INT, BOOL, IP, PREFIX, PAIR, SET, STRING,
7db7b7db 81 IF, THEN, ELSE, CASE,
23b1539b 82 TRUE, FALSE,
db1326aa 83 FROM, GW, NET, MASK, SOURCE,
36bbfc70 84 LEN,
f4536657 85 DEFINED,
430da60f 86 FILTER, WHERE)
b9d70dc8 87
f4536657 88%nonassoc THEN
4ed8718a 89%nonassoc ELSE
f4536657 90
db1326aa 91%type <x> term block cmds cmd function_body constant print_one print_list var_list var_listn dynamic_attr function_call
430da60f 92%type <f> filter filter_body where_filter
4515bdba 93%type <i> type break_command pair
41be4444 94%type <e> set_item set_items switch_body
d3dd620b 95%type <v> set_atom prefix prefix_s ipa
6dc7a0cb 96%type <s> decls declsn one_decl function_params
b9d70dc8
PM
97
98CF_GRAMMAR
99
e0f2e42f
MM
100CF_ADDTO(conf, filter_def)
101filter_def:
cb8034f4 102 FILTER SYM { cf_push_scope( $2 ); } filter_body {
ae3e1af2
PM
103 cf_define_symbol($2, SYM_FILTER, $4);
104 $4->name = $2->name;
d4d75628 105 DBG( "We have new filter defined (%s)\n", $2->name );
ae3e1af2 106 cf_pop_scope();
b9d70dc8
PM
107 }
108 ;
109
ba921648
PM
110type:
111 INT { $$ = T_INT; }
112 | BOOL { $$ = T_BOOL; }
113 | IP { $$ = T_IP; }
114 | PREFIX { $$ = T_PREFIX; }
115 | PAIR { $$ = T_PAIR; }
116 | STRING { $$ = T_STRING; }
117 | type SET {
118 switch ($1) {
119 default:
120 cf_error( "You can not create sets of this type\n" );
121 case T_INT: case T_IP: case T_PREFIX: case T_PAIR:
122 }
123 $$ = $1 | T_SET;
124 }
125 ;
126
6dc7a0cb
PM
127one_decl:
128 type SYM {
4107df1d 129 cf_define_symbol($2, SYM_VARIABLE | $1, NULL);
d4d75628 130 DBG( "New variable %s type %x\n", $2->name, $1 );
cb8034f4 131 $2->aux = 0;
d3dd620b
PM
132 {
133 struct f_val * val;
134 val = cfg_alloc(sizeof(struct f_val));
135 val->type = $1;
136 $2->aux2 = val;
137 }
6542ece9 138 $$=$2;
ba921648
PM
139 }
140 ;
141
6dc7a0cb
PM
142/* Decls with ';' at the end */
143decls: /* EMPTY */ { $$ = NULL; }
144 | one_decl ';' decls {
145 $$ = $1;
cb8034f4 146 $$->aux = (int) $3;
6dc7a0cb
PM
147 }
148 ;
149
3c989eb4 150/* Declarations that have no ';' at the end. */
6dc7a0cb
PM
151declsn: one_decl { $$ = $1; }
152 | declsn ';' one_decl {
4515bdba
PM
153 $$ = $1;
154 $$->aux = (int) $3;
6dc7a0cb
PM
155 }
156 ;
157
e0f2e42f 158filter_body:
ba921648 159 function_body {
e0f2e42f
MM
160 struct filter *f = cfg_alloc(sizeof(struct filter));
161 f->name = NULL;
ba921648 162 f->root = $1;
e0f2e42f
MM
163 $$ = f;
164 }
165 ;
166
167filter:
168 SYM {
169 if ($1->class != SYM_FILTER) cf_error("No such filter");
170 $$ = $1->def;
171 }
172 | filter_body
173 ;
174
430da60f
MM
175where_filter:
176 WHERE term {
177 /* Construct 'IF term THEN ACCEPT; REJECT;' */
178 struct filter *f = cfg_alloc(sizeof(struct filter));
179 struct f_inst *i, *acc, *rej;
180 acc = f_new_inst(); /* ACCEPT */
2d496d20 181 acc->code = P('p',',');
430da60f
MM
182 acc->a1.p = NULL;
183 acc->a2.i = F_ACCEPT;
184 rej = f_new_inst(); /* REJECT */
2d496d20 185 rej->code = P('p',',');
430da60f
MM
186 rej->a1.p = NULL;
187 rej->a2.i = F_REJECT;
188 i = f_new_inst(); /* IF */
189 i->code = '?';
190 i->a1.p = $2;
191 i->a2.p = acc;
192 i->next = rej;
193 f->name = NULL;
194 f->root = i;
195 $$ = f;
196 }
197 ;
198
ba921648 199function_params:
d4d75628 200 '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
6dc7a0cb 201 | '(' ')' { $$=NULL; }
ba921648 202 ;
b9d70dc8 203
ba921648
PM
204function_body:
205 decls '{' cmds '}' {
206 $$ = $3;
84c7e194 207 }
ba921648
PM
208 ;
209
210CF_ADDTO(conf, function_def)
211function_def:
d4d75628 212 FUNCTION SYM { DBG( "Begining of function %s\n", $2->name ); cf_push_scope($2); } function_params function_body {
ba921648 213 extern struct f_inst *startup_func;
ae3e1af2 214 cf_define_symbol($2, SYM_FUNCTION, $5);
ba921648 215 if (!strcasecmp($2->name, "startup"))
ae3e1af2 216 startup_func = $5;
cb8034f4 217 $2->aux = (int) $4;
ae3e1af2 218 $2->aux2 = $5;
d4d75628 219 DBG("Hmm, we've got one function here - %s\n", $2->name);
ae3e1af2 220 cf_pop_scope();
ba921648
PM
221 }
222 ;
223
224/* Programs */
225
226cmds: /* EMPTY */ { $$ = NULL; }
227 | cmd cmds {
84c7e194 228 if ($1) {
7db7b7db
PM
229 if ($1->next)
230 bug("Command has next already set\n");
ba921648 231 $1->next = $2;
84c7e194 232 $$ = $1;
ba921648 233 } else $$ = $2;
84c7e194
PM
234 }
235 ;
236
2575593e 237block:
ba921648 238 cmd {
2575593e
PM
239 $$=$1;
240 }
241 | '{' cmds '}' {
242 $$=$2;
243 }
244 ;
245
d3dd620b
PM
246/*
247 * Simple types, their bison value is int
248 */
249pair:
250 '(' NUM ',' NUM ')' { $$ = $2 << 16 | $4; }
251 ;
252
253/*
254 * Complex types, their bison value is struct f_val
255 */
256prefix_s:
455ca441 257 IPA '/' NUM { $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3; if (ipa_nonzero(ipa_and($$.val.px.ip, ipa_not(ipa_mkmask($$.val.px.len))))) cf_error( "%I/%d is not really prefix\n", $$.val.px.ip, $$.val.px.len ); }
d3dd620b
PM
258 ;
259
260prefix:
261 prefix_s { $$ = $1; }
262 | prefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
263 | prefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
6dc7a0cb 264 | prefix_s '{' NUM ',' NUM '}' { $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8); }
d3dd620b
PM
265 ;
266
267ipa:
6dc7a0cb 268 IPA { $$.type = T_IP; $$.val.px.ip = $1; }
d3dd620b
PM
269 ;
270
38506f71 271set_atom:
d3dd620b
PM
272 NUM { $$.type = T_INT; $$.val.i = $1; }
273 | pair { $$.type = T_PAIR; $$.val.i = $1; }
274 | ipa { $$ = $1; }
275 | prefix { $$ = $1; }
38506f71
PM
276 ;
277
278set_item:
995e5894
PM
279 set_atom {
280 $$ = f_new_tree();
281 $$->from = $1;
282 if ($1.type != T_PREFIX)
283 $$->to = $1;
284 else {
285 $$->to = $1;
286 $$->to.val.px.ip = ipa_or( $$->to.val.px.ip, ipa_not( ipa_mkmask( $$->to.val.px.len ) ));
287 }
288 }
289 | set_atom '.' '.' set_atom {
290 $$ = f_new_tree();
291 $$->from = $1;
292 $$->to = $4;
293 if (($1.type == T_PREFIX) || ($4.type == T_PREFIX)) cf_error( "You can not use prefixes for range" );
294 }
38506f71
PM
295 ;
296
297set_items:
298 set_item { $$ = $1; }
299 | set_items ',' set_item { $$ = $3; $$->left = $1; }
300 ;
301
41be4444
PM
302switch_body: /* EMPTY */ { $$ = NULL; }
303 | set_item ':' cmds switch_body {
304 $$ = $1;
305 $$->data = $3;
306 $$->left = $4;
307 }
308 | ELSE ':' cmds {
309 $$ = f_new_tree();
310 $$->from.type = T_VOID;
311 $$->to.type = T_VOID;
312 $$->data = $3;
313 }
314 ;
d3dd620b 315
e4a73dbf
PM
316/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
317
23b1539b 318constant:
e4a73dbf 319 NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
c7b43f33
PM
320 | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
321 | FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; }
322 | TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
323 | pair { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PAIR; $$->a2.i = $1; }
d3dd620b 324 | ipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
2f702671 325 | prefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
d4d75628 326 | '[' 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" ); }
c7b43f33 327 | ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
23b1539b
PM
328 ;
329
db1326aa
MM
330/*
331 * Maybe there are no dynamic attributes defined by protocols.
332 * For such cases, we force the dynamic_attr list to contain
333 * at least an invalid token, so it's syntantically correct.
334 */
335CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
f4536657 336
2e18b87d 337rtadot: /* EMPTY, we are not permitted RTA. prefix */
6c14255d 338 ;
f4536657 339
2d496d20
PM
340function_call:
341 SYM '(' var_list ')' {
342 struct symbol *sym;
343 struct f_inst *inst = $3;
344 if ($1->class != SYM_FUNCTION)
345 cf_error("You can not call something which is not function. Really.");
d4d75628 346 DBG("You are calling function %s\n", $1->name);
2d496d20
PM
347 $$ = f_new_inst();
348 $$->code = P('c','a');
349 $$->a1.p = inst;
350 $$->a2.p = $1->aux2;
351 sym = (void *) $1->aux;
352 while (sym || inst) {
353 if (!sym || !inst)
354 cf_error("wrong number of arguments for function %s.", $1->name);
d4d75628 355 DBG( "You should pass parameter called %s\n", sym->name);
2d496d20
PM
356 inst->a1.p = sym;
357 sym = (void *) sym->aux;
358 inst = inst->next;
359 }
360 }
361 ;
362
84c7e194 363term:
f4536657 364 '(' term ')' { $$ = $2; }
d4d75628 365 | term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; }
2d496d20 366 | term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
d4d75628
PM
367 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; }
368 | term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; }
369 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; }
370 | term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; }
371 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; }
372 | term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; }
995e5894 373 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
2d496d20 374 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; }
23b1539b 375
1183b6b2 376 | constant { $$ = $1; }
2575593e
PM
377 | SYM {
378 $$ = f_new_inst();
379 switch ($1->class) {
ba921648 380 case SYM_VARIABLE | T_INT:
d3dd620b
PM
381 case SYM_VARIABLE | T_PAIR:
382 case SYM_VARIABLE | T_PREFIX:
383 case SYM_VARIABLE | T_IP:
384 $$->code = 'C';
385 $$->a1.p = $1->aux2;
2575593e
PM
386 break;
387 default:
1183b6b2 388 cf_error("Can not use this class of symbol (%s,%x) as variable.", $1->name, $1->class );
2575593e
PM
389 }
390 }
4515bdba 391
6c14255d 392 | rtadot FROM { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, from); }
36bbfc70 393
6c14255d
PM
394 | rtadot GW { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_IP; $$->a2.i = OFFSETOF(struct rta, gw); }
395 | rtadot NET { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_PREFIX; $$->a2.i = 0x12345678; }
b1573615 396 | rtadot SOURCE { $$ = f_new_inst(); $$->code = 'a'; $$->aux = T_ENUM_RTS; $$->a2.i = OFFSETOF(struct rta, source); }
6dc7a0cb 397
db1326aa 398 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
36bbfc70 399
2d496d20
PM
400 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
401 | term '.' LEN { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_INT; }
402 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
995e5894
PM
403/* function_call is inlined here */
404 | SYM '(' var_list ')' {
405 struct symbol *sym;
406 struct f_inst *inst = $3;
407 if ($1->class != SYM_FUNCTION)
408 cf_error("You can not call something which is not function. Really.");
409 DBG("You are calling function %s\n", $1->name);
410 $$ = f_new_inst();
411 $$->code = P('c','a');
412 $$->a1.p = inst;
413 $$->a2.p = $1->aux2;
414 sym = (void *) $1->aux;
415 while (sym || inst) {
416 if (!sym || !inst)
417 cf_error("wrong number of arguments for function %s.", $1->name);
418 DBG( "You should pass parameter called %s\n", sym->name);
419 inst->a1.p = sym;
420 sym = (void *) sym->aux;
421 inst = inst->next;
422 }
423 }
ba921648
PM
424 ;
425
426break_command:
427 QUITBIRD { $$ = F_QUITBIRD }
428 | ACCEPT { $$ = F_ACCEPT }
429 | REJECT { $$ = F_REJECT }
430 | ERROR { $$ = F_ERROR }
23b1539b 431 | PRINT { $$ = F_NOP }
d3dd620b 432 | PRINTN { $$ = F_NONL }
ba921648
PM
433 ;
434
23b1539b 435print_one:
2db3b288 436 term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
23b1539b
PM
437 ;
438
439print_list: /* EMPTY */ { $$ = NULL; }
995e5894
PM
440 | print_one { $$ = $1; }
441 | print_one ',' print_list {
23b1539b 442 if ($1) {
995e5894 443 $1->next = $3;
23b1539b 444 $$ = $1;
995e5894 445 } else $$ = $3;
23b1539b 446 }
995e5894 447
23b1539b
PM
448 ;
449
6dc7a0cb 450var_listn: term {
d3dd620b
PM
451 $$ = f_new_inst();
452 $$->code = 's';
453 $$->a1.p = NULL;
454 $$->a2.p = $1;
455 $$->next = NULL;
456 }
6dc7a0cb 457 | term ',' var_listn {
6542ece9
PM
458 $$ = f_new_inst();
459 $$->code = 's';
460 $$->a1.p = NULL;
461 $$->a2.p = $1;
462 $$->next = $3;
463 }
464 ;
465
6dc7a0cb
PM
466var_list: /* EMPTY */ { $$ = NULL; }
467 | var_listn { $$ = $1; }
468 ;
469
23b1539b 470cmd:
49955645
MM
471 IF term THEN block {
472 $$ = f_new_inst();
473 $$->code = '?';
474 $$->a1.p = $2;
475 $$->a2.p = $4;
23b1539b 476 }
49955645
MM
477 | IF term THEN block ELSE block {
478 struct f_inst *i = f_new_inst();
479 i->code = '?';
480 i->a1.p = $2;
481 i->a2.p = $4;
23b1539b
PM
482 $$ = f_new_inst();
483 $$->code = '?';
49955645
MM
484 $$->a1.p = i;
485 $$->a2.p = $6;
23b1539b 486 }
ba921648 487 | SYM '=' term ';' {
84c7e194 488 $$ = f_new_inst();
d4d75628 489 DBG( "Ook, we'll set value\n" );
ba921648
PM
490 if (($1->class & ~T_MASK) != SYM_VARIABLE)
491 cf_error( "You may only set variables, and this is %x.\n", $1->class );
23b1539b 492 $$->code = 's';
2db3b288
PM
493 $$->a1.p = $1;
494 $$->a2.p = $3;
b9d70dc8 495 }
2d496d20
PM
496 | RETURN term ';' {
497 $$ = f_new_inst();
d4d75628 498 DBG( "Ook, we'll return the value\n" );
2d496d20
PM
499 $$->code = 'r';
500 $$->a1.p = $2;
501 }
db1326aa 502 | rtadot dynamic_attr '=' term ';' {
6c14255d 503 $$ = $2;
2d496d20 504 $$->code = P('e','S');
6c14255d 505 $$->a1.p = $4;
f31156ca 506 }
db1326aa 507 | UNSET '(' rtadot dynamic_attr ')' ';' {
6c14255d 508 $$ = $4;
9f4929e7 509 $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
2d496d20 510 $$->code = P('e','S');
48f9e019 511 $$->a1.p = NULL;
c7b43f33 512 }
2d496d20
PM
513 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
514 | function_call ';' { $$ = $1; }
7db7b7db
PM
515 | CASE term '{' switch_body '}' {
516 $$ = f_new_inst();
2d496d20 517 $$->code = P('S','W');
7db7b7db 518 $$->a1.p = $2;
41be4444 519 $$->a2.p = build_tree( $4 );
7db7b7db 520 }
b9d70dc8
PM
521 ;
522
523CF_END