Statistics
| Branch: | Revision:

iof-bird / bird-2.0.1 / filter / config.Y @ 6b3f1a54

History | View | Annotate | Download (29.2 KB)

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 ((kind != EC_GENERIC) && (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
  /* IP->Quad implicit conversion */
236
  else if (tk->code == 'C') {
237
    c1 = 1;
238
    struct f_val *val = tk->a1.p;
239

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

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

    
260
  if (c1 && c2) {
261
    u64 ec;
262

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

    
278
    NEW_F_VAL;
279
    rv = f_new_inst();
280
    rv->code = 'C';
281
    rv->a1.p = val;
282
    val->type = T_EC;
283
    val->val.ec = ec;
284
  }
285
  else {
286
    rv = f_new_inst();
287
    rv->code = P('m','c');
288
    rv->aux = kind;
289
    rv->a1.p = tk;
290
    rv->a2.p = tv;
291
  }
292

    
293
  return rv;
294
}
295

    
296
static inline struct f_inst *
297
f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
298
{
299
  struct f_inst *rv;
300

    
301
  if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) {
302
    if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
303
      cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
304

    
305
    rv = f_new_inst();
306
    rv->code = 'C';
307

    
308
    NEW_F_VAL;
309
    rv->a1.p = val;
310
    val->type = T_LC;
311
    val->val.lc = (lcomm) { t1->a2.i, t2->a2.i, t3->a2.i };
312
  }
313
  else
314
  {
315
    rv = cfg_allocz(sizeof(struct f_inst3));
316
    rv->lineno = ifs->lino;
317
    rv->code = P('m','l');
318
    rv->a1.p = t1;
319
    rv->a2.p = t2;
320
    INST3(rv).p = t3;
321
  }
322

    
323
  return rv;
324
}
325

    
326
/*
327
 * Remove all new lines and doubled whitespaces
328
 * and convert all tabulators to spaces
329
 * and return a copy of string
330
 */
331
char *
332
assert_copy_expr(const char *start, size_t len)
333
{
334
  /* XXX: Allocates maybe a little more memory than we really finally need */
335
  char *str = cfg_alloc(len + 1);
336

    
337
  char *dst = str;
338
  const char *src = start - 1;
339
  const char *end = start + len;
340
  while (++src < end)
341
  {
342
    if (*src == '\n')
343
      continue;
344

    
345
    /* Skip doubled whitespaces */
346
    if (src != start)
347
    {
348
      const char *prev = src - 1;
349
      if ((*src == ' ' || *src == '\t') && (*prev == ' ' || *prev == '\t'))
350
	continue;
351
    }
352

    
353
    if (*src == '\t')
354
      *dst = ' ';
355
    else
356
      *dst = *src;
357

    
358
    dst++;
359
  }
360
  *dst = '\0';
361

    
362
  return str;
363
}
364

    
365
/*
366
 * assert_done - create f_instruction of bt_assert
367
 * @expr: expression in bt_assert()
368
 * @start: pointer to first char of test expression
369
 * @end: pointer to the last char of test expression
370
 */
371
static struct f_inst *
372
assert_done(struct f_inst *expr, const char *start, const char *end)
373
{
374
  struct f_inst *i;
375
  i = f_new_inst();
376
  i->code = P('a','s');
377
  i->a1.p = expr;
378

    
379
  if (end >= start)
380
  {
381
    i->a2.p = assert_copy_expr(start, end - start + 1);
382
  }
383
  else
384
  {
385
    /* this is a break of lexer buffer */
386
    i->a2.p = "???";
387
  }
388

    
389
  return i;
390
}
391

    
392
CF_DECLS
393

    
394
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
395
	ACCEPT, REJECT, ERROR, QUITBIRD,
396
	INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
397
	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
398
	IF, THEN, ELSE, CASE,
399
	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
400
	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
401
	PREFERENCE,
402
	ROA_CHECK, ASN,
403
	IS_V4, IS_V6,
404
	LEN, MAXLEN,
405
	DEFINED,
406
	ADD, DELETE, CONTAINS, RESET,
407
	PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
408
	EMPTY,
409
	FILTER, WHERE, EVAL,
410
	BT_ASSERT, BT_TEST_SUITE, FORMAT)
