Statistics
| Branch: | Revision:

iof-bird-daemon / filter / config.Y @ 117e3c4b

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

    
29
static inline struct f_tree *
30
f_new_item(struct f_val from, struct f_val to)
31
{
32
  struct f_tree *t = f_new_tree();
33
  t->right = t;
34
  t->from = from;
35
  t->to = to;
36
  return t;
37
}
38

    
39
static inline struct f_tree *
40
f_merge_items(struct f_tree *a, struct f_tree *b)
41
{
42
  if (!a) return b;
43
  a->right->left = b;
44
  a->right = b->right;
45
  b->right = NULL;
46
  return a;
47
}
48

    
49
static inline struct f_tree *
50
f_new_pair_item(int fa, int ta, int fb, int tb)
51
{
52
  struct f_tree *t = f_new_tree();
53
  t->right = t;
54
  t->from.type = t->to.type = T_PAIR;
55
  t->from.val.i = pair(fa, fb);
56
  t->to.val.i = pair(ta, tb);
57
  return t;
58
}
59

    
60
static inline struct f_tree *
61
f_new_pair_set(int fa, int ta, int fb, int tb)
62
{
63
  struct f_tree *lst = NULL;
64
  int i;
65

    
66
  if ((fa == ta) || ((fb == 0) && (tb == 0xFFFF)))
67
    return f_new_pair_item(fa, ta, fb, tb);
68
  
69
  if ((ta < fa) || (tb < fb))
70
    cf_error( "From value cannot be higher that To value in pair sets");
71

    
72
  for (i = fa; i <= ta; i++)
73
    lst = f_merge_items(lst, f_new_pair_item(i, i, fb, tb));
74

    
75
  return lst;
76
}
77

    
78
#define EC_ALL 0xFFFFFFFF
79

    
80
static struct f_tree *
81
f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
82
{
83
  u64 fm, to;
84

    
85
  if (ipv4_used || (key >= 0x10000)) {
86
    check_u16(vf);
87
    if (vt == EC_ALL)
88
      vt = 0xFFFF;
89
    else
90
      check_u16(vt);
91
  }
92

    
93
  if (kind == EC_GENERIC) {
94
    fm = ec_generic(key, vf);
95
    to = ec_generic(key, vt);
96
  }
97
  else if (ipv4_used) {
98
    fm = ec_ip4(kind, key, vf);
99
    to = ec_ip4(kind, key, vt);
100
  }
101
  else if (key < 0x10000) {
102
    fm = ec_as2(kind, key, vf);
103
    to = ec_as2(kind, key, vt);
104
  }
105
  else {
106
    fm = ec_as4(kind, key, vf);
107
    to = ec_as4(kind, key, vt);
108
  }
109

    
110
  struct f_tree *t = f_new_tree();
111
  t->right = t;
112
  t->from.type = t->to.type = T_EC;
113
  t->from.val.ec = fm;
114
  t->to.val.ec = to;
115
  return t;
116
}
117

    
118
static inline struct f_inst *
119
f_generate_empty(struct f_inst *dyn)
120
{ 
121
  struct f_inst *e = f_new_inst();
122
  e->code = 'E';
123

    
124
  switch (dyn->aux & EAF_TYPE_MASK) {
125
    case EAF_TYPE_AS_PATH:
126
      e->aux = T_PATH;
127
      break;
128
    case EAF_TYPE_INT_SET:
129
      e->aux = T_CLIST;
130
      break;
131
    case EAF_TYPE_EC_SET:
132
      e->aux = T_ECLIST;
133
      break;
134
    default:
135
      cf_error("Can't empty that attribute");
136
  }
137

    
138
  dyn->code = P('e','S');
139
  dyn->a1.p = e;
140
  return dyn;
141
}
142

    
143

    
144
static inline struct f_inst *
145
f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
146
{
147
  struct f_inst *rv;
148

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

    
153
    check_u16(t1->a2.i);
154
    check_u16(t2->a2.i);
155

    
156
    rv = f_new_inst();
157
    rv->code = 'c';
158
    rv->aux = T_PAIR;
159
    rv->a2.i = pair(t1->a2.i, t2->a2.i);
160
  }
