Statistics
| Branch: | Revision:

iof-bird-daemon / filter / filter.c @ 0dc4431c

History | View | Annotate | Download (20 KB)

1
/*
2
 *        Filters: utility functions
3
 *
4
 *        Copyright 1998 Pavel Machek <pavel@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 *
8
 */
9

    
10
/**
11
 * DOC: Filters
12
 *
13
 * You can find sources of filters language in filter/
14
 * directory. filter/config.Y filter grammar, and basically translates
15
 * source from user into tree of &f_inst structures. These trees are
16
 * later interpreted using code in filter/filter.c. Filters internally
17
 * work with values/variables in struct f_val, which contains type of
18
 * value and value.
19
 *
20
 * Filter consists of tree of &f_inst structures, one structure per
21
 * "instruction". Each &f_inst contains code, aux value which is
22
 * usually type of data this instruction operates on, and two generic
23
 * arguments (a1, a2). Some instructinos contain pointer(s) to other
24
 * instructions in their (a1, a2) fields.
25
 *
26
 * Filters use structure &f_val for its variables. Each &f_val
27
 * contains type and value. Types are constants prefixed with %T_. Few
28
 * of types are special; %T_RETURN can be or-ed with type to indicate
29
 * that return from function/from whole filter should be
30
 * forced. Important thing about &f_val s is that they may be copied
31
 * with simple =. That's fine for all currently defined types: strings
32
 * are read-only (and therefore okay), paths are copied for each
33
 * operation (okay too).  */
34

    
35
#undef LOCAL_DEBUG
36

    
37
#include "nest/bird.h"
38
#include "lib/lists.h"
39
#include "lib/resource.h"
40
#include "lib/socket.h"
41
#include "lib/string.h"
42
#include "lib/unaligned.h"
43
#include "nest/route.h"
44
#include "nest/protocol.h"
45
#include "nest/iface.h"
46
#include "nest/attrs.h"
47
#include "conf/conf.h"
48
#include "filter/filter.h"
49

    
50
#define P(a,b) ((a<<8) | b)
51

    
52
#define CMP_ERROR 999
53

    
54
struct adata *
55
adata_empty(struct linpool *pool)
56
{
57
  struct adata *res = lp_alloc(pool, sizeof(struct adata));
58
  res->length = 0;
59
  return res;
60
}
61

    
62
static int
63
pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2)
64
{
65
  while (1) {
66
    if ((!m1) || (!m2))
67
      return !((!m1) && (!m2));
68
    m1 = m1->next;
69
    m2 = m2->next;
70
  }
71
}
72

    
73
/* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
74
int
75
val_compare(struct f_val v1, struct f_val v2)
76
{
77
  if ((v1.type == T_VOID) && (v2.type == T_VOID))
78
    return 0;
79
  if (v1.type == T_VOID)        /* Hack for else */
80
    return -1;
81
  if (v2.type == T_VOID)
82
    return 1;
83

    
84
  if (v1.type != v2.type) {
85
    debug( "Types do not match in val_compare\n" );
86
    return CMP_ERROR;
87
  }
88
  switch (v1.type) {
89
  case T_ENUM:
90
  case T_INT: 
91
  case T_PAIR:
92
    if (v1.val.i == v2.val.i) return 0;
93
    if (v1.val.i < v2.val.i) return -1;
94
    return 1;
95
  case T_IP:
96
  case T_PREFIX:
97
    return ipa_compare(v1.val.px.ip, v2.val.px.ip);
98
  case T_PATH_MASK:
99
    return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
100
  default:
101
    debug( "Compare of unkown entities: %x\n", v1.type );
102
    return CMP_ERROR;
103
  }
104
}
105

    
106
int
107
val_simple_in_range(struct f_val v1, struct f_val v2)
108
{
109
  if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
110
    return as_path_match(v1.val.ad, v2.val.path_mask);
111
  if ((v1.type == T_PAIR) && (v2.type == T_CLIST))
112
    return int_set_contains(v2.val.ad, v1.val.i);
113

    
114
  if ((v1.type == T_IP) && (v2.type == T_PREFIX))
115
    return !(ipa_compare(ipa_and(v2.val.px.ip, ipa_mkmask(v2.val.px.len)), ipa_and(v1.val.px.ip, ipa_mkmask(v2.val.px.len))));
116

    
117
  if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) {
118
    ip_addr mask;
119
    if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE))
120
      return CMP_ERROR;
121
    mask = ipa_mkmask( v2.val.px.len & LEN_MASK );
