Statistics
| Branch: | Revision:

iof-bird-daemon / filter / filter.c @ 26c09e1d

History | View | Annotate | Download (19.2 KB)

1 23b1539b Pavel Machek
/*
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 29818140 Pavel Machek
 *
8 23b1539b Pavel Machek
 */
9
10 2337ade7 Pavel Machek
/**
11
 * DOC: Filters
12
 *
13 fe613ecd Pavel Machek
 * 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 2337ade7 Pavel Machek
 * 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 fe613ecd Pavel Machek
 * operation (okay too).  */
34 2337ade7 Pavel Machek
35 9a220cab Martin Mares
#undef LOCAL_DEBUG
36 6b9fa320 Martin Mares
37 23b1539b Pavel Machek
#include "nest/bird.h"
38
#include "lib/lists.h"
39
#include "lib/resource.h"
40
#include "lib/socket.h"
41 38506f71 Pavel Machek
#include "lib/string.h"
42 7f77e250 Pavel Machek
#include "lib/unaligned.h"
43 23b1539b Pavel Machek
#include "nest/route.h"
44
#include "nest/protocol.h"
45
#include "nest/iface.h"
46 159fa4ce Pavel Machek
#include "nest/attrs.h"
47 23b1539b Pavel Machek
#include "conf/conf.h"
48
#include "filter/filter.h"
49
50 2d496d20 Pavel Machek
#define P(a,b) ((a<<8) | b)
51
52 38506f71 Pavel Machek
#define CMP_ERROR 999
53
54 ad9074e9 Pavel Machek
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 b0c9c21c Pavel Machek
static int
63 2e5a8735 Pavel Machek
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 38506f71 Pavel Machek
/* 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 41be4444 Pavel Machek
  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 f71bded6 Pavel Machek
  if (v1.type != v2.type) {
85
    debug( "Types do not match in val_compare\n" );
86 7db7b7db Pavel Machek
    return CMP_ERROR;
87 f71bded6 Pavel Machek
  }
88 38506f71 Pavel Machek
  switch (v1.type) {
89 f4536657 Pavel Machek
  case T_ENUM:
90 38506f71 Pavel Machek
  case T_INT: 
91 d3dd620b Pavel Machek
  case T_PAIR:
92 38506f71 Pavel Machek
    if (v1.val.i == v2.val.i) return 0;
93
    if (v1.val.i < v2.val.i) return -1;
94
    return 1;
95 43fc099b Pavel Machek
  case T_IP:
96 6dc7a0cb Pavel Machek
  case T_PREFIX:
97
    return ipa_compare(v1.val.px.ip, v2.val.px.ip);
98 2e5a8735 Pavel Machek
  case T_PATH_MASK:
99
    return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
100 3076b5ae Martin Mares
  default:
101 f71bded6 Pavel Machek
    debug( "Compare of unkown entities: %x\n", v1.type );
102 3076b5ae Martin Mares
    return CMP_ERROR;
103 38506f71 Pavel Machek
  }
104
}
105
106 f71bded6 Pavel Machek
int
107 6dc7a0cb Pavel Machek
val_simple_in_range(struct f_val v1, struct f_val v2)
108
{
109 10a53608 Pavel Machek
  if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
110 2a40efa5 Pavel Machek
    return as_path_match(v1.val.ad, v2.val.path_mask);
111 2bd2de01 Pavel Machek
  if ((v1.type == T_PAIR) && (v2.type == T_CLIST))
112
    return int_set_contains(v2.val.ad, v1.val.i);
113 10a53608 Pavel Machek
114 6dc7a0cb Pavel Machek
  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 8f013d9c Pavel Machek
125 6dc7a0cb Pavel Machek
    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 7db7b7db Pavel Machek
int
138
val_in_range(struct f_val v1, struct f_val v2)
139
{
140 6dc7a0cb Pavel Machek
  int res;
141
142
  res = val_simple_in_range(v1, v2);
143
144
  if (res != CMP_ERROR)
145
    return res;
146
147 2f702671 Pavel Machek
  if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) {
148 6dc7a0cb Pavel Machek
    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 7db7b7db Pavel Machek
  return CMP_ERROR;
155
}
156
157 38506f71 Pavel Machek
static void
158
tree_print(struct f_tree *t)
159
{
160
  if (!t) {
161 3cf4a2e2 Martin Mares
    debug( "() " );
162 38506f71 Pavel Machek
    return;
163
  }
164 3cf4a2e2 Martin Mares
  debug( "[ " );
165 38506f71 Pavel Machek
  tree_print( t->left );
166 3cf4a2e2 Martin Mares
  debug( ", " ); val_print( t->from ); debug( ".." ); val_print( t->to ); debug( ", " );
167 38506f71 Pavel Machek
  tree_print( t->right );
168 3cf4a2e2 Martin Mares
  debug( "] " );
169 38506f71 Pavel Machek
}
170
171
void
172
val_print(struct f_val v)
173
{
174
  char buf[2048];
175 ecd25633 Pavel Machek
  char buf2[1024];
176 38506f71 Pavel Machek
#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 6dc7a0cb Pavel Machek
  case T_IP: PRINTF( "%I", v.val.px.ip ); break;
184 720d911d Pavel Machek
  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 38506f71 Pavel Machek
  case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
187 346a12c2 Pavel Machek
  case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
188 ecd25633 Pavel Machek
  case T_PATH: as_path_format(v.val.ad, buf2, 1020); PRINTF( "(path %s)", buf2 ); break;
189 159fa4ce Pavel Machek
  case T_CLIST: int_set_format(v.val.ad, buf2, 1020); PRINTF( "(clist %s)", buf2 ); break;
190 ad9074e9 Pavel Machek
  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 38506f71 Pavel Machek
  default: PRINTF( "[unknown type %x]", v.type );
192 7f77e250 Pavel Machek
#undef PRINTF
193 38506f71 Pavel Machek
  }
194 3cf4a2e2 Martin Mares
  debug( buf );
195 38506f71 Pavel Machek
}
196
197 48f9e019 Pavel Machek
static struct rte **f_rte, *f_rte_old;
198 f31156ca Pavel Machek
static struct linpool *f_pool;
199 31e79264 Pavel Machek
static struct ea_list **f_tmp_attrs;
200 0a06a9b8 Pavel Machek
static int f_flags;
201 74a7da48 Martin Mares
static rta *f_rta_copy;
202 36bbfc70 Pavel Machek
203 26c09e1d Pavel Machek
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 9a4037d4 Pavel Machek
#define runtime(x) do { \
216 a96a979d Pavel Machek
    log( L_ERR "filters, line %d: %s", what->lineno, x); \
217 9a4037d4 Pavel Machek
    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 2d496d20 Pavel Machek
        if (x.type & T_RETURN) \
225 9a4037d4 Pavel Machek
                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 7db7b7db Pavel Machek
234
static struct f_val
235 23b1539b Pavel Machek
interpret(struct f_inst *what)
236
{
237
  struct symbol *sym;
238
  struct f_val v1, v2, res;
239 38506f71 Pavel Machek
  int i,j,k;
240 23b1539b Pavel Machek
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 9f0d45d6 Pavel Machek
  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 23b1539b Pavel Machek
  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 38506f71 Pavel Machek
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 23b1539b Pavel Machek
    break;
297 38506f71 Pavel Machek
298 2d496d20 Pavel Machek
  case P('!','='): COMPARE(i!=0);
299
  case P('=','='): COMPARE(i==0);
300 38506f71 Pavel Machek
  case '<': COMPARE(i==-1);
301 2d496d20 Pavel Machek
  case P('<','='): COMPARE(i!=1);
302 38506f71 Pavel Machek
303 995e5894 Pavel Machek
  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 38506f71 Pavel Machek
  case '~':
312
    TWOARGS;
313 23b1539b Pavel Machek
    res.type = T_BOOL;
314 7db7b7db Pavel Machek
    res.val.i = val_in_range(v1, v2);
315
    if (res.val.i == CMP_ERROR)
316
      runtime( "~ applied on unknown type pair" );
317 23b1539b Pavel Machek
    break;
318 2d496d20 Pavel Machek
  case P('d','e'):
319 f4536657 Pavel Machek
    ONEARG;
320
    res.type = T_BOOL;
321
    res.val.i = (v1.type != T_VOID);
322
    break;
323 23b1539b Pavel Machek
324 d3dd620b Pavel Machek
  /* Set to indirect value, a1 = variable, a2 = value */
