Annotation of embedaddon/bird/filter/config.Y, revision 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>