122
    if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask)))
123
      return 0;
124

    
125
    if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK)))
126
      return 0;
127
    if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK)))
128
      return 0;
129
    if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16)))
130
                                        || (v1.val.px.len > (0xff & (v2.val.px.len >> 8)))))
131
      return 0;
132
    return 1;    
133
  }
134
  return CMP_ERROR;
135
}
136

    
137
int
138
val_in_range(struct f_val v1, struct f_val v2)
139
{
140
  int res;
141

    
142
  res = val_simple_in_range(v1, v2);
143

    
144
  if (res != CMP_ERROR)
145
    return res;
146

    
147
  if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) {
148
    struct f_tree *n;
149
    n = find_tree(v2.val.t, v1);
150
    if (!n)
151
      return 0;
152
    return !! (val_simple_in_range(v1, n->from));        /* We turn CMP_ERROR into compared ok, and that's fine */
153
  }
154
  return CMP_ERROR;
155
}
156

    
157
static void
158
tree_print(struct f_tree *t)
159
{
160
  if (!t) {
161
    debug( "() " );
162
    return;
163
  }
164
  debug( "[ " );
165
  tree_print( t->left );
166
  debug( ", " ); val_print( t->from ); debug( ".." ); val_print( t->to ); debug( ", " );
167
  tree_print( t->right );
168
  debug( "] " );
169
}
170

    
171
void
172
val_print(struct f_val v)
173
{
174
  char buf[2048];
175
  char buf2[1024];
176
#define PRINTF(a...) bsnprintf( buf, 2040, a )
177
  buf[0] = 0;
178
  switch (v.type) {
179
  case T_VOID: PRINTF( "(void)" ); break;
180
  case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
181
  case T_INT: PRINTF( "%d ", v.val.i ); break;
182
  case T_STRING: PRINTF( "%s", v.val.s ); break;
183
  case T_IP: PRINTF( "%I", v.val.px.ip ); break;
184
  case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
185
  case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
186
  case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
187
  case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
188
  case T_PATH: as_path_format(v.val.ad, buf2, 1020); PRINTF( "(path %s)", buf2 ); break;
189
  case T_CLIST: int_set_format(v.val.ad, buf2, 1020); PRINTF( "(clist %s)", buf2 ); break;
190
  case T_PATH_MASK: debug( "(pathmask " ); { struct f_path_mask *p = v.val.path_mask; while (p) { debug("%d ", p->val); p=p->next; } debug(")" ); } break;
191
  default: PRINTF( "[unknown type %x]", v.type );
192
#undef PRINTF
193
  }
194
  debug( buf );
195
}
196

    
197
static struct rte **f_rte, *f_rte_old;
198
static struct linpool *f_pool;
199
static struct ea_list **f_tmp_attrs;
200
static int f_flags;
201
static rta *f_rta_copy;
202

    
203
void
204
rta_cow(void)
205
{
206
  if (!f_rta_copy) {
207
    f_rta_copy = lp_alloc(f_pool, sizeof(rta));
208
    memcpy(f_rta_copy, (*f_rte)->attrs, sizeof(rta));
209
    f_rta_copy->aflags = 0;
210
    *f_rte = rte_cow(*f_rte);
211
    (*f_rte)->attrs = f_rta_copy;
212
  }
213
}
214

    
215
#define runtime(x) do { \
216
    log( L_ERR "filters, line %d: %s", what->lineno, x); \
217
    res.type = T_RETURN; \
218
    res.val.i = F_ERROR; \
219
    return res; \
220
  } while(0)
221

    
222
#define ARG(x,y) \
223
        x = interpret(what->y); \
224
        if (x.type & T_RETURN) \
225
                return x;
226

    
227
#define ONEARG ARG(v1, a1.p)
228
#define TWOARGS ARG(v1, a1.p) \
229
                ARG(v2, a2.p)
230
#define TWOARGS_C TWOARGS \
231
                  if (v1.type != v2.type) \
232
                    runtime( "Can not operate with values of incompatible types" );