325 23b1539b Pavel Machek
  case 's':
326 2db3b288 Pavel Machek
    ARG(v2, a2.p);
327
    sym = what->a1.p;
328 23b1539b Pavel Machek
    switch (res.type = v2.type) {
329
    case T_VOID: runtime( "Can not assign void values" );
330 f4536657 Pavel Machek
    case T_ENUM:
331 23b1539b Pavel Machek
    case T_INT: 
332 d3dd620b Pavel Machek
    case T_IP: 
333
    case T_PREFIX: 
334
    case T_PAIR: 
335 e399b6f6 Pavel Machek
    case T_PATH:
336
    case T_CLIST:
337 dcab7890 Pavel Machek
    case T_PATH_MASK:
338 d3dd620b Pavel Machek
      if (sym->class != (SYM_VARIABLE | v2.type))
339 23b1539b Pavel Machek
        runtime( "Variable of bad type" );
340 d3dd620b Pavel Machek
      * (struct f_val *) sym->aux2 = v2; 
341 23b1539b Pavel Machek
      break;
342 d3dd620b Pavel Machek
    default:
343 3076b5ae Martin Mares
      bug( "Set to invalid type" );
344 23b1539b Pavel Machek
    }
345
    break;
346
347 d3dd620b Pavel Machek
  case 'c':        /* integer (or simple type) constant */
