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