Statistics
| Branch: | Revision:

iof-bird-daemon / filter / config.Y @ 04632fd7

History | View | Annotate | Download (24.5 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
  /* IP->Quad implicit conversion */
209
  else if (tk->code == 'C') {
210
    c1 = 1;
211
    struct f_val *val = tk->a1.p;
212

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

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

    
233
  if (c1 && c2) {
234
    u64 ec;
235

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

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

    
266
  return rv;
267
}
268

    
269

    
270

    
271
CF_DECLS
272

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

    
288
%nonassoc THEN
289
%nonassoc ELSE
290

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

    
302
CF_GRAMMAR
303

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

    
315
CF_ADDTO(conf, filter_eval)
316
filter_eval:
317
   EVAL term { f_eval_int($2); }
318
 ;
319

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

    
343
	  case T_NET:
344
	       $$ = T_PREFIX_SET;
345
	    break;
346

    
347
	  default:
348
		cf_error( "You can't create sets of this type." );
349
	}
350
   }
351
 ;
352

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

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

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

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

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

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

    
421
function_params:
422
   '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
423
 | '(' ')' { $$=NULL; }
424
 ;
425

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

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

    
452
/* Programs */
453

    
454
/* Hack: $$ of cmds_int is the last node.
455
   $$->next of cmds_int is temporary used for the first node */
456

    
457
cmds: /* EMPTY */ { $$ = NULL; }
458
 | cmds_int { $$ = $1->next; $1->next = NULL; }
459
 ;
460

    
461
cmds_int: cmd { $$ = $1; $1->next = $1; }
462
 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
463
 ;
464

    
465
block:
466
   cmd {
467
     $$=$1;
468
   }
469
 | '{' cmds '}' {
470
     $$=$2;
471
   }
472
 ;
473

    
474
/*
475
 * Complex types, their bison value is struct f_val
476
 */
477
fipa:
478
   IP4 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip4($1); }
479
 | IP6 %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.ip = ipa_from_ip6($1); }
480
 ;
481

    
482

    
483

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

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

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

    
513
pair_expr:
514
   term { $$ = f_eval_int($1); check_u16($$); }
515

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

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

    
534
ec_expr:
535
   term { $$ = f_eval_int($1); }
536

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
651

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

    
659
rtadot: /* EMPTY, we are not permitted RTA. prefix */
660
 ;
661

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

    
685
symbol:
686
   SYM {
687
     $$ = f_new_inst();
688

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

    
695
     $$->a1.p = $1->def;
696
     $$->a2.p = $1->name;
697
   }
698

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

    
712
term:
713
   '(' term ')'      { $$ = $2; }
714
 | term '+' term     { $$ = f_new_inst(); $$->code = '+';        $$->a1.p = $1; $$->a2.p = $3; }
715
 | term '-' term     { $$ = f_new_inst(); $$->code = '-';        $$->a1.p = $1; $$->a2.p = $3; }
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 AND term     { $$ = f_new_inst(); $$->code = '&';        $$->a1.p = $1; $$->a2.p = $3; }
719
 | term OR  term     { $$ = f_new_inst(); $$->code = '|';        $$->a1.p = $1; $$->a2.p = $3; }
720
 | term '=' term     { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; }
721
 | term NEQ term { $$ = f_new_inst(); $$->code = P('!','=');     $$->a1.p = $1; $$->a2.p = $3; }
722
 | term '<' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $1; $$->a2.p = $3; }
723
 | term LEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $1; $$->a2.p = $3; }
724
 | term '>' term     { $$ = f_new_inst(); $$->code = '<';        $$->a1.p = $3; $$->a2.p = $1; }
725
 | term GEQ term { $$ = f_new_inst(); $$->code = P('<','=');     $$->a1.p = $3; $$->a2.p = $1; }
726
 | term '~' term     { $$ = f_new_inst(); $$->code = '~';        $$->a1.p = $1; $$->a2.p = $3; }
727
 | '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; }
728
 | DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e');  $$->a1.p = $3; }
729

    
730
 | symbol   { $$ = $1; }
731
 | constant { $$ = $1; }
732
 | constructor { $$ = $1; }
733

    
734
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
735

    
736
 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
737

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

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

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

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

    
762
/*
763
 | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
764
 | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
765
*/
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