161
  else {
162
    rv = f_new_inst();
163
    rv->code = P('m', 'p');
164
    rv->a1.p = t1;
165
    rv->a2.p = t2;
166
  }
167

    
168
  return rv;
169
}
170

    
171
static inline struct f_inst *
172
f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
173
{
174
  struct f_inst *rv;
175
  int c1 = 0, c2 = 0, ipv4_used = 0;
176
  u32 key = 0, val2 = 0;
177

    
178
  if (tk->code == 'c') {
179
    c1 = 1;
180

    
181
    if (tk->aux == T_INT) {
182
      ipv4_used = 0; key = tk->a2.i;
183
    }
184
    else if (tk->aux == T_QUAD) {
185
      ipv4_used = 1; key = tk->a2.i;
186
    }
187
    else
188
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
189
  }
190

    
191
#ifndef IPV6
192
  /* IP->Quad implicit conversion */
193
  else if (tk->code == 'C') {
194
    c1 = 1;
195
    struct f_val *val = tk->a1.p;
196
    if (val->type == T_IP) {
197
      ipv4_used = 1; key = ipa_to_u32(val->val.px.ip);
198
    }
199
    else
200
      cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
201
  }
202
#endif
203

    
204
  if (tv->code == 'c') {
205
    if (tv->aux != T_INT)
206
      cf_error("Can't operate with value of non-integer type in EC constructor");
207
    c2 = 1;
208
    val2 = tv->a2.i;
209
  }
210

    
211
  if (c1 && c2) {
212
    u64 ec;
213
  
214
    if (kind == EC_GENERIC) {
215
      ec = ec_generic(key, val2);
216
    }
217
    else if (ipv4_used) {
218
      check_u16(val2);
219
      ec = ec_ip4(kind, key, val2);
220
    }
221
    else if (key < 0x10000) {
222
      ec = ec_as2(kind, key, val2);
223
    }
224
    else {
225
      check_u16(val2);
226
      ec = ec_as4(kind, key, val2);
227
    }
228

    
229
    NEW_F_VAL;
230
    rv = f_new_inst();
231
    rv->code = 'C';
232
    rv->a1.p = val;    
233
    val->type = T_EC;
234
    val->val.ec = ec;
235
  }
236
  else {
237
    rv = f_new_inst();
238
    rv->code = P('m','c');
239
    rv->aux = kind;
240
    rv->a1.p = tk;
241
    rv->a2.p = tv;
242
  }
243

    
244
  return rv;
245
}
246

    
247

    
248

    
249
CF_DECLS
250

    
251
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
252
	ACCEPT, REJECT, ERROR, QUITBIRD,
253
	INT, BOOL, IP, PREFIX, PAIR, QUAD, EC,
254
	SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST,
255
	IF, THEN, ELSE, CASE,
256
	TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
257
	FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, CAST, DEST, PREFERENCE,
258
	LEN,
259
	DEFINED,
260
	ADD, DELETE, CONTAINS, RESET,
261
	PREPEND, FIRST, LAST, MATCH,
262
	EMPTY,
263
	FILTER, WHERE, EVAL)
264

    
265
%nonassoc THEN
266
%nonassoc ELSE
267

    
268
%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
269
%type <f> filter filter_body where_filter
270
%type <i> type break_command pair_expr ec_kind
271
%type <i32> pair_atom ec_expr
272
%type <e> pair_item ec_item set_item switch_item set_items switch_items switch_body
273
%type <trie> fprefix_set
274
%type <v> set_atom switch_atom fprefix fprefix_s fipa
275
%type <s> decls declsn one_decl function_params 
276
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
277

    
278
CF_GRAMMAR
279

    
280
CF_ADDTO(conf, filter_def)
281
filter_def:
282
   FILTER SYM { $2 = cf_define_symbol($2, SYM_FILTER, NULL); cf_push_scope( $2 ); }
