]> git.ipfire.org Git - thirdparty/bird.git/blame - filter/filter.c
Added `show route for <prefix-or-ipa>' which looks up route leading to
[thirdparty/bird.git] / filter / filter.c
CommitLineData
23b1539b
PM
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.
29818140 7 *
23b1539b
PM
8 */
9
2337ade7
PM
10/**
11 * DOC: Filters
12 *
13 * Filter consists of tree of &f_inst structures, one structure per
14 * "instruction". Each &f_inst contains code, aux value which is
15 * usually type of data this instruction operates on, and two generic
16 * arguments (a1, a2). Some instructinos contain pointer(s) to other
17 * instructions in their (a1, a2) fields.
18 *
19 * Filters use structure &f_val for its variables. Each &f_val
20 * contains type and value. Types are constants prefixed with %T_. Few
21 * of types are special; %T_RETURN can be or-ed with type to indicate
22 * that return from function/from whole filter should be
23 * forced. Important thing about &f_val s is that they may be copied
24 * with simple =. That's fine for all currently defined types: strings
25 * are read-only (and therefore okay), paths are copied for each
26 * operation (okay too).
27 */
28
9a220cab 29#undef LOCAL_DEBUG
6b9fa320 30
23b1539b
PM
31#include "nest/bird.h"
32#include "lib/lists.h"
33#include "lib/resource.h"
34#include "lib/socket.h"
38506f71 35#include "lib/string.h"
7f77e250 36#include "lib/unaligned.h"
23b1539b
PM
37#include "nest/route.h"
38#include "nest/protocol.h"
39#include "nest/iface.h"
159fa4ce 40#include "nest/attrs.h"
23b1539b
PM
41#include "conf/conf.h"
42#include "filter/filter.h"
43
2d496d20
PM
44#define P(a,b) ((a<<8) | b)
45
7a86a8b0 46struct f_inst *startup_func = NULL, *test1_func, *test2_func;
23b1539b 47
38506f71
PM
48#define CMP_ERROR 999
49
b0c9c21c 50static int
2e5a8735
PM
51pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2)
52{
53 while (1) {
54 if ((!m1) || (!m2))
55 return !((!m1) && (!m2));
56 m1 = m1->next;
57 m2 = m2->next;
58 }
59}
60
38506f71
PM
61/* Compare two values, returns -1, 0, 1 compared, ERROR 999 */
62int
63val_compare(struct f_val v1, struct f_val v2)
64{
41be4444
PM
65 if ((v1.type == T_VOID) && (v2.type == T_VOID))
66 return 0;
67 if (v1.type == T_VOID) /* Hack for else */
68 return -1;
69 if (v2.type == T_VOID)
70 return 1;
71
f71bded6
PM
72 if (v1.type != v2.type) {
73 debug( "Types do not match in val_compare\n" );
7db7b7db 74 return CMP_ERROR;
f71bded6 75 }
38506f71 76 switch (v1.type) {
f4536657 77 case T_ENUM:
38506f71 78 case T_INT:
d3dd620b 79 case T_PAIR:
38506f71
PM
80 if (v1.val.i == v2.val.i) return 0;
81 if (v1.val.i < v2.val.i) return -1;
82 return 1;
43fc099b 83 case T_IP:
6dc7a0cb
PM
84 case T_PREFIX:
85 return ipa_compare(v1.val.px.ip, v2.val.px.ip);
2e5a8735
PM
86 case T_PATH_MASK:
87 return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
3076b5ae 88 default:
f71bded6 89 debug( "Compare of unkown entities: %x\n", v1.type );
3076b5ae 90 return CMP_ERROR;
38506f71
PM
91 }
92}
93
f71bded6 94int
6dc7a0cb
PM
95val_simple_in_range(struct f_val v1, struct f_val v2)
96{
10a53608 97 if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
2a40efa5 98 return as_path_match(v1.val.ad, v2.val.path_mask);
2bd2de01
PM
99 if ((v1.type == T_PAIR) && (v2.type == T_CLIST))
100 return int_set_contains(v2.val.ad, v1.val.i);
10a53608 101
6dc7a0cb
PM
102 if ((v1.type == T_IP) && (v2.type == T_PREFIX))
103 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))));
104
105 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX)) {
106 ip_addr mask;
107 if (v1.val.px.len & (LEN_PLUS | LEN_MINUS | LEN_RANGE))
108 return CMP_ERROR;
109 mask = ipa_mkmask( v2.val.px.len & LEN_MASK );
110 if (ipa_compare(ipa_and(v2.val.px.ip, mask), ipa_and(v1.val.px.ip, mask)))
111 return 0;
8f013d9c 112
6dc7a0cb
PM
113 if ((v2.val.px.len & LEN_MINUS) && (v1.val.px.len <= (v2.val.px.len & LEN_MASK)))
114 return 0;
115 if ((v2.val.px.len & LEN_PLUS) && (v1.val.px.len < (v2.val.px.len & LEN_MASK)))
116 return 0;
117 if ((v2.val.px.len & LEN_RANGE) && ((v1.val.px.len < (0xff & (v2.val.px.len >> 16)))
118 || (v1.val.px.len > (0xff & (v2.val.px.len >> 8)))))
119 return 0;
120 return 1;
121 }
122 return CMP_ERROR;
123}
124
7db7b7db
PM
125int
126val_in_range(struct f_val v1, struct f_val v2)
127{
6dc7a0cb
PM
128 int res;
129
130 res = val_simple_in_range(v1, v2);
131
132 if (res != CMP_ERROR)
133 return res;
134
2f702671 135 if (((v1.type == T_INT) || ((v1.type == T_IP) || (v1.type == T_PREFIX)) && (v2.type == T_SET))) {
6dc7a0cb
PM
136 struct f_tree *n;
137 n = find_tree(v2.val.t, v1);
138 if (!n)
139 return 0;
140 return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */
141 }
7db7b7db
PM
142 return CMP_ERROR;
143}
144
38506f71
PM
145static void
146tree_print(struct f_tree *t)
147{
148 if (!t) {
3cf4a2e2 149 debug( "() " );
38506f71
PM
150 return;
151 }
3cf4a2e2 152 debug( "[ " );
38506f71 153 tree_print( t->left );
3cf4a2e2 154 debug( ", " ); val_print( t->from ); debug( ".." ); val_print( t->to ); debug( ", " );
38506f71 155 tree_print( t->right );
3cf4a2e2 156 debug( "] " );
38506f71
PM
157}
158
159void
160val_print(struct f_val v)
161{
162 char buf[2048];
ecd25633 163 char buf2[1024];
38506f71
PM
164#define PRINTF(a...) bsnprintf( buf, 2040, a )
165 buf[0] = 0;
166 switch (v.type) {
167 case T_VOID: PRINTF( "(void)" ); break;
168 case T_BOOL: PRINTF( v.val.i ? "TRUE" : "FALSE" ); break;
169 case T_INT: PRINTF( "%d ", v.val.i ); break;
170 case T_STRING: PRINTF( "%s", v.val.s ); break;
6dc7a0cb 171 case T_IP: PRINTF( "%I", v.val.px.ip ); break;
720d911d
PM
172 case T_PREFIX: PRINTF( "%I/%d", v.val.px.ip, v.val.px.len ); break;
173 case T_PAIR: PRINTF( "(%d,%d)", v.val.i >> 16, v.val.i & 0xffff ); break;
38506f71 174 case T_SET: tree_print( v.val.t ); PRINTF( "\n" ); break;
346a12c2 175 case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
ecd25633 176 case T_PATH: as_path_format(v.val.ad, buf2, 1020); PRINTF( "(path %s)", buf2 ); break;
159fa4ce 177 case T_CLIST: int_set_format(v.val.ad, buf2, 1020); PRINTF( "(clist %s)", buf2 ); break;
ecd25633 178 case T_PATH_MASK: debug( "(pathmask " ); { struct f_path_mask *p = v.val.s; while (p) { debug("%d ", p->val); p=p->next; } debug(")" ); } break;
38506f71 179 default: PRINTF( "[unknown type %x]", v.type );
7f77e250 180#undef PRINTF
38506f71 181 }
3cf4a2e2 182 debug( buf );
38506f71
PM
183}
184
48f9e019 185static struct rte **f_rte, *f_rte_old;
f31156ca 186static struct linpool *f_pool;
31e79264 187static struct ea_list **f_tmp_attrs;
0a06a9b8 188static int f_flags;
74a7da48 189static rta *f_rta_copy;
36bbfc70 190
9a4037d4
PM
191#define runtime(x) do { \
192 log( L_ERR x ); \
193 res.type = T_RETURN; \
194 res.val.i = F_ERROR; \
195 return res; \
196 } while(0)
197
198#define ARG(x,y) \
199 x = interpret(what->y); \
2d496d20 200 if (x.type & T_RETURN) \
9a4037d4
PM
201 return x;
202
203#define ONEARG ARG(v1, a1.p)
204#define TWOARGS ARG(v1, a1.p) \
205 ARG(v2, a2.p)
206#define TWOARGS_C TWOARGS \
207 if (v1.type != v2.type) \
208 runtime( "Can not operate with values of incompatible types" );
7db7b7db 209
23b1539b
PM
210static struct f_val
211interpret(struct f_inst *what)
212{
213 struct symbol *sym;
214 struct f_val v1, v2, res;
38506f71 215 int i,j,k;
23b1539b
PM
216
217 res.type = T_VOID;
218 if (!what)
219 return res;
220
221 switch(what->code) {
222 case ',':
223 TWOARGS;
224 break;
225
226/* Binary operators */
227 case '+':
228 TWOARGS_C;
229 switch (res.type = v1.type) {
230 case T_VOID: runtime( "Can not operate with values of type void" );
231 case T_INT: res.val.i = v1.val.i + v2.val.i; break;
232 default: runtime( "Usage of unknown type" );
233 }
234 break;
235 case '/':
236 TWOARGS_C;
237 switch (res.type = v1.type) {
238 case T_VOID: runtime( "Can not operate with values of type void" );
239 case T_INT: res.val.i = v1.val.i / v2.val.i; break;
240 case T_IP: if (v2.type != T_INT)
241 runtime( "Operator / is <ip>/<int>" );
242 break;
243 default: runtime( "Usage of unknown type" );
244 }
245 break;
246
247/* Relational operators */
38506f71
PM
248
249#define COMPARE(x) \
250 TWOARGS_C; \
251 res.type = T_BOOL; \
252 i = val_compare(v1, v2); \
253 if (i==CMP_ERROR) \
254 runtime( "Error in comparation" ); \
255 res.val.i = (x); \
23b1539b 256 break;
38506f71 257
2d496d20
PM
258 case P('!','='): COMPARE(i!=0);
259 case P('=','='): COMPARE(i==0);
38506f71 260 case '<': COMPARE(i==-1);
2d496d20 261 case P('<','='): COMPARE(i!=1);
38506f71 262
995e5894
PM
263 case '!':
264 ONEARG;
265 if (v1.type != T_BOOL)
266 runtime( "not applied to non-boolean" );
267 res = v1;
268 res.val.i = !res.val.i;
269 break;
270
38506f71
PM
271 case '~':
272 TWOARGS;
23b1539b 273 res.type = T_BOOL;
7db7b7db
PM
274 res.val.i = val_in_range(v1, v2);
275 if (res.val.i == CMP_ERROR)
276 runtime( "~ applied on unknown type pair" );
23b1539b 277 break;
2d496d20 278 case P('d','e'):
f4536657
PM
279 ONEARG;
280 res.type = T_BOOL;
281 res.val.i = (v1.type != T_VOID);
282 break;
23b1539b 283
d3dd620b 284 /* Set to indirect value, a1 = variable, a2 = value */
23b1539b 285 case 's':
2db3b288
PM
286 ARG(v2, a2.p);
287 sym = what->a1.p;
23b1539b
PM
288 switch (res.type = v2.type) {
289 case T_VOID: runtime( "Can not assign void values" );
f4536657 290 case T_ENUM:
23b1539b 291 case T_INT:
d3dd620b
PM
292 case T_IP:
293 case T_PREFIX:
294 case T_PAIR:
e399b6f6
PM
295 case T_PATH:
296 case T_CLIST:
dcab7890 297 case T_PATH_MASK:
d3dd620b 298 if (sym->class != (SYM_VARIABLE | v2.type))
23b1539b 299 runtime( "Variable of bad type" );
d3dd620b 300 * (struct f_val *) sym->aux2 = v2;
23b1539b 301 break;
d3dd620b 302 default:
3076b5ae 303 bug( "Set to invalid type" );
23b1539b
PM
304 }
305 break;
306
d3dd620b 307 case 'c': /* integer (or simple type) constant */
c7b43f33 308 res.type = what->aux;
d3dd620b 309 res.val.i = what->a2.i;
23b1539b 310 break;
38506f71
PM
311 case 'C':
312 res = * ((struct f_val *) what->a1.p);
313 break;
23b1539b
PM
314 case 'p':
315 ONEARG;
38506f71 316 val_print(v1);
23b1539b
PM
317 break;
318 case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
319 ONEARG;
320 if (v1.type != T_BOOL)
321 runtime( "If requires bool expression" );
322 if (v1.val.i) {
2db3b288 323 ARG(res,a2.p);
23b1539b
PM
324 res.val.i = 0;
325 } else res.val.i = 1;
326 res.type = T_BOOL;
327 break;
328 case '0':
3cf4a2e2 329 debug( "No operation\n" );
23b1539b 330 break;
2d496d20 331 case P('p',','):
23b1539b 332 ONEARG;
798df5b1 333 if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
3cf4a2e2 334 debug( "\n" );
23b1539b 335
2db3b288 336 switch (what->a2.i) {
23b1539b
PM
337 case F_QUITBIRD:
338 die( "Filter asked me to die" );
339 case F_ACCEPT:
340 /* Should take care about turning ACCEPT into MODIFY */
341 case F_ERROR:
2ad6dcdb 342 case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
23b1539b 343 res.type = T_RETURN;
2ad6dcdb 344 res.val.i = what->a2.i;
7e1f9971 345 return res; /* We have to return now, no more processing. */
d3dd620b 346 case F_NONL:
23b1539b
PM
347 case F_NOP:
348 break;
349 default:
350 bug( "unknown return type: can not happen");
351 }
352 break;
36bbfc70
PM
353 case 'a': /* rta access */
354 {
355 struct rta *rta = (*f_rte)->attrs;
c7b43f33 356 res.type = what->aux;
36bbfc70
PM
357 switch(res.type) {
358 case T_IP:
6dc7a0cb 359 res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
36bbfc70 360 break;
c7b43f33
PM
361 case T_ENUM:
362 res.val.i = * ((char *) rta + what->a2.i);
363 break;
36bbfc70
PM
364 case T_PREFIX: /* Warning: this works only for prefix of network */
365 {
366 res.val.px.ip = (*f_rte)->net->n.prefix;
367 res.val.px.len = (*f_rte)->net->n.pxlen;
368 break;
369 }
370 default:
3076b5ae 371 bug( "Invalid type for rta access (%x)", res.type );
36bbfc70
PM
372 }
373 }
374 break;
2d496d20 375 case P('e','a'): /* Access to extended attributes */
91447965 376 {
0a06a9b8 377 eattr *e = NULL;
3076b5ae 378 if (!(f_flags & FF_FORCE_TMPATTR))
0a06a9b8 379 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
31e79264
PM
380 if (!e)
381 e = ea_find( (*f_tmp_attrs), what->a2.i );
3076b5ae 382 if ((!e) && (f_flags & FF_FORCE_TMPATTR))
0a06a9b8
PM
383 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
384
91447965
PM
385 if (!e) {
386 res.type = T_VOID;
387 break;
388 }
0150e521
PM
389 switch (what->aux & EAF_TYPE_MASK) {
390 case EAF_TYPE_INT:
391 res.type = T_INT;
91447965
PM
392 res.val.i = e->u.data;
393 break;
0150e521
PM
394 case EAF_TYPE_AS_PATH:
395 res.type = T_PATH;
396 res.val.ad = e->u.ptr;
397 break;
398 case EAF_TYPE_INT_SET:
399 res.type = T_CLIST;
10a53608
PM
400 res.val.ad = e->u.ptr;
401 break;
2803c9dd
MM
402 default:
403 bug("Unknown type in e,a\n");
91447965
PM
404 }
405 }
6dc7a0cb 406 break;
2d496d20 407 case P('e','S'):
f31156ca 408 ONEARG;
f31156ca
PM
409 {
410 struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
411
412 l->next = NULL;
413 l->flags = EALF_SORTED;
414 l->count = 1;
415 l->attrs[0].id = what->a2.i;
913ce95b
PM
416 l->attrs[0].flags = 0;
417 l->attrs[0].type = what->aux | EAF_ORIGINATED;
31e79264
PM
418 switch (what->aux & EAF_TYPE_MASK) {
419 case EAF_TYPE_INT:
420 if (v1.type != T_INT)
421 runtime( "Setting int attribute to non-int value" );
f31156ca
PM
422 l->attrs[0].u.data = v1.val.i;
423 break;
10a53608
PM
424 case EAF_TYPE_AS_PATH:
425 if (v1.type != T_PATH)
426 runtime( "Setting path attribute to non-path value" );
427 l->attrs[0].u.ptr = v1.val.ad;
428 break;
708711c3
PM
429 case EAF_TYPE_INT_SET:
430 if (v1.type != T_CLIST)
431 runtime( "Setting int set attribute to non-clist value" );
432 l->attrs[0].u.ptr = v1.val.ad;
433 break;
31e79264
PM
434 case EAF_TYPE_UNDEF:
435 if (v1.type != T_VOID)
436 runtime( "Setting void attribute to non-void value" );
48f9e019
PM
437 l->attrs[0].u.data = 0;
438 break;
0150e521 439 default: bug("Unknown type in e,S");
f31156ca 440 }
31e79264 441
3076b5ae 442 if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
74a7da48
MM
443 if (!f_rta_copy) {
444 f_rta_copy = lp_alloc(f_pool, sizeof(rta));
445 memcpy(f_rta_copy, (*f_rte)->attrs, sizeof(rta));
446 f_rta_copy->aflags = 0;
447 *f_rte = rte_cow(*f_rte);
448 (*f_rte)->attrs = f_rta_copy;
449 }
450 l->next = f_rta_copy->eattrs;
451 f_rta_copy->eattrs = l;
31e79264
PM
452 } else {
453 l->next = (*f_tmp_attrs);
454 (*f_tmp_attrs) = l;
455 }
f31156ca 456 }
f31156ca 457 break;
48f9e019 458
684c6f5a
PM
459 case 'L': /* Get length of */
460 ONEARG;
461 res.type = T_INT;
462 switch(v1.type) {
463 case T_PREFIX: res.val.i = v1.val.px.len; break;
464 case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
465 default: bug( "Length of what?" );
466 }
467 break;
2d496d20 468 case P('c','p'): /* Convert prefix to ... */
36bbfc70
PM
469 ONEARG;
470 if (v1.type != T_PREFIX)
471 runtime( "Can not convert non-prefix this way" );
c7b43f33 472 res.type = what->aux;
36bbfc70 473 switch(res.type) {
684c6f5a 474 /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */
6dc7a0cb 475 case T_IP: res.val.px.ip = v1.val.px.ip; break;
3076b5ae 476 default: bug( "Unknown prefix to conversion" );
36bbfc70
PM
477 }
478 break;
2d496d20
PM
479 case 'r':
480 ONEARG;
481 res = v1;
482 res.type |= T_RETURN;
483 break;
484 case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */
6542ece9
PM
485 ONEARG;
486 res = interpret(what->a2.p);
2d496d20
PM
487 if (res.type == T_RETURN)
488 return res;
489 res.type &= ~T_RETURN;
6542ece9 490 break;
2d496d20 491 case P('S','W'):
7db7b7db 492 ONEARG;
41be4444
PM
493 {
494 struct f_tree *t = find_tree(what->a2.p, v1);
495 if (!t) {
496 v1.type = T_VOID;
497 t = find_tree(what->a2.p, v1);
498 if (!t) {
3cf4a2e2 499 debug( "No else statement?\n ");
41be4444
PM
500 break;
501 }
502 }
503 if (!t->data)
3076b5ae 504 bug( "Impossible: no code associated!" );
41be4444
PM
505 return interpret(t->data);
506 }
7db7b7db 507 break;
2d496d20 508 case P('i','M'): /* IP.MASK(val) */
f4536657
PM
509 TWOARGS;
510 if (v2.type != T_INT)
511 runtime( "Can not use this type for mask.");
512 if (v1.type != T_IP)
513 runtime( "You can mask only IP addresses." );
514 {
515 ip_addr mask = ipa_mkmask(v2.val.i);
516 res.type = T_IP;
517 res.val.px.ip = ipa_and(mask, v1.val.px.ip);
518 }
d3dd620b 519 break;
afc54517
PM
520
521 case 'E': /* Create empty attribute */
522 res.type = what->aux;
523 res.val.ad = adata_empty(f_pool);
524 break;
525 case P('A','p'): /* Path prepend */
526 TWOARGS;
527 if (v1.type != T_PATH)
528 runtime("Can't prepend to non-path");
529 if (v2.type != T_INT)
530 runtime("Can't prepend non-integer");
531
532 res.type = T_PATH;
533 res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
534 break;
535
9c400ec9
PM
536 case P('C','a'): /* Community list add or delete */
537 TWOARGS;
538 if (v1.type != T_CLIST)
539 runtime("Can't add/delete to non-clist");
540 if (v2.type != T_PAIR)
541 runtime("Can't add/delete non-pair");
542
543 res.type = T_CLIST;
544 switch (what->aux) {
545 case 'a': res.val.ad = int_set_add(f_pool, v1.val.ad, v2.val.i); break;
546 case 'd': res.val.ad = int_set_del(f_pool, v1.val.ad, v2.val.i); break;
547 default: bug("unknown Ca operation");
548 }
549 break;
550
23b1539b
PM
551 default:
552 bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
553 }
554 if (what->next)
555 return interpret(what->next);
556 return res;
557}
558
2d496d20 559#undef ARG
9a4037d4
PM
560#define ARG(x,y) \
561 if (!i_same(f1->y, f2->y)) \
562 return 0;
563
564#define ONEARG ARG(v1, a1.p)
565#define TWOARGS ARG(v1, a1.p) \
566 ARG(v2, a2.p)
567
568#define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
569
570int
571i_same(struct f_inst *f1, struct f_inst *f2)
572{
9a4037d4
PM
573 if ((!!f1) != (!!f2))
574 return 0;
d4d75628
PM
575 if (!f1)
576 return 1;
9a4037d4
PM
577 if (f1->aux != f2->aux)
578 return 0;
579 if (f1->code != f2->code)
580 return 0;
d4d75628
PM
581 if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
582 return 1;
9a4037d4
PM
583
584 switch(f1->code) {
585 case ',': /* fall through */
586 case '+':
587 case '/':
2d496d20
PM
588 case P('!','='):
589 case P('=','='):
9a4037d4 590 case '<':
2d496d20 591 case P('<','='): TWOARGS; break;
9a4037d4 592
995e5894 593 case '!': ONEARG; break;
9a4037d4 594 case '~': TWOARGS; break;
2d496d20 595 case P('d','e'): ONEARG; break;
9a4037d4
PM
596
597 case 's':
598 ARG(v2, a2.p);
599 {
600 struct symbol *s1, *s2;
601 s1 = f1->a1.p;
602 s2 = f2->a1.p;
603 if (strcmp(s1->name, s2->name))
604 return 0;
605 if (s1->class != s2->class)
606 return 0;
607 }
608 break;
609
610 case 'c': A2_SAME; break;
611 case 'C':
f71bded6 612 if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
9a4037d4
PM
613 return 0;
614 break;
684c6f5a 615 case 'p': case 'L': ONEARG; break;
9a4037d4 616 case '?': TWOARGS; break;
afc54517 617 case '0': case 'E': break;
2d496d20 618 case P('p',','): ONEARG; A2_SAME; break;
9a4037d4 619 case 'a': A2_SAME; break;
2d496d20
PM
620 case P('e','a'): A2_SAME; break;
621 case P('e','S'): ONEARG; A2_SAME; break;
9a4037d4 622
2d496d20
PM
623 case 'r': ONEARG; break;
624 case P('c','p'): ONEARG; break;
d4d75628
PM
625 case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
626 ONEARG;
627 if (!i_same(f1->a2.p, f2->a2.p))
628 return 0;
629 f2->a2.p = f1->a2.p;
630 break;
2d496d20
PM
631 case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
632 case P('i','M'): TWOARGS; break;
afc54517 633 case P('A','p'): TWOARGS; break;
9c400ec9 634 case P('C','a'): TWOARGS; break;
9a4037d4
PM
635 default:
636 bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
637 }
638 return i_same(f1->next, f2->next);
639}
640
ff95080f
PM
641/**
642 * f_run - external entry point to filters
643 * @filter: pointer to filter to run
644 * @rte: pointer to pointer to rte being filtered. When route is modified, this is changed with rte_cow.
645 * @tmp_pool: all filter allocations go from this pool
ff95080f 646 */
23b1539b 647int
0a06a9b8 648f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
23b1539b
PM
649{
650 struct f_inst *inst;
651 struct f_val res;
6b9fa320 652 DBG( "Running filter `%s'...", filter->name );
23b1539b 653
0a06a9b8 654 f_flags = flags;
31e79264 655 f_tmp_attrs = tmp_attrs;
36bbfc70 656 f_rte = rte;
48f9e019 657 f_rte_old = *rte;
74a7da48 658 f_rta_copy = NULL;
f31156ca 659 f_pool = tmp_pool;
23b1539b
PM
660 inst = filter->root;
661 res = interpret(inst);
662 if (res.type != T_RETURN)
663 return F_ERROR;
6b9fa320 664 DBG( "done (%d)\n", res.val.i );
23b1539b
PM
665 return res.val.i;
666}
667
23b1539b
PM
668void
669filters_postconfig(void)
670{
671 struct f_val res;
7a86a8b0 672
f71bded6 673#if 1
7a86a8b0
PM
674 if (!i_same(test1_func, test2_func))
675 bug("i_same does not work");
f71bded6 676#endif
8ba2cc06 677 if (startup_func) {
3cf4a2e2 678 debug( "Launching startup function...\n" );
e399b6f6 679 f_pool = lp_new(&root_pool, 1024);
23b1539b 680 res = interpret(startup_func);
bad631e0 681 if (res.type == F_ERROR)
8ba2cc06 682 die( "Startup function resulted in error." );
3cf4a2e2 683 debug( "done\n" );
8ba2cc06 684 }
23b1539b 685}
30a6108c 686
ff95080f
PM
687/**
688 * filter_same - compare two filters
689 * @new: first filter to be compared
690 * @old: second filter to be compared, notice that this filter is
691 * damaged while comparing.
692 *
693 * Returns 1 in case filters are same, otherwise 0. If there are
694 * underlying bugs, it will rather say 0 on same filters than say
695 * 1 on different.
696 */
30a6108c
MM
697int
698filter_same(struct filter *new, struct filter *old)
699{
81ce667b
MM
700 if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
701 return 1;
702 if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
703 new == FILTER_ACCEPT || new == FILTER_REJECT)
704 return 0;
9a4037d4 705 return i_same(new->root, old->root);
30a6108c 706}
7f77e250 707
7f77e250 708struct adata *
0a40e973 709adata_empty(struct linpool *pool)
7f77e250
PM
710{
711 struct adata *res = lp_alloc(pool, sizeof(struct adata));
712 res->length = 0;
713 return res;
714}