Statistics
| Branch: | Revision:

iof-bird-daemon / filter / config.Y @ 5e173e9f

History | View | Annotate | Download (24.4 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
    return 1;
40

    
41
  default:
42
    return 0;
43
  }
44
}
45

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

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

    
66
static inline struct f_tree *
67
f_new_pair_item(int fa, int ta, int fb, int tb)
68
{
69
  struct f_tree *t = f_new_tree();
70
  t->right = t;
71
  t->from.type = t->to.type = T_PAIR;
72
  t->from.val.i = pair(fa, fb);
73
  t->to.val.i = pair(ta, tb);
74
  return t;
75
}
76

    
77
static inline struct f_tree *
78
f_new_pair_set(int fa, int ta, int fb, int tb)
79
{
80
  struct f_tree *lst = NULL;
81
  int i;
82

    
83
  if ((fa == ta) || ((fb == 0) && (tb == 0xFFFF)))
84
    return f_new_pair_item(fa, ta, fb, tb);
85
  
86
  if ((ta < fa) || (tb < fb))
87
    cf_error( "From value cannot be higher that To value in pair sets");
88

    
89
  for (i = fa; i <= ta; i++)
90
    lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
91

    
92
  return lst;
93
}
94

    
95
#define EC_ALL 0xFFFFFFFF
96

    
97
static struct f_tree *
98
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
99
{
100
  u64 fm, to;
101

    
102
  if (ipv4_used || (key >= 0x10000)) {
103
    check_u16(vf);
104
    if (vt == EC_ALL)
105
      vt = 0xFFFF;
106
    else
107
      check_u16(vt);
108
  }
109

    
110
  if (kind == EC_GENERIC) {
111
    fm = ec_generic(key, vf);
112
    to = ec_generic(key, vt);
113
  }
114
  else if (ipv4_used) {
115
    fm = ec_ip4(kind, key, vf);
116
    to = ec_ip4(kind, key, vt);
117
  }
118
  else if (key < 0x10000) {
119
    fm = ec_as2(kind, key, vf);
120
    to = ec_as2(kind, key, vt);
121
  }
122
  else {
123
    fm = ec_as4(kind, key, vf);
124
    to = ec_as4(kind, key, vt);
125
  }
126

    
127
  struct f_tree *t = f_new_tree();
128
  t->right = t;
129
  t->from.type = t->to.type = T_EC;
130
  t->from.val.ec = fm;
131
  t->to.val.ec = to;
132
  return t;
133
}
134

    
135
static inline struct f_inst *
136
f_generate_empty(struct f_inst *dyn)
137
{
138
  struct f_inst *e = f_new_inst();
139
  e->code = 'E';
140

    
141
  switch (dyn->aux & EAF_TYPE_MASK) {
142
    case EAF_TYPE_AS_PATH:
143
      e->aux = T_PATH;
144
      break;
145
    case EAF_TYPE_INT_SET:
146
      e->aux = T_CLIST;
147
      break;
148
    case EAF_TYPE_EC_SET:
149
      e->aux = T_ECLIST;
150
      break;
151
    default:
152
      cf_error("Can't empty that attribute");
153
  }
154

    
155
  dyn->code = P('e','S');
156
  dyn->a1.p = e;
157
  return dyn;
158
}
159

    
160

    
161
static inline struct f_inst *
162
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
163
{
164
  struct f_inst *rv;
165

    
166
  if ((t1->code == 'c') && (t2->code == 'c')) {
167
    if ((t1->aux != T_INT) || (t2->aux != T_INT))
168
      cf_error( "Can't operate with value of non-integer type in pair constructor");
169

    
170
    check_u16(t1->a2.i);
171
    check_u16(t2->a2.i);
172

    
173
    rv = f_new_inst();
174
    rv->code = 'c';
175
    rv->aux = T_PAIR;
176
    rv->a2.i = pair(t1->a2.i, t2->a2.i);
177
  }
178
  else {
179
    rv = f_new_inst();
180
    rv->code = P('m', 'p');
181
    rv->a1.p = t1;
182
    rv->a2.p = t2;
183
  }
184

    
185
  return rv;
186
}
187

    
188
static inline struct f_inst *
189
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
190
{
191
  struct f_inst *rv;
192
  int c1 = 0, c2 = 0, ipv4_used = 0;
193
  u32 key = 0, val2 = 0;
194

    
195
  if (tk->code == 'c') {
196
    c1 = 1;
197

    
198
    if (tk->aux == T_INT) {
199
      ipv4_used = 0; key = tk->a2.i;
200
    }
201
    else if (tk->aux == T_QUAD) {
202
      ipv4_used = 1; key = tk->a2.i;
203
    }
204
    else
205
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
206
  }
207

    
208
#ifndef IPV6
209
  /* IP->Quad implicit conversion */
210
  else if (tk->code == 'C') {
211
    c1 = 1;
212
    struct f_val *val = tk->a1.p;
213

    
214
    if (val->type == T_INT) {
215
      ipv4_used = 0; key = val->val.i;
216
    }
217
    else if (val->type == T_QUAD) {
218
      ipv4_used = 1; key = val->val.i;
219
    }
220
    else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
221
      ipv4_used = 1; key = ipa_to_u32(val->val.ip);
222
    }
223
    else
224
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
225
  }