233

    
234
static struct f_val
235
interpret(struct f_inst *what)
236
{
237
  struct symbol *sym;
238
  struct f_val v1, v2, res;
239
  int i,j,k;
240

    
241
  res.type = T_VOID;
242
  if (!what)
243
    return res;
244

    
245
  switch(what->code) {
246
  case ',':
247
    TWOARGS;
248
    break;
249

    
250
/* Binary operators */
251
  case '+':
252
    TWOARGS_C;
253
    switch (res.type = v1.type) {
254
    case T_VOID: runtime( "Can not operate with values of type void" );
255
    case T_INT: res.val.i = v1.val.i + v2.val.i; break;
256
    default: runtime( "Usage of unknown type" );
257
    }
258
    break;
259
  case '-':
260
    TWOARGS_C;
261
    switch (res.type = v1.type) {
262
    case T_VOID: runtime( "Can not operate with values of type void" );
263
    case T_INT: res.val.i = v1.val.i - v2.val.i; break;
264
    default: runtime( "Usage of unknown type" );
265
    }
266
    break;
267
  case '*':
268
    TWOARGS_C;
269
    switch (res.type = v1.type) {
270
    case T_VOID: runtime( "Can not operate with values of type void" );
271
    case T_INT: res.val.i = v1.val.i * v2.val.i; break;
272
    default: runtime( "Usage of unknown type" );
273
    }
274
    break;
275
  case '/':
276
    TWOARGS_C;
277
    switch (res.type = v1.type) {
278
    case T_VOID: runtime( "Can not operate with values of type void" );
279
    case T_INT: res.val.i = v1.val.i / v2.val.i; break;
280
    case T_IP: if (v2.type != T_INT)
281
                 runtime( "Operator / is <ip>/<int>" );
282
               break;
283
    default: runtime( "Usage of unknown type" );
284
    }
285
    break;
286

    
287
/* Relational operators */
288

    
289
#define COMPARE(x) \
290
    TWOARGS_C; \
291
    res.type = T_BOOL; \
292
    i = val_compare(v1, v2); \
293
    if (i==CMP_ERROR) \
294
      runtime( "Error in comparation" ); \
295
    res.val.i = (x); \
296
    break;
297

    
298
  case P('!','='): COMPARE(i!=0);
299
  case P('=','='): COMPARE(i==0);
300
  case '<': COMPARE(i==-1);
301
  case P('<','='): COMPARE(i!=1);
302

    
303
  case '!':
304
    ONEARG;
305
    if (v1.type != T_BOOL)
306
      runtime( "not applied to non-boolean" );
307
    res = v1;
308
    res.val.i = !res.val.i;
309
    break;
310

    
311
  case '~':
312
    TWOARGS;
313
    res.type = T_BOOL;
314
    res.val.i = val_in_range(v1, v2);
315
    if (res.val.i == CMP_ERROR)
316
      runtime( "~ applied on unknown type pair" );
317
    break;
318
  case P('d','e'):
319
    ONEARG;
320
    res.type = T_BOOL;
321
    res.val.i = (v1.type != T_VOID);
322
    break;
323

    
324
  /* Set to indirect value, a1 = variable, a2 = value */
325
  case 's':
326
    ARG(v2, a2.p);
327
    sym = what->a1.p;
328
    switch (res.type = v2.type) {
329
    case T_VOID: runtime( "Can not assign void values" );
330
    case T_ENUM:
331
    case T_INT: 
332
    case T_IP: 
333
    case T_PREFIX: 
334
    case T_PAIR: 
335
    case T_PATH:
336
    case T_CLIST:
337
    case T_PATH_MASK:
338
      if (sym->class != (SYM_VARIABLE | v2.type))
339
        runtime( "Variable of bad type" );
340
      * (struct f_val *) sym->aux2 = v2; 
341
      break;
342
    default:
343
      bug( "Set to invalid type" );
344
    }
345
    break;
346

    
347
  case 'c':        /* integer (or simple type) constant */
348
    res.type = what->aux;
349
    res.val.i = what->a2.i;
350
    break;
351
  case 'C':
352
    res = * ((struct f_val *) what->a1.p);
353
    break;
354
  case 'p':
355
    ONEARG;
356
    val_print(v1);
357
    break;
358
  case '?':        /* ? has really strange error value, so we can implement if ... else nicely :-) */
359
    ONEARG;
360
    if (v1.type != T_BOOL)
361
      runtime( "If requires bool expression" );
362
    if (v1.val.i) {
363
      ARG(res,a2.p);
364
      res.val.i = 0;
365
    } else res.val.i = 1;
366
    res.type = T_BOOL;
367
    break;
368
  case '0':
369
    debug( "No operation\n" );
370
    break;
371
  case P('p',','):
372
    ONEARG;
373
    if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
374
      debug( "\n" );
375

    
376
    switch (what->a2.i) {
377
    case F_QUITBIRD:
378
      die( "Filter asked me to die" );
379
    case F_ACCEPT:
380
      /* Should take care about turning ACCEPT into MODIFY */
381
    case F_ERROR:
382
    case F_REJECT:        /* FIXME (noncritical) Should print complete route along with reason to reject route */
383
      res.type = T_RETURN;
384
      res.val.i = what->a2.i;
385
      return res;        /* We have to return now, no more processing. */
386
    case F_NONL:
387
    case F_NOP:
388
      break;
389
    default:
390
      bug( "unknown return type: can not happen");
391
    }
392
    break;
393
  case 'a':        /* rta access */
394
    {
395
      struct rta *rta = (*f_rte)->attrs;
396
      res.type = what->aux;
397
      switch(res.type) {
398
      case T_IP:
399
        res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
400
        break;
401
      case T_ENUM:
402
        res.val.i = * ((char *) rta + what->a2.i);
403
        break;
404
      case T_PREFIX:        /* Warning: this works only for prefix of network */
405
        {
406
          res.val.px.ip = (*f_rte)->net->n.prefix;
407
          res.val.px.len = (*f_rte)->net->n.pxlen;
408
          break;
409
        }
410
      default:
411
        bug( "Invalid type for rta access (%x)", res.type );
412
      }
413
    }
414
    break;
415
  case P('a','S'):
416
    ONEARG;
417
    if (what->aux != v1.type)
418
      runtime( "Attempt to set static attribute to invalid type" );
419
    rta_cow();
420
    {
421
      struct rta *rta = (*f_rte)->attrs;
422
      switch (what->aux) {
423
      case T_ENUM:
424
        * ((char *) rta + what->a2.i) = v1.val.i;
425
        break;
426
      case T_IP:
427
        * (ip_addr *) ((char *) rta + what->a2.i) = v1.val.px.ip;
428
        break;
429
      default:
430
        bug( "Unknown type in set of static attribute" );
431
      }
432
    }
433
    break;
434
  case P('e','a'):        /* Access to extended attributes */
435
    {
436
      eattr *e = NULL;
437
      if (!(f_flags & FF_FORCE_TMPATTR))
438
        e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
439
      if (!e) 
440
        e = ea_find( (*f_tmp_attrs), what->a2.i );
441
      if ((!e) && (f_flags & FF_FORCE_TMPATTR))
442
        e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
443
      
444
      switch (what->aux & EAF_TYPE_MASK) {
445
      case EAF_TYPE_INT:
446
        if (!e) {
447
          res.type = T_VOID;
448
          break;
449
        }
450
        res.type = T_INT;
451
        res.val.i = e->u.data;
452
        break;
453
      case EAF_TYPE_AS_PATH:
454
        if (!e) {
455
          res.type = T_VOID;
456
          break;
457
        }
458
        res.type = T_PATH;
459
        res.val.ad = e->u.ptr;
460
        break;
461
      case EAF_TYPE_INT_SET:
462
        if (!e) {
463
          res.type = T_CLIST;
464
          res.val.ad = adata_empty(f_pool);
465
          break;
466
        }
467
        res.type = T_CLIST;
468
        res.val.ad = e->u.ptr;
469
        break;
470
      default:
471
        bug("Unknown type in e,a");
472
      }
473
    }
474
    break;
475
  case P('e','S'):
476
    ONEARG;
477
    {
478
      struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
479

    
480
      l->next = NULL;
481
      l->flags = EALF_SORTED;
482
      l->count = 1;
483
      l->attrs[0].id = what->a2.i;
484
      l->attrs[0].flags = 0;
485
      l->attrs[0].type = what->aux | EAF_ORIGINATED;
486
      switch (what->aux & EAF_TYPE_MASK) {
487
      case EAF_TYPE_INT:
488
        if (v1.type != T_INT)
489
          runtime( "Setting int attribute to non-int value" );
490
        l->attrs[0].u.data = v1.val.i;
491
        break;
492
      case EAF_TYPE_AS_PATH:
493
        if (v1.type != T_PATH)
494
          runtime( "Setting path attribute to non-path value" );
495
        l->attrs[0].u.ptr = v1.val.ad;
496
        break;
497
      case EAF_TYPE_INT_SET:
498
        if (v1.type != T_CLIST)
499
          runtime( "Setting int set  attribute to non-clist value" );
500
        l->attrs[0].u.ptr = v1.val.ad;
501
        break;
502
      case EAF_TYPE_UNDEF:
503
        if (v1.type != T_VOID)
504
          runtime( "Setting void attribute to non-void value" );
505
        l->attrs[0].u.data = 0;
506
        break;
507
      default: bug("Unknown type in e,S");
508
      }
509

    
510
      if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
511
        rta_cow();
512
        l->next = f_rta_copy->eattrs;
513
        f_rta_copy->eattrs = l;
514
      } else {
515
        l->next = (*f_tmp_attrs);
516
        (*f_tmp_attrs) = l;
517
      }
518
    }
519
    break;
520
  case 'P':
521
    res.type = T_INT;
522
    res.val.i = (*f_rte)->pref;
523
    break;
524
  case P('P','S'):
525
    ONEARG;
526
    if (v1.type != T_INT)
527
      runtime( "Can not set preference to non-integer" );
528
    *f_rte = rte_cow(*f_rte);
529
    (*f_rte)->pref = v1.val.i;
530
    break;
531
  case 'L':        /* Get length of */
532
    ONEARG;
533
    res.type = T_INT;
534
    switch(v1.type) {
535
    case T_PREFIX: res.val.i = v1.val.px.len; break;
536
    case T_PATH:   res.val.i = as_path_getlen(v1.val.ad); break;
537
    default: bug( "Length of what?" );
538
    }
539
    break;
540
  case P('c','p'):        /* Convert prefix to ... */
541
    ONEARG;
542
    if (v1.type != T_PREFIX)
543
      runtime( "Can not convert non-prefix this way" );
544
    res.type = what->aux;
545
    switch(res.type) {
546
      /*    case T_INT:        res.val.i = v1.val.px.len; break; Not needed any more */
547
    case T_IP: res.val.px.ip = v1.val.px.ip; break;
548
    default: bug( "Unknown prefix to conversion" );
549
    }
550
    break;
551
  case 'r':
552
    ONEARG;
553
    res = v1;
554
    res.type |= T_RETURN;
555
    break;
556
  case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out  */
557
    ONEARG;
558
    res = interpret(what->a2.p);
559
    if (res.type == T_RETURN)
560
      return res;
561
    res.type &= ~T_RETURN;    
562
    break;
563
  case P('S','W'):
564
    ONEARG;
565
    {
566
      struct f_tree *t = find_tree(what->a2.p, v1);
567
      if (!t) {
568
        v1.type = T_VOID;
569
        t = find_tree(what->a2.p, v1);
570
        if (!t) {
571
          debug( "No else statement?\n");
572
          break;
573
        }
574
      }        
575
      if (!t->data)
576
        bug( "Impossible: no code associated!" );
577
      return interpret(t->data);
578
    }
579
    break;
580
  case P('i','M'): /* IP.MASK(val) */
581
    TWOARGS;
582
    if (v2.type != T_INT)
583
      runtime( "Can not use this type for mask.");
584
    if (v1.type != T_IP)
585
      runtime( "You can mask only IP addresses." );
586
    {
587
      ip_addr mask = ipa_mkmask(v2.val.i);
588
      res.type = T_IP;
589
      res.val.px.ip = ipa_and(mask, v1.val.px.ip);
590
    }
591
    break;
592

    
593
  case 'E':        /* Create empty attribute */
594
    res.type = what->aux;
595
    res.val.ad = adata_empty(f_pool);
596
    break;
597
  case P('A','p'):        /* Path prepend */
598
    TWOARGS;
599
    if (v1.type != T_PATH)
600
      runtime("Can't prepend to non-path");
601
    if (v2.type != T_INT)
602
      runtime("Can't prepend non-integer");
603

    
604
    res.type = T_PATH;
605
    res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
606
    break;
607

    
608
  case P('C','a'):        /* Community list add or delete */
609
    TWOARGS;
610
    if (v1.type != T_CLIST)
611
      runtime("Can't add/delete to non-clist");
612
    if (v2.type != T_PAIR)
613
      runtime("Can't add/delete non-pair");
614

    
615
    res.type = T_CLIST;
616
    switch (what->aux) {
617
    case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break;
618
    case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break;
619
    default: bug("unknown Ca operation");
620
    }
621
    break;
622

    
623
  default:
624
    bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
625
  }