283
     filter_body {
284
     $2->def = $4;
285
     $4->name = $2->name;
286
     DBG( "We have new filter defined (%s)\n", $2->name );
287
     cf_pop_scope();
288
   }
289
 ;
290

    
291
CF_ADDTO(conf, filter_eval)
292
filter_eval:
293
   EVAL term { f_eval_int($2); }
294
 ;
295

    
296
type:
297
   INT { $$ = T_INT; }
298
 | BOOL { $$ = T_BOOL; }
299
 | IP { $$ = T_IP; }
300
 | PREFIX { $$ = T_PREFIX; }
301
 | PAIR { $$ = T_PAIR; }
302
 | QUAD { $$ = T_QUAD; }
303
 | EC { $$ = T_EC; }
304
 | STRING { $$ = T_STRING; }
305
 | BGPMASK { $$ = T_PATH_MASK; }
306
 | BGPPATH { $$ = T_PATH; }
307
 | CLIST { $$ = T_CLIST; }
308
 | ECLIST { $$ = T_ECLIST; }
309
 | type SET { 
310
	switch ($1) {
311
	  case T_INT:
312
	  case T_PAIR:
313
	  case T_QUAD:
314
	  case T_EC:
315
	  case T_IP:
316
	       $$ = T_SET;
317
	       break;
318

    
319
	  case T_PREFIX:
320
	       $$ = T_PREFIX_SET;
321
	    break;
322

    
323
	  default:
324
		cf_error( "You can't create sets of this type." );
325
	}
326
   }
327
 ;
328

    
329
one_decl:
330
   type SYM {
331
     struct f_val * val = cfg_alloc(sizeof(struct f_val)); 
332
     val->type = $1; 
333
     $2 = cf_define_symbol($2, SYM_VARIABLE | $1, val);
334
     DBG( "New variable %s type %x\n", $2->name, $1 );
335
     $2->aux2 = NULL;
336
     $$=$2;
337
   }
338
 ;
339

    
340
/* Decls with ';' at the end */
341
decls: /* EMPTY */ { $$ = NULL; }
342
 | one_decl ';' decls {
343
     $$ = $1;
344
     $$->aux2 = $3;
345
   }
346
 ;
347

    
348
/* Declarations that have no ';' at the end. */
349
declsn: one_decl { $$ = $1; }
350
 | one_decl ';' declsn {
351
     $$ = $1;
352
     $$->aux2 = $3;
353
   }
354
 ;
355

    
356
filter_body:
357
   function_body {
358
     struct filter *f = cfg_alloc(sizeof(struct filter));
359
     f->name = NULL;
360
     f->root = $1;
361
     $$ = f;
362
   }
363
 ;
364

    
365
filter:
366
   SYM {
367
     if ($1->class != SYM_FILTER) cf_error("No such filter.");
368
     $$ = $1->def;
369
   }
370
 | filter_body
371
 ;
372

    
373
where_filter:
374
   WHERE term {
375
     /* Construct 'IF term THEN ACCEPT; REJECT;' */
376
     struct filter *f = cfg_alloc(sizeof(struct filter));
377
     struct f_inst *i, *acc, *rej;
378
     acc = f_new_inst();		/* ACCEPT */
379
     acc->code = P('p',',');
380
     acc->a1.p = NULL;
381
     acc->a2.i = F_ACCEPT;
382
     rej = f_new_inst();		/* REJECT */
383
     rej->code = P('p',',');
384
     rej->a1.p = NULL;
385
     rej->a2.i = F_REJECT;
386
     i = f_new_inst();			/* IF */
387
     i->code = '?';
388
     i->a1.p = $2;
389
     i->a2.p = acc;
390
     i->next = rej;
391
     f->name = NULL;
392
     f->root = i;
393
     $$ = f;
394
  }
