Statistics
| Branch: | Revision:

iof-bird-daemon / filter / config.Y @ fe9f1a6d

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
#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) {
221
      ipv4_used = 1; key = ipa_to_u32(val->val.px.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 fprefix fprefix_s fipa
301
%type <s> decls declsn one_decl function_params 
302
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
303

    
304
CF_GRAMMAR
305

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

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

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

    
345
	  case T_PREFIX:
346
	       $$ = T_PREFIX_SET;
347
	    break;
348

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

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

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

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

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

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

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

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

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

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

    
454
/* Programs */
455

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

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

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

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

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

    
483

    
484

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

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

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

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

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

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

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

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

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

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

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

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

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

    
575
fprefix_s:
576
   ipa_raw '/' NUM %prec '/' {
577
     if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
578
     $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
579
   }
580
 ;
581

    
582
fprefix:
583
   fprefix_s { $$ = $1; }
584
 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
585
 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
586
 | fprefix_s '{' NUM ',' NUM '}' { 
587
     if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
588
     $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
589
   }
590
 ;
591

    
592
fprefix_set:
593
   fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_fprefix($$, &($1.val.px)); }
594
 | fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
595
 ;
596

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

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

    
616
bgp_path_expr:
617
   symbol       { $$ = $1; }   
618
 | '(' term ')' { $$ = $2; }
619
 ;
620

    
621
bgp_path:
622
   PO  bgp_path_tail1 PC  { $$ = $2; }
623
 | '/' bgp_path_tail2 '/' { $$ = $2; }
624
 ;
625

    
626
bgp_path_tail1:
627
   NUM bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN;      $$->val = $1; }
628
 | '*' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val  = 0; }
629
 | '?' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; $$->val  = 0; }
630
 | bgp_path_expr bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
631
 |  		      { $$ = NULL; }
632
 ;
633

    
634
bgp_path_tail2:
635
   NUM bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN;      $$->val = $1; }
636
 | '?' bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val  = 0; }
637
 | 		      { $$ = NULL; }
638
 ;
639

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

    
653
constructor:
654
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
655
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
656
 ;
657

    
658

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

    
666
rtadot: /* EMPTY, we are not permitted RTA. prefix */
667
 ;
668

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

    
692
symbol:
693
   SYM {
694
     $$ = f_new_inst();
695

    
696
     switch ($1->class & 0xff00) {
697
       case SYM_CONSTANT: $$->code = 'C'; break;
698
       case SYM_VARIABLE: $$->code = 'V'; break;
699
       default: cf_error("%s: variable expected.", $1->name);
700
     }
701

    
702
     $$->a1.p = $1->def;
703
     $$->a2.p = $1->name;
704
   }
705

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

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

    
737
 | symbol   { $$ = $1; }
738
 | constant { $$ = $1; }
739
 | constructor { $$ = $1; }
740

    
741
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
742

    
743
 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
744

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

    
747
 | term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; }
748
 | term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; }
749
 | term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; }
750
 | term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; }
751
 | term '.' LAST  { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; }
752

    
753
/* Communities */
754
/* This causes one shift/reduce conflict
755
 | rtadot dynamic_attr '.' ADD '(' term ')' { }
756
 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
757
 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
758
 | rtadot dynamic_attr '.' RESET{ }
759
*/
760

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

    
769
 | ROA_CHECK '(' SYM ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
770
 | ROA_CHECK '(' SYM ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
771

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

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

    
797
break_command:
798
   QUITBIRD { $$ = F_QUITBIRD; }
799
 | ACCEPT { $$ = F_ACCEPT; }
800
 | REJECT { $$ = F_REJECT; }
801
 | ERROR { $$ = F_ERROR; }
802
 | PRINT { $$ = F_NOP; }
803
 | PRINTN { $$ = F_NONL; }
804
 ;
805

    
806
print_one:
807
   term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
808
 ;
809

    
810
print_list: /* EMPTY */ { $$ = NULL; }
811
 | print_one { $$ = $1; }
812
 | print_one ',' print_list {
813
     if ($1) {
814
       $1->next = $3;
815
       $$ = $1;
816
     } else $$ = $3;
817
   }
818
 ;
819

    
820
var_listn: term { 
821
     $$ = f_new_inst();
822
     $$->code = 's';
823
     $$->a1.p = NULL;
824
     $$->a2.p = $1;
825
     $$->next = NULL;
826
   }
827
 | term ',' var_listn {
828
     $$ = f_new_inst();
829
     $$->code = 's';
830
     $$->a1.p = NULL;
831
     $$->a2.p = $1;
832
     $$->next = $3;
833
   }
834
 ;
835

    
836
var_list: /* EMPTY */ { $$ = NULL; }
837
 | var_listn { $$ = $1; }
838
 ;
839

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

    
904

    
905
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
906
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
907
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
908
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
909
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
910
 ;
911

    
912
CF_END