226
#endif
227

    
228
  if (tv->code == 'c') {
229
    if (tv->aux != T_INT)
230
      cf_error("Can't operate with value of non-integer type in EC constructor");
231
    c2 = 1;
232
    val2 = tv->a2.i;
233
  }
234

    
235
  if (c1 && c2) {
236
    u64 ec;
237

    
238
    if (kind == EC_GENERIC) {
239
      ec = ec_generic(key, val2);
240
    }
241
    else if (ipv4_used) {
242
      check_u16(val2);
243
      ec = ec_ip4(kind, key, val2);
244
    }
245
    else if (key < 0x10000) {
246
      ec = ec_as2(kind, key, val2);
247
    }
248
    else {
249
      check_u16(val2);
250
      ec = ec_as4(kind, key, val2);
251
    }
252

    
253
    NEW_F_VAL;
254
    rv = f_new_inst();
255
    rv->code = 'C';
256
    rv->a1.p = val;
257
    val->type = T_EC;
258
    val->val.ec = ec;
259
  }
260
  else {
261
    rv = f_new_inst();
262
    rv->code = P('m','c');
263
    rv->aux = kind;
264
    rv->a1.p = tk;
265
    rv->a2.p = tv;
266
  }
267

    
268
  return rv;
269
}
270

    
271

    
272

    
273
CF_DECLS
274

    
275
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
276
	ACCEPT, REJECT, ERROR, QUITBIRD,
277
	INT, BOOL, IP, PREFIX, PAIR, QUAD, EC,
278
	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
279
	IF, THEN, ELSE, CASE,
280
	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
281
	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, IFNAME, IFINDEX,
282
	PREFERENCE,
283
	LEN,
284
	DEFINED,
285
	ADD, DELETE, CONTAINS, RESET,
286
	PREPEND, FIRST, LAST, MATCH,
287
	ROA_CHECK,
288
	EMPTY,
289
	FILTER, WHERE, EVAL)
290

    
291
%nonassoc THEN
292
%nonassoc ELSE
293

    
294
%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
295
%type <f> filter filter_body where_filter
296
%type <i> type break_command pair_expr ec_kind
297
%type <i32> pair_atom ec_expr
298
%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body
299
%type <trie> fprefix_set
300
%type <v> set_atom switch_atom fipa
301
%type <px> fprefix
302
%type <s> decls declsn one_decl function_params
303
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
304

    
305
CF_GRAMMAR
306

    
307
CF_ADDTO(conf, filter_def)
308
filter_def:
309
   FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
310
     filter_body {
311
     $2->def = $4;
312
     $4->name = $2->name;
313
     DBG( "We have new filter defined (%s)\n", $2->name );
314
     cf_pop_scope();
315
   }
