config.Y 27 KB
Newer Older
1 2 3
/*
 *	BIRD - filters
 *
4
 *	Copyright 1998--2000 Pavel Machek
5 6
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
7
 *
Pavel Machek's avatar
Pavel Machek committed
8
	FIXME: priority of ! should be lower
9 10 11 12
 */

CF_HDR

13 14
CF_DEFINES

15 16 17 18 19 20 21 22 23 24 25
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; }


/*
 * Sets and their items are during parsing handled as lists, linked
 * through left ptr. The first item in a list also contains a pointer
 * to the last item in a list (right ptr). For convenience, even items
 * are handled as one-item lists. Lists are merged by f_merge_items().
 */
26 27 28 29 30 31 32 33 34 35 36
static int
f_valid_set_type(int type)
{
  switch (type)
  {
  case T_INT:
  case T_PAIR:
  case T_QUAD:
  case T_ENUM:
  case T_IP:
  case T_EC:
37
  case T_LC:
38 39 40 41 42 43
    return 1;

  default:
    return 0;
  }
}
44 45 46

static inline struct f_tree *
f_new_item(struct f_val from, struct f_val to)
47
{
48 49 50 51 52 53
  struct f_tree *t = f_new_tree();
  t->right = t;
  t->from = from;
  t->to = to;
  return t;
}
54

55 56 57 58 59 60 61 62 63
static inline struct f_tree *
f_merge_items(struct f_tree *a, struct f_tree *b)
{
  if (!a) return b;
  a->right->left = b;
  a->right = b->right;
  b->right = NULL;
  return a;
}
64

65 66 67
static inline struct f_tree *
f_new_pair_item(int fa, int ta, int fb, int tb)
{
68 69 70 71 72 73 74 75
  check_u16(fa);
  check_u16(ta);
  check_u16(fb);
  check_u16(tb);

  if ((ta < fa) || (tb < fb))
    cf_error( "From value cannot be higher that To value in pair sets");

76 77 78 79 80 81
  struct f_tree *t = f_new_tree();
  t->right = t;
  t->from.type = t->to.type = T_PAIR;
  t->from.val.i = pair(fa, fb);
  t->to.val.i = pair(ta, tb);
  return t;
82 83
}

84 85
static inline struct f_tree *
f_new_pair_set(int fa, int ta, int fb, int tb)
86
{
87 88 89 90
  check_u16(fa);
  check_u16(ta);
  check_u16(fb);
  check_u16(tb);
Ondřej Filip's avatar
Ondřej Filip committed
91

92 93
  if ((ta < fa) || (tb < fb))
    cf_error( "From value cannot be higher that To value in pair sets");
Ondřej Filip's avatar
Ondřej Filip committed
94

95 96 97
  struct f_tree *lst = NULL;
  int i;

98 99 100 101
  for (i = fa; i <= ta; i++)
    lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));

  return lst;
102 103
}

104
#define CC_ALL 0xFFFF
105
#define EC_ALL 0xFFFFFFFF
106
#define LC_ALL 0xFFFFFFFF
107 108 109 110 111 112

static struct f_tree *
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
{
  u64 fm, to;

113
  if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
    check_u16(vf);
    if (vt == EC_ALL)
      vt = 0xFFFF;
    else
      check_u16(vt);
  }

  if (kind == EC_GENERIC) {
    fm = ec_generic(key, vf);
    to = ec_generic(key, vt);
  }
  else if (ipv4_used) {
    fm = ec_ip4(kind, key, vf);
    to = ec_ip4(kind, key, vt);
  }
  else if (key < 0x10000) {
    fm = ec_as2(kind, key, vf);
    to = ec_as2(kind, key, vt);
  }
  else {
    fm = ec_as4(kind, key, vf);
    to = ec_as4(kind, key, vt);
  }

  struct f_tree *t = f_new_tree();
  t->right = t;
  t->from.type = t->to.type = T_EC;
  t->from.val.ec = fm;
  t->to.val.ec = to;
  return t;
}