395
 ;
396

    
397
function_params:
398
   '(' declsn ')' { DBG( "Have function parameters\n" ); $$=$2; }
399
 | '(' ')' { $$=NULL; }
400
 ;
401

    
402
function_body:
403
   decls '{' cmds '}' {
404
     if ($1) {
405
       /* Prepend instruction to clear local variables */
406
       $$ = f_new_inst();
407
       $$->code = P('c','v');
408
       $$->a1.p = $1;
409
       $$->next = $3;
410
     } else
411
       $$ = $3;
412
   }
413
 ;
414

    
415
CF_ADDTO(conf, function_def)
416
function_def:
417
   FUNCTION SYM { DBG( "Beginning of function %s\n", $2->name );
418
     $2 = cf_define_symbol($2, SYM_FUNCTION, NULL);
419
     cf_push_scope($2);
420
   } function_params function_body {
421
     $2->def = $5;
422
     $2->aux2 = $4;
423
     DBG("Hmm, we've got one function here - %s\n", $2->name); 
424
     cf_pop_scope();
425
   }
426
 ;
427

    
428
/* Programs */
429

    
430
/* Hack: $$ of cmds_int is the last node.
431
   $$->next of cmds_int is temporary used for the first node */
432

    
433
cmds: /* EMPTY */ { $$ = NULL; }
434
 | cmds_int { $$ = $1->next; $1->next = NULL; }
435
 ;
436

    
437
cmds_int: cmd { $$ = $1; $1->next = $1; }
438
 | cmds_int cmd { $$ = $2; $2->next = $1->next ; $1->next = $2; }
439
 ;
440

    
441
block:
442
   cmd {
443
     $$=$1;
444
   }
445
 | '{' cmds '}' {
446
     $$=$2;
447
   }
448
 ;
449

    
450
/*
451
 * Complex types, their bison value is struct f_val
452
 */
453
fipa:
454
   IPA %prec PREFIX_DUMMY { $$.type = T_IP; $$.val.px.ip = $1; }
455
 ;
456

    
457

    
458

    
459
/*
460
 * Set constants. They are also used in switch cases. We use separate
461
 * nonterminals for switch (set_atom/switch_atom, set_item/switch_item ...)
462
 * to elude a collision between symbol (in expr) in set_atom and symbol
463
 * as a function call in switch case cmds.
464
 */
465

    
466
set_atom:
467
   expr  { $$.type = T_INT; $$.val.i = $1; }
468
 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
469
 | fipa  { $$ = $1; }
470
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
471
 ;
472

    
473
switch_atom:
474
   NUM   { $$.type = T_INT; $$.val.i = $1; }
475
 | '(' term ')' { $$.type = T_INT; $$.val.i = f_eval_int($2); }
476
 | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
477
 | fipa  { $$ = $1; }
478
 | ENUM  { $$.type = pair_a($1); $$.val.i = pair_b($1); }
479
 ;
480

    
481
pair_expr:
482
   term { $$ = f_eval_int($1); check_u16($$); }
483

    
484
pair_atom:
485
   pair_expr { $$ = pair($1, $1); }
486
 | pair_expr DDOT pair_expr { $$ = pair($1, $3); }
487
 | '*' { $$ = 0xFFFF; }
488
 ;
489

    
490
pair_item:
491
   '(' pair_atom ',' pair_atom ')' {
492
     $$ = f_new_pair_set(pair_a($2), pair_b($2), pair_a($4), pair_b($4));
493
   }
494
 | '(' pair_atom ',' pair_atom ')' DDOT '(' pair_expr ',' pair_expr ')' {
495
     /* Hack: $2 and $4 should be pair_expr, but that would cause shift/reduce conflict */
496
     if ((pair_a($2) != pair_b($2)) || (pair_a($4) != pair_b($4)))
497
       cf_error("syntax error");
498
     $$ = f_new_pair_item(pair_b($2), $8, pair_b($4), $10); 
499
   }