316
 ;
317

    
318
CF_ADDTO(conf, filter_eval)
319
filter_eval:
320
   EVAL term { f_eval_int($2); }
321
 ;
322

    
323
type:
324
   INT { $$ = T_INT; }
325
 | BOOL { $$ = T_BOOL; }
326
 | IP { $$ = T_IP; }
327
 | PREFIX { $$ = T_NET; }
328
 | PAIR { $$ = T_PAIR; }
329
 | QUAD { $$ = T_QUAD; }
330
 | EC { $$ = T_EC; }
331
 | STRING { $$ = T_STRING; }
332
 | BGPMASK { $$ = T_PATH_MASK; }
333
 | BGPPATH { $$ = T_PATH; }
334
 | CLIST { $$ = T_CLIST; }
335
 | ECLIST { $$ = T_ECLIST; }
336
 | type SET { 
337
	switch ($1) {
338
	  case T_INT:
339
	  case T_PAIR:
340
	  case T_QUAD:
341
	  case T_EC:
342
	  case T_IP:
343
	       $$ = T_SET;
344
	       break;
345

    
346
	  case T_NET:
347
	       $$ = T_PREFIX_SET;
348
	    break;
349

    
350
	  default:
351
		cf_error( "You can't create sets of this type." );
352
	}
353
   }
354
 ;
355

    
356
one_decl:
357
   type SYM {
358
     struct f_val * val = cfg_alloc(sizeof(struct f_val));
359
     val->type = T_VOID;
360
     $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
361
     DBG( "New variable %s type %x\n", $2->name, $1 );
362
     $2->aux2 = NULL;
363
     $$=$2;
364
   }
365
 ;
366

    
367
/* Decls with ';' at the end */
368
decls: /* EMPTY */ { $$ = NULL; }
369
 | one_decl ';' decls {
370
     $$ = $1;
371
     $$->aux2 = $3;
372
   }
373
 ;
374

    
375
/* Declarations that have no ';' at the end. */
376
declsn: one_decl { $$ = $1; }
377
 | one_decl ';' declsn {
378
     $$ = $1;
379
     $$->aux2 = $3;
380
   }
381
 ;
382

    
383
filter_body:
384
   function_body {
385
     struct filter *f = cfg_alloc(sizeof(struct filter));
386
     f->name = NULL;
387
     f->root = $1;
388
     $$ = f;
389
   }
390
 ;
391

    
392
filter:
393
   SYM {
394
     if ($1->class != SYM_FILTER) cf_error("No such filter.");
395
     $$ = $1->def;
396
   }
397
 | filter_body
398
 ;
399

    
400
where_filter:
401
   WHERE term {
402
     /* Construct 'IF term THEN ACCEPT; REJECT;' */
403
     struct filter *f = cfg_alloc(sizeof(struct filter));
404
     struct f_inst *i, *acc, *rej;
405
     acc = f_new_inst();		/* ACCEPT */
406
     acc->code = P('p',',');
407
     acc->a1.p = NULL;
408
     acc->a2.i = F_ACCEPT;
409
     rej = f_new_inst();		/* REJECT */
410
     rej->code = P('p',',');
411
     rej->a1.p = NULL;
412
     rej->a2.i = F_REJECT;
413
     i = f_new_inst();			/* IF */
414
     i->code = '?';
415
     i->a1.p = $2;
416
     i->a2.p = acc;
417
     i->next = rej;
418
     f->name = NULL;
419
     f->root = i;
420
     $$ = f;
421
  }
422
 ;
423

    
424
function_params:
425
   '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
426
 | '(' ')' { $$=NULL; }
427
 ;
428

    
429
function_body:
430
   decls '{' cmds '}' {
431
     if ($1) {
432
       /* Prepend instruction to clear local variables */
433
       $$ = f_new_inst();
434
       $$->code = P('c','v');
435
       $$->a1.p = $1;
436
       $$->next = $3;
437
     } else
438
       $$ = $3;
439
   }
440
 ;