411

    
412
%nonassoc THEN
413
%nonassoc ELSE
414

    
415
%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
416
%type <f> filter filter_body where_filter
417
%type <i> type break_command ec_kind
418
%type <i32> cnum
419
%type <e> pair_item ec_item lc_item set_item switch_item set_items switch_items switch_body
420
%type <trie> fprefix_set
421
%type <v> set_atom switch_atom fipa
422
%type <px> fprefix
423
%type <s> decls declsn one_decl function_params
424
%type <h> bgp_path bgp_path_tail
425
%type <t> get_cf_position
426

    
427
CF_GRAMMAR
428

    
429
CF_ADDTO(conf, filter_def)
430
filter_def:
431
   FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
432
     filter_body {
433
     $2->def = $4;
434
     $4->name = $2->name;
435
     DBG( "We have new filter defined (%s)\n", $2->name );
436
     cf_pop_scope();
437
   }
438
 ;
439

    
440
CF_ADDTO(conf, filter_eval)
441
filter_eval:
442
   EVAL term { f_eval_int($2); }
443
 ;
444

    
445
CF_ADDTO(conf, bt_test_suite)
446
bt_test_suite:
447
 BT_TEST_SUITE '(' SYM ',' text ')' {
448
  if (!($3->class & SYM_FUNCTION))
449
    cf_error("Function expected");
450

    
451
  struct f_bt_test_suite *t = cfg_alloc(sizeof(struct f_bt_test_suite));
452
  t->fn = $3->def;
453
  t->fn_name = $3->name;
454
  t->dsc = $5;
455

    
456
  add_tail(&new_config->tests, &t->n);
457
 }
458
 ;
459

    
460
type:
461
   INT { $$ = T_INT; }
462
 | BOOL { $$ = T_BOOL; }
463
 | IP { $$ = T_IP; }
464
 | RD { $$ = T_RD; }
465
 | PREFIX { $$ = T_NET; }
466
 | PAIR { $$ = T_PAIR; }
467
 | QUAD { $$ = T_QUAD; }
468
 | EC { $$ = T_EC; }
469
 | LC { $$ = T_LC; }
470
 | STRING { $$ = T_STRING; }
471
 | BGPMASK { $$ = T_PATH_MASK; }
472
 | BGPPATH { $$ = T_PATH; }
473
 | CLIST { $$ = T_CLIST; }
474
 | ECLIST { $$ = T_ECLIST; }
475
 | LCLIST { $$ = T_LCLIST; }
476
 | type SET {
477
	switch ($1) {
478
	  case T_INT:
479
	  case T_PAIR:
480
	  case T_QUAD:
481
	  case T_EC:
482
	  case T_LC:
483
	  case T_IP:
484
	       $$ = T_SET;
485
	       break;
486

    
487
	  case T_NET:
488
	       $$ = T_PREFIX_SET;
489
	    break;
490

    
491
	  default:
492
		cf_error( "You can't create sets of this type." );
493
	}
494
   }
495
 ;
496

    
497
one_decl:
498
   type SYM {
499
     struct f_val * val = cfg_alloc(sizeof(struct f_val));
500
     val->type = T_VOID;
501
     $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
502
     DBG( "New variable %s type %x\n", $2->name, $1 );
503
     $2->aux2 = NULL;
504
     $$=$2;
505
   }
506
 ;
507

    
508
/* Decls with ';' at the end */
509
decls: /* EMPTY */ { $$ = NULL; }
510
 | one_decl ';' decls {
511
     $$ = $1;
512
     $$->aux2 = $3;
513
   }
514
 ;
515

    
516
/* Declarations that have no ';' at the end. */
517
declsn: one_decl { $$ = $1; }
518
 | one_decl ';' declsn {
519
     $$ = $1;
520
     $$->aux2 = $3;
521
   }
522
 ;
523

    
524
filter_body:
525
   function_body {
526
     struct filter *f = cfg_alloc(sizeof(struct filter));
527
     f->name = NULL;
528
     f->root = $1;
529
     $$ = f;
530
   }