146 147 148 149 150 151 152 153 154 155 156
static struct f_tree *
f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
{
  struct f_tree *t = f_new_tree();
  t->right = t;
  t->from.type = t->to.type = T_LC;
  t->from.val.lc = (lcomm) {f1, f2, f3};
  t->to.val.lc = (lcomm) {t1, t2, t3};
  return t;
}

157
static inline struct f_inst *
158
f_generate_empty(struct f_dynamic_attr dyn)
Ondřej Zajíček's avatar
Ondřej Zajíček committed
159
{
160
  struct f_inst *e = f_new_inst(FI_EMPTY);
161

162
  switch (dyn.type & EAF_TYPE_MASK) {
163 164 165 166 167 168 169 170 171
    case EAF_TYPE_AS_PATH:
      e->aux = T_PATH;
      break;
    case EAF_TYPE_INT_SET:
      e->aux = T_CLIST;
      break;
    case EAF_TYPE_EC_SET:
      e->aux = T_ECLIST;
      break;
172 173 174
    case EAF_TYPE_LC_SET:
      e->aux = T_LCLIST;
      break;
175 176 177 178
    default:
      cf_error("Can't empty that attribute");
  }

179 180 181
  struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
  s->a1.p = e;
  return s;
182 183 184 185 186 187 188 189
}


static inline struct f_inst *
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
{
  struct f_inst *rv;

190
  if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
191 192 193 194 195 196
    if ((t1->aux != T_INT) || (t2->aux != T_INT))
      cf_error( "Can't operate with value of non-integer type in pair constructor");

    check_u16(t1->a2.i);
    check_u16(t2->a2.i);

197
    rv = f_new_inst(FI_CONSTANT);
198 199 200 201
    rv->aux = T_PAIR;
    rv->a2.i = pair(t1->a2.i, t2->a2.i);
  }
  else {
202
    rv = f_new_inst(FI_PAIR_CONSTRUCT);
203 204 205 206 207 208 209 210 211 212 213 214 215 216
    rv->a1.p = t1;
    rv->a2.p = t2;
  }

  return rv;
}

static inline struct f_inst *
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
{
  struct f_inst *rv;
  int c1 = 0, c2 = 0, ipv4_used = 0;
  u32 key = 0, val2 = 0;

217
  if (tk->fi_code == FI_CONSTANT) {
218 219 220 221 222 223 224 225 226 227 228 229 230 231
    c1 = 1;

    if (tk->aux == T_INT) {
      ipv4_used = 0; key = tk->a2.i;
    }
    else if (tk->aux == T_QUAD) {
      ipv4_used = 1; key = tk->a2.i;
    }
    else
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
  }

#ifndef IPV6
  /* IP->Quad implicit conversion */
232
  else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
233 234
    c1 = 1;
    struct f_val *val = tk->a1.p;
235 236 237 238 239 240 241 242

    if (val->type == T_INT) {
      ipv4_used = 0; key = val->val.i;
    }
    else if (val->type == T_QUAD) {
      ipv4_used = 1; key = val->val.i;
    }
    else if (val->type == T_IP) {
243 244 245 246 247 248 249
      ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
    }
    else
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
  }
#endif