626
  if (what->next)
627
    return interpret(what->next);
628
  return res;
629
}
630

    
631
#undef ARG
632
#define ARG(x,y) \
633
        if (!i_same(f1->y, f2->y)) \
634
                return 0;
635

    
636
#define ONEARG ARG(v1, a1.p)
637
#define TWOARGS ARG(v1, a1.p) \
638
                ARG(v2, a2.p)
639

    
640
#define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
641

    
642
int
643
i_same(struct f_inst *f1, struct f_inst *f2)
644
{
645
  if ((!!f1) != (!!f2))
646
    return 0;
647
  if (!f1)
648
    return 1;
649
  if (f1->aux != f2->aux)
650
    return 0;
651
  if (f1->code != f2->code)
652
    return 0;
653
  if (f1 == f2)                /* It looks strange, but it is possible with call rewriting trickery */
654
    return 1;
655

    
656
  switch(f1->code) {
657
  case ',': /* fall through */
658
  case '+':
659
  case '-':
660
  case '*':
661
  case '/':
662
  case P('!','='):
663
  case P('=','='):
664
  case '<':
665
  case P('<','='): TWOARGS; break;
666

    
667
  case '!': ONEARG; break;
668
  case '~': TWOARGS; break;
669
  case P('d','e'): ONEARG; break;
670

    
671
  case 's':
672
    ARG(v2, a2.p);
673
    {
674
      struct symbol *s1, *s2;
675
      s1 = f1->a1.p;
676
      s2 = f2->a1.p;
677
      if (strcmp(s1->name, s2->name))
678
        return 0;
679
      if (s1->class != s2->class)
680
        return 0;
681
    }
682
    break;
683

    
684
  case 'c': A2_SAME; break;
685
  case 'C': 
686
    if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
687
      return 0;
688
    break;
689
  case 'p': case 'L': ONEARG; break;
690
  case '?': TWOARGS; break;
691
  case '0': case 'E': break;
692
  case P('p',','): ONEARG; A2_SAME; break;
693
  case 'P':
694
  case 'a': A2_SAME; break;
695
  case P('e','a'): A2_SAME; break;
696
  case P('P','S'):
697
  case P('a','S'):
698
  case P('e','S'): ONEARG; A2_SAME; break;
699

    
700
  case 'r': ONEARG; break;
701
  case P('c','p'): ONEARG; break;
702
  case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
703
             ONEARG; 
704
             if (!i_same(f1->a2.p, f2->a2.p))
705
               return 0; 
706
             f2->a2.p = f1->a2.p;
707
             break;
708
  case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
709
  case P('i','M'): TWOARGS; break;
710
  case P('A','p'): TWOARGS; break;
711
  case P('C','a'): TWOARGS; break;
712
  default:
713
    bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
714
  }
715
  return i_same(f1->next, f2->next);
716
}
717

    
718
/**
719
 * f_run - external entry point to filters
720
 * @filter: pointer to filter to run
721
 * @rte: pointer to pointer to rte being filtered. When route is modified, this is changed with rte_cow.
722
 * @tmp_pool: all filter allocations go from this pool
723
 */