531
 ;
532

    
533
filter:
534
   SYM {
535
     if ($1->class != SYM_FILTER) cf_error("No such filter.");
536
     $$ = $1->def;
537
   }
538
 | filter_body
539
 ;
540

    
541
where_filter:
542
   WHERE term {
543
     /* Construct 'IF term THEN ACCEPT; REJECT;' */
544
     struct filter *f = cfg_alloc(sizeof(struct filter));
545
     struct f_inst *i, *acc, *rej;
546
     acc = f_new_inst();		/* ACCEPT */
547
     acc->code = P('p',',');
548
     acc->a1.p = NULL;
549
     acc->a2.i = F_ACCEPT;
550
     rej = f_new_inst();		/* REJECT */
551
     rej->code = P('p',',');
552
     rej->a1.p = NULL;
553
     rej->a2.i = F_REJECT;
554
     i = f_new_inst();			/* IF */
555
     i->code = '?';
556
     i->a1.p = $2;
557
     i->a2.p = acc;
558
     i->next = rej;
559
     f->name = NULL;
560
     f->root = i;
561
     $$ = f;
562
  }
563
 ;
564

    
565
function_params:
566
   '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
567
 | '(' ')' { $$=NULL; }
568
 ;
569

    
570
function_body:
571
   decls '{' cmds '}' {
572
     if ($1) {
573
       /* Prepend instruction to clear local variables */
574
       $$ = f_new_inst();
575
       $$->code = P('c','v');
576
       $$->a1.p = $1;
577
       $$->next = $3;
578
     } else
579
       $$ = $3;
580
   }
581
 ;
582

    
583
CF_ADDTO(conf, function_def)
584
function_def:
585
   FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
586
     $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
587
     cf_push_scope($2);
588
   } function_params function_body {
589
     $2->def = $5;
590
     $2->aux2 = $4;
591
     DBG("Hmm, we've got one function here - %s\n", $2->name);
592
     cf_pop_scope();
593
   }
594
 ;
595

    
596
/* Programs */
597

    
598
/* Hack: $$ of cmds_int is the last node.
599
   $$->next of cmds_int is temporary used for the first node */
600

    
601
cmds: /* EMPTY */ { $$ = NULL; }
602
 | cmds_int { $$ = $1->next; $1->next = NULL; }
603
 ;
604

    
605
cmds_int: cmd { $$ = $1; $1->next = $1; }
606
 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
607
 ;
608

    
609
block:
610
   cmd {
611
     $$=$1;
612
   }
613
 | '{' cmds '}' {
614
     $$=$2;
615
   }
616
 ;
617

    
618
/*
619
 * Complex types, their bison value is struct f_val
620
 */
621
fipa:
622
   IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
623
 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
624
 ;
625

    
626

    
627

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

    
635
set_atom:
636
   NUM   { $$.type = T_INT; $$.val.i = $1; }
637
 | fipa  { $$ = $1; }
638
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
639
 | '(' term ')' {
640
     $$ = f_eval($2, cfg_mem);
641
     if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
642
   }
643
 | SYM {
644
     if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
645
     if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
646
     $$ = *(struct f_val *)($1->def);
647
   }
648
 ;
649

    
650
switch_atom:
651
   NUM   { $$.type = T_INT; $$.val.i = $1; }
652
 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
653
 | fipa  { $$ = $1; }
654
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
655
 ;
656

    
657
cnum:
658
   term { $$ = f_eval_int($1); }
659

    
660
pair_item:
661
   '(' cnum ',' cnum ')'		{ $$ = f_new_pair_item($2, $2, $4, $4); }
662
 | '(' cnum ',' cnum DDOT cnum ')'	{ $$ = f_new_pair_item($2, $2, $4, $6); }
663
 | '(' cnum ',' '*' ')'			{ $$ = f_new_pair_item($2, $2, 0, CC_ALL); }
664
 | '(' cnum DDOT cnum ',' cnum ')'	{ $$ = f_new_pair_set($2, $4, $6, $6); }
665
 | '(' cnum DDOT cnum ',' cnum DDOT cnum ')' { $$ = f_new_pair_set($2, $4, $6, $8); }
