BIRD User's Guide: Filters

Next Previous Contents

## 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` and `false`. Boolean is the only type you can use in `if` statements.

`int`

  This is a general integer type, you can expect it to store signed values from -2000000000 to +2000000000. 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, but you can't concatenate two strings. String literals are written as `"This is a string constant"`.

`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` or `fec0:3:4::1`). You can apply special operator `.mask(num)` on values of type ip. It masks out all but first `num` bits from the IP address. So `1.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`, or `ipaddress/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. So `1.2.0.0/16.pxlen = 16` is true.

`int|pair|quad|ip|prefix|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.

  Sets of prefixes are special: their literals does not allow ranges, but allows prefix patterns that are written as `ipaddress/pxlen{low,high}`. Prefix `ip1/len1` matches prefix pattern `ip2/len2{l,h}` iff the first `min(len1, len2)` bits of `ip1` and `ip2` are identical and `len1 <= ip1 <= len2`. A valid prefix pattern has to satisfy `low <= high`, but `pxlen` is not constrained by `low` or `high`. Obviously, a prefix matches a prefix set literal iff it matches any prefix pattern in the prefix set literal.

  There are also two shorthands for prefix patterns: `address/len+` is a shorthand for `address/len{len,maxlen}` (where `maxlen` is 32 for IPv4 and 128 for IPv6), that means network prefix `address/len` and all its subnets. `address/len-` is a shorthand for `address/len{0,len}`, that means network prefix `address/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 prefix `1.0.0.0/8`, all subprefixes of `2.0.0.0/8`, all superprefixes of `3.0.0.0/8` and prefixes `4.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 address `1.2.3.4`. `1.2.0.0/16 ~ [ 1.0.0.0/8{15,17} ]` is true, but `1.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 as `10.0.0.0/8{16,24}`, `192.168.0.0/16 le 24` as `192.168.0.0/16{16,24}` and `192.168.0.0/16 ge 24` as `192.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.

  Both `first` and `last` 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.

  `P.len` returns the length of path P.

  `prepend(P,A)` prepends ASN A to path P and returns the result. Statement `P = prepend(P, A);` can be shortened to `P.prepend(A);` if P is appropriate route attribute (for example `bgp_path`).

`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, if `bgp_path` is 4 3 2 1, then: `bgp_path ~ [= * 4 3 * =]` is true, but `bgp_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 =]`. There is also old 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 two special operators on clists:

  `add(C,P)` adds pair (or quad) P to clist C and returns the result.

  `delete(C,P)` deletes pair (or quad) P from clist C and returns the result.

  Statement `C = add(C, P);` can be shortened to `C.add(P);` if C is appropriate route attribute (for example `bgp_community`). Similarly for `delete`.

## 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 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 pair and clist (returning true if the pair (or quad) is element of the clist).

## 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` and `SCOPE_ORGANIZATION` for private routes and `SCOPE_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 is `SCOPE_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. Read-only.

`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_EXT`, `RTS_BGP`, `RTS_PIPE`.

`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_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). Read-only.

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