]>
git.ipfire.org Git - thirdparty/bird.git/blob - filter/filter.c
2 * Filters: utility functions
4 * Copyright 1998 Pavel Machek <pavel@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
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|.
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.
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).
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"
49 #define P(a,b) ((a<<8) | b)
54 adata_empty(struct linpool
*pool
)
56 struct adata
*res
= lp_alloc(pool
, sizeof(struct adata
));
62 pm_path_compare(struct f_path_mask
*m1
, struct f_path_mask
*m2
)
66 return !((!m1
) && (!m2
));
73 * val_compare - compare two values
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.
82 val_compare(struct f_val v1
, struct f_val v2
)
84 if ((v1
.type
== T_VOID
) && (v2
.type
== T_VOID
))
86 if (v1
.type
== T_VOID
) /* Hack for else */
88 if (v2
.type
== T_VOID
)
91 if (v1
.type
!= v2
.type
) {
92 debug( "Types do not match in val_compare\n" );
99 if (v1
.val
.i
== v2
.val
.i
) return 0;
100 if (v1
.val
.i
< v2
.val
.i
) return -1;
104 return ipa_compare(v1
.val
.px
.ip
, v2
.val
.px
.ip
);
106 return pm_path_compare(v1
.val
.path_mask
, v2
.val
.path_mask
);
108 debug( "Compare of unkown entities: %x\n", v1
.type
);
114 * val_simple_in_range - check if @v1 ~ @v2 for everything except sets
117 val_simple_in_range(struct f_val v1
, struct f_val v2
)
119 if ((v1
.type
== T_PATH
) && (v2
.type
== T_PATH_MASK
))
120 return as_path_match(v1
.val
.ad
, v2
.val
.path_mask
);
121 if ((v1
.type
== T_PAIR
) && (v2
.type
== T_CLIST
))
122 return int_set_contains(v2
.val
.ad
, v1
.val
.i
);
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
))));
127 if ((v1
.type
== T_PREFIX
) && (v2
.type
== T_PREFIX
)) {
129 if (v1
.val
.px
.len
& (LEN_PLUS
| LEN_MINUS
| LEN_RANGE
))
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
)))
135 if ((v2
.val
.px
.len
& LEN_MINUS
) && (v1
.val
.px
.len
<= (v2
.val
.px
.len
& LEN_MASK
)))
137 if ((v2
.val
.px
.len
& LEN_PLUS
) && (v1
.val
.px
.len
< (v2
.val
.px
.len
& LEN_MASK
)))
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)))))
148 * val_in_range - implement |~| operator
152 * Checks if @v1 is element (|~| operator) of @v2. Sets are internally represented as balanced trees, see
153 * |tree.c| module (this is not limited to sets, but for non-set cases, val_simple_in_range() is called early).
156 val_in_range(struct f_val v1
, struct f_val v2
)
160 res
= val_simple_in_range(v1
, v2
);
162 if (res
!= CMP_ERROR
)
165 if (v2
.type
== T_SET
)
173 n
= find_tree(v2
.val
.t
, v1
);
176 return !! (val_simple_in_range(v1
, n
->from
)); /* We turn CMP_ERROR into compared ok, and that's fine */
183 tree_print(struct f_tree
*t
)
190 tree_print( t
->left
);
191 debug( ", " ); val_print( t
->from
); debug( ".." ); val_print( t
->to
); debug( ", " );
192 tree_print( t
->right
);
197 * val_print - format filter value
200 val_print(struct f_val v
)
204 #define PRINTF(a...) bsnprintf( buf, 2040, a )
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;
211 case T_IP
: PRINTF( "%I", v
.val
.px
.ip
); break;
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;
214 case T_SET
: tree_print( v
.val
.t
); PRINTF( "\n" ); break;
215 case T_ENUM
: PRINTF( "(enum %x)%d", v
.type
, v
.val
.i
); break;
216 case T_PATH
: as_path_format(v
.val
.ad
, buf2
, 1020); PRINTF( "(path %s)", buf2
); break;
217 case T_CLIST
: int_set_format(v
.val
.ad
, buf2
, 1020); PRINTF( "(clist %s)", buf2
); break;
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;
219 default: PRINTF( "[unknown type %x]", v
.type
);
225 static struct rte
**f_rte
, *f_rte_old
;
226 static struct linpool
*f_pool
;
227 static struct ea_list
**f_tmp_attrs
;
229 static rta
*f_rta_copy
;
232 * rta_cow - prepare rta for modification by filter
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
);
242 rta_free((*f_rte
)->attrs
);
243 (*f_rte
)->attrs
= f_rta_copy
;
247 #define runtime(x) do { \
248 log( L_ERR "filters, line %d: %s", what->lineno, x); \
249 res.type = T_RETURN; \
250 res.val.i = F_ERROR; \
255 x = interpret(what->y); \
256 if (x.type & T_RETURN) \
259 #define ONEARG ARG(v1, a1.p)
260 #define TWOARGS ARG(v1, a1.p) \
262 #define TWOARGS_C TWOARGS \
263 if (v1.type != v2.type) \
264 runtime( "Can't operate with values of incompatible types" );
268 * @what: filter to interpret
270 * Interpret given tree of filter instructions. This is core function
271 * of filter system and does all the hard work.
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.
280 * &f_val structures are copied around, so there are no problems with
284 interpret(struct f_inst
*what
)
287 struct f_val v1
, v2
, res
;
299 /* Binary operators */
302 switch (res
.type
= v1
.type
) {
303 case T_VOID
: runtime( "Can't operate with values of type void" );
304 case T_INT
: res
.val
.i
= v1
.val
.i
+ v2
.val
.i
; break;
305 default: runtime( "Usage of unknown type" );
310 switch (res
.type
= v1
.type
) {
311 case T_VOID
: runtime( "Can't operate with values of type void" );
312 case T_INT
: res
.val
.i
= v1
.val
.i
- v2
.val
.i
; break;
313 default: runtime( "Usage of unknown type" );
318 switch (res
.type
= v1
.type
) {
319 case T_VOID
: runtime( "Can't operate with values of type void" );
320 case T_INT
: res
.val
.i
= v1
.val
.i
* v2
.val
.i
; break;
321 default: runtime( "Usage of unknown type" );
326 switch (res
.type
= v1
.type
) {
327 case T_VOID
: runtime( "Can't operate with values of type void" );
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;
330 case T_IP
: if (v2
.type
!= T_INT
)
331 runtime( "Incompatible types in / operator" );
333 default: runtime( "Usage of unknown type" );
340 if (res
.type
!= T_BOOL
) runtime( "Can't do boolean operation on non-booleans" );
341 res
.val
.i
= v1
.val
.i
&& v2
.val
.i
;
346 if (res
.type
!= T_BOOL
) runtime( "Can't do boolean operation on non-booleans" );
347 res
.val
.i
= v1
.val
.i
|| v2
.val
.i
;
350 /* Relational operators */
355 i = val_compare(v1, v2); \
357 runtime( "Error in comparison" ); \
361 case P('!','='): COMPARE(i
!=0);
362 case P('=','='): COMPARE(i
==0);
363 case '<': COMPARE(i
==-1);
364 case P('<','='): COMPARE(i
!=1);
368 if (v1
.type
!= T_BOOL
)
369 runtime( "Not applied to non-boolean" );
371 res
.val
.i
= !res
.val
.i
;
377 res
.val
.i
= val_in_range(v1
, v2
);
378 if (res
.val
.i
== CMP_ERROR
)
379 runtime( "~ applied on unknown type pair" );
384 res
.val
.i
= (v1
.type
!= T_VOID
);
387 /* Set to indirect value, a1 = variable, a2 = value */
391 switch (res
.type
= v2
.type
) {
392 case T_VOID
: runtime( "Can't assign void values" );
401 if (sym
->class != (SYM_VARIABLE
| v2
.type
))
402 runtime( "Assigning to variable of incompatible type" );
403 * (struct f_val
*) sym
->aux2
= v2
;
406 bug( "Set to invalid type" );
410 case 'c': /* integer (or simple type) constant */
411 res
.type
= what
->aux
;
412 res
.val
.i
= what
->a2
.i
;
415 res
= * ((struct f_val
*) what
->a1
.p
);
421 case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */
423 if (v1
.type
!= T_BOOL
)
424 runtime( "If requires boolean expression" );
428 } else res
.val
.i
= 1;
432 debug( "No operation\n" );
436 if (what
->a2
.i
== F_NOP
|| (what
->a2
.i
!= F_NONL
&& what
->a1
.p
))
439 switch (what
->a2
.i
) {
441 die( "Filter asked me to die" );
443 /* Should take care about turning ACCEPT into MODIFY */
445 case F_REJECT
: /* FIXME (noncritical) Should print complete route along with reason to reject route */
447 res
.val
.i
= what
->a2
.i
;
448 return res
; /* We have to return now, no more processing. */
453 bug( "unknown return type: Can't happen");
456 case 'a': /* rta access */
458 struct rta
*rta
= (*f_rte
)->attrs
;
459 res
.type
= what
->aux
;
462 res
.val
.px
.ip
= * (ip_addr
*) ((char *) rta
+ what
->a2
.i
);
465 res
.val
.i
= * ((char *) rta
+ what
->a2
.i
);
467 case T_PREFIX
: /* Warning: this works only for prefix of network */
469 res
.val
.px
.ip
= (*f_rte
)->net
->n
.prefix
;
470 res
.val
.px
.len
= (*f_rte
)->net
->n
.pxlen
;
474 bug( "Invalid type for rta access (%x)", res
.type
);
480 if (what
->aux
!= v1
.type
)
481 runtime( "Attempt to set static attribute to incompatible type" );
484 struct rta
*rta
= (*f_rte
)->attrs
;
487 * ((char *) rta
+ what
->a2
.i
) = v1
.val
.i
;
490 * (ip_addr
*) ((char *) rta
+ what
->a2
.i
) = v1
.val
.px
.ip
;
493 bug( "Unknown type in set of static attribute" );
497 case P('e','a'): /* Access to extended attributes */
500 if (!(f_flags
& FF_FORCE_TMPATTR
))
501 e
= ea_find( (*f_rte
)->attrs
->eattrs
, what
->a2
.i
);
503 e
= ea_find( (*f_tmp_attrs
), what
->a2
.i
);
504 if ((!e
) && (f_flags
& FF_FORCE_TMPATTR
))
505 e
= ea_find( (*f_rte
)->attrs
->eattrs
, what
->a2
.i
);
507 switch (what
->aux
& EAF_TYPE_MASK
) {
514 res
.val
.i
= e
->u
.data
;
516 case EAF_TYPE_AS_PATH
:
522 res
.val
.ad
= e
->u
.ptr
;
524 case EAF_TYPE_INT_SET
:
527 res
.val
.ad
= adata_empty(f_pool
);
531 res
.val
.ad
= e
->u
.ptr
;
534 bug("Unknown type in e,a");
541 struct ea_list
*l
= lp_alloc(f_pool
, sizeof(struct ea_list
) + sizeof(eattr
));
544 l
->flags
= EALF_SORTED
;
546 l
->attrs
[0].id
= what
->a2
.i
;
547 l
->attrs
[0].flags
= 0;
548 l
->attrs
[0].type
= what
->aux
| EAF_ORIGINATED
;
549 switch (what
->aux
& EAF_TYPE_MASK
) {
551 if (v1
.type
!= T_INT
)
552 runtime( "Setting int attribute to non-int value" );
553 l
->attrs
[0].u
.data
= v1
.val
.i
;
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
;
560 case EAF_TYPE_INT_SET
:
561 if (v1
.type
!= T_CLIST
)
562 runtime( "Setting int set attribute to non-clist value" );
563 l
->attrs
[0].u
.ptr
= v1
.val
.ad
;
566 if (v1
.type
!= T_VOID
)
567 runtime( "Setting void attribute to non-void value" );
568 l
->attrs
[0].u
.data
= 0;
570 default: bug("Unknown type in e,S");
573 if (!(what
->aux
& EAF_TEMP
) && (!(f_flags
& FF_FORCE_TMPATTR
))) {
575 l
->next
= f_rta_copy
->eattrs
;
576 f_rta_copy
->eattrs
= l
;
578 l
->next
= (*f_tmp_attrs
);
585 res
.val
.i
= (*f_rte
)->pref
;
589 if (v1
.type
!= T_INT
)
590 runtime( "Can't set preference to non-integer" );
591 *f_rte
= rte_cow(*f_rte
);
592 (*f_rte
)->pref
= v1
.val
.i
;
594 case 'L': /* Get length of */
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?" );
603 case P('c','p'): /* Convert prefix to ... */
605 if (v1
.type
!= T_PREFIX
)
606 runtime( "Prefix expected" );
607 res
.type
= what
->aux
;
609 /* case T_INT: res.val.i = v1.val.px.len; break; Not needed any more */
610 case T_IP
: res
.val
.px
.ip
= v1
.val
.px
.ip
; break;
611 default: bug( "Unknown prefix to conversion" );
617 res
.type
|= T_RETURN
;
619 case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */
621 res
= interpret(what
->a2
.p
);
622 if (res
.type
== T_RETURN
)
624 res
.type
&= ~T_RETURN
;
629 struct f_tree
*t
= find_tree(what
->a2
.p
, v1
);
632 t
= find_tree(what
->a2
.p
, v1
);
634 debug( "No else statement?\n");
638 /* It is actually possible to have t->data NULL */
639 return interpret(t
->data
);
642 case P('i','M'): /* IP.MASK(val) */
644 if (v2
.type
!= T_INT
)
645 runtime( "Integer expected");
647 runtime( "You can mask only IP addresses" );
649 ip_addr mask
= ipa_mkmask(v2
.val
.i
);
651 res
.val
.px
.ip
= ipa_and(mask
, v1
.val
.px
.ip
);
655 case 'E': /* Create empty attribute */
656 res
.type
= what
->aux
;
657 res
.val
.ad
= adata_empty(f_pool
);
659 case P('A','p'): /* Path prepend */
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");
667 res
.val
.ad
= as_path_prepend(f_pool
, v1
.val
.ad
, v2
.val
.i
);
670 case P('C','a'): /* Community list add or delete */
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");
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");
686 bug( "Unknown instruction %d (%c)", what
->code
, what
->code
& 0xff);
689 return interpret(what
->next
);
695 if (!i_same(f1->y, f2->y)) \
698 #define ONEARG ARG(v1, a1.p)
699 #define TWOARGS ARG(v1, a1.p) \
702 #define A2_SAME if (f1->a2.i != f2->a2.i) return 0;
705 * i_same - function that does real comparing of instruction trees, you should call filter_same from outside
708 i_same(struct f_inst
*f1
, struct f_inst
*f2
)
710 if ((!!f1
) != (!!f2
))
714 if (f1
->aux
!= f2
->aux
)
716 if (f1
->code
!= f2
->code
)
718 if (f1
== f2
) /* It looks strange, but it is possible with call rewriting trickery */
722 case ',': /* fall through */
732 case P('<','='): TWOARGS
; break;
734 case '!': ONEARG
; break;
735 case '~': TWOARGS
; break;
736 case P('d','e'): ONEARG
; break;
741 struct symbol
*s1
, *s2
;
744 if (strcmp(s1
->name
, s2
->name
))
746 if (s1
->class != s2
->class)
751 case 'c': A2_SAME
; break;
753 if (val_compare(* (struct f_val
*) f1
->a1
.p
, * (struct f_val
*) f2
->a1
.p
))
756 case 'p': case 'L': ONEARG
; break;
757 case '?': TWOARGS
; break;
758 case '0': case 'E': break;
759 case P('p',','): ONEARG
; A2_SAME
; break;
761 case 'a': A2_SAME
; break;
762 case P('e','a'): A2_SAME
; break;
765 case P('e','S'): ONEARG
; A2_SAME
; break;
767 case 'r': ONEARG
; break;
768 case P('c','p'): ONEARG
; break;
769 case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */
771 if (!i_same(f1
->a2
.p
, f2
->a2
.p
))
775 case P('S','W'): ONEARG
; if (!same_tree(f1
->a2
.p
, f2
->a2
.p
)) return 0; break;
776 case P('i','M'): TWOARGS
; break;
777 case P('A','p'): TWOARGS
; break;
778 case P('C','a'): TWOARGS
; break;
780 bug( "Unknown instruction %d in same (%c)", f1
->code
, f1
->code
& 0xff);
782 return i_same(f1
->next
, f2
->next
);
786 * f_run - external entry point to filters
787 * @filter: pointer to filter to run
788 * @tmp_attrs: where to store newly generated temporary attributes
789 * @rte: pointer to pointer to &rte being filtered. When route is modified, this is changed with rte_cow().
790 * @tmp_pool: all filter allocations go from this pool
794 f_run(struct filter
*filter
, struct rte
**rte
, struct ea_list
**tmp_attrs
, struct linpool
*tmp_pool
, int flags
)
798 DBG( "Running filter `%s'...", filter
->name
);
801 f_tmp_attrs
= tmp_attrs
;
807 res
= interpret(inst
);
808 if (res
.type
!= T_RETURN
) {
809 log( L_ERR
"Filter %s did not return accept nor reject. Make up your mind", filter
->name
);
812 DBG( "done (%d)\n", res
.val
.i
);
817 f_eval_int(struct f_inst
*expr
)
827 res
= interpret(expr
);
828 if (res
.type
!= T_INT
)
829 cf_error("Integer expression expected");
834 * filter_same - compare two filters
835 * @new: first filter to be compared
836 * @old: second filter to be compared, notice that this filter is
837 * damaged while comparing.
839 * Returns 1 in case filters are same, otherwise 0. If there are
840 * underlying bugs, it will rather say 0 on same filters than say
844 filter_same(struct filter
*new, struct filter
*old
)
846 if (old
== new) /* Handle FILTER_ACCEPT and FILTER_REJECT */
848 if (old
== FILTER_ACCEPT
|| old
== FILTER_REJECT
||
849 new == FILTER_ACCEPT
|| new == FILTER_REJECT
)
851 return i_same(new->root
, old
->root
);