Statistics
| Branch: | Revision:

iof-bird-daemon / filter / config.Y @ 9b0a0ba9

History | View | Annotate | Download (29 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 (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, PREFIX, 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, CAST, DEST, IFNAME, IFINDEX,
401
	PREFERENCE,
402
	ROA_CHECK,
403
	LEN,
404
	DEFINED,
405
	ADD, DELETE, CONTAINS, RESET,
406
	PREPEND, FIRST, LAST, LAST_NONAGGREGATED, MATCH,
407
	EMPTY,
408
	FILTER, WHERE, EVAL,
409
	BT_ASSERT, BT_TEST_SUITE)
410

    
411
%nonassoc THEN
412
%nonassoc ELSE
413

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

    
426
CF_GRAMMAR
427

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

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

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

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

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

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

    
485
	  case T_NET:
486
	       $$ = T_PREFIX_SET;
487
	    break;
488

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

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

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

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

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

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

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

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

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

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

    
594
/* Programs */
595

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

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

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

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

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

    
624

    
625

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

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

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

    
655
cnum:
656
   term { $$ = f_eval_int($1); }
657

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

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

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

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

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

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

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

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

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

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

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

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

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

    
763
bgp_path:
764
   PO  bgp_path_tail1 PC  { $$ = $2; }
765
 | '/' bgp_path_tail2 '/' { $$ = $2; }
766
 ;
767

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

    
777
bgp_path_tail2:
778
   NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
779
 | '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
780
 | 		      { $$ = NULL; }
781
 ;
782

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

    
796
constructor:
797
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
798
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
799
 | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
800
 ;
801

    
802

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

    
810
rtadot: /* EMPTY, we are not permitted RTA. prefix */
811
 ;
812

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

    
836
symbol:
837
   SYM {
838
     $$ = f_new_inst();
839

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

    
846
     $$->a1.p = $1->def;
847
     $$->a2.p = $1->name;
848
   }
849

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

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

    
882
 | symbol   { $$ = $1; }
883
 | constant { $$ = $1; }
884
 | constructor { $$ = $1; }
885

    
886
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
887

    
888
 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
889

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

    
892
 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
893
 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->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
 | bt_assert { $$ = $1; }
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
 | bt_assert ';' { $$ = $1; }
1053

    
1054

    
1055
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
1056
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
1057
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
1058
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
1059
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
1060
 ;
1061

    
1062
 bt_assert:
1063
   BT_ASSERT '(' get_cf_position term get_cf_position ')' { $$ = assert_done($4, $3 + 1, $5 - 1); }
1064
 ;
1065

    
1066
get_cf_position:
1067
{
1068
  $$ = cf_text;
1069
};
1070

    
1071

    
1072
CF_END