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