500
 ;
501

    
502
ec_expr:
503
   term { $$ = f_eval_int($1); }
504

    
505
ec_kind:
506
   RT { $$ = EC_RT; }
507
 | RO { $$ = EC_RO; }
508
 | UNKNOWN NUM { $$ = $2; }
509
 | GENERIC { $$ = EC_GENERIC; }
510
 ;
511

    
512
ec_item:
513
   '(' ec_kind ',' ec_expr ',' ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $6); }
514
 | '(' ec_kind ',' ec_expr ',' ec_expr DDOT ec_expr ')' { $$ = f_new_ec_item($2, 0, $4, $6, $8); }
515
 | '(' ec_kind ',' ec_expr ',' '*' ')' {  $$ = f_new_ec_item($2, 0, $4, 0, EC_ALL); }
516
 ;
517

    
518
set_item:
519
   pair_item
520
 | ec_item
521
 | set_atom { $$ = f_new_item($1, $1); }
522
 | set_atom DDOT set_atom { $$ = f_new_item($1, $3); }
523
 ;
524

    
525
switch_item:
526
   pair_item
527
 | ec_item
528
 | switch_atom { $$ = f_new_item($1, $1); }
529
 | switch_atom DDOT switch_atom { $$ = f_new_item($1, $3); }
530
 ;
531

    
532
set_items:
533
   set_item
534
 | set_items ',' set_item { $$ = f_merge_items($1, $3); }
535
 ;
536

    
537
switch_items:
538
   switch_item
539
 | switch_items ',' switch_item { $$ = f_merge_items($1, $3); }
540
 ;
541

    
542
fprefix_s:
543
   IPA '/' NUM %prec '/' {
544
     if (($3 < 0) || ($3 > MAX_PREFIX_LENGTH) || !ip_is_prefix($1, $3)) cf_error("Invalid network prefix: %I/%d.", $1, $3);
545
     $$.type = T_PREFIX; $$.val.px.ip = $1; $$.val.px.len = $3;
546
   }
547
 ;
548

    
549
fprefix:
550
   fprefix_s { $$ = $1; }
551
 | fprefix_s '+' { $$ = $1; $$.val.px.len |= LEN_PLUS; }
552
 | fprefix_s '-' { $$ = $1; $$.val.px.len |= LEN_MINUS; }
553
 | fprefix_s '{' NUM ',' NUM '}' { 
554
     if (! ((0 <= $3) && ($3 <= $5) && ($5 <= MAX_PREFIX_LENGTH))) cf_error("Invalid prefix pattern range: {%d, %d}.", $3, $5);
555
     $$ = $1; $$.val.px.len |= LEN_RANGE | ($3 << 16) | ($5 << 8);
556
   }
557
 ;
558

    
559
fprefix_set:
560
   fprefix { $$ = f_new_trie(cfg_mem); trie_add_fprefix($$, &($1.val.px)); }
561
 | fprefix_set ',' fprefix { $$ = $1; trie_add_fprefix($$, &($3.val.px)); }
562
 ;
563

    
564
switch_body: /* EMPTY */ { $$ = NULL; }
565
 | switch_body switch_items ':' cmds  {
566
     /* Fill data fields */
567
     struct f_tree *t;
568
     for (t = $2; t; t = t->left)
569
       t->data = $4;
570
     $$ = f_merge_items($1, $2);
571
   }
572
 | switch_body ELSECOL cmds { 
573
     struct f_tree *t = f_new_tree();
574
     t->from.type = t->to.type = T_VOID;
575
     t->right = t;
576
     t->data = $3;
577
     $$ = f_merge_items($1, t);
578
 }
579
 ;
580

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

    
583
bgp_path_expr:
584
   symbol       { $$ = $1; }   
585
 | '(' term ')' { $$ = $2; }
