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