666
 | '(' cnum DDOT cnum ',' '*' ')'	{ $$ = f_new_pair_item($2, $4, 0, CC_ALL); }
667
 | '(' '*' ',' cnum ')'			{ $$ = f_new_pair_set(0, CC_ALL, $4, $4); }
668
 | '(' '*' ',' cnum DDOT cnum ')'	{ $$ = f_new_pair_set(0, CC_ALL, $4, $6); }
669
 | '(' '*' ',' '*' ')'			{ $$ = f_new_pair_item(0, CC_ALL, 0, CC_ALL); }
670
 | '(' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ')'
671
   { $$ = f_new_pair_item($2, $8, $4, $10); }
672
 ;
673

    
674
ec_kind:
675
   RT { $$ = EC_RT; }
676
 | RO { $$ = EC_RO; }
677
 | UNKNOWN NUM { $$ = $2; }
678
 | GENERIC { $$ = EC_GENERIC; }
679
 ;
680

    
681
ec_item:
682
   '(' ec_kind ',' cnum ',' cnum ')'		{ $$ = f_new_ec_item($2, 0, $4, $6, $6); }
683
 | '(' ec_kind ',' cnum ',' cnum DDOT cnum ')'	{ $$ = f_new_ec_item($2, 0, $4, $6, $8); }