586
 ;
587

    
588
bgp_path:
589
   PO  bgp_path_tail1 PC  { $$ = $2; }
590
 | '/' bgp_path_tail2 '/' { $$ = $2; }
591
 ;
592

    
593
bgp_path_tail1:
594
   NUM bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN;      $$->val = $1; }
595
 | '*' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val  = 0; }
596
 | '?' bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; $$->val  = 0; }
597
 | bgp_path_expr bgp_path_tail1 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
598
 |  		      { $$ = NULL; }
599
 ;
600

    
601
bgp_path_tail2:
602
   NUM bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN;      $$->val = $1; }
603
 | '?' bgp_path_tail2 { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; $$->val  = 0; }
604
 | 		      { $$ = NULL; }
605
 ;
606

    
607
constant:
608
   NUM    { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT;  $$->a2.i = $1; }
609
 | TRUE   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1;  }
610
 | FALSE  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0;  }
611
 | TEXT   { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; }
612
 | fipa	   { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
613
 | fprefix_s {NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; }
614
 | RTRID  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_QUAD;  $$->a2.i = $1; }
615
 | '[' 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" ); }
616
 | '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET;  $$->a2.p = $2; }
617
 | ENUM	  { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
618
 | bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
619
 ;
620

    
621
constructor:
622
   '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
623
 | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
624
 ;
625

    
626

    
627
/*
628
 *  Maybe there are no dynamic attributes defined by protocols.
629
 *  For such cases, we force the dynamic_attr list to contain
630
 *  at least an invalid token, so it is syntantically correct.
631
 */
632
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; })
633

    
634
rtadot: /* EMPTY, we are not permitted RTA. prefix */
635
 ;
636

    
637
function_call:
638
   SYM '(' var_list ')' {
639
     struct symbol *sym;
640
     struct f_inst *inst = $3;
641
     if ($1->class != SYM_FUNCTION)
642
       cf_error("You can't call something which is not a function. Really.");
643
     DBG("You are calling function %s\n", $1->name);
644
     $$ = f_new_inst();
645
     $$->code = P('c','a');
646
     $$->a1.p = inst;
647
     $$->a2.p = $1->def;
648
     sym = $1->aux2;
649
     while (sym || inst) {
650
       if (!sym || !inst)
651
	 cf_error("Wrong number of arguments for function %s.", $1->name);
652
       DBG( "You should pass parameter called %s\n", sym->name);
653
       inst->a1.p = sym;
654
       sym = sym->aux2;
655
       inst = inst->next;
656
     }
657
   }
658
 ;
659

    
660
symbol:
661
   SYM {
662
     $$ = f_new_inst();
663
     switch ($1->class) {
664
       case SYM_NUMBER:
665
	$$ = f_new_inst();
666
	$$->code = 'c'; 
667
	$$->aux = T_INT; 
668
	$$->a2.i = $1->aux;
669
	break;
670
       case SYM_IPA:
671
	{ NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; val->type = T_IP; val->val.px.ip = * (ip_addr *) ($1->def); }
672
	break;
673
       case SYM_VARIABLE | T_BOOL:
674
       case SYM_VARIABLE | T_INT:
675
       case SYM_VARIABLE | T_PAIR:
676
       case SYM_VARIABLE | T_QUAD:
677
       case SYM_VARIABLE | T_EC:
678
       case SYM_VARIABLE | T_STRING:
679
       case SYM_VARIABLE | T_IP:
680
       case SYM_VARIABLE | T_PREFIX:
681
       case SYM_VARIABLE | T_PREFIX_SET:
682
       case SYM_VARIABLE | T_SET:
683
       case SYM_VARIABLE | T_PATH:
684
       case SYM_VARIABLE | T_PATH_MASK:
685
       case SYM_VARIABLE | T_CLIST:
686
       case SYM_VARIABLE | T_ECLIST:
687
	 $$->code = 'V';
688
	 $$->a1.p = $1->def;
689
	 $$->a2.p = $1->name;
690
	 break;
691
       default:
692
	 cf_error("%s: variable expected.", $1->name );
693
     }
694
   }