441

    
442
CF_ADDTO(conf, function_def)
443
function_def:
444
   FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
445
     $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
446
     cf_push_scope($2);
447
   } function_params function_body {
448
     $2->def = $5;
449
     $2->aux2 = $4;
450
     DBG("Hmm, we've got one function here - %s\n", $2->name); 
451
     cf_pop_scope();
452
   }
453
 ;
454

    
455
/* Programs */
456

    
457
/* Hack: $$ of cmds_int is the last node.
458
   $$->next of cmds_int is temporary used for the first node */
459

    
460
cmds: /* EMPTY */ { $$ = NULL; }
461
 | cmds_int { $$ = $1->next; $1->next = NULL; }
462
 ;
463

    
464
cmds_int: cmd { $$ = $1; $1->next = $1; }
465
 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
466
 ;
467

    
468
block:
469
   cmd {
470
     $$=$1;
471
   }
472
 | '{' cmds '}' {
473
     $$=$2;
474
   }
475
 ;
476

    
477
/*
478
 * Complex types, their bison value is struct f_val
479
 */
480
fipa:
481
   ipa_raw %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = $1; }
482
 ;
483

    
484

    
485

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

    
493
set_atom:
494
   NUM   { $$.type = T_INT; $$.val.i = $1; }
495
 | fipa  { $$ = $1; }
496
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
497
 | '(' term ')' {
498
     $$ = f_eval($2, cfg_mem);
499
     if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
500
   }
501
 | SYM {
502
     if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
503
     if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
504
     $$ = *(struct f_val *)($1->def);
505
   }
506
 ;
507

    
508
switch_atom:
509
   NUM   { $$.type = T_INT; $$.val.i = $1; }
510
 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
511
 | fipa  { $$ = $1; }
512
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
513
 ;
514

    
515
pair_expr:
516
   term { $$ = f_eval_int($1); check_u16($$); }
517

    
518
pair_atom:
519
   pair_expr { $$ = pair($1, $1); }
520
 | pair_expr DDOT pair_expr { $$ = pair($1, $3); }
521
 | '*' { $$ = 0xFFFF; }
522
 ;
523

    
524
pair_item:
525
   '(' pair_atom ',' pair_atom ')' {
526
     $$ = f_new_pair_set(pair_a($2), pair_b($2), pair_a($4), pair_b($4));
527
   }
528
 | '(' pair_atom ',' pair_atom ')' DDOT '(' pair_expr ',' pair_expr ')' {
529
     /* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */
530
     if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4)))
531
       cf_error("syntax error");
532
     $$ = f_new_pair_item(pair_b($2), $8, pair_b($4), $10); 
533
   }
534
 ;
535

    
536
ec_expr:
537
   term { $$ = f_eval_int($1); }
538

    
539
ec_kind:
540
   RT { $$ = EC_RT; }
541
 | RO { $$ = EC_RO; }
542
 | UNKNOWN NUM { $$ = $2; }
543
 | GENERIC { $$ = EC_GENERIC; }
544
 ;
545

    
546
ec_item:
547
   '(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
548
 | '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
549
 | '(' ec_kind ',' ec_expr ',' '*' ')' {  $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
550
 ;
551

    
552
set_item:
553
   pair_item
554
 | ec_item
555
 | set_atom { $$ = f_new_item($1, $1); }
556
 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
557
 ;
558

    
559
switch_item:
560
   pair_item
561
 | ec_item
562
 | switch_atom { $$ = f_new_item($1, $1); }
563
 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
564
 ;
565

    
566
set_items:
567
   set_item
568
 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
569
 ;
570

    
571
switch_items:
572
   switch_item
573
 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
574
 ;
575

    
576
fprefix:
577
   net_ip	{ $$.net = $1; $$.lo = $1.n.pxlen; $$.hi = $1.n.pxlen; }
578
 | net_ip '+'	{ $$.net = $1; $$.lo = $1.n.pxlen; $$.hi = net_max_prefix_length[$1.n.type]; }
579
 | net_ip '-'	{ $$.net = $1; $$.lo = 0; $$.hi = $1.n.pxlen; }
580
 | net_ip '{' NUM ',' NUM '}' {
581
     $$.net = $1; $$.lo = $3; $$.hi = $5;
582
     if ((0 > $3) || ($3 > $5) || ($5 > net_max_prefix_length[$1.n.type]))
583
       cf_error("Invalid prefix pattern range: {%d, %d}", $3, $5);
584
   }
585
 ;
586

    
587
fprefix_set:
588
   fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net.n), $1.lo, $1.hi); }
