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