]> git.ipfire.org Git - thirdparty/bird.git/blob - filter/filter.c
Allows some modifications of dest attribute in filters.
[thirdparty/bird.git] / filter / filter.c
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.
7 *
8 */
9
10 /**
11 * DOC: Filters
12 *
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|.
17 *
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.
23 *
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
30 * are read-only (and therefore okay), paths are copied for each
31 * operation (okay too).
32 */
33
34 #undef LOCAL_DEBUG
35
36 #include "nest/bird.h"
37 #include "lib/lists.h"
38 #include "lib/resource.h"
39 #include "lib/socket.h"
40 #include "lib/string.h"
41 #include "lib/unaligned.h"
42 #include "nest/route.h"
43 #include "nest/protocol.h"
44 #include "nest/iface.h"
45 #include "nest/attrs.h"
46 #include "conf/conf.h"
47 #include "filter/filter.h"
48
49 #define P(a,b) ((a<<8) | b)
50
51 #define CMP_ERROR 999
52
53 static struct adata *
54 adata_empty(struct linpool *pool, int l)
55 {
56 struct adata *res = lp_alloc(pool, sizeof(struct adata) + l);
57 res->length = l;
58 return res;
59 }
60
61 static int
62 pm_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
68 /* FIXME: buggy, should return -1, 0, 1; but it doesn't matter */
69 if ((m1->kind != m2->kind) || (m1->val != m2->val)) return 1;
70 m1 = m1->next;
71 m2 = m2->next;
72 }
73 }
74
75 u32 f_eval_asn(struct f_inst *expr);
76
77 static void
78 pm_format(struct f_path_mask *p, byte *buf, unsigned int size)
79 {
80 byte *end = buf + size - 16;
81
82 while (p)
83 {
84 if (buf > end)
85 {
86 strcpy(buf, " ...");
87 return;
88 }
89
90 switch(p->kind)
91 {
92 case PM_ASN:
93 buf += bsprintf(buf, " %u", p->val);
94 break;
95
96 case PM_QUESTION:
97 buf += bsprintf(buf, " ?");
98 break;
99
100 case PM_ASTERISK:
101 buf += bsprintf(buf, " *");
102 break;
103
104 case PM_ASN_EXPR:
105 buf += bsprintf(buf, " %u", f_eval_asn((struct f_inst *) p->val));
106 break;
107 }
108
109 p = p->next;
110 }
111
112 *buf = 0;
113 }
114
115 static inline int int_cmp(int i1, int i2)
116 {
117 if (i1 == i2) return 0;
118 if (i1 < i2) return -1;
119 else return 1;
120 }
121
122 static inline int uint_cmp(unsigned int i1, unsigned int i2)
123 {
124 if (i1 == i2) return 0;
125 if (i1 < i2) return -1;
126 else return 1;
127 }
128
129 static inline int u64_cmp(u64 i1, u64 i2)
130 {
131 if (i1 == i2) return 0;
132 if (i1 < i2) return -1;
133 else return 1;
134 }
135
136 /**
137 * val_compare - compare two values
138 * @v1: first value
139 * @v2: second value
140 *
141 * Compares two values and returns -1, 0, 1 on <, =, > or 999 on error.
142 * Tree module relies on this giving consistent results so that it can
143 * build balanced trees.
144 */
145 int
146 val_compare(struct f_val v1, struct f_val v2)
147 {
148 int rc;
149
150 if ((v1.type == T_VOID) && (v2.type == T_VOID))
151 return 0;
152 if (v1.type == T_VOID) /* Hack for else */
153 return -1;
154 if (v2.type == T_VOID)
155 return 1;
156
157 if (v1.type != v2.type) {
158 #ifndef IPV6
159 /* IP->Quad implicit conversion */
160 if ((v1.type == T_QUAD) && (v2.type == T_IP))
161 return uint_cmp(v1.val.i, ipa_to_u32(v2.val.px.ip));
162 if ((v1.type == T_IP) && (v2.type == T_QUAD))
163 return uint_cmp(ipa_to_u32(v1.val.px.ip), v2.val.i);
164 #endif
165
166 debug( "Types do not match in val_compare\n" );
167 return CMP_ERROR;
168 }
169 switch (v1.type) {
170 case T_ENUM:
171 case T_INT:
172 case T_BOOL:
173 return int_cmp(v1.val.i, v2.val.i);
174 case T_PAIR:
175 case T_QUAD:
176 return uint_cmp(v1.val.i, v2.val.i);
177 case T_EC:
178 return u64_cmp(v1.val.ec, v2.val.ec);
179 case T_IP:
180 return ipa_compare(v1.val.px.ip, v2.val.px.ip);
181 case T_PREFIX:
182 if (rc = ipa_compare(v1.val.px.ip, v2.val.px.ip))
183 return rc;
184 if (v1.val.px.len < v2.val.px.len)
185 return -1;
186 if (v1.val.px.len > v2.val.px.len)
187 return 1;
188 return 0;
189 case T_PATH_MASK:
190 return pm_path_compare(v1.val.path_mask, v2.val.path_mask);
191 case T_STRING:
192 return strcmp(v1.val.s, v2.val.s);
193 default:
194 debug( "Compare of unknown entities: %x\n", v1.type );
195 return CMP_ERROR;
196 }
197 }
198
199 int
200 tree_compare(const void *p1, const void *p2)
201 {
202 return val_compare((* (struct f_tree **) p1)->from, (* (struct f_tree **) p2)->from);
203 }
204
205 void
206 fprefix_get_bounds(struct f_prefix *px, int *l, int *h)
207 {
208 *l = *h = px->len & LEN_MASK;
209
210 if (px->len & LEN_MINUS)
211 *l = 0;
212
213 else if (px->len & LEN_PLUS)
214 *h = MAX_PREFIX_LENGTH;
215
216 else if (px->len & LEN_RANGE)
217 {
218 *l = 0xff & (px->len >> 16);
219 *h = 0xff & (px->len >> 8);
220 }
221 }
222
223 /*
224 * val_simple_in_range - check if @v1 ~ @v2 for everything except sets
225 */
226 static int
227 val_simple_in_range(struct f_val v1, struct f_val v2)
228 {
229 if ((v1.type == T_PATH) && (v2.type == T_PATH_MASK))
230 return as_path_match(v1.val.ad, v2.val.path_mask);
231 if ((v1.type == T_INT) && (v2.type == T_PATH))
232 return as_path_is_member(v2.val.ad, v1.val.i);
233
234 if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
235 return int_set_contains(v2.val.ad, v1.val.i);
236 #ifndef IPV6
237 /* IP->Quad implicit conversion */
238 if ((v1.type == T_IP) && (v2.type == T_CLIST))
239 return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.px.ip));
240 #endif
241 if ((v1.type == T_EC) && (v2.type == T_ECLIST))
242 return ec_set_contains(v2.val.ad, v1.val.ec);
243
244 if ((v1.type == T_STRING) && (v2.type == T_STRING))
245 return patmatch(v2.val.s, v1.val.s);
246
247 if ((v1.type == T_IP) && (v2.type == T_PREFIX))
248 return ipa_in_net(v1.val.px.ip, v2.val.px.ip, v2.val.px.len);
249
250 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX))
251 return net_in_net(v1.val.px.ip, v1.val.px.len, v2.val.px.ip, v2.val.px.len);
252
253 return CMP_ERROR;
254 }
255
256 static int
257 clist_set_type(struct f_tree *set, struct f_val *v)
258 {
259 switch (set->from.type) {
260 case T_PAIR:
261 v->type = T_PAIR;
262 return 1;
263 case T_QUAD:
264 #ifndef IPV6
265 case T_IP:
266 #endif
267 v->type = T_QUAD;
268 return 1;
269 break;
270 default:
271 v->type = T_VOID;
272 return 0;
273 }
274 }
275
276 static inline int
277 eclist_set_type(struct f_tree *set)
278 { return set->from.type == T_EC; }
279
280 static int
281 clist_match_set(struct adata *clist, struct f_tree *set)
282 {
283 if (!clist)
284 return 0;
285
286 struct f_val v;
287 if (!clist_set_type(set, &v))
288 return CMP_ERROR;
289
290 u32 *l = (u32 *) clist->data;
291 u32 *end = l + clist->length/4;
292
293 while (l < end) {
294 v.val.i = *l++;
295 if (find_tree(set, v))
296 return 1;
297 }
298 return 0;
299 }
300
301 static int
302 eclist_match_set(struct adata *list, struct f_tree *set)
303 {
304 if (!list)
305 return 0;
306
307 if (!eclist_set_type(set))
308 return CMP_ERROR;
309
310 struct f_val v;
311 u32 *l = int_set_get_data(list);
312 int len = int_set_get_size(list);
313 int i;
314
315 v.type = T_EC;
316 for (i = 0; i < len; i += 2) {
317 v.val.ec = ec_get(l, i);
318 if (find_tree(set, v))
319 return 1;
320 }
321
322 return 0;
323 }
324
325 static struct adata *
326 clist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
327 {
328 if (!list)
329 return NULL;
330
331 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
332 struct f_val v;
333 if (tree)
334 clist_set_type(set.val.t, &v);
335 else
336 v.type = T_PAIR;
337
338 int len = int_set_get_size(list);
339 u32 *l = int_set_get_data(list);
340 u32 tmp[len];
341 u32 *k = tmp;
342 u32 *end = l + len;
343
344 while (l < end) {
345 v.val.i = *l++;
346 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
347 if ((tree ? !!find_tree(set.val.t, v) : int_set_contains(set.val.ad, v.val.i)) == pos)
348 *k++ = v.val.i;
349 }
350
351 int nl = (k - tmp) * 4;
352 if (nl == list->length)
353 return list;
354
355 struct adata *res = adata_empty(pool, nl);
356 memcpy(res->data, tmp, nl);
357 return res;
358 }
359
360 static struct adata *
361 eclist_filter(struct linpool *pool, struct adata *list, struct f_val set, int pos)
362 {
363 if (!list)
364 return NULL;
365
366 int tree = (set.type == T_SET); /* 1 -> set is T_SET, 0 -> set is T_CLIST */
367 struct f_val v;
368
369 int len = int_set_get_size(list);
370 u32 *l = int_set_get_data(list);
371 u32 tmp[len];
372 u32 *k = tmp;
373 int i;
374
375 v.type = T_EC;
376 for (i = 0; i < len; i += 2) {
377 v.val.ec = ec_get(l, i);
378 /* pos && member(val, set) || !pos && !member(val, set), member() depends on tree */
379 if ((tree ? !!find_tree(set.val.t, v) : ec_set_contains(set.val.ad, v.val.ec)) == pos) {
380 *k++ = l[i];
381 *k++ = l[i+1];
382 }
383 }
384
385 int nl = (k - tmp) * 4;
386 if (nl == list->length)
387 return list;
388
389 struct adata *res = adata_empty(pool, nl);
390 memcpy(res->data, tmp, nl);
391 return res;
392 }
393
394 /**
395 * val_in_range - implement |~| operator
396 * @v1: element
397 * @v2: set
398 *
399 * Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see
400 * |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early).
401 */
402 static int
403 val_in_range(struct f_val v1, struct f_val v2)
404 {
405 int res;
406
407 res = val_simple_in_range(v1, v2);
408
409 if (res != CMP_ERROR)
410 return res;
411
412 if ((v1.type == T_PREFIX) && (v2.type == T_PREFIX_SET))
413 return trie_match_fprefix(v2.val.ti, &v1.val.px);
414
415 if ((v1.type == T_CLIST) && (v2.type == T_SET))
416 return clist_match_set(v1.val.ad, v2.val.t);
417
418 if ((v1.type == T_ECLIST) && (v2.type == T_SET))
419 return eclist_match_set(v1.val.ad, v2.val.t);
420
421 if (v2.type == T_SET)
422 switch (v1.type) {
423 case T_ENUM:
424 case T_INT:
425 case T_PAIR:
426 case T_QUAD:
427 case T_IP:
428 case T_EC:
429 {
430 struct f_tree *n;
431 n = find_tree(v2.val.t, v1);
432 if (!n)
433 return 0;
434 return !! (val_simple_in_range(v1, n->from)); /* We turn CMP_ERROR into compared ok, and that's fine */
435 }
436 }
437 return CMP_ERROR;
438 }
439
440 static void val_print(struct f_val v);
441
442 static void
443 tree_node_print(struct f_tree *t, char **sep)
444 {
445 if (t == NULL)
446 return;
447
448 tree_node_print(t->left, sep);
449
450 logn(*sep);
451 val_print(t->from);
452 if (val_compare(t->from, t->to) != 0)
453 {
454 logn( ".." );
455 val_print(t->to);
456 }
457 *sep = ", ";
458
459 tree_node_print(t->right, sep);
460 }
461
462 static void
463 tree_print(struct f_tree *t)
464 {
465 char *sep = "";
466 logn( "[" );
467 tree_node_print(t, &sep);
468 logn( "] " );
469 }
470
471 /*
472 * val_print - format filter value
473 */
474 static void
475 val_print(struct f_val v)
476 {
477 char buf2[1024];
478 switch (v.type) {
479 case T_VOID: logn("(void)"); return;
480 case T_BOOL: logn(v.val.i ? "TRUE" : "FALSE"); return;
481 case T_INT: logn("%d", v.val.i); return;
482 case T_STRING: logn("%s", v.val.s); return;
483 case T_IP: logn("%I", v.val.px.ip); return;
484 case T_PREFIX: logn("%I/%d", v.val.px.ip, v.val.px.len); return;
485 case T_PAIR: logn("(%d,%d)", v.val.i >> 16, v.val.i & 0xffff); return;
486 case T_QUAD: logn("%R", v.val.i); return;
487 case T_EC: ec_format(buf2, v.val.ec); logn("%s", buf2); return;
488 case T_PREFIX_SET: trie_print(v.val.ti); return;
489 case T_SET: tree_print(v.val.t); return;
490 case T_ENUM: logn("(enum %x)%d", v.type, v.val.i); return;
491 case T_PATH: as_path_format(v.val.ad, buf2, 1000); logn("(path %s)", buf2); return;
492 case T_CLIST: int_set_format(v.val.ad, 1, -1, buf2, 1000); logn("(clist %s)", buf2); return;
493 case T_ECLIST: ec_set_format(v.val.ad, -1, buf2, 1000); logn("(eclist %s)", buf2); return;
494 case T_PATH_MASK: pm_format(v.val.path_mask, buf2, 1000); logn("(pathmask%s)", buf2); return;
495 default: logn( "[unknown type %x]", v.type ); return;
496 }
497 }
498
499 static struct rte **f_rte;
500 static struct rta *f_old_rta;
501 static struct ea_list **f_tmp_attrs;
502 static struct linpool *f_pool;
503 static int f_flags;
504
505 static inline void f_rte_cow(void)
506 {
507 *f_rte = rte_cow(*f_rte);
508 }
509
510 /*
511 * rta_cow - prepare rta for modification by filter
512 */
513 static void
514 f_rta_cow(void)
515 {
516 if ((*f_rte)->attrs->aflags & RTAF_CACHED) {
517
518 /* Prepare to modify rte */
519 f_rte_cow();
520
521 /* Store old rta to free it later */
522 f_old_rta = (*f_rte)->attrs;
523
524 /*
525 * Alloc new rta, do shallow copy and update rte. Fields eattrs
526 * and nexthops of rta are shared with f_old_rta (they will be
527 * copied when the cached rta will be obtained at the end of
528 * f_run()), also the lock of hostentry is inherited (we suppose
529 * hostentry is not changed by filters).
530 */
531 rta *ra = lp_alloc(f_pool, sizeof(rta));
532 memcpy(ra, f_old_rta, sizeof(rta));
533 ra->aflags = 0;
534 (*f_rte)->attrs = ra;
535 }
536 }
537
538 static struct rate_limit rl_runtime_err;
539
540 #define runtime(x) do { \
541 log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \
542 res.type = T_RETURN; \
543 res.val.i = F_ERROR; \
544 return res; \
545 } while(0)
546
547 #define ARG(x,y) \
548 x = interpret(what->y); \
549 if (x.type & T_RETURN) \
550 return x;
551
552 #define ONEARG ARG(v1, a1.p)
553 #define TWOARGS ARG(v1, a1.p) \
554 ARG(v2, a2.p)
555 #define TWOARGS_C TWOARGS \
556 if (v1.type != v2.type) \
557 runtime( "Can't operate with values of incompatible types" );
558
559 /**
560 * interpret
561 * @what: filter to interpret
562 *
563 * Interpret given tree of filter instructions. This is core function
564 * of filter system and does all the hard work.
565 *
566 * Each instruction has 4 fields: code (which is instruction code),
567 * aux (which is extension to instruction code, typically type),
568 * arg1 and arg2 - arguments. Depending on instruction, arguments
569 * are either integers, or pointers to instruction trees. Common
570 * instructions like +, that have two expressions as arguments use
571 * TWOARGS macro to get both of them evaluated.
572 *
573 * &f_val structures are copied around, so there are no problems with
574 * memory managment.
575 */
576 static struct f_val
577 interpret(struct f_inst *what)
578 {
579 struct symbol *sym;
580 struct f_val v1, v2, res, *vp;
581 unsigned u1, u2;
582 int i;
583 u32 as;
584
585 res.type = T_VOID;
586 if (!what)
587 return res;
588
589 switch(what->code) {
590 case ',':
591 TWOARGS;
592 break;
593
594 /* Binary operators */
595 case '+':
596 TWOARGS_C;
597 switch (res.type = v1.type) {
598 case T_VOID: runtime( "Can't operate with values of type void" );
599 case T_INT: res.val.i = v1.val.i + v2.val.i; break;
600 default: runtime( "Usage of unknown type" );
601 }
602 break;
603 case '-':
604 TWOARGS_C;
605 switch (res.type = v1.type) {
606 case T_VOID: runtime( "Can't operate with values of type void" );
607 case T_INT: res.val.i = v1.val.i - v2.val.i; break;
608 default: runtime( "Usage of unknown type" );
609 }
610 break;
611 case '*':
612 TWOARGS_C;
613 switch (res.type = v1.type) {
614 case T_VOID: runtime( "Can't operate with values of type void" );
615 case T_INT: res.val.i = v1.val.i * v2.val.i; break;
616 default: runtime( "Usage of unknown type" );
617 }
618 break;
619 case '/':
620 TWOARGS_C;
621 switch (res.type = v1.type) {
622 case T_VOID: runtime( "Can't operate with values of type void" );
623 case T_INT: if (v2.val.i == 0) runtime( "Mother told me not to divide by 0" );
624 res.val.i = v1.val.i / v2.val.i; break;
625 case T_IP: if (v2.type != T_INT)
626 runtime( "Incompatible types in / operator" );
627 break;
628 default: runtime( "Usage of unknown type" );
629 }
630 break;
631
632 case '&':
633 case '|':
634 ARG(v1, a1.p);
635 if (v1.type != T_BOOL)
636 runtime( "Can't do boolean operation on non-booleans" );
637 if (v1.val.i == (what->code == '|')) {
638 res.type = T_BOOL;
639 res.val.i = v1.val.i;
640 break;
641 }
642
643 ARG(v2, a2.p);
644 if (v2.type != T_BOOL)
645 runtime( "Can't do boolean operation on non-booleans" );
646 res.type = T_BOOL;
647 res.val.i = v2.val.i;
648 break;
649
650 case P('m','p'):
651 TWOARGS;
652 if ((v1.type != T_INT) || (v2.type != T_INT))
653 runtime( "Can't operate with value of non-integer type in pair constructor" );
654 u1 = v1.val.i;
655 u2 = v2.val.i;
656 if ((u1 > 0xFFFF) || (u2 > 0xFFFF))
657 runtime( "Can't operate with value out of bounds in pair constructor" );
658 res.val.i = (u1 << 16) | u2;
659 res.type = T_PAIR;
660 break;
661
662 case P('m','c'):
663 {
664 TWOARGS;
665
666 int check, ipv4_used;
667 u32 key, val;
668
669 if (v1.type == T_INT) {
670 ipv4_used = 0; key = v1.val.i;
671 }
672 else if (v1.type == T_QUAD) {
673 ipv4_used = 1; key = v1.val.i;
674 }
675 #ifndef IPV6
676 /* IP->Quad implicit conversion */
677 else if (v1.type == T_IP) {
678 ipv4_used = 1; key = ipa_to_u32(v1.val.px.ip);
679 }
680 #endif
681 else
682 runtime("Can't operate with key of non-integer/IPv4 type in EC constructor");
683
684 if (v2.type != T_INT)
685 runtime("Can't operate with value of non-integer type in EC constructor");
686 val = v2.val.i;
687
688 res.type = T_EC;
689
690 if (what->aux == EC_GENERIC) {
691 check = 0; res.val.ec = ec_generic(key, val);
692 }
693 else if (ipv4_used) {
694 check = 1; res.val.ec = ec_ip4(what->aux, key, val);
695 }
696 else if (key < 0x10000) {
697 check = 0; res.val.ec = ec_as2(what->aux, key, val);
698 }
699 else {
700 check = 1; res.val.ec = ec_as4(what->aux, key, val);
701 }
702
703 if (check && (val > 0xFFFF))
704 runtime("Can't operate with value out of bounds in EC constructor");
705
706 break;
707 }
708
709 /* Relational operators */
710
711 #define COMPARE(x) \
712 TWOARGS; \
713 i = val_compare(v1, v2); \
714 if (i==CMP_ERROR) \
715 runtime( "Can't compare values of incompatible types" ); \
716 res.type = T_BOOL; \
717 res.val.i = (x); \
718 break;
719
720 case P('!','='): COMPARE(i!=0);
721 case P('=','='): COMPARE(i==0);
722 case '<': COMPARE(i==-1);
723 case P('<','='): COMPARE(i!=1);
724
725 case '!':
726 ONEARG;
727 if (v1.type != T_BOOL)
728 runtime( "Not applied to non-boolean" );
729 res = v1;
730 res.val.i = !res.val.i;
731 break;
732
733 case '~':
734 TWOARGS;
735 res.type = T_BOOL;
736 res.val.i = val_in_range(v1, v2);
737 if (res.val.i == CMP_ERROR)
738 runtime( "~ applied on unknown type pair" );
739 res.val.i = !!res.val.i;
740 break;
741 case P('d','e'):
742 ONEARG;
743 res.type = T_BOOL;
744 res.val.i = (v1.type != T_VOID);
745 break;
746
747 /* Set to indirect value, a1 = variable, a2 = value */
748 case 's':
749 ARG(v2, a2.p);
750 sym = what->a1.p;
751 vp = sym->def;
752 if ((sym->class != (SYM_VARIABLE | v2.type)) && (v2.type != T_VOID)) {
753 #ifndef IPV6
754 /* IP->Quad implicit conversion */
755 if ((sym->class == (SYM_VARIABLE | T_QUAD)) && (v2.type == T_IP)) {
756 vp->type = T_QUAD;
757 vp->val.i = ipa_to_u32(v2.val.px.ip);
758 break;
759 }
760 #endif
761 runtime( "Assigning to variable of incompatible type" );
762 }
763 *vp = v2;
764 break;
765
766 /* some constants have value in a2, some in *a1.p, strange. */
767 case 'c': /* integer (or simple type) constant, string, set, or prefix_set */
768 res.type = what->aux;
769
770 if (res.type == T_PREFIX_SET)
771 res.val.ti = what->a2.p;
772 else if (res.type == T_SET)
773 res.val.t = what->a2.p;
774 else if (res.type == T_STRING)
775 res.val.s = what->a2.p;
776 else
777 res.val.i = what->a2.i;
778 break;
779 case 'V':
780 case 'C':
781 res = * ((struct f_val *) what->a1.p);
782 break;
783 case 'p':
784 ONEARG;
785 val_print(v1);
786 break;
787 case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
788 ONEARG;
789 if (v1.type != T_BOOL)
790 runtime( "If requires boolean expression" );
791 if (v1.val.i) {
792 ARG(res,a2.p);
793 res.val.i = 0;
794 } else res.val.i = 1;
795 res.type = T_BOOL;
796 break;
797 case '0':
798 debug( "No operation\n" );
799 break;
800 case P('p',','):
801 ONEARG;
802 if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p))
803 log_commit(*L_INFO);
804
805 switch (what->a2.i) {
806 case F_QUITBIRD:
807 die( "Filter asked me to die" );
808 case F_ACCEPT:
809 /* Should take care about turning ACCEPT into MODIFY */
810 case F_ERROR:
811 case F_REJECT: /* FIXME (noncritical) Should print complete route along with reason to reject route */
812 res.type = T_RETURN;
813 res.val.i = what->a2.i;
814 return res; /* We have to return now, no more processing. */
815 case F_NONL:
816 case F_NOP:
817 break;
818 default:
819 bug( "unknown return type: Can't happen");
820 }
821 break;
822 case 'a': /* rta access */
823 {
824 struct rta *rta = (*f_rte)->attrs;
825 res.type = what->aux;
826 switch(res.type) {
827 case T_IP:
828 res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i);
829 break;
830 case T_ENUM:
831 res.val.i = * ((char *) rta + what->a2.i);
832 break;
833 case T_STRING: /* Warning: this is a special case for proto attribute */
834 res.val.s = rta->proto->name;
835 break;
836 case T_PREFIX: /* Warning: this works only for prefix of network */
837 {
838 res.val.px.ip = (*f_rte)->net->n.prefix;
839 res.val.px.len = (*f_rte)->net->n.pxlen;
840 break;
841 }
842 default:
843 bug( "Invalid type for rta access (%x)", res.type );
844 }
845 }
846 break;
847 case P('a','S'):
848 ONEARG;
849 if (what->aux != v1.type)
850 runtime( "Attempt to set static attribute to incompatible type" );
851 f_rta_cow();
852 {
853 struct rta *rta = (*f_rte)->attrs;
854 switch (what->aux) {
855
856 case T_IP:
857 * (ip_addr *) ((char *) rta + what->a2.i) = v1.val.px.ip;
858 break;
859
860 case T_ENUM_SCOPE:
861 rta->scope = v1.val.i;
862 break;
863
864 case T_ENUM_RTD:
865 i = v1.val.i;
866 if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
867 runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
868 rta->dest = i;
869 rta->gw = IPA_NONE;
870 rta->iface = NULL;
871 rta->nexthops = NULL;
872 break;
873
874 default:
875 bug( "Unknown type in set of static attribute" );
876 }
877 }
878 break;
879 case P('e','a'): /* Access to extended attributes */
880 {
881 eattr *e = NULL;
882 if (!(f_flags & FF_FORCE_TMPATTR))
883 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
884 if (!e)
885 e = ea_find( (*f_tmp_attrs), what->a2.i );
886 if ((!e) && (f_flags & FF_FORCE_TMPATTR))
887 e = ea_find( (*f_rte)->attrs->eattrs, what->a2.i );
888
889 if (!e) {
890 /* A special case: undefined int_set looks like empty int_set */
891 if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
892 res.type = T_CLIST;
893 res.val.ad = adata_empty(f_pool, 0);
894 break;
895 }
896 /* The same special case for ec_set */
897 else if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
898 res.type = T_ECLIST;
899 res.val.ad = adata_empty(f_pool, 0);
900 break;
901 }
902
903 /* Undefined value */
904 res.type = T_VOID;
905 break;
906 }
907
908 switch (what->aux & EAF_TYPE_MASK) {
909 case EAF_TYPE_INT:
910 res.type = T_INT;
911 res.val.i = e->u.data;
912 break;
913 case EAF_TYPE_ROUTER_ID:
914 res.type = T_QUAD;
915 res.val.i = e->u.data;
916 break;
917 case EAF_TYPE_OPAQUE:
918 res.type = T_ENUM_EMPTY;
919 res.val.i = 0;
920 break;
921 case EAF_TYPE_IP_ADDRESS:
922 res.type = T_IP;
923 struct adata * ad = e->u.ptr;
924 res.val.px.ip = * (ip_addr *) ad->data;
925 break;
926 case EAF_TYPE_AS_PATH:
927 res.type = T_PATH;
928 res.val.ad = e->u.ptr;
929 break;
930 case EAF_TYPE_INT_SET:
931 res.type = T_CLIST;
932 res.val.ad = e->u.ptr;
933 break;
934 case EAF_TYPE_EC_SET:
935 res.type = T_ECLIST;
936 res.val.ad = e->u.ptr;
937 break;
938 case EAF_TYPE_UNDEF:
939 res.type = T_VOID;
940 break;
941 default:
942 bug("Unknown type in e,a");
943 }
944 }
945 break;
946 case P('e','S'):
947 ONEARG;
948 {
949 struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
950
951 l->next = NULL;
952 l->flags = EALF_SORTED;
953 l->count = 1;
954 l->attrs[0].id = what->a2.i;
955 l->attrs[0].flags = 0;
956 l->attrs[0].type = what->aux | EAF_ORIGINATED;
957 switch (what->aux & EAF_TYPE_MASK) {
958 case EAF_TYPE_INT:
959 case EAF_TYPE_ROUTER_ID:
960 if (v1.type != T_INT)
961 runtime( "Setting int attribute to non-int value" );
962 l->attrs[0].u.data = v1.val.i;
963 break;
964 case EAF_TYPE_OPAQUE:
965 runtime( "Setting opaque attribute is not allowed" );
966 break;
967 case EAF_TYPE_IP_ADDRESS:
968 if (v1.type != T_IP)
969 runtime( "Setting ip attribute to non-ip value" );
970 int len = sizeof(ip_addr);
971 struct adata *ad = lp_alloc(f_pool, sizeof(struct adata) + len);
972 ad->length = len;
973 (* (ip_addr *) ad->data) = v1.val.px.ip;
974 l->attrs[0].u.ptr = ad;
975 break;
976 case EAF_TYPE_AS_PATH:
977 if (v1.type != T_PATH)
978 runtime( "Setting path attribute to non-path value" );
979 l->attrs[0].u.ptr = v1.val.ad;
980 break;
981 case EAF_TYPE_INT_SET:
982 if (v1.type != T_CLIST)
983 runtime( "Setting clist attribute to non-clist value" );
984 l->attrs[0].u.ptr = v1.val.ad;
985 break;
986 case EAF_TYPE_EC_SET:
987 if (v1.type != T_ECLIST)
988 runtime( "Setting eclist attribute to non-eclist value" );
989 l->attrs[0].u.ptr = v1.val.ad;
990 break;
991 case EAF_TYPE_UNDEF:
992 if (v1.type != T_VOID)
993 runtime( "Setting void attribute to non-void value" );
994 l->attrs[0].u.data = 0;
995 break;
996 default: bug("Unknown type in e,S");
997 }
998
999 if (!(what->aux & EAF_TEMP) && (!(f_flags & FF_FORCE_TMPATTR))) {
1000 f_rta_cow();
1001 l->next = (*f_rte)->attrs->eattrs;
1002 (*f_rte)->attrs->eattrs = l;
1003 } else {
1004 l->next = (*f_tmp_attrs);
1005 (*f_tmp_attrs) = l;
1006 }
1007 }
1008 break;
1009 case 'P':
1010 res.type = T_INT;
1011 res.val.i = (*f_rte)->pref;
1012 break;
1013 case P('P','S'):
1014 ONEARG;
1015 if (v1.type != T_INT)
1016 runtime( "Can't set preference to non-integer" );
1017 if ((v1.val.i < 0) || (v1.val.i > 0xFFFF))
1018 runtime( "Setting preference value out of bounds" );
1019 f_rte_cow();
1020 (*f_rte)->pref = v1.val.i;
1021 break;
1022 case 'L': /* Get length of */
1023 ONEARG;
1024 res.type = T_INT;
1025 switch(v1.type) {
1026 case T_PREFIX: res.val.i = v1.val.px.len; break;
1027 case T_PATH: res.val.i = as_path_getlen(v1.val.ad); break;
1028 default: runtime( "Prefix or path expected" );
1029 }
1030 break;
1031 case P('c','p'): /* Convert prefix to ... */
1032 ONEARG;
1033 if (v1.type != T_PREFIX)
1034 runtime( "Prefix expected" );
1035 res.type = what->aux;
1036 switch(res.type) {
1037 /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */
1038 case T_IP: res.val.px.ip = v1.val.px.ip; break;
1039 default: bug( "Unknown prefix to conversion" );
1040 }
1041 break;
1042 case P('a','f'): /* Get first ASN from AS PATH */
1043 ONEARG;
1044 if (v1.type != T_PATH)
1045 runtime( "AS path expected" );
1046
1047 as = 0;
1048 as_path_get_first(v1.val.ad, &as);
1049 res.type = T_INT;
1050 res.val.i = as;
1051 break;
1052 case P('a','l'): /* Get last ASN from AS PATH */
1053 ONEARG;
1054 if (v1.type != T_PATH)
1055 runtime( "AS path expected" );
1056
1057 as = 0;
1058 as_path_get_last(v1.val.ad, &as);
1059 res.type = T_INT;
1060 res.val.i = as;
1061 break;
1062 case 'r':
1063 ONEARG;
1064 res = v1;
1065 res.type |= T_RETURN;
1066 return res;
1067 case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */
1068 ONEARG;
1069 res = interpret(what->a2.p);
1070 if (res.type == T_RETURN)
1071 return res;
1072 res.type &= ~T_RETURN;
1073 break;
1074 case P('c','v'): /* Clear local variables */
1075 for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
1076 ((struct f_val *) sym->def)->type = T_VOID;
1077 break;
1078 case P('S','W'):
1079 ONEARG;
1080 {
1081 struct f_tree *t = find_tree(what->a2.p, v1);
1082 if (!t) {
1083 v1.type = T_VOID;
1084 t = find_tree(what->a2.p, v1);
1085 if (!t) {
1086 debug( "No else statement?\n");
1087 break;
1088 }
1089 }
1090 /* It is actually possible to have t->data NULL */
1091
1092 res = interpret(t->data);
1093 if (res.type & T_RETURN)
1094 return res;
1095 }
1096 break;
1097 case P('i','M'): /* IP.MASK(val) */
1098 TWOARGS;
1099 if (v2.type != T_INT)
1100 runtime( "Integer expected");
1101 if (v1.type != T_IP)
1102 runtime( "You can mask only IP addresses" );
1103 {
1104 ip_addr mask = ipa_mkmask(v2.val.i);
1105 res.type = T_IP;
1106 res.val.px.ip = ipa_and(mask, v1.val.px.ip);
1107 }
1108 break;
1109
1110 case 'E': /* Create empty attribute */
1111 res.type = what->aux;
1112 res.val.ad = adata_empty(f_pool, 0);
1113 break;
1114 case P('A','p'): /* Path prepend */
1115 TWOARGS;
1116 if (v1.type != T_PATH)
1117 runtime("Can't prepend to non-path");
1118 if (v2.type != T_INT)
1119 runtime("Can't prepend non-integer");
1120
1121 res.type = T_PATH;
1122 res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
1123 break;
1124
1125 case P('C','a'): /* (Extended) Community list add or delete */
1126 TWOARGS;
1127 if (v1.type == T_CLIST)
1128 {
1129 /* Community (or cluster) list */
1130 struct f_val dummy;
1131 int arg_set = 0;
1132 i = 0;
1133
1134 if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
1135 i = v2.val.i;
1136 #ifndef IPV6
1137 /* IP->Quad implicit conversion */
1138 else if (v2.type == T_IP)
1139 i = ipa_to_u32(v2.val.px.ip);
1140 #endif
1141 else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
1142 arg_set = 1;
1143 else if (v2.type == T_CLIST)
1144 arg_set = 2;
1145 else
1146 runtime("Can't add/delete non-pair");
1147
1148 res.type = T_CLIST;
1149 switch (what->aux)
1150 {
1151 case 'a':
1152 if (arg_set == 1)
1153 runtime("Can't add set");
1154 else if (!arg_set)
1155 res.val.ad = int_set_add(f_pool, v1.val.ad, i);
1156 else
1157 res.val.ad = int_set_union(f_pool, v1.val.ad, v2.val.ad);
1158 break;
1159
1160 case 'd':
1161 if (!arg_set)
1162 res.val.ad = int_set_del(f_pool, v1.val.ad, i);
1163 else
1164 res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 0);
1165 break;
1166
1167 case 'f':
1168 if (!arg_set)
1169 runtime("Can't filter pair");
1170 res.val.ad = clist_filter(f_pool, v1.val.ad, v2, 1);
1171 break;
1172
1173 default:
1174 bug("unknown Ca operation");
1175 }
1176 }
1177 else if (v1.type == T_ECLIST)
1178 {
1179 /* Extended community list */
1180 int arg_set = 0;
1181
1182 /* v2.val is either EC or EC-set */
1183 if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
1184 arg_set = 1;
1185 else if (v2.type == T_ECLIST)
1186 arg_set = 2;
1187 else if (v2.type != T_EC)
1188 runtime("Can't add/delete non-pair");
1189
1190 res.type = T_ECLIST;
1191 switch (what->aux)
1192 {
1193 case 'a':
1194 if (arg_set == 1)
1195 runtime("Can't add set");
1196 else if (!arg_set)
1197 res.val.ad = ec_set_add(f_pool, v1.val.ad, v2.val.ec);
1198 else
1199 res.val.ad = ec_set_union(f_pool, v1.val.ad, v2.val.ad);
1200 break;
1201
1202 case 'd':
1203 if (!arg_set)
1204 res.val.ad = ec_set_del(f_pool, v1.val.ad, v2.val.ec);
1205 else
1206 res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 0);
1207 break;
1208
1209 case 'f':
1210 if (!arg_set)
1211 runtime("Can't filter ec");
1212 res.val.ad = eclist_filter(f_pool, v1.val.ad, v2, 1);
1213 break;
1214
1215 default:
1216 bug("unknown Ca operation");
1217 }
1218 }
1219 else
1220 runtime("Can't add/delete to non-(e)clist");
1221
1222 break;
1223
1224 case P('R','C'): /* ROA Check */
1225 if (what->arg1)
1226 {
1227 TWOARGS;
1228 if ((v1.type != T_PREFIX) || (v2.type != T_INT))
1229 runtime("Invalid argument to roa_check()");
1230
1231 as = v2.val.i;
1232 }
1233 else
1234 {
1235 v1.val.px.ip = (*f_rte)->net->n.prefix;
1236 v1.val.px.len = (*f_rte)->net->n.pxlen;
1237
1238 /* We ignore temporary attributes, probably not a problem here */
1239 /* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
1240 eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02));
1241
1242 if (!e || e->type != EAF_TYPE_AS_PATH)
1243 runtime("Missing AS_PATH attribute");
1244
1245 as_path_get_last(e->u.ptr, &as);
1246 }
1247
1248 struct roa_table_config *rtc = ((struct f_inst_roa_check *) what)->rtc;
1249 if (!rtc->table)
1250 runtime("Missing ROA table");
1251
1252 res.type = T_ENUM_ROA;
1253 res.val.i = roa_check(rtc->table, v1.val.px.ip, v1.val.px.len, as);
1254 break;
1255
1256 default:
1257 bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff);
1258 }
1259 if (what->next)
1260 return interpret(what->next);
1261 return res;
1262 }
1263
1264 #undef ARG
1265 #define ARG(x,y) \
1266 if (!i_same(f1->y, f2->y)) \
1267 return 0;
1268
1269 #define ONEARG ARG(v1, a1.p)
1270 #define TWOARGS ARG(v1, a1.p) \
1271 ARG(v2, a2.p)
1272
1273 #define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
1274
1275 /*
1276 * i_same - function that does real comparing of instruction trees, you should call filter_same from outside
1277 */
1278 int
1279 i_same(struct f_inst *f1, struct f_inst *f2)
1280 {
1281 if ((!!f1) != (!!f2))
1282 return 0;
1283 if (!f1)
1284 return 1;
1285 if (f1->aux != f2->aux)
1286 return 0;
1287 if (f1->code != f2->code)
1288 return 0;
1289 if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
1290 return 1;
1291
1292 switch(f1->code) {
1293 case ',': /* fall through */
1294 case '+':
1295 case '-':
1296 case '*':
1297 case '/':
1298 case '|':
1299 case '&':
1300 case P('m','p'):
1301 case P('m','c'):
1302 case P('!','='):
1303 case P('=','='):
1304 case '<':
1305 case P('<','='): TWOARGS; break;
1306
1307 case '!': ONEARG; break;
1308 case '~': TWOARGS; break;
1309 case P('d','e'): ONEARG; break;
1310
1311 case 's':
1312 ARG(v2, a2.p);
1313 {
1314 struct symbol *s1, *s2;
1315 s1 = f1->a1.p;
1316 s2 = f2->a1.p;
1317 if (strcmp(s1->name, s2->name))
1318 return 0;
1319 if (s1->class != s2->class)
1320 return 0;
1321 }
1322 break;
1323
1324 case 'c':
1325 switch (f1->aux) {
1326
1327 case T_PREFIX_SET:
1328 if (!trie_same(f1->a2.p, f2->a2.p))
1329 return 0;
1330 break;
1331
1332 case T_SET:
1333 if (!same_tree(f1->a2.p, f2->a2.p))
1334 return 0;
1335 break;
1336
1337 case T_STRING:
1338 if (strcmp(f1->a2.p, f2->a2.p))
1339 return 0;
1340 break;
1341
1342 default:
1343 A2_SAME;
1344 }
1345 break;
1346 case 'C':
1347 if (val_compare(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
1348 return 0;
1349 break;
1350 case 'V':
1351 if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
1352 return 0;
1353 break;
1354 case 'p': case 'L': ONEARG; break;
1355 case '?': TWOARGS; break;
1356 case '0': case 'E': break;
1357 case P('p',','): ONEARG; A2_SAME; break;
1358 case 'P':
1359 case 'a': A2_SAME; break;
1360 case P('e','a'): A2_SAME; break;
1361 case P('P','S'):
1362 case P('a','S'):
1363 case P('e','S'): ONEARG; A2_SAME; break;
1364
1365 case 'r': ONEARG; break;
1366 case P('c','p'): ONEARG; break;
1367 case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
1368 ONEARG;
1369 if (!i_same(f1->a2.p, f2->a2.p))
1370 return 0;
1371 f2->a2.p = f1->a2.p;
1372 break;
1373 case P('c','v'): break; /* internal instruction */
1374 case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
1375 case P('i','M'): TWOARGS; break;
1376 case P('A','p'): TWOARGS; break;
1377 case P('C','a'): TWOARGS; break;
1378 case P('a','f'):
1379 case P('a','l'): ONEARG; break;
1380 case P('R','C'):
1381 TWOARGS;
1382 /* Does not really make sense - ROA check resuls may change anyway */
1383 if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
1384 ((struct f_inst_roa_check *) f2)->rtc->name))
1385 return 0;
1386 break;
1387 default:
1388 bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff);
1389 }
1390 return i_same(f1->next, f2->next);
1391 }
1392
1393 /**
1394 * f_run - run a filter for a route
1395 * @filter: filter to run
1396 * @rte: route being filtered, may be modified
1397 * @tmp_attrs: temporary attributes, prepared by caller or generated by f_run()
1398 * @tmp_pool: all filter allocations go from this pool
1399 * @flags: flags
1400 *
1401 * If filter needs to modify the route, there are several
1402 * posibilities. @rte might be read-only (with REF_COW flag), in that
1403 * case rw copy is obtained by rte_cow() and @rte is replaced. If
1404 * @rte is originally rw, it may be directly modified (and it is never
1405 * copied).
1406 *
1407 * The returned rte may reuse the (possibly cached, cloned) rta, or
1408 * (if rta was modificied) contains a modified uncached rta, which
1409 * uses parts allocated from @tmp_pool and parts shared from original
1410 * rta. There is one exception - if @rte is rw but contains a cached
1411 * rta and that is modified, rta in returned rte is also cached.
1412 *
1413 * Ownership of cached rtas is consistent with rte, i.e.
1414 * if a new rte is returned, it has its own clone of cached rta
1415 * (and cached rta of read-only source rte is intact), if rte is
1416 * modified in place, old cached rta is possibly freed.
1417 */
1418 int
1419 f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
1420 {
1421 int rte_cow = ((*rte)->flags & REF_COW);
1422 DBG( "Running filter `%s'...", filter->name );
1423
1424 f_rte = rte;
1425 f_old_rta = NULL;
1426 f_tmp_attrs = tmp_attrs;
1427 f_pool = tmp_pool;
1428 f_flags = flags;
1429
1430 log_reset();
1431 struct f_val res = interpret(filter->root);
1432
1433 if (f_old_rta) {
1434 /*
1435 * Cached rta was modified and f_rte contains now an uncached one,
1436 * sharing some part with the cached one. The cached rta should
1437 * be freed (if rte was originally COW, f_old_rta is a clone
1438 * obtained during rte_cow()).
1439 *
1440 * This also implements the exception mentioned in f_run()
1441 * description. The reason for this is that rta reuses parts of
1442 * f_old_rta, and these may be freed during rta_free(f_old_rta).
1443 * This is not the problem if rte was COW, because original rte
1444 * also holds the same rta.
1445 */
1446 if (!rte_cow)
1447 (*f_rte)->attrs = rta_lookup((*f_rte)->attrs);
1448
1449 rta_free(f_old_rta);
1450 }
1451
1452
1453 if (res.type != T_RETURN) {
1454 log( L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
1455 return F_ERROR;
1456 }
1457 DBG( "done (%d)\n", res.val.i );
1458 return res.val.i;
1459 }
1460
1461 int
1462 f_eval_int(struct f_inst *expr)
1463 {
1464 /* Called independently in parse-time to eval expressions */
1465 struct f_val res;
1466
1467 f_flags = 0;
1468 f_tmp_attrs = NULL;
1469 f_rte = NULL;
1470 f_pool = cfg_mem;
1471
1472 log_reset();
1473 res = interpret(expr);
1474
1475 if (res.type != T_INT)
1476 cf_error("Integer expression expected");
1477 return res.val.i;
1478 }
1479
1480 u32
1481 f_eval_asn(struct f_inst *expr)
1482 {
1483 /* Called as a part of another interpret call, therefore no log_reset() */
1484 struct f_val res = interpret(expr);
1485 return (res.type == T_INT) ? res.val.i : 0;
1486 }
1487
1488 /**
1489 * filter_same - compare two filters
1490 * @new: first filter to be compared
1491 * @old: second filter to be compared, notice that this filter is
1492 * damaged while comparing.
1493 *
1494 * Returns 1 in case filters are same, otherwise 0. If there are
1495 * underlying bugs, it will rather say 0 on same filters than say
1496 * 1 on different.
1497 */
1498 int
1499 filter_same(struct filter *new, struct filter *old)
1500 {
1501 if (old == new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
1502 return 1;
1503 if (old == FILTER_ACCEPT || old == FILTER_REJECT ||
1504 new == FILTER_ACCEPT || new == FILTER_REJECT)
1505 return 0;
1506 return i_same(new->root, old->root);
1507 }