348 c7b43f33 Pavel Machek
    res.type = what->aux;
349 d3dd620b Pavel Machek
    res.val.i = what->a2.i;
350 23b1539b Pavel Machek
    break;
351 38506f71 Pavel Machek
  case 'C':
352
    res = * ((struct f_val *) what->a1.p);
353
    break;
354 23b1539b Pavel Machek
  case 'p':
355
    ONEARG;
356 38506f71 Pavel Machek
    val_print(v1);
357 23b1539b Pavel Machek
    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 2db3b288 Pavel Machek
      ARG(res,a2.p);
364 23b1539b Pavel Machek
      res.val.i = 0;
365
    } else res.val.i = 1;
366
    res.type = T_BOOL;
367
    break;
368
  case '0':
369 3cf4a2e2 Martin Mares
    debug( "No operation\n" );
370 23b1539b Pavel Machek
    break;
371 2d496d20 Pavel Machek
  case P('p',','):
372 23b1539b Pavel Machek
    ONEARG;
373 798df5b1 Martin Mares
    if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
374 3cf4a2e2 Martin Mares
      debug( "\n" );
375 23b1539b Pavel Machek
376 2db3b288 Pavel Machek
    switch (what->a2.i) {
377 23b1539b Pavel Machek
    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 2ad6dcdb Martin Mares
    case F_REJECT:        /* FIXME (noncritical) Should print complete route along with reason to reject route */
383 23b1539b Pavel Machek
      res.type = T_RETURN;
384 2ad6dcdb Martin Mares
      res.val.i = what->a2.i;
385 7e1f9971 Pavel Machek
      return res;        /* We have to return now, no more processing. */
386 d3dd620b Pavel Machek
    case F_NONL:
387 23b1539b Pavel Machek
    case F_NOP:
388
      break;
389
    default:
390
      bug( "unknown return type: can not happen");
391
    }
392
    break;
393 36bbfc70 Pavel Machek
  case 'a':        /* rta access */
