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