684
 | '(' ec_kind ',' cnum ',' '*' ')'		{ $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
685
 ;
686

    
687
lc_item:
688
   '(' cnum ',' cnum ',' cnum ')'	    { $$ = f_new_lc_item($2, $2, $4, $4, $6, $6); }
689
 | '(' cnum ',' cnum ',' cnum DDOT cnum ')' { $$ = f_new_lc_item($2, $2, $4, $4, $6, $8); }
690
 | '(' cnum ',' cnum ',' '*' ')'	    { $$ = f_new_lc_item($2, $2, $4, $4, 0, LC_ALL); }
691
 | '(' cnum ',' cnum DDOT cnum ',' '*' ')'  { $$ = f_new_lc_item($2, $2, $4, $6, 0, LC_ALL); }
692
 | '(' cnum ',' '*' ',' '*' ')'		    { $$ = f_new_lc_item($2, $2, 0, LC_ALL, 0, LC_ALL); }
693
 | '(' cnum DDOT cnum ',' '*' ',' '*' ')'   { $$ = f_new_lc_item($2, $4, 0, LC_ALL, 0, LC_ALL); }
694
 | '(' '*' ',' '*' ',' '*' ')'		    { $$ = f_new_lc_item(0, LC_ALL, 0, LC_ALL, 0, LC_ALL); }
695
 | '(' cnum ',' cnum ',' cnum ')' DDOT '(' cnum ',' cnum ',' cnum ')'
696
   { $$ = f_new_lc_item($2, $10, $4, $12, $6, $14); }
697
;
698

    
699
set_item:
700
   pair_item
701
 | ec_item
702
 | lc_item
703
 | set_atom { $$ = f_new_item($1, $1); }
704
 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
705
 ;
706

    
707
switch_item:
708
   pair_item
709
 | ec_item
710
 | lc_item
711
 | switch_atom { $$ = f_new_item($1, $1); }
712
 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
713
 ;
714

    
715
set_items:
716
   set_item
717
 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
718
 ;
719

    
720
switch_items:
721
   switch_item
722
 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
723
 ;
724

    
725
fprefix:
726
   net_ip_	{ $$.net = $1; $$.lo = $1.pxlen; $$.hi = $1.pxlen; }
727
 | net_ip_ '+'	{ $$.net = $1; $$.lo = $1.pxlen; $$.hi = net_max_prefix_length[$1.type]; }
728
 | net_ip_ '-'	{ $$.net = $1; $$.lo = 0; $$.hi = $1.pxlen; }
729
 | net_ip_ '{' NUM ',' NUM '}' {
730
     $$.net = $1; $$.lo = $3; $$.hi = $5;
731
     if (($3 > $5) || ($5 > net_max_prefix_length[$1.type]))
732
       cf_error("Invalid prefix pattern range: {%u, %u}", $3, $5);
733
   }
734
 ;
735

    
736
fprefix_set:
737
   fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
738
 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
739
 ;
740

    
741
switch_body: /* EMPTY */ { $$ = NULL; }
742
 | switch_body switch_items ':' cmds  {
743
     /* Fill data fields */
744
     struct f_tree *t;
745
     for (t = $2; t; t = t->left)
746
       t->data = $4;
747
     $$ = f_merge_items($1, $2);
748
   }
749
 | switch_body ELSECOL cmds {
750
     struct f_tree *t = f_new_tree();
751
     t->from.type = t->to.type = T_VOID;
752
     t->right = t;
753
     t->data = $3;
754
     $$ = f_merge_items($1, t);
755
 }
756
 ;
757

    
758
/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
759

    
760
bgp_path_expr:
761
   symbol       { $$ = $1; }
762
 | '(' term ')' { $$ = $2; }
763
 ;
764

    
765
bgp_path:
766
   PO  bgp_path_tail PC  { $$ = $2; }
767
 ;
768

    
769
bgp_path_tail:
770
   NUM bgp_path_tail		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
771
 | NUM DDOT NUM bgp_path_tail	{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
772
 | '*' bgp_path_tail		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
773
 | '?' bgp_path_tail		{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
774
 | bgp_path_expr bgp_path_tail	{ $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
775
 | 				{ $$ = NULL; }
776
 ;
777

    
778
constant:
779
   NUM    { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT;  $$->a2.i = $1; }
780
 | TRUE   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1;  }
781
 | FALSE  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0;  }
782
 | TEXT   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
783
 | fipa	  { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
784
 | VPN_RD { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
785
 | net_   { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
786
 | '[' 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" ); }
787
 | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET;  $$->a2.p = $2; }
788
 | ENUM	  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
789
 | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
790
 ;
791

    
792
constructor:
793
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
794
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
795
 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
796
 ;
797

    
798

    
799
/*
800
 *  Maybe there are no dynamic attributes defined by protocols.
801
 *  For such cases, we force the dynamic_attr list to contain
802
 *  at least an invalid token, so it is syntantically correct.
803
 */
804
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
805

    
806
rtadot: /* EMPTY, we are not permitted RTA. prefix */
807
 ;
808

    
809
function_call:
810
   SYM '(' var_list ')' {
811
     struct symbol *sym;
812
     struct f_inst *inst = $3;
813
     if ($1->class != SYM_FUNCTION)
814
       cf_error("You can't call something which is not a function. Really.");
815
     DBG("You are calling function %s\n", $1->name);
816
     $$ = f_new_inst();
817
     $$->code = P('c','a');
818
     $$->a1.p = inst;
819
     $$->a2.p = $1->def;
820
     sym = $1->aux2;
821
     while (sym || inst) {
822
       if (!sym || !inst)
823
	 cf_error("Wrong number of arguments for function %s.", $1->name);
824
       DBG( "You should pass parameter called %s\n", sym->name);
825
       inst->a1.p = sym;
826
       sym = sym->aux2;
827
       inst = inst->next;
828
     }
829
   }
830
 ;
831

    
832
symbol:
833
   SYM {
834
     $$ = f_new_inst();
835

    
836
     switch ($1->class & 0xff00) {
837
       case SYM_CONSTANT: $$->code = 'C'; break;
838
       case SYM_VARIABLE: $$->code = 'V'; break;
839
       default: cf_error("%s: variable expected.", $1->name);
840
     }
841

    
842
     $$->a1.p = $1->def;
843
     $$->a2.p = $1->name;
844
   }
845

    
846
static_attr:
847
   FROM    { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_FROM;	$$->a1.i = 1; }
848
 | GW      { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_GW;	$$->a1.i = 1; }
849
 | NET     { $$ = f_new_inst(); $$->aux = T_NET;        $$->a2.i = SA_NET; }
850
 | PROTO   { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = SA_PROTO; }
851
 | SOURCE  { $$ = f_new_inst(); $$->aux = T_ENUM_RTS;   $$->a2.i = SA_SOURCE; }
852
 | SCOPE   { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE;	$$->a1.i = 1; }
853
 | DEST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTD;   $$->a2.i = SA_DEST;	$$->a1.i = 1; }
854
 | IFNAME  { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = SA_IFNAME; }
855
 | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT;        $$->a2.i = SA_IFINDEX; }
856
 ;
857

    
858
term:
859
   '(' term ')'      { $$ = $2; }
860
 | term '+' term     { $$ = f_new_inst(); $$->code = '+';        $$->a1.p = $1; $$->a2.p = $3; }
861
 | term '-' term     { $$ = f_new_inst(); $$->code = '-';        $$->a1.p = $1; $$->a2.p = $3; }
862
 | term '*' term     { $$ = f_new_inst(); $$->code = '*';        $$->a1.p = $1; $$->a2.p = $3; }
863
 | term '/' term     { $$ = f_new_inst(); $$->code = '/';        $$->a1.p = $1; $$->a2.p = $3; }
864
 | term AND term     { $$ = f_new_inst(); $$->code = '&';        $$->a1.p = $1; $$->a2.p = $3; }
865
 | term OR  term     { $$ = f_new_inst(); $$->code = '|';        $$->a1.p = $1; $$->a2.p = $3; }
866
 | term '=' term     { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
867
 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','=');     $$->a1.p = $1; $$->a2.p = $3; }
868
 | term '<' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $1; $$->a2.p = $3; }
869
 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $1; $$->a2.p = $3; }
870
 | term '>' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $3; $$->a2.p = $1; }