589
 | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net.n), $3.lo, $3.hi); }
590
 ;
591

    
592
switch_body: /* EMPTY */ { $$ = NULL; }
593
 | switch_body switch_items ':' cmds  {
594
     /* Fill data fields */
595
     struct f_tree *t;
596
     for (t = $2; t; t = t->left)
597
       t->data = $4;
598
     $$ = f_merge_items($1, $2);
599
   }
600
 | switch_body ELSECOL cmds {
601
     struct f_tree *t = f_new_tree();
602
     t->from.type = t->to.type = T_VOID;
603
     t->right = t;
604
     t->data = $3;
605
     $$ = f_merge_items($1, t);
606
 }
607
 ;
608

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

    
611
bgp_path_expr:
612
   symbol       { $$ = $1; }   
613
 | '(' term ')' { $$ = $2; }
614
 ;
615

    
616
bgp_path:
617
   PO  bgp_path_tail1 PC  { $$ = $2; }
618
 | '/' bgp_path_tail2 '/' { $$ = $2; }
619
 ;
620

    
621
bgp_path_tail1:
622
   NUM bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN;      $$->val = $1; }
623
 | '*' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val  = 0; }
624
 | '?' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; $$->val  = 0; }
625
 | bgp_path_expr bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
626
 |  		      { $$ = NULL; }
627
 ;
628

    
629
bgp_path_tail2:
630
   NUM bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN;      $$->val = $1; }
631
 | '?' bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val  = 0; }
632
 | 		      { $$ = NULL; }
633
 ;
634

    
635
constant:
636
   NUM    { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT;  $$->a2.i = $1; }
637
 | TRUE   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1;  }
638
 | FALSE  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0;  }
639
 | TEXT   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
640
 | fipa	  { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
641
 | net_any { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
642
 | '[' 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" ); }
643
 | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET;  $$->a2.p = $2; }
644
 | ENUM	  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
645
 | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
646
 ;
647

    
648
constructor:
649
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
650
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
651
 ;
652

    
653

    
654
/*
655
 *  Maybe there are no dynamic attributes defined by protocols.
656
 *  For such cases, we force the dynamic_attr list to contain
657
 *  at least an invalid token, so it is syntantically correct.
658
 */
659
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
660

    
661
rtadot: /* EMPTY, we are not permitted RTA. prefix */
662
 ;
663

    
664
function_call:
665
   SYM '(' var_list ')' {
666
     struct symbol *sym;
667
     struct f_inst *inst = $3;
668
     if ($1->class != SYM_FUNCTION)
669
       cf_error("You can't call something which is not a function. Really.");
670
     DBG("You are calling function %s\n", $1->name);
671
     $$ = f_new_inst();
672
     $$->code = P('c','a');
673
     $$->a1.p = inst;
674
     $$->a2.p = $1->def;
675
     sym = $1->aux2;
676
     while (sym || inst) {
677
       if (!sym || !inst)
678
	 cf_error("Wrong number of arguments for function %s.", $1->name);
679
       DBG( "You should pass parameter called %s\n", sym->name);
680
       inst->a1.p = sym;
681
       sym = sym->aux2;
682
       inst = inst->next;
683
     }
684
   }
685
 ;
686

    
687
symbol:
688
   SYM {
689
     $$ = f_new_inst();
690

    
691
     switch ($1->class & 0xff00) {
692
       case SYM_CONSTANT: $$->code = 'C'; break;
693
       case SYM_VARIABLE: $$->code = 'V'; break;
694
       default: cf_error("%s: variable expected.", $1->name);
695
     }
696

    
697
     $$->a1.p = $1->def;
698
     $$->a2.p = $1->name;
699
   }
700

    
701
static_attr:
702
   FROM    { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_FROM;	$$->a1.i = 1; }
703
 | GW      { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = SA_GW;	$$->a1.i = 1; }
704
 | NET     { $$ = f_new_inst(); $$->aux = T_NET;        $$->a2.i = SA_NET; }
705
 | PROTO   { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = SA_PROTO; }
706
 | SOURCE  { $$ = f_new_inst(); $$->aux = T_ENUM_RTS;   $$->a2.i = SA_SOURCE; }
707
 | SCOPE   { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE;	$$->a1.i = 1; }
708
 | CAST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTC;   $$->a2.i = SA_CAST; }