250
  if (tv->fi_code == FI_CONSTANT) {
251 252 253 254 255 256 257 258
    if (tv->aux != T_INT)
      cf_error("Can't operate with value of non-integer type in EC constructor");
    c2 = 1;
    val2 = tv->a2.i;
  }

  if (c1 && c2) {
    u64 ec;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
259

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
    if (kind == EC_GENERIC) {
      ec = ec_generic(key, val2);
    }
    else if (ipv4_used) {
      check_u16(val2);
      ec = ec_ip4(kind, key, val2);
    }
    else if (key < 0x10000) {
      ec = ec_as2(kind, key, val2);
    }
    else {
      check_u16(val2);
      ec = ec_as4(kind, key, val2);
    }

    NEW_F_VAL;
276
    rv = f_new_inst(FI_CONSTANT_INDIRECT);
Ondřej Zajíček's avatar
Ondřej Zajíček committed
277
    rv->a1.p = val;
278 279 280 281
    val->type = T_EC;
    val->val.ec = ec;
  }
  else {
282
    rv = f_new_inst(FI_EC_CONSTRUCT);
283 284 285 286 287 288
    rv->aux = kind;
    rv->a1.p = tk;
    rv->a2.p = tv;
  }

  return rv;
289
}
290

291 292 293 294 295
static inline struct f_inst *
f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{
  struct f_inst *rv;

296
  if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
297 298 299
    if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
      cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");

300
    rv = f_new_inst(FI_CONSTANT_INDIRECT);
301 302 303 304 305 306 307 308 309 310

    NEW_F_VAL;
    rv->a1.p = val;
    val->type = T_LC;
    val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
  }
  else
  {
    rv = cfg_allocz(sizeof(struct f_inst3));
    rv->lineno = ifs->lino;
311
    rv->fi_code = FI_LC_CONSTRUCT;
312 313 314 315 316 317 318 319
    rv->a1.p = t1;
    rv->a2.p = t2;
    INST3(rv).p = t3;
  }

  return rv;
}

320 321 322
static inline struct f_inst *
f_generate_path_mask(struct f_path_mask *t)
{
323 324
  struct f_path_mask *tt;
  for (tt = t; tt; tt = tt->next) {
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
    if (tt->kind == PM_ASN_EXPR) {
      struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
      mrv->a1.p = t;
      return mrv;
    }
  }

  NEW_F_VAL;
  val->type = T_PATH_MASK;
  val->val.path_mask = t;

  struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT);
  rv->a1.p = val;

  return rv;
}
341 342


343 344
CF_DECLS

Pavel Machek's avatar
Pavel Machek committed
345
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
346
	ACCEPT, REJECT, ERROR, QUITBIRD,
347 348
	INT, BOOL, IP, PREFIX, PAIR, QUAD, EC, LC,
	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
349
	IF, THEN, ELSE, CASE,
350
	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
351 352
	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
	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

364 365 366
%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
%type <fda> dynamic_attr
%type <fsa> static_attr
367
%type <f> filter filter_body where_filter
368 369 370
%type <i> type break_command ec_kind
%type <i32> cnum
%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
Ondřej Zajíček's avatar
Ondřej Zajíček committed
373
%type <s> decls declsn one_decl function_params
374
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
375 376 377

CF_GRAMMAR