724
int
725
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
726
{
727
  struct f_inst *inst;
728
  struct f_val res;
729
  DBG( "Running filter `%s'...", filter->name );
730

    
731
  f_flags = flags;
732
  f_tmp_attrs = tmp_attrs;
733
  f_rte = rte;
734
  f_rte_old = *rte;
735
  f_rta_copy = NULL;
736
  f_pool = tmp_pool;
737
  inst = filter->root;
738
  res = interpret(inst);
739
  if (res.type != T_RETURN)
740
    return F_ERROR;
741
  DBG( "done (%d)\n", res.val.i );
742
  return res.val.i;
743
}
744

    
745
int
746
f_eval_int(struct f_inst *expr)
747
{
748
  struct f_val res;
749

    
750
  f_flags = 0;
751
  f_tmp_attrs = NULL;
752
  f_rte = NULL;
753
  f_rte_old = NULL;
754
  f_rta_copy = NULL;
755
  f_pool = cfg_mem;
756
  res = interpret(expr);
757
  if (res.type != T_INT)
758
    cf_error("Integer expression expected");
759
  return res.val.i;
760
}
761

    
762
/**
763
 * filter_same - compare two filters
764
 * @new: first filter to be compared
765
 * @old: second filter to be compared, notice that this filter is
766
 * damaged while comparing.
767
 *
768
 * Returns 1 in case filters are same, otherwise 0. If there are
769
 * underlying bugs, it will rather say 0 on same filters than say
770
 * 1 on different.
771
 */
772
int
773
filter_same(struct filter *new, struct filter *old)
774
{
775
  if (old == new)        /* Handle FILTER_ACCEPT and FILTER_REJECT */
776
    return 1;
777
  if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
778
      new == FILTER_ACCEPT || new == FILTER_REJECT)
779
    return 0;
780
  return i_same(new->root, old->root);
781
}