709
 | DEST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTD;   $$->a2.i = SA_DEST;	$$->a1.i = 1; }
710
 | IFNAME  { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = SA_IFNAME; }
711
 | IFINDEX { $$ = f_new_inst(); $$->aux = T_INT;        $$->a2.i = SA_IFINDEX; }
712
 ;
713

    
714
term:
715
   '(' term ')'      { $$ = $2; }
716
 | term '+' term     { $$ = f_new_inst(); $$->code = '+';        $$->a1.p = $1; $$->a2.p = $3; }
717
 | term '-' term     { $$ = f_new_inst(); $$->code = '-';        $$->a1.p = $1; $$->a2.p = $3; }
718
 | term '*' term     { $$ = f_new_inst(); $$->code = '*';        $$->a1.p = $1; $$->a2.p = $3; }
719
 | term '/' term     { $$ = f_new_inst(); $$->code = '/';        $$->a1.p = $1; $$->a2.p = $3; }
720
 | term AND term     { $$ = f_new_inst(); $$->code = '&';        $$->a1.p = $1; $$->a2.p = $3; }
721
 | term OR  term     { $$ = f_new_inst(); $$->code = '|';        $$->a1.p = $1; $$->a2.p = $3; }
722
 | term '=' term     { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
723
 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','=');     $$->a1.p = $1; $$->a2.p = $3; }
724
 | term '<' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $1; $$->a2.p = $3; }
725
 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $1; $$->a2.p = $3; }
726
 | term '>' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $3; $$->a2.p = $1; }
727
 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $3; $$->a2.p = $1; }
728
 | term '~' term     { $$ = f_new_inst(); $$->code = '~';        $$->a1.p = $1; $$->a2.p = $3; }
729
 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
730
 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e');  $$->a1.p = $3; }
731

    
732
 | symbol   { $$ = $1; }
733
 | constant { $$ = $1; }
734
 | constructor { $$ = $1; }
735

    
736
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
737

    
738
 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
739

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

    
742
 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
743
 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
744
 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
745
 | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
746
 | term '.' LAST  { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
747

    
748
/* Communities */
749
/* This causes one shift/reduce conflict
750
 | rtadot dynamic_attr '.' ADD '(' term ')' { }
751
 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
752
 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
753
 | rtadot dynamic_attr '.' RESET{ }
754
*/
755

    
756
 | '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; }
757
 | '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; }
758
 | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; }
759
 | PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } 
760
 | ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } 
761
 | DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
762
 | FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
763

    
764
 | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
765
 | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
766

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

    
769
/* function_call is inlined here */
770
 | SYM '(' var_list ')' {
771
     struct symbol *sym;
772
     struct f_inst *inst = $3;
773
     if ($1->class != SYM_FUNCTION)
774
       cf_error("You can't call something which is not a function. Really.");
775
     DBG("You are calling function %s\n", $1->name);
776
     $$ = f_new_inst();
777
     $$->code = P('c','a');
778
     $$->a1.p = inst;
779
     $$->a2.p = $1->def;
780
     sym = $1->aux2;
781
     while (sym || inst) {
782
       if (!sym || !inst)
783
	 cf_error("Wrong number of arguments for function %s.", $1->name);
784
       DBG( "You should pass parameter called %s\n", sym->name);
785
       inst->a1.p = sym;
786
       sym = sym->aux2;
787
       inst = inst->next;
788
     }
789
   }