394
    {
395
      struct rta *rta = (*f_rte)->attrs;
396 c7b43f33 Pavel Machek
      res.type = what->aux;
397 36bbfc70 Pavel Machek
      switch(res.type) {
398
      case T_IP:
399 6dc7a0cb Pavel Machek
        res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
400 36bbfc70 Pavel Machek
        break;
401 c7b43f33 Pavel Machek
      case T_ENUM:
402
        res.val.i = * ((char *) rta + what->a2.i);
403
        break;
404 36bbfc70 Pavel Machek
      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 3076b5ae Martin Mares
        bug( "Invalid type for rta access (%x)", res.type );
412 36bbfc70 Pavel Machek
      }
413
    }
414
    break;
415 2d496d20 Pavel Machek
  case P('e','a'):        /* Access to extended attributes */
416 91447965 Pavel Machek
    {
417 0a06a9b8 Pavel Machek
      eattr *e = NULL;
418 3076b5ae Martin Mares
      if (!(f_flags & FF_FORCE_TMPATTR))
419 0a06a9b8 Pavel Machek
        e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
420 31e79264 Pavel Machek
      if (!e) 
421
        e = ea_find( (*f_tmp_attrs), what->a2.i );
422 3076b5ae Martin Mares
      if ((!e) && (f_flags & FF_FORCE_TMPATTR))
423 0a06a9b8 Pavel Machek
        e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
424
      
425 0150e521 Pavel Machek
      switch (what->aux & EAF_TYPE_MASK) {
426
      case EAF_TYPE_INT:
427 e66e6c21 Pavel Machek
        if (!e) {
428
          res.type = T_VOID;
429
          break;
430
        }
431 0150e521 Pavel Machek
        res.type = T_INT;
432 91447965 Pavel Machek
        res.val.i = e->u.data;
433
        break;
434 0150e521 Pavel Machek
      case EAF_TYPE_AS_PATH:
435 e66e6c21 Pavel Machek
        if (!e) {
436
          res.type = T_VOID;
437
          break;
438
        }
439 0150e521 Pavel Machek
        res.type = T_PATH;
440
        res.val.ad = e->u.ptr;
441
        break;
442
      case EAF_TYPE_INT_SET:
443 e66e6c21 Pavel Machek
        if (!e) {
444
          res.type = T_CLIST;
445
          res.val.ad = adata_empty(f_pool);
446
          break;
447
        }
448 0150e521 Pavel Machek
        res.type = T_CLIST;
449 10a53608 Pavel Machek
        res.val.ad = e->u.ptr;
450
        break;
451 2803c9dd Martin Mares
      default:
452 ad9074e9 Pavel Machek
        bug("Unknown type in e,a");
453 91447965 Pavel Machek
      }
454
    }
455 6dc7a0cb Pavel Machek
    break;
456 2d496d20 Pavel Machek
  case P('e','S'):
457 f31156ca Pavel Machek
    ONEARG;
458
    {
459
      struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
460
461
      l->next = NULL;
462
      l->flags = EALF_SORTED;
463
      l->count = 1;
464
      l->attrs[0].id = what->a2.i;
465 913ce95b Pavel Machek
      l->attrs[0].flags = 0;
466
      l->attrs[0].type = what->aux | EAF_ORIGINATED;
467 31e79264 Pavel Machek
      switch (what->aux & EAF_TYPE_MASK) {
468
      case EAF_TYPE_INT:
469
        if (v1.type != T_INT)
470
          runtime( "Setting int attribute to non-int value" );
471 f31156ca Pavel Machek
        l->attrs[0].u.data = v1.val.i;
472
        break;
473 10a53608 Pavel Machek
      case EAF_TYPE_AS_PATH:
474
        if (v1.type != T_PATH)
475
          runtime( "Setting path attribute to non-path value" );
476
        l->attrs[0].u.ptr = v1.val.ad;
477
        break;
478 708711c3 Pavel Machek
      case EAF_TYPE_INT_SET:
479
        if (v1.type != T_CLIST)
480
          runtime( "Setting int set  attribute to non-clist value" );
481
        l->attrs[0].u.ptr = v1.val.ad;
482
        break;
483 31e79264 Pavel Machek
      case EAF_TYPE_UNDEF:
484
        if (v1.type != T_VOID)
485
          runtime( "Setting void attribute to non-void value" );
486 48f9e019 Pavel Machek
        l->attrs[0].u.data = 0;
487
        break;
488 0150e521 Pavel Machek
      default: bug("Unknown type in e,S");
489 f31156ca Pavel Machek
      }
490 31e79264 Pavel Machek
491 3076b5ae Martin Mares
      if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
492 26c09e1d Pavel Machek
        rta_cow();
493 74a7da48 Martin Mares
        l->next = f_rta_copy->eattrs;
494
        f_rta_copy->eattrs = l;
495 31e79264 Pavel Machek
      } else {
496
        l->next = (*f_tmp_attrs);
497
        (*f_tmp_attrs) = l;
498
      }