695

    
696
static_attr:
697
   FROM    { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = OFFSETOF(struct rta, from);   $$->a1.i = 1; }
698

    
699
 | GW      { $$ = f_new_inst(); $$->aux = T_IP;         $$->a2.i = OFFSETOF(struct rta, gw);     $$->a1.i = 1; }
700
 | NET     { $$ = f_new_inst(); $$->aux = T_PREFIX;     $$->a2.i = 0x12345678; /* This is actually ok - T_PREFIX is special-cased. */ }
701
 | PROTO   { $$ = f_new_inst(); $$->aux = T_STRING;     $$->a2.i = 0x12345678; /* T_STRING is also special-cased. */ }
702
 | SOURCE  { $$ = f_new_inst(); $$->aux = T_ENUM_RTS;   $$->a2.i = OFFSETOF(struct rta, source); }
703
 | SCOPE   { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = OFFSETOF(struct rta, scope);  $$->a1.i = 1; }
704
 | CAST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTC;   $$->a2.i = OFFSETOF(struct rta, cast); }
705
 | DEST    { $$ = f_new_inst(); $$->aux = T_ENUM_RTD;   $$->a2.i = OFFSETOF(struct rta, dest); }
706
 ;
707

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

    
726
 | symbol   { $$ = $1; }
727
 | constant { $$ = $1; }
728
 | constructor { $$ = $1; }
729

    
730
 | PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; }
731

    
732
 | rtadot static_attr { $$ = $2; $$->code = 'a'; }
733

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

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

    
742
/* Communities */
743
/* This causes one shift/reduce conflict
744
 | rtadot dynamic_attr '.' ADD '(' term ')' { }
745
 | rtadot dynamic_attr '.' DELETE '(' term ')' { }
746
 | rtadot dynamic_attr '.' CONTAINS '(' term ')' { }
747
 | rtadot dynamic_attr '.' RESET{ }
748
*/
749

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

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

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

    
783
break_command:
784
   QUITBIRD { $$ = F_QUITBIRD; }
785
 | ACCEPT { $$ = F_ACCEPT; }
786
 | REJECT { $$ = F_REJECT; }
787
 | ERROR { $$ = F_ERROR; }
788
 | PRINT { $$ = F_NOP; }
789
 | PRINTN { $$ = F_NONL; }
790
 ;
791

    
792
print_one:
793
   term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; }
794
 ;
795

    
796
print_list: /* EMPTY */ { $$ = NULL; }
797
 | print_one { $$ = $1; }
798
 | print_one ',' print_list {
799
     if ($1) {
800
       $1->next = $3;
801
       $$ = $1;
802
     } else $$ = $3;
803
   }
804
 
805
 ;
806

    
807
var_listn: term { 
808
     $$ = f_new_inst();
809
     $$->code = 's';
810
     $$->a1.p = NULL;
811
     $$->a2.p = $1;
812
     $$->next = NULL;
813
   }
814
 | term ',' var_listn {
815
     $$ = f_new_inst();
816
     $$->code = 's';
817
     $$->a1.p = NULL;
818
     $$->a2.p = $1;
819
     $$->next = $3;
820
   }
821
 ;
822

    
823
var_list: /* EMPTY */ { $$ = NULL; }
824
 | var_listn { $$ = $1; }
825
 ;
826

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

    
891

    
892
 | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
893
 | rtadot dynamic_attr '.' PREPEND '(' term ')' ';'   { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); }
894
 | rtadot dynamic_attr '.' ADD '(' term ')' ';'       { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); }
895
 | rtadot dynamic_attr '.' DELETE '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); }
896
 | rtadot dynamic_attr '.' FILTER '(' term ')' ';'    { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); }
897
 ;
898

    
899
CF_END