790
 ;
791

    
792
break_command:
793
   QUITBIRD { $$ = F_QUITBIRD; }
794
 | ACCEPT { $$ = F_ACCEPT; }
795
 | REJECT { $$ = F_REJECT; }
796
 | ERROR { $$ = F_ERROR; }
797
 | PRINT { $$ = F_NOP; }
798
 | PRINTN { $$ = F_NONL; }
799
 ;
800

    
801
print_one:
802
   term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
803
 ;
804

    
805
print_list: /* EMPTY */ { $$ = NULL; }
806
 | print_one { $$ = $1; }
807
 | print_one ',' print_list {
808
     if ($1) {
809
       $1->next = $3;
810
       $$ = $1;
811
     } else $$ = $3;
812
   }
813
 ;
814

    
815
var_listn: term { 
816
     $$ = f_new_inst();
817
     $$->code = 's';
818
     $$->a1.p = NULL;
819
     $$->a2.p = $1;
820
     $$->next = NULL;
821
   }
822
 | term ',' var_listn {
823
     $$ = f_new_inst();
824
     $$->code = 's';
825
     $$->a1.p = NULL;
826
     $$->a2.p = $1;
827
     $$->next = $3;
828
   }
829
 ;
830

    
831
var_list: /* EMPTY */ { $$ = NULL; }
832
 | var_listn { $$ = $1; }
833
 ;
834

    
835
cmd:
836
   IF term THEN block {
837
     $$ = f_new_inst();
838
     $$->code = '?';
839
     $$->a1.p = $2;
840
     $$->a2.p = $4;
841
   }
842
 | IF term THEN block ELSE block {
843
     struct f_inst *i = f_new_inst();
844
     i->code = '?';
845
     i->a1.p = $2;
846
     i->a2.p = $4;
847
     $$ = f_new_inst();
848
     $$->code = '?';
849
     $$->a1.p = i;
850
     $$->a2.p = $6;
851
   }
852
 | SYM '=' term ';' {
853
     $$ = f_new_inst();
854
     DBG( "Ook, we'll set value\n" );
855
     if (($1->class & ~T_MASK) != SYM_VARIABLE)
856
       cf_error( "You may set only variables." );
857
     $$->code = 's';
858
     $$->a1.p = $1;
859
     $$->a2.p = $3;
860
   }
861
 | RETURN term ';' {
862
     $$ = f_new_inst();
863
     DBG( "Ook, we'll return the value\n" );
864
     $$->code = 'r';
865
     $$->a1.p = $2;
866
   }
867
 | rtadot dynamic_attr '=' term ';' {
868
     $$ = $2;
869
     $$->code = P('e','S');
870
     $$->a1.p = $4;
871
   }
872
 | rtadot static_attr '=' term ';' {
873
     $$ = $2;
874
     if (!$$->a1.i)
875
       cf_error( "This static attribute is read-only.");
876
     $$->code = P('a','S');
877
     $$->a1.p = $4;
878
   }
879
 | PREFERENCE '=' term ';' {
880
     $$ = f_new_inst();
881
     $$->code = P('P','S');
882
     $$->a1.p = $3;
883
   } 
884
 | UNSET '(' rtadot dynamic_attr ')' ';' {
885
     $$ = $4;
886
     $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
887
     $$->code = P('e','S');
888
     $$->a1.p = NULL;
889
   }
890
 | break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; }
891
 | function_call ';' { $$ = $1; }
892
 | CASE term '{' switch_body '}' {
893
      $$ = f_new_inst();
894
      $$->code = P('S','W');
895
      $$->a1.p = $2;
896
      $$->a2.p = build_tree( $4 );
897
   }
898

    
899

    
900
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
901
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
902
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
903
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
904
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
905
 ;
906

    
907
CF_END