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