499 f31156ca Pavel Machek
    }
500
    break;
501 48f9e019 Pavel Machek
502 684c6f5a Pavel Machek
  case 'L':        /* Get length of */
503
    ONEARG;
504
    res.type = T_INT;
505
    switch(v1.type) {
506
    case T_PREFIX: res.val.i = v1.val.px.len; break;
507
    case T_PATH:   res.val.i = as_path_getlen(v1.val.ad); break;
508
    default: bug( "Length of what?" );
509
    }
510
    break;
511 2d496d20 Pavel Machek
  case P('c','p'):        /* Convert prefix to ... */
512 36bbfc70 Pavel Machek
    ONEARG;
513
    if (v1.type != T_PREFIX)
514
      runtime( "Can not convert non-prefix this way" );
515 c7b43f33 Pavel Machek
    res.type = what->aux;
516 36bbfc70 Pavel Machek
    switch(res.type) {
517 684c6f5a Pavel Machek
      /*    case T_INT:        res.val.i = v1.val.px.len; break; Not needed any more */
518 6dc7a0cb Pavel Machek
    case T_IP: res.val.px.ip = v1.val.px.ip; break;
519 3076b5ae Martin Mares
    default: bug( "Unknown prefix to conversion" );
520 36bbfc70 Pavel Machek
    }
521
    break;
522 2d496d20 Pavel Machek
  case 'r':
523
    ONEARG;
524
    res = v1;
525
    res.type |= T_RETURN;
526
    break;
527
  case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out  */
528 6542ece9 Pavel Machek
    ONEARG;
529
    res = interpret(what->a2.p);
530 2d496d20 Pavel Machek
    if (res.type == T_RETURN)
531
      return res;
532
    res.type &= ~T_RETURN;    
533 6542ece9 Pavel Machek
    break;
534 2d496d20 Pavel Machek
  case P('S','W'):
535 7db7b7db Pavel Machek
    ONEARG;
536 41be4444 Pavel Machek
    {
537
      struct f_tree *t = find_tree(what->a2.p, v1);
538
      if (!t) {
539
        v1.type = T_VOID;
540
        t = find_tree(what->a2.p, v1);
541
        if (!t) {
542 ad9074e9 Pavel Machek
          debug( "No else statement?\n");
543 41be4444 Pavel Machek
          break;
544
        }
545
      }        
546
      if (!t->data)
547 3076b5ae Martin Mares
        bug( "Impossible: no code associated!" );
548 41be4444 Pavel Machek
      return interpret(t->data);
549
    }
550 7db7b7db Pavel Machek
    break;
551 2d496d20 Pavel Machek
  case P('i','M'): /* IP.MASK(val) */
552 f4536657 Pavel Machek
    TWOARGS;
553
    if (v2.type != T_INT)
554
      runtime( "Can not use this type for mask.");
555
    if (v1.type != T_IP)
556
      runtime( "You can mask only IP addresses." );
557
    {
558
      ip_addr mask = ipa_mkmask(v2.val.i);
559
      res.type = T_IP;
560
      res.val.px.ip = ipa_and(mask, v1.val.px.ip);
561
    }