378 379
CF_ADDTO(conf, filter_def)
filter_def:
380 381 382
   FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
     filter_body {
     $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 390 391 392 393
CF_ADDTO(conf, filter_eval)
filter_eval:
   EVAL term { f_eval_int($2); }
 ;

394 395 396 397 398 399
type:
   INT { $$ = T_INT; }
 | BOOL { $$ = T_BOOL; }
 | IP { $$ = T_IP; }
 | PREFIX { $$ = T_PREFIX; }
 | PAIR { $$ = T_PAIR; }
400
 | QUAD { $$ = T_QUAD; }
401
 | EC { $$ = T_EC; }
402
 | LC { $$ = T_LC; }
403
 | STRING { $$ = T_STRING; }
404 405 406
 | BGPMASK { $$ = T_PATH_MASK; }
 | BGPPATH { $$ = T_PATH; }
 | CLIST { $$ = T_CLIST; }
407
 | ECLIST { $$ = T_ECLIST; }
408
 | LCLIST { $$ = T_LCLIST; }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
409
 | type SET {
410
	switch ($1) {
411 412
	  case T_INT:
	  case T_PAIR:
413
	  case T_QUAD:
414
	  case T_EC:
415
	  case T_LC:
416
	  case T_IP:
417 418 419 420 421 422 423
	       $$ = T_SET;
	       break;

	  case T_PREFIX:
	       $$ = T_PREFIX_SET;
	    break;

424
	  default:
Pavel Machek's avatar
Pavel Machek committed
425
		cf_error( "You can't create sets of this type." );
426
	}
427
   }
428 429
 ;

430 431
one_decl:
   type SYM {
432 433
     struct f_val * val = cfg_alloc(sizeof(struct f_val));
     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 442 443 444
/* Decls with ';' at the end */
decls: /* EMPTY */ { $$ = NULL; }
 | one_decl ';' decls {
     $$ = $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 460
     struct filter *f = cfg_alloc(sizeof(struct filter));
     f->name = NULL;
461
     f->root = $1;
462 463 464 465 466 467
     $$ = f;
   }
 ;

filter:
   SYM {
Pavel Machek's avatar
Pavel Machek committed
468
     if ($1->class != SYM_FILTER) cf_error("No such filter.");
469 470 471 472 473
     $$ = $1->def;
   }
 | filter_body
 ;

474 475 476 477 478
where_filter:
   WHERE term {
     /* Construct 'IF term THEN ACCEPT; REJECT;' */
     struct filter *f = cfg_alloc(sizeof(struct filter));
     struct f_inst *i, *acc, *rej;
479
     acc = f_new_inst(FI_PRINT_AND_DIE);	/* ACCEPT */
480 481
     acc->a1.p = NULL;
     acc->a2.i = F_ACCEPT;
482
     rej = f_new_inst(FI_PRINT_AND_DIE);	/* REJECT */
483 484
     rej->a1.p = NULL;
     rej->a2.i = F_REJECT;
485
     i = f_new_inst(FI_CONDITION);			/* IF */
486 487 488 489 490 491 492 493 494
     i->a1.p = $2;
     i->a2.p = acc;
     i->next = rej;
     f->name = NULL;
     f->root = i;
     $$ = f;
  }
 ;

495
function_params:
496
   '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
497
 | '(' ')' { $$=NULL; }
498
 ;
499

500 501
function_body:
   decls '{' cmds '}' {
502 503
     if ($1) {
       /* Prepend instruction to clear local variables */
504
       $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
505 506 507 508
       $$->a1.p = $1;
       $$->next = $3;
     } else
       $$ = $3;
509
   }
510 511 512 513
 ;

CF_ADDTO(conf, function_def)
function_def:
514 515 516 517 518
   FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
     $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
     cf_push_scope($2);
   } function_params function_body {
     $2->def = $5;
519
     $2->aux2 = $4;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
520
     DBG("Hmm, we've got one function here - %s\n", $2->name);
521
     cf_pop_scope();
522 523 524 525 526
   }
 ;

/* Programs */

527 528 529
/* Hack: $$ of cmds_int is the last node.
   $$->next of cmds_int is temporary used for the first node */

530
cmds: /* EMPTY */ { $$ = NULL; }
531 532 533 534 535
 | cmds_int { $$ = $1->next; $1->next = NULL; }
 ;

cmds_int: cmd { $$ = $1; $1->next = $1; }
 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
536 537
 ;

538
block:
539
   cmd {
540 541 542 543 544 545 546
     $$=$1;
   }
 | '{' cmds '}' {
     $$=$2;
   }
 ;

547 548 549
/*
 * Complex types, their bison value is struct f_val
 */
550
fipa:
551
   IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
552 553
 ;

554 555 556 557 558 559 560 561 562


/*
 * Set constants. They are also used in switch cases. We use separate
 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
 * to elude a collision between symbol (in expr) in set_atom and symbol
 * as a function call in switch case cmds.
 */

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 569 570 571 572 573 574 575 576
 | '(' term ')' {
     $$ = f_eval($2, cfg_mem);
     if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
   }
 | SYM {
     if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
     if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
     $$ = *(struct f_val *)($1->def);
   }
577
 ;
578

579 580 581 582 583 584 585 586
switch_atom:
   NUM   { $$.type = T_INT; $$.val.i = $1; }
 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
 | fipa  { $$ = $1; }
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
 ;

587 588
cnum:
   term { $$ = f_eval_int($1); }
589 590

pair_item:
591 592 593 594 595 596 597 598 599 600 601
   '(' cnum ',' cnum ')'		{ $$ = f_new_pair_item($2, $2, $4, $4); }
 | '(' cnum ',' cnum DDOT cnum ')'	{ $$ = f_new_pair_item($2, $2, $4, $6); }
 | '(' cnum ',' '*' ')'			{ $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
 | '(' cnum DDOT cnum ',' cnum ')'	{ $$ = f_new_pair_set($2, $4, $6, $6); }
 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
 | '(' cnum DDOT cnum ',' '*' ')'	{ $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
 | '(' '*' ',' cnum ')'			{ $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
 | '(' '*' ',' cnum DDOT cnum ')'	{ $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
 | '(' '*' ',' '*' ')'			{ $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
   { $$ = f_new_pair_item($2, $8, $4, $10); }
602 603
 ;

604 605 606 607 608 609 610 611
ec_kind:
   RT { $$ = EC_RT; }
 | RO { $$ = EC_RO; }
 | UNKNOWN NUM { $$ = $2; }
 | GENERIC { $$ = EC_GENERIC; }
 ;

ec_item:
612 613 614
   '(' ec_kind ',' cnum ',' cnum ')'		{ $$ = f_new_ec_item($2, 0, $4, $6, $6); }
 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')'	{ $$ = f_new_ec_item($2, 0, $4, $6, $8); }
 | '(' ec_kind ',' cnum ',' '*' ')'		{ $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
615 616
 ;

617 618 619 620 621 622 623 624 625 626 627 628
lc_item:
   '(' cnum ',' cnum ',' cnum ')'	    { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
 | '(' cnum ',' cnum ',' '*' ')'	    { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
 | '(' cnum ',' cnum DDOT cnum ',' '*' ')'  { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
 | '(' cnum ',' '*' ',' '*' ')'		    { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
 | '(' cnum DDOT cnum ',' '*' ',' '*' ')'   { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
 | '(' '*' ',' '*' ',' '*' ')'		    { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
   { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
;

629 630
set_item:
   pair_item
631
 | ec_item
632
 | lc_item
633 634 635 636 637 638
 | set_atom { $$ = f_new_item($1, $1); }
 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
 ;

switch_item:
   pair_item
639
 | ec_item
640
 | lc_item
641 642 643 644
 | switch_atom { $$ = f_new_item($1, $1); }
 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
 ;

645
set_items:
646 647 648 649 650 651 652
   set_item
 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
 ;

switch_items:
   switch_item
 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
653 654
 ;

655 656 657 658 659 660 661 662 663 664 665
fprefix_s:
   IPA '/' NUM %prec '/' {
     if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
     $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
   }
 ;

fprefix:
   fprefix_s { $$ = $1; }
 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
666
 | fprefix_s '{' NUM ',' NUM '}' {
667 668 669 670 671 672
     if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
     $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
   }
 ;

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
 ;

Pavel Machek's avatar
Pavel Machek committed
677
switch_body: /* EMPTY */ { $$ = NULL; }
678 679 680 681 682 683
 | switch_body switch_items ':' cmds  {
     /* Fill data fields */
     struct f_tree *t;
     for (t = $2; t; t = t->left)
       t->data = $4;
     $$ = f_merge_items($1, $2);
Pavel Machek's avatar
Pavel Machek committed
684
   }
Ondřej Zajíček's avatar
Ondřej Zajíček committed
685
 | switch_body ELSECOL cmds {
686 687 688 689 690 691
     struct f_tree *t = f_new_tree();
     t->from.type = t->to.type = T_VOID;
     t->right = t;
     t->data = $3;
     $$ = f_merge_items($1, t);
 }
Pavel Machek's avatar
Pavel Machek committed
692
 ;
693

694
/* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
Pavel Machek's avatar
Pavel Machek committed
695

696
bgp_path_expr:
Ondřej Zajíček's avatar
Ondřej Zajíček committed
697
   symbol       { $$ = $1; }
698 699 700
 | '(' term ')' { $$ = $2; }
 ;

701
bgp_path:
702
   PO  bgp_path_tail1 PC  { $$ = $2; }
703 704 705 706
 | '/' bgp_path_tail2 '/' { $$ = $2; }
 ;

bgp_path_tail1:
707 708 709 710 711 712
   NUM bgp_path_tail1		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
 | NUM DDOT NUM bgp_path_tail1	{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
 | '*' bgp_path_tail1		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
 | '?' bgp_path_tail1		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
 | bgp_path_expr bgp_path_tail1	{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
 | 				{ $$ = NULL; }
713
 ;
714

715
bgp_path_tail2:
716 717
   NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
 | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
718
 | 		      { $$ = NULL; }
719 720
 ;

721
constant:
722 723 724 725 726 727 728 729 730 731
   NUM    { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT;  $$->a2.i = $1; }
 | TRUE   { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1;  }
 | FALSE  { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0;  }
 | TEXT   { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
 | fipa	   { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
 | fprefix_s {NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
 | RTRID  { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_QUAD;  $$->a2.i = $1; }
 | '[' 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" ); }
 | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET;  $$->a2.p = $2; }
 | ENUM	  { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
732 733
 ;

734
constructor:
735 736
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
737
 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
738
 | bgp_path { $$ = f_generate_path_mask($1); }
739 740
 ;

741

742 743 744
/*
 *  Maybe there are no dynamic attributes defined by protocols.
 *  For such cases, we force the dynamic_attr list to contain
745
 *  at least an invalid token, so it is syntantically correct.
746
 */
747
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = (struct f_dynamic_attr) {}; })
748

Pavel Machek's avatar
Pavel Machek committed
749
rtadot: /* EMPTY, we are not permitted RTA. prefix */
750
 ;
751

752 753 754 755 756
function_call:
   SYM '(' var_list ')' {
     struct symbol *sym;
     struct f_inst *inst = $3;
     if ($1->class != SYM_FUNCTION)
Pavel Machek's avatar
Pavel Machek committed
757
       cf_error("You can't call something which is not a function. Really.");
758
     DBG("You are calling function %s\n", $1->name);
759
     $$ = f_new_inst(FI_CALL);
760
     $$->a1.p = inst;
761 762
     $$->a2.p = $1->def;
     sym = $1->aux2;
763 764
     while (sym || inst) {
       if (!sym || !inst)
Pavel Machek's avatar
Pavel Machek committed
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 770 771 772 773
       inst = inst->next;
     }
   }
 ;

774 775
symbol:
   SYM {
776
     switch ($1->class & 0xff00) {
777 778
       case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
       case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
779
       default: cf_error("%s: variable expected.", $1->name);
780
     }
781 782 783

     $$->a1.p = $1->def;
     $$->a2.p = $1->name;
784 785
   }

786
static_attr:
787 788 789 790 791 792 793 794
   FROM    { $$ = f_new_static_attr(T_IP,         SA_FROM,	1); }
 | GW      { $$ = f_new_static_attr(T_IP,         SA_GW,	1); }
 | NET     { $$ = f_new_static_attr(T_PREFIX,     SA_NET,	0); }
 | PROTO   { $$ = f_new_static_attr(T_STRING,     SA_PROTO,	0); }
 | SOURCE  { $$ = f_new_static_attr(T_ENUM_RTS,   SA_SOURCE,	0); }
 | SCOPE   { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE,	1); }
 | CAST    { $$ = f_new_static_attr(T_ENUM_RTC,   SA_CAST,	0); }
 | 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); }
797 798
 ;

799
term:
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
   '(' term ')'		{ $$ = $2; }
 | term '+' term	{ $$ = f_new_inst(FI_ADD);	$$->a1.p = $1; $$->a2.p = $3; }
 | term '-' term	{ $$ = f_new_inst(FI_SUBTRACT);	$$->a1.p = $1; $$->a2.p = $3; }
 | term '*' term	{ $$ = f_new_inst(FI_MULTIPLY);	$$->a1.p = $1; $$->a2.p = $3; }
 | term '/' term	{ $$ = f_new_inst(FI_DIVIDE);	$$->a1.p = $1; $$->a2.p = $3; }
 | term AND term	{ $$ = f_new_inst(FI_AND);	$$->a1.p = $1; $$->a2.p = $3; }
 | term OR  term	{ $$ = f_new_inst(FI_OR);	$$->a1.p = $1; $$->a2.p = $3; }
 | term '=' term	{ $$ = f_new_inst(FI_EQ);	$$->a1.p = $1; $$->a2.p = $3; }
 | term NEQ term	{ $$ = f_new_inst(FI_NEQ);	$$->a1.p = $1; $$->a2.p = $3; }
 | term '<' term	{ $$ = f_new_inst(FI_LT);	$$->a1.p = $1; $$->a2.p = $3; }
 | term LEQ term	{ $$ = f_new_inst(FI_LTE);	$$->a1.p = $1; $$->a2.p = $3; }
 | term '>' term	{ $$ = f_new_inst(FI_LT);	$$->a1.p = $3; $$->a2.p = $1; }
 | term GEQ term	{ $$ = f_new_inst(FI_LTE);	$$->a1.p = $3; $$->a2.p = $1; }
 | term '~' term	{ $$ = f_new_inst(FI_MATCH);	$$->a1.p = $1; $$->a2.p = $3; }
 | term NMA term	{ $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
 | '!' term		{ $$ = f_new_inst(FI_NOT);	$$->a1.p = $2; }
 | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED);	$$->a1.p = $3; }
817

818
 | symbol   { $$ = $1; }
819
 | constant { $$ = $1; }
820
 | constructor { $$ = $1; }
821

822
 | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
823

824
 | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
825

826
 | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
827

828 829 830 831 832 833
 | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
 | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
 | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
 | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
 | term '.' LAST  { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
 | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
834 835

/* Communities */
836 837 838 839
/* This causes one shift/reduce conflict
 | rtadot dynamic_attr '.' ADD '(' term ')' { }
 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
840
 | rtadot dynamic_attr '.' RESET{ }
841
*/
842

843 844 845 846 847 848 849 850
 | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
 | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
 | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
 | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
 | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
851

852 853 854
 | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
 | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }

855 856 857 858 859
/* function_call is inlined here */
 | SYM '(' var_list ')' {
     struct symbol *sym;
     struct f_inst *inst = $3;
     if ($1->class != SYM_FUNCTION)
Pavel Machek's avatar
Pavel Machek committed
860
       cf_error("You can't call something which is not a function. Really.");
861
     DBG("You are calling function %s\n", $1->name);
862
     $$ = f_new_inst(FI_CALL);
863
     $$->a1.p = inst;
864 865
     $$->a2.p = $1->def;
     sym = $1->aux2;
866 867
     while (sym || inst) {
       if (!sym || !inst)
Pavel Machek's avatar
Pavel Machek committed
868
	 cf_error("Wrong number of arguments for function %s.", $1->name);
869 870
       DBG( "You should pass parameter called %s\n", sym->name);
       inst->a1.p = sym;
871
       sym = sym->aux2;
872 873 874
       inst = inst->next;
     }
   }
875 876 877
 ;

break_command:
878 879 880 881 882 883
   QUITBIRD { $$ = F_QUITBIRD; }
 | ACCEPT { $$ = F_ACCEPT; }
 | REJECT { $$ = F_REJECT; }
 | ERROR { $$ = F_ERROR; }
 | PRINT { $$ = F_NOP; }
 | PRINTN { $$ = F_NONL; }
884 885
 ;

886
print_one:
887
   term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
888 889 890
 ;

print_list: /* EMPTY */ { $$ = NULL; }
891 892
 | print_one { $$ = $1; }
 | print_one ',' print_list {
893
     if ($1) {
894
       $1->next = $3;
895
       $$ = $1;
896
     } else $$ = $3;
897 898 899
   }
 ;

Ondřej Zajíček's avatar
Ondřej Zajíček committed
900
var_listn: term {
901
     $$ = f_new_inst(FI_SET);
902 903 904 905
     $$->a1.p = NULL;
     $$->a2.p = $1;
     $$->next = NULL;
   }
906
 | term ',' var_listn {
907
     $$ = f_new_inst(FI_SET);
908 909 910 911 912 913
     $$->a1.p = NULL;
     $$->a2.p = $1;
     $$->next = $3;
   }
 ;

914 915 916 917
var_list: /* EMPTY */ { $$ = NULL; }
 | var_listn { $$ = $1; }
 ;

918
cmd:
919
   IF term THEN block {
920
     $$ = f_new_inst(FI_CONDITION);
921 922
     $$->a1.p = $2;
     $$->a2.p = $4;
923
   }
924
 | IF term THEN block ELSE block {
925
     struct f_inst *i = f_new_inst(FI_CONDITION);
926 927
     i->a1.p = $2;
     i->a2.p = $4;
928
     $$ = f_new_inst(FI_CONDITION);
929 930
     $$->a1.p = i;
     $$->a2.p = $6;
931
   }
932
 | SYM '=' term ';' {
933
     DBG( "Ook, we'll set value\n" );
934
     if (($1->class & ~T_MASK) != SYM_VARIABLE)
Pavel Machek's avatar
Pavel Machek committed
935
       cf_error( "You may set only variables." );
936
     $$ = f_new_inst(FI_SET);
937 938
     $$->a1.p = $1;
     $$->a2.p = $3;
939
   }
940
 | RETURN term ';' {
941
     DBG( "Ook, we'll return the value\n" );
942
     $$ = f_new_inst(FI_RETURN);
943 944
     $$->a1.p = $2;
   }
945
 | rtadot dynamic_attr '=' term ';' {
946
     $$ = f_new_inst_da(FI_EA_SET, $2);
947
     $$->a1.p = $4;
948
   }
949
 | rtadot static_attr '=' term ';' {
950
     $$ = f_new_inst_sa(FI_RTA_SET, $2);
951 952 953 954 955
     if (!$$->a1.i)
       cf_error( "This static attribute is read-only.");
     $$->a1.p = $4;
   }
 | PREFERENCE '=' term ';' {
956
     $$ = f_new_inst(FI_PREF_SET);
957
     $$->a1.p = $3;
Ondřej Zajíček's avatar
Ondřej Zajíček committed
958
   }
959
 | UNSET '(' rtadot dynamic_attr ')' ';' {
960
     $$ = f_new_inst_da(FI_EA_SET, $4);
961
     $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
962
     $$->a1.p = NULL;
963
   }
964
 | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
965
 | function_call ';' { $$ = $1; }
966
 | CASE term '{' switch_body '}' {
967
      $$ = f_new_inst(FI_SWITCH);
968
      $$->a1.p = $2;
Pavel Machek's avatar
Pavel Machek committed
969
      $$->a2.p = build_tree( $4 );
970
   }
971 972


973
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
974 975 976 977
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
978 979 980
 ;

CF_END