Migrating from bird to bird2 - part 1

I’ve been putting off upgrading from bird to bird2 for a while. I feel it’s finally time to migrate since it seems bird 1.6.x is only getting bug fixes and no new features for a while.

There are numerous updates in the new version, but the biggest change from my perspecitive is that it now runs a single daemon. Previously bird ran two instances. One for IPv4 and one for IPv6. Now there is a single instance running both protocols, although if you wish you can still run a separate instance per protocol. This will require numerous updates to my parser code collecing information for @bgp4_table and @bgp6_table

Part 1 of this post will go over migrating an existing bird insall to bird2.

Installing

As of Ubuntu 19.10, bird2 is finally in the repository. If not running 19.10, or another flavour you’ll need to compile and install, or find a repository with the compiled version in place. As I’m lazy, I’m just going to upgrade to 19.10 and install it from there. First make a backup of your existing .conf files and then install.

$ sudo cp /etc/bird/bird.conf /etc/bird/bird.bak
$ sudo cp /etc/bird/bird6.conf /etc/bird/bird6.bak

$ sudo apt install bird2

If you already have bird installed, installing bird2 will uninstall bird.

Configuration

First it helps to see my topology. I have three collectors, each which runs multihop eBGP with some peers. The three collecors then run iBGP with each other. As I want all of them to reflect all routes, each BGP speaker considers the other two to be route reflector clients. bgp-topology

As I’ll be using the same configuration over and over again, I’ll create a template for each, then inherit the template for each peer.

log "/var/log/bird" all;

router id x.x.x.x;

define my_asn = 64533;

protocol device { }

filter noroutes {
  reject;
}

filter allroutes {
  accept;
}

protocol kernel {
        ipv4 {                  
              import none;      
              export none;      
        };
}
protocol kernel {
        ipv6 {                  
              import none;      
              export none; 
        };
}

template bgp infra_v4 {
  rr client;
  hold time 600;
  password "xxx";
  multihop;
  ipv4 {
    import filter bgp_ipv4_in;
    export filter allroutes;
  };
  local as my_asn;
}

template bgp infra_v6 {
  rr client;
  hold time 600;
  password "xxx";
  multihop;
  ipv6 {
    import filter bgp_ipv6_in;
    export filter allroutes;
  };
  local as my_asn;
}

template bgp peers_v4 {
  hold time 600;
  multihop;
  ipv4 {
    import filter bgp_ipv4_in;
    export filter noroutes;
  };
  local as my_asn;
}

template bgp peers_v6 {
  hold time 600;
  multihop;
  ipv6 {
    import filter bgp_ipv6_in;
    export filter noroutes;
  };
  local as my_asn;
}

##################
# Internal peers #
##################
protocol bgp BGP2v4 from infra_v4 {
  neighbor x.x.x.x as my_asn;
  rr cluster id x.x.x.x;
}

protocol bgp BGP2v6 from infra_v6 {
  neighbor xx:xx::x as my_asn;
  rr cluster id x.x.x.x;
}
##############
# IPv4 PEERS #
##############
protocol bgp PEER1_v4 from peers_v4 {
  neighbor x.x.x.x as xxxx;
  password "xxxx";
}

##############
# IPv6 PEERS #
##############
protocol bgp PEER1_v6 from peers_v6 {
  neighbor xx:xx::x as xxxx;
  password "xxx";
}

I do not export or import any routes into the kernel routing table as I don’t use it for forwarding. Bird2 complies with RFC8212 meaning that eBGP neighours will no longer send or receive all routes by default. A policy has to be applied else nothing is advertised. For my iBGP peers I reflect all routes. For my eBGP peers I advertise nothing. Incoming from my eBGP peers I have quite a large filter rejectng bogons and subnets larger than /24 and /48s.

The big difference between bird and bird2 here is that under each protocol you specificy the address family, instead of it being inferred from which daemon is running.

That’s it for part 1. In part 2 I’ll go over ROA/RPKI and then in part 3 the code changes I specifically require for bgpstuff.net, @bgp4_table, and @bgp6_table