562 d3dd620b Pavel Machek
    break;
563 afc54517 Pavel Machek
564
  case 'E':        /* Create empty attribute */
565
    res.type = what->aux;
566
    res.val.ad = adata_empty(f_pool);
567
    break;
568
  case P('A','p'):        /* Path prepend */
569
    TWOARGS;
570
    if (v1.type != T_PATH)
571
      runtime("Can't prepend to non-path");
572
    if (v2.type != T_INT)
573
      runtime("Can't prepend non-integer");
574
575
    res.type = T_PATH;
576
    res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
577
    break;
578
579 9c400ec9 Pavel Machek
  case P('C','a'):        /* Community list add or delete */
580
    TWOARGS;
581
    if (v1.type != T_CLIST)
582
      runtime("Can't add/delete to non-clist");
583
    if (v2.type != T_PAIR)
584
      runtime("Can't add/delete non-pair");
585
586
    res.type = T_CLIST;
587
    switch (what->aux) {
588
    case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break;
589
    case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break;
590
    default: bug("unknown Ca operation");
591
    }
592
    break;
593
594 23b1539b Pavel Machek
  default:
595
    bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
596
  }
597
  if (what->next)
598
    return interpret(what->next);
599
  return res;
600
}
601
602 2d496d20 Pavel Machek
#undef ARG
603 9a4037d4 Pavel Machek
#define ARG(x,y) \
604
        if (!i_same(f1->y, f2->y)) \
605
                return 0;
606
607
#define ONEARG ARG(v1, a1.p)
608
#define TWOARGS ARG(v1, a1.p) \
609
                ARG(v2, a2.p)
610
611
#define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
612
613
int
614
i_same(struct f_inst *f1, struct f_inst *f2)
615
{
616
  if ((!!f1) != (!!f2))
617
    return 0;
618 d4d75628 Pavel Machek
  if (!f1)
619
    return 1;
620 9a4037d4 Pavel Machek
  if (f1->aux != f2->aux)
621
    return 0;
622
  if (f1->code != f2->code)
623
    return 0;
624 d4d75628 Pavel Machek
  if (f1 == f2)                /* It looks strange, but it is possible with call rewriting trickery */
625
    return 1;
626 9a4037d4 Pavel Machek
627
  switch(f1->code) {
628
  case ',': /* fall through */
629
  case '+':
630 9f0d45d6 Pavel Machek
  case '-':
631
  case '*':
632 9a4037d4 Pavel Machek
  case '/':
633 2d496d20 Pavel Machek
  case P('!','='):
634
  case P('=','='):
635 9a4037d4 Pavel Machek
  case '<':
636 2d496d20 Pavel Machek
  case P('<','='): TWOARGS; break;
637 9a4037d4 Pavel Machek
638 995e5894 Pavel Machek
  case '!': ONEARG; break;
639 9a4037d4 Pavel Machek
  case '~': TWOARGS; break;
640 2d496d20 Pavel Machek
  case P('d','e'): ONEARG; break;
641 9a4037d4 Pavel Machek
642
  case 's':
643
    ARG(v2, a2.p);
644
    {
645
      struct symbol *s1, *s2;
646
      s1 = f1->a1.p;
647
      s2 = f2->a1.p;
648
      if (strcmp(s1->name, s2->name))
649
        return 0;
650
      if (s1->class != s2->class)
651
        return 0;
652
    }
653
    break;
654
655
  case 'c': A2_SAME; break;
656
  case 'C': 
657 f71bded6 Pavel Machek
    if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
658 9a4037d4 Pavel Machek
      return 0;
659
    break;
660 684c6f5a Pavel Machek
  case 'p': case 'L': ONEARG; break;
661 9a4037d4 Pavel Machek
  case '?': TWOARGS; break;
662 afc54517 Pavel Machek
  case '0': case 'E': break;
663 2d496d20 Pavel Machek
  case P('p',','): ONEARG; A2_SAME; break;
664 9a4037d4 Pavel Machek
  case 'a': A2_SAME; break;
665 2d496d20 Pavel Machek
  case P('e','a'): A2_SAME; break;
666
  case P('e','S'): ONEARG; A2_SAME; break;
667 9a4037d4 Pavel Machek
668 2d496d20 Pavel Machek
  case 'r': ONEARG; break;
669
  case P('c','p'): ONEARG; break;
670 d4d75628 Pavel Machek
  case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
671
             ONEARG; 
672
             if (!i_same(f1->a2.p, f2->a2.p))
673
               return 0; 
674
             f2->a2.p = f1->a2.p;
675
             break;
676 2d496d20 Pavel Machek
  case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
677
  case P('i','M'): TWOARGS; break;
678 afc54517 Pavel Machek
  case P('A','p'): TWOARGS; break;
679 9c400ec9 Pavel Machek
  case P('C','a'): TWOARGS; break;
680 9a4037d4 Pavel Machek
  default:
681
    bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
682
  }
683
  return i_same(f1->next, f2->next);
684
}
685
686 ff95080f Pavel Machek
/**
687
 * f_run - external entry point to filters
688
 * @filter: pointer to filter to run
689
 * @rte: pointer to pointer to rte being filtered. When route is modified, this is changed with rte_cow.
690
 * @tmp_pool: all filter allocations go from this pool
691
 */
