5. Filters
5.1 Introduction
BIRD contains a simple programming language. (No, it can't yet read mail :-).
There are two objects in this language: filters and functions. Filters are
interpreted by BIRD core when a route is being passed between protocols and
routing tables. The filter language contains control structures such as if's and
switches, but it allows no loops. An example of a filter using many features can
be found in filter/test.conf
.
Filter gets the route, looks at its attributes and modifies some of them if
it wishes. At the end, it decides whether to pass the changed route through
(using accept
) or whether to reject
it. A simple filter looks like
this:
filter not_too_far int var; { if defined( rip_metric ) then var = rip_metric; else { var = 1; rip_metric = 1; } if rip_metric > 10 then reject "RIP metric is too big"; else accept "ok"; }
As you can see, a filter has a header, a list of local variables, and a body.
The header consists of the filter
keyword followed by a (unique) name of
filter. The list of local variables consists of type name;
pairs where each pair defines one local variable. The body consists of { statements }
. Each statement is terminated by a ;
. You
can group several statements to a single compound statement by using braces
({ statements }
) which is useful if you want to make a bigger
block of code conditional.
BIRD supports functions, so that you don't have to repeat the same blocks of code over and over. Functions can have zero or more parameters and they can have local variables. Recursion is not allowed. Function definitions look like this:
function name () int local_variable; { local_variable = 5; } function with_parameters (int parameter) { print parameter; }
Unlike in C, variables are declared after the function
line, but before
the first {
. You can't declare variables in nested blocks. Functions are
called like in C: name(); with_parameters(5);
. Function may return
values using the return [expr]
command. Returning a value exits
from current function (this is similar to C).
Filters are declared in a way similar to functions except they can't have
explicit parameters. They get a route table entry as an implicit parameter, it
is also passed automatically to any functions called. The filter must terminate
with either accept
or reject
statement. If there's a runtime error in
filter, the route is rejected.
A nice trick to debug filters is to use show route filter name
from the command line client. An example session might look like:
pavel@bug:~/bird$ ./birdc -s bird.ctl BIRD 0.0.0 ready. bird> show route 10.0.0.0/8 dev eth0 [direct1 23:21] (240) 195.113.30.2/32 dev tunl1 [direct1 23:21] (240) 127.0.0.0/8 dev lo [direct1 23:21] (240) bird> show route ? show route [<prefix>] [table <t>] [filter <f>] [all] [primary]... bird> show route filter { if 127.0.0.5 ~ net then accept; } 127.0.0.0/8 dev lo [direct1 23:21] (240) bird>
5.2 Data types
Each variable and each value has certain type. Booleans, integers and enums are incompatible with each other (that is to prevent you from shooting in the foot).
bool
This is a boolean type, it can have only two values,
true
andfalse
. Boolean is the only type you can use inif
statements.int
This is a general integer type. It is an unsigned 32bit type; i.e., you can expect it to store values from 0 to 4294967295. Overflows are not checked. You can use
0x1234
syntax to write hexadecimal values.pair
This is a pair of two short integers. Each component can have values from 0 to 65535. Literals of this type are written as
(1234,5678)
. The same syntax can also be used to construct a pair from two arbitrary integer expressions (for example(1+2,a)
).quad
This is a dotted quad of numbers used to represent router IDs (and others). Each component can have a value from 0 to 255. Literals of this type are written like IPv4 addresses.
string
This is a string of characters. There are no ways to modify strings in filters. You can pass them between functions, assign them to variables of type
string
, print such variables, use standard string comparison operations (e.g.=, !=, <, >, <=, >=
), but you can't concatenate two strings. String literals are written as"This is a string constant"
. Additionally matching (~, !~
) operators could be used to match a string value against a shell pattern (represented also as a string).ip
This type can hold a single IP address. Depending on the compile-time configuration of BIRD you are using, it is either an IPv4 or IPv6 address. IP addresses are written in the standard notation (
10.20.30.40
orfec0:3:4::1
). You can apply special operator.mask(num)
on values of type ip. It masks out all but firstnum
bits from the IP address. So1.2.3.4.mask(8) = 1.0.0.0
is true.prefix
This type can hold a network prefix consisting of IP address and prefix length. Prefix literals are written as
ipaddress/pxlen
, oripaddress/netmask
. There are two special operators on prefixes:.ip
which extracts the IP address from the pair, and.len
, which separates prefix length from the pair. So1.2.0.0/16.len = 16
is true.ec
This is a specialized type used to represent BGP extended community values. It is essentially a 64bit value, literals of this type are usually written as
(kind, key, value)
, wherekind
is a kind of extended community (e.g.rt
/ro
for a route target / route origin communities), the format and possible values ofkey
andvalue
are usually integers, but it depends on the used kind. Similarly to pairs, ECs can be constructed using expressions forkey
andvalue
parts, (e.g.(ro, myas, 3*10)
, wheremyas
is an integer variable).lc
This is a specialized type used to represent BGP large community values. It is essentially a triplet of 32bit values, where the first value is reserved for the AS number of the issuer, while meaning of remaining parts is defined by the issuer. Literals of this type are written as
(123, 456, 789)
, with any integer values. Similarly to pairs, LCs can be constructed using expressions for its parts, (e.g.(myas, 10+20, 3*10)
, wheremyas
is an integer variable).int|pair|quad|ip|prefix|ec|lc|enum set
Filters recognize four types of sets. Sets are similar to strings: you can pass them around but you can't modify them. Literals of type
int set
look like[ 1, 2, 5..7 ]
. As you can see, both simple values and ranges are permitted in sets.For pair sets, expressions like
(123,*)
can be used to denote ranges (in that case(123,0)..(123,65535)
). You can also use(123,5..100)
for range(123,5)..(123,100)
. You can also use*
anda..b
expressions in the first part of a pair, note that such expressions are translated to a set of intervals, which may be memory intensive. E.g.(*,4..20)
is translated to(0,4..20), (1,4..20), (2,4..20), ... (65535, 4..20)
.EC sets use similar expressions like pair sets, e.g.
(rt, 123, 10..20)
or(ro, 123, *)
. Expressions requiring the translation (like(rt, *, 3)
) are not allowed (as they usually have 4B range for ASNs).Also LC sets use similar expressions like pair sets. You can use ranges and wildcards, but if one field uses that, more specific (later) fields must be wildcards. E.g.,
(10, 20..30, *)
or(10, 20, 30..40)
is valid, while(10, *, 20..30)
or(10, 20..30, 40)
is not valid.You can also use expressions for int, pair, EC and LC set values. However, it must be possible to evaluate these expressions before daemon boots. So you can use only constants inside them. E.g.
define one=1; define myas=64500; int set odds; pair set ps; ec set es; odds = [ one, 2+1, 6-one, 2*2*2-1, 9, 11 ]; ps = [ (1,one+one), (3,4)..(4,8), (5,*), (6,3..6), (7..9,*) ]; es = [ (rt, myas, 3*10), (rt, myas+one, 0..16*16*16-1), (ro, myas+2, *) ];
Sets of prefixes are special: their literals does not allow ranges, but allows prefix patterns that are written as
ipaddress/pxlen{low,high}
. Prefixip1/len1
matches prefix patternip2/len2{l,h}
if the firstmin(len1, len2)
bits ofip1
andip2
are identical andlen1 <= ip1 <= len2
. A valid prefix pattern has to satisfylow <= high
, butpxlen
is not constrained bylow
orhigh
. Obviously, a prefix matches a prefix set literal if it matches any prefix pattern in the prefix set literal.There are also two shorthands for prefix patterns:
address/len+
is a shorthand foraddress/len{len,maxlen}
(wheremaxlen
is 32 for IPv4 and 128 for IPv6), that means network prefixaddress/len
and all its subnets.address/len-
is a shorthand foraddress/len{0,len}
, that means network prefixaddress/len
and all its supernets (network prefixes that contain it).For example,
[ 1.0.0.0/8, 2.0.0.0/8+, 3.0.0.0/8-, 4.0.0.0/8{16,24} ]
matches prefix1.0.0.0/8
, all subprefixes of2.0.0.0/8
, all superprefixes of3.0.0.0/8
and prefixes4.X.X.X
whose prefix length is 16 to 24.[ 0.0.0.0/0{20,24} ]
matches all prefixes (regardless of IP address) whose prefix length is 20 to 24,[ 1.2.3.4/32- ]
matches any prefix that contains IP address1.2.3.4
.1.2.0.0/16 ~ [ 1.0.0.0/8{15,17} ]
is true, but1.0.0.0/16 ~ [ 1.0.0.0/8- ]
is false.Cisco-style patterns like
10.0.0.0/8 ge 16 le 24
can be expressed in BIRD as10.0.0.0/8{16,24}
,192.168.0.0/16 le 24
as192.168.0.0/16{16,24}
and192.168.0.0/16 ge 24
as192.168.0.0/16{24,32}
.enum
Enumeration types are fixed sets of possibilities. You can't define your own variables of such type, but some route attributes are of enumeration type. Enumeration types are incompatible with each other.
bgppath
BGP path is a list of autonomous system numbers. You can't write literals of this type. There are several special operators on bgppaths:
P.first
returns the first ASN (the neighbor ASN) in path P.P.last
returns the last ASN (the source ASN) in path P.P.last_nonaggregated
returns the last ASN in the non-aggregated part of the path P.Both
first
andlast
return zero if there is no appropriate ASN, for example if the path contains an AS set element as the first (or the last) part. If the path ends with an AS set,last_nonaggregated
may be used to get last ASN before any AS set.P.len
returns the length of path P.P.empty
resets path P to empty path.prepend(P,A)
prepends ASN A to path P and returns the result.delete(P,A)
deletes all instances of ASN A from from path P and returns the result. A may also be an integer set, in that case the operator deletes all ASNs from path P that are also members of set A.filter(P,A)
deletes all ASNs from path P that are not members of integer set A. I.e.,filter
do the same asdelete
with inverted set A.Statement
P = prepend(P, A);
can be shortened toP.prepend(A);
if P is appropriate route attribute (for examplebgp_path
). Similarly fordelete
andfilter
.bgpmask
BGP masks are patterns used for BGP path matching (using
path ~ [= 2 3 5 * =]
syntax). The masks resemble wildcard patterns as used by UNIX shells. Autonomous system numbers match themselves,*
matches any (even empty) sequence of arbitrary AS numbers and?
matches one arbitrary AS number. For example, ifbgp_path
is 4 3 2 1, then:bgp_path ~ [= * 4 3 * =]
is true, butbgp_path ~ [= * 4 5 * =]
is false. BGP mask expressions can also contain integer expressions enclosed in parenthesis and integer variables, for example[= * 4 (1+2) a =]
. You can also use ranges, for example[= * 3..5 2 100..200 * =]
. There is also old (deprecated) syntax that uses / .. / instead of [= .. =] and ? instead of *.clist
Clist is similar to a set, except that unlike other sets, it can be modified. The type is used for community list (a set of pairs) and for cluster list (a set of quads). There exist no literals of this type. There are three special operators on clists:
C.len
returns the length of clist C.C.empty
resets clist C to empty clist.add(C,P)
adds pair (or quad) P to clist C and returns the result. If item P is already in clist C, it does nothing. P may also be a clist, in that case all its members are added; i.e., it works as clist union.delete(C,P)
deletes pair (or quad) P from clist C and returns the result. If clist C does not contain item P, it does nothing. P may also be a pair (or quad) set, in that case the operator deletes all items from clist C that are also members of set P. Moreover, P may also be a clist, which works analogously; i.e., it works as clist difference.filter(C,P)
deletes all items from clist C that are not members of pair (or quad) set P. I.e.,filter
do the same asdelete
with inverted set P. P may also be a clist, which works analogously; i.e., it works as clist intersection.Statement
C = add(C, P);
can be shortened toC.add(P);
if C is appropriate route attribute (for examplebgp_community
). Similarly fordelete
andfilter
.eclist
Eclist is a data type used for BGP extended community lists. Eclists are very similar to clists, but they are sets of ECs instead of pairs. The same operations (like
add
,delete
or~
and!~
membership operators) can be used to modify or test eclists, with ECs instead of pairs as arguments.lclist
Lclist is a data type used for BGP large community lists. Like eclists, lclists are very similar to clists, but they are sets of LCs instead of pairs. The same operations (like
add
,delete
or~
and!~
membership operators) can be used to modify or test lclists, with LCs instead of pairs as arguments.
5.3 Operators
The filter language supports common integer operators (+,-,*,/)
,
parentheses (a*(b+c))
, comparison (a=b, a!=b, a<b, a>=b)
.
Logical operations include unary not (!
), and (&&
) and or
(||
). Special operators include (~
,
!~
) for "is (not) element of a set" operation - it can be used on
element and set of elements of the same type (returning true if element is
contained in the given set), or on two strings (returning true if first string
matches a shell-like pattern stored in second string) or on IP and prefix
(returning true if IP is within the range defined by that prefix), or on prefix
and prefix (returning true if first prefix is more specific than second one) or
on bgppath and bgpmask (returning true if the path matches the mask) or on
number and bgppath (returning true if the number is in the path) or on bgppath
and int (number) set (returning true if any ASN from the path is in the set) or
on pair/quad and clist (returning true if the pair/quad is element of the
clist) or on clist and pair/quad set (returning true if there is an element of
the clist that is also a member of the pair/quad set).
There is one operator related to ROA infrastructure - roa_check()
. It
examines a ROA table and does RFC 6483 route origin validation for a
given network prefix. The basic usage is roa_check(table)
, which
checks current route (which should be from BGP to have AS_PATH argument) in the
specified ROA table and returns ROA_UNKNOWN if there is no relevant ROA,
ROA_VALID if there is a matching ROA, or ROA_INVALID if there are some relevant
ROAs but none of them match. There is also an extended variant
roa_check(table, prefix, asn)
, which allows to specify a
prefix and an ASN as arguments.
5.4 Control structures
Filters support two control structures: conditions and case switches.
Syntax of a condition is: if boolean expression then command1;
else command2;
and you can use { command_1; command_2;
... }
instead of either command. The else
clause may be
omitted. If the boolean expression
is true, command1 is
executed, otherwise command2 is executed.
The case
is similar to case from Pascal. Syntax is case
expr { else: | num_or_prefix [ .. num_or_prefix]: statement ; [
... ] }
. The expression after case
can be of any type which can be
on the left side of the ~ operator and anything that could be a member of
a set is allowed before :
. Multiple commands are allowed without {}
grouping. If expr
matches one of the :
clauses, statements
between it and next :
statement are executed. If expr
matches
neither of the :
clauses, the statements after else:
are executed.
Here is example that uses if
and case
structures:
case arg1 { 2: print "two"; print "I can do more commands without {}"; 3 .. 5: print "three to five"; else: print "something else"; } if 1234 = i then printn "."; else { print "not 1234"; print "You need {} around multiple commands"; }
5.5 Route attributes
A filter is implicitly passed a route, and it can access its attributes just
like it accesses variables. Attempts to access undefined attribute result in a
runtime error; you can check if an attribute is defined by using the
defined( attribute )
operator. One notable exception to this
rule are attributes of clist type, where undefined value is regarded as empty
clist for most purposes.
prefix net
Network the route is talking about. Read-only. (See the chapter about routing tables.)
enum scope
The scope of the route. Possible values:
SCOPE_HOST
for routes local to this host,SCOPE_LINK
for those specific for a physical link,SCOPE_SITE
andSCOPE_ORGANIZATION
for private routes andSCOPE_UNIVERSE
for globally visible routes. This attribute is not interpreted by BIRD and can be used to mark routes in filters. The default value for new routes isSCOPE_UNIVERSE
.int preference
Preference of the route. Valid values are 0-65535. (See the chapter about routing tables.)
ip from
The router which the route has originated from.
ip gw
Next hop packets routed using this route should be forwarded to.
string proto
The name of the protocol which the route has been imported from. Read-only.
enum source
what protocol has told me about this route. Possible values:
RTS_DUMMY
,RTS_STATIC
,RTS_INHERIT
,RTS_DEVICE
,RTS_STATIC_DEVICE
,RTS_REDIRECT
,RTS_RIP
,RTS_OSPF
,RTS_OSPF_IA
,RTS_OSPF_EXT1
,RTS_OSPF_EXT2
,RTS_BGP
,RTS_PIPE
,RTS_BABEL
.enum cast
Route type (Currently
RTC_UNICAST
for normal routes,RTC_BROADCAST
,RTC_MULTICAST
,RTC_ANYCAST
will be used in the future for broadcast, multicast and anycast routes). Read-only.enum dest
Type of destination the packets should be sent to (
RTD_ROUTER
for forwarding to a neighboring router,RTD_DEVICE
for routing to a directly-connected network,RTD_MULTIPATH
for multipath destinations,RTD_BLACKHOLE
for packets to be silently discarded,RTD_UNREACHABLE
,RTD_PROHIBIT
for packets that should be returned with ICMP host unreachable / ICMP administratively prohibited messages). Can be changed, but only toRTD_BLACKHOLE
,RTD_UNREACHABLE
orRTD_PROHIBIT
.string ifname
Name of the outgoing interface. Sink routes (like blackhole, unreachable or prohibit) and multipath routes have no interface associated with them, so
ifname
returns an empty string for such routes. Setting it would also change route to a direct one (remove gateway).int ifindex
Index of the outgoing interface. System wide index of the interface. May be used for interface matching, however indexes might change on interface creation/removal. Zero is returned for routes with undefined outgoing interfaces. Read-only.
int igp_metric
The optional attribute that can be used to specify a distance to the network for routes that do not have a native protocol metric attribute (like
ospf_metric1
for OSPF routes). It is used mainly by BGP to compare internal distances to boundary routers (see below). It is also used when the route is exported to OSPF as a default value for OSPF type 1 metric.
There also exist some protocol-specific attributes which are described in the corresponding protocol sections.
5.6 Other statements
The following statements are available:
variable = expr
Set variable to a given value.
accept|reject [ expr ]
Accept or reject the route, possibly printing
expr
.return expr
Return
expr
from the current function, the function ends at this point.print|printn expr [, expr...]
Prints given expressions; useful mainly while debugging filters. The
printn
variant does not terminate the line.quitbird
Terminates BIRD. Useful when debugging the filter interpreter.
Next Previous Contents