Installing and configuring BIRD (BGP)

For example, I will install BIRD on Ubuntu Server 20.04 and show an example of configuring BGP.

Switch to the root user:

sudo -i

To install, run the command (in Ubuntu Server 20.04 version BIRD 1.6.8 was installed):

apt install bird

Let’s allow forwarding of IPv4 packets between network interfaces (for example, if the server will be used as a router):

sysctl net.ipv4.conf.all.forwarding
cat /proc/sys/net/ipv4/ip_forward

sysctl -w net.ipv4.conf.all.forwarding=1

nano /etc/sysctl.conf
net.ipv4.conf.all.forwarding=1
sysctl -p

Let’s set up the logs as I described in the article:
Setting up BIRD logs

Rename the original BIRD configuration file:

mv /etc/bird/bird.conf /etc/bird/bird.conf.original

Create a new one and open it in a text editor:

touch /etc/bird/bird.conf
nano /etc/bird/bird.conf

Specify globally router id – router ID, IP address of the server that looks to the world, then in the bgp, ospf, etc. sections. it will be possible to specify additionally other router ids, if you do not specify this globally, then a random IP address on the interface will be selected:

router id X.X.X.X;

In order not to specify our AS several times in the configuration, we define the my_as variable for it, which we will specify later:

define my_as=XXXXX;

protocol direct defines the network interfaces that will be monitored (the * symbol means everything, I indicated those that look out into the world to other BGP neighbors):

protocol direct {
#       interface "*";
        interface "ens1f0", "ens1f1";
}

The protocol kernel synchronizes the routes of bird with the routes of the operating system kernel:

protocol kernel {
        persist off;
        scan time 20;
        learn;
        import all;
        export none;
}

Let me describe some options:
persist – do not delete routes after bird stops (persist off – delete).
scan time 20 – Scan the kernel route table every 20 seconds.
learn – learning kernel routes
import all – default
export none – by default (since there is only one uplink, I specified none, since I manually specified the default route 0.0.0.0 in netplan and do not use the same one that sends uplink. If you specify it manually and accept it, there will be a warning Netlink: File exists, if there are several uplink neighbors, then the default route specified manually must be removed).

protocol device is needed to scan the state of interfaces (up/down), for example, every 10 seconds, if there are a lot of interfaces, then you can increase the time:

protocol device {
        scan time 10;
}

protocol static allows you to specify static routes (I specified my white network, which I will give Uplink to my neighbor):

protocol static {
#   import all;
    preference 254;
    route X.X.X.0/23 blackhole;
}

An example of a function that defines its networks with white IPs:

function my_nets()
prefix set my_nets;
{
my_nets = [ X.X.X.0/23+, X.X.2.0/24+ ];
if net ~ my_nets then return true;
return false;
}

Define networks with gray IP:

function bogons()
prefix set bogons;
{
bogons = [ 169.254.0.0/16+, 172.16.0.0/12+, 192.168.0.0/16+, 10.0.0.0/8+,
224.0.0.0/4+, 240.0.0.0/4+, 0.0.0.0/32-, 0.0.0.0/0{25,32}, 0.0.0.0/0{0,7} ];
# Avoid RFC1918 and similar networks
if net ~ bogons then return true;
return false;
}

Let’s create a filter in which we will prohibit accepting our network and gray networks, we will allow everything else:

filter PROVIDER1_IN {
if bogons() || my_nets() then reject;
#bgp_local_pref = 205;
accept;
}

Another example of a filter that allows only the default route, and forbids everything else:

filter DEFAULT {
   if net ~ [ 0.0.0.0/0 ] then {
       accept;
   }
   else reject;
}

If there are several providers, then we will create more filters:

filter PROVIDER2_IN {
#bgp_local_pref = 200;
   if net ~ [ 0.0.0.0/0 ] then {
       accept;
   }
   else reject;
}

bgp_local_pref allows you to balance the outgoing load, the less – the better, you can apply changes without breaking the session by rereading the provider configuration:

birdc
reload IXNFO_COM

Let’s create a filter in which we will allow to export only our network, I will give a few examples:

filter PROVIDER1_OUT {
    if bogons() then reject;
    if my_nets() then
    {
        bgp_community.delete([(my_as,*)]);
        accept;
    }
    reject;
}


filter PROVIDER1_OUT {
    if bogons() then reject;
#   if net.len = 32 then reject;
    if my_nets() then
    {
#       bgp_path.prepend(my_as);
#       bgp_path.prepend(my_as);bgp_path.prepend(my_as);bgp_path.prepend(my_as);
        bgp_community.empty;
        accept;
    }
    reject;
}

Now let’s configure BGP for the first provider:

protocol bgp IXNFO_COM {
    debug { states, events };
    #table master;
    router id X.X.X.X;
    description "IXNFO_COM";
    local as my_as;
    neighbor X.X.X.X as XXXXX;

    hold time 60;
    startup hold time 60;
    connect retry time 120;
    keepalive time 20;
    start delay time 5;
    error wait time 60, 300;
    error forget time 300;
    next hop self;
    path metric 1;
    default bgp_med 0;

    source address X.X.X.X;

    export where net = X.X.X.0/23;
#   export filter PROVIDER1_OUT;
    import filter PROVIDER1_IN;
#   import none;

#    gateway direct;
}

Let me describe some options:
hold time – time to wait for a keepalive message from a neighbor, 240 seconds by default.
connect retry time – time to wait in seconds before trying to connect again.
error wait time – minimum and maximum delay in seconds between protocol failure and automatic restart, default 60, 300.
error forget time – maximum time in seconds between two protocol failures that causes an exponential increase in error timeout, default 300.
keepalive time – delay in seconds between sending two consecutive keepalive messages.
path metric – path length comparison when choosing the best BGP route, enabled by default.
export where net – since there is only one network, I directly indicated what can be exported without using a filter.
import none – if there is only one provider, and the default route is specified manually in the network settings, then nothing needs to be imported from the provider.

Let’s configure the second provider in the same way:

protocol bgp PROVIDER2 {
...
}

You can create a template for BGP so as not to duplicate settings for different providers:

template bgp EXTERNAL {
debug { states, events };
local as my_as;
keepalive time 30;
hold time 240;
interpret communities no;
import keep filtered;
startup hold time 240;
connect retry time 120;
start delay time 5;
error wait time 60, 300;
error forget time 300;
path metric 1;
default bgp_med 0;
default bgp_local_pref 150;
}

And then specify this template:

protocol bgp IXNFO_COM from EXTERNAL{
description "IXNFO_COM";
neighbor X.X.X.X as XXXXX;
source address X.X.X.X;
export filter PROVIDER1_OUT;
import filter PROVIDER1_IN;
}

protocol bgp IXNFO_COM2 from EXTERNAL{
description "IXNFO_COM2";
neighbor X.X.X.X as XXXXX;
source address X.X.X.X;
export filter PROVIDER2_OUT;
import filter PROVIDER2_IN;
}

Some more export examples:

export where (net = 0.0.0.0/0) || ((my_as,XXXXX) ~ bgp_community) || ((my_as,XXXXX) ~ bgp_community);


protocol static static_bgp { 
        import all;
        route X.X.X.0/24 reject;
}
export where proto = "static_bgp";

Let’s open the BIRD console:

birdc

Let’s make sure that the session has risen and see the routes:

show protocols
show protocols all

show route
show route all
show route export IXNFO_COM
show route advertising-protocol bgp X.X.X.X
show static

show memory
show ?
exit
ip route | grep -E "(default|nexthop)"

The BIRD version can be viewed like this:

show status

You can also execute BIRD commands from Linux, for example to monitor the result via Zabbix:

birdc show route|less
birdc show protocols

Let’s check if bird autorun is activated when the operating system starts:

systemctl is-enabled bird.service
systemctl is-enabled bird6.service

systemctl enable bird.service
systemctl disable bird6.service

systemctl restart bird.service
systemctl stop bird6.service

systemctl status bird.service
systemctl status bird6.service

See also my articles:
IPTables Rules for BGP
Configuring OSPF in BIRD
Setting up BGP in Quagga
Taskset – bind process to CPU cores

Leave a comment

Leave a Reply