692 23b1539b Pavel Machek
int
693 0a06a9b8 Pavel Machek
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
694 23b1539b Pavel Machek
{
695
  struct f_inst *inst;
696
  struct f_val res;
697 6b9fa320 Martin Mares
  DBG( "Running filter `%s'...", filter->name );
698 23b1539b Pavel Machek
699 0a06a9b8 Pavel Machek
  f_flags = flags;
700 31e79264 Pavel Machek
  f_tmp_attrs = tmp_attrs;
701 36bbfc70 Pavel Machek
  f_rte = rte;
702 48f9e019 Pavel Machek
  f_rte_old = *rte;
703 74a7da48 Martin Mares
  f_rta_copy = NULL;
704 f31156ca Pavel Machek
  f_pool = tmp_pool;
705 23b1539b Pavel Machek
  inst = filter->root;
706
  res = interpret(inst);
707
  if (res.type != T_RETURN)
708
    return F_ERROR;
709 6b9fa320 Martin Mares
  DBG( "done (%d)\n", res.val.i );
710 23b1539b Pavel Machek
  return res.val.i;
711
}
712
713 b1c9d871 Martin Mares
int
714
f_eval_int(struct f_inst *expr)
715 1c20608e Martin Mares
{
716
  struct f_val res;
717
718 b1c9d871 Martin Mares
  f_flags = 0;
719
  f_tmp_attrs = NULL;
720
  f_rte = NULL;
721
  f_rte_old = NULL;
722
  f_rta_copy = NULL;
723
  f_pool = cfg_mem;
724
  res = interpret(expr);
725
  if (res.type != T_INT)
726
    cf_error("Integer expression expected");
727
  return res.val.i;
728
}
729 1c20608e Martin Mares
730 ff95080f Pavel Machek
/**
731
 * filter_same - compare two filters
732
 * @new: first filter to be compared
733
 * @old: second filter to be compared, notice that this filter is
734
 * damaged while comparing.
735
 *
736
 * Returns 1 in case filters are same, otherwise 0. If there are
737
 * underlying bugs, it will rather say 0 on same filters than say
738
 * 1 on different.
739
 */
740 30a6108c Martin Mares
int
741
filter_same(struct filter *new, struct filter *old)
742
{
743 81ce667b Martin Mares
  if (old == new)        /* Handle FILTER_ACCEPT and FILTER_REJECT */
744
    return 1;
745
  if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
746
      new == FILTER_ACCEPT || new == FILTER_REJECT)
747
    return 0;
748 9a4037d4 Pavel Machek
  return i_same(new->root, old->root);
749 30a6108c Martin Mares
}