871
 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $3; $$->a2.p = $1; }
872
 | term '~' term     { $$ = f_new_inst(); $$->code = '~';        $$->a1.p = $1; $$->a2.p = $3; }
873
 | term NMA term { $$ = f_new_inst(); $$->code = P('!','~');     $$->a1.p = $1; $$->a2.p = $3; }
874
 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
875
 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e');  $$->a1.p = $3; }
876

    
877
 | symbol   { $$ = $1; }
878
 | constant { $$ = $1; }
879
 | constructor { $$ = $1; }
880

    
881
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
882

    
883
 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
884

    
885
 | rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); }
886

    
887
 | term '.' IS_V4 { $$ = f_new_inst(); $$->code = P('I','i'); $$->a1.p = $1; }
888
 | term '.' TYPE { $$ = f_new_inst(); $$->code = 'T'; $$->a1.p = $1; }
889
 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
890
 | term '.' RD { $$ = f_new_inst(); $$->code = P('R','D'); $$->a1.p = $1; $$->aux = T_RD; }
891
 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
892
 | term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; }
893
 | term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; }
894
 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
895
 | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
896
 | term '.' LAST  { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
897
 | term '.' LAST_NONAGGREGATED  { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; }
898

    
899
/* Communities */
900
/* This causes one shift/reduce conflict
901
 | rtadot dynamic_attr '.' ADD '(' term ')' { }
902
 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
903
 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
904
 | rtadot dynamic_attr '.' RESET{ }
905
*/
906

    
907
 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
908
 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
909
 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
910
 | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; }
911
 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; }
912
 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
913
 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
914
 | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
915

    
916
 | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
917
 | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
918

    
919
 | FORMAT '(' term ')' {  $$ = f_new_inst(); $$->code = P('f','m'); $$->a1.p = $3; }
920

    
921
/* | term '.' LEN { $$->code = P('P','l'); } */
922

    
923
/* function_call is inlined here */
924
 | SYM '(' var_list ')' {
925
     struct symbol *sym;
926
     struct f_inst *inst = $3;
927
     if ($1->class != SYM_FUNCTION)
928
       cf_error("You can't call something which is not a function. Really.");
929
     DBG("You are calling function %s\n", $1->name);
930
     $$ = f_new_inst();
931
     $$->code = P('c','a');
932
     $$->a1.p = inst;
933
     $$->a2.p = $1->def;
934
     sym = $1->aux2;
935
     while (sym || inst) {
936
       if (!sym || !inst)
937
	 cf_error("Wrong number of arguments for function %s.", $1->name);
938
       DBG( "You should pass parameter called %s\n", sym->name);
939
       inst->a1.p = sym;
940
       sym = sym->aux2;
941
       inst = inst->next;
942
     }
943
   }
944
 ;
945

    
946
break_command:
947
   QUITBIRD { $$ = F_QUITBIRD; }
948
 | ACCEPT { $$ = F_ACCEPT; }
949
 | REJECT { $$ = F_REJECT; }
950
 | ERROR { $$ = F_ERROR; }
951
 | PRINT { $$ = F_NOP; }
952
 | PRINTN { $$ = F_NONL; }
953
 ;
954

    
955
print_one:
956
   term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
957
 ;
958

    
959
print_list: /* EMPTY */ { $$ = NULL; }
960
 | print_one { $$ = $1; }
961
 | print_one ',' print_list {
962
     if ($1) {
963
       $1->next = $3;
964
       $$ = $1;
965
     } else $$ = $3;
966
   }
967
 ;
968

    
969
var_listn: term {
970
     $$ = f_new_inst();
971
     $$->code = 's';
972
     $$->a1.p = NULL;
973
     $$->a2.p = $1;
974
     $$->next = NULL;
975
   }
976
 | term ',' var_listn {
977
     $$ = f_new_inst();
978
     $$->code = 's';
979
     $$->a1.p = NULL;
980
     $$->a2.p = $1;
981
     $$->next = $3;
982
   }
983
 ;
984

    
985
var_list: /* EMPTY */ { $$ = NULL; }
986
 | var_listn { $$ = $1; }
987
 ;
988

    
989
cmd:
990
   IF term THEN block {
991
     $$ = f_new_inst();
992
     $$->code = '?';
993
     $$->a1.p = $2;
994
     $$->a2.p = $4;
995
   }
996
 | IF term THEN block ELSE block {
997
     struct f_inst *i = f_new_inst();
998
     i->code = '?';
999
     i->a1.p = $2;
1000
     i->a2.p = $4;
1001
     $$ = f_new_inst();
1002
     $$->code = '?';
1003
     $$->a1.p = i;
1004
     $$->a2.p = $6;
1005
   }
1006
 | SYM '=' term ';' {
1007
     $$ = f_new_inst();
1008
     DBG( "Ook, we'll set value\n" );
1009
     if (($1->class & ~T_MASK) != SYM_VARIABLE)
1010
       cf_error( "You may set only variables." );
1011
     $$->code = 's';
1012
     $$->a1.p = $1;
1013
     $$->a2.p = $3;
1014
   }
1015
 | RETURN term ';' {
1016
     $$ = f_new_inst();
1017
     DBG( "Ook, we'll return the value\n" );
1018
     $$->code = 'r';
1019
     $$->a1.p = $2;
1020
   }
1021
 | rtadot dynamic_attr '=' term ';' {
1022
     $$ = $2;
1023
     $$->code = P('e','S');
1024
     $$->a1.p = $4;
1025
   }
1026
 | rtadot static_attr '=' term ';' {
1027
     $$ = $2;
1028
     if (!$$->a1.i)
1029
       cf_error( "This static attribute is read-only.");
1030
     $$->code = P('a','S');
1031
     $$->a1.p = $4;
1032
   }
1033
 | PREFERENCE '=' term ';' {
1034
     $$ = f_new_inst();
1035
     $$->code = P('P','S');
1036
     $$->a1.p = $3;
1037
   }
1038
 | UNSET '(' rtadot dynamic_attr ')' ';' {
1039
     $$ = $4;
1040
     $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
1041
     $$->code = P('e','S');
1042
     $$->a1.p = NULL;
1043
   }
1044
 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
1045
 | function_call ';' { $$ = $1; }
1046
 | CASE term '{' switch_body '}' {
1047
      $$ = f_new_inst();
1048
      $$->code = P('S','W');
1049
      $$->a1.p = $2;
1050
      $$->a2.p = build_tree( $4 );
1051
   }
1052

    
1053
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
1054
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
1055
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
1056
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
1057
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
1058
 | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
1059
 ;
1060

    
1061
get_cf_position:
1062
{
1063
  $$ = cf_text;
1064
};
1065

    
1066

    
1067
CF_END