How to Configure CloudRouter containers as a Route Server

 

For this article we will be using the CloudRouter bird docker container to show case how we can configure a bird daemon that's running inside multiple docker containers and still perform the usual functionality of being a Route Server.

Pull down the CloudRouter fedora bird container from the public repository – https://registry.hub.docker.com/repos/cloudrouter/

 

# docker pull cloudrouter/bird-fedora
Pulling repository cloudrouter/bird-fedora
19e1acd93cd5: Download complete 
511136ea3c5a: Download complete 
782cf93a8f16: Download complete 
6cece30db4f9: Download complete 
4dcfc015c438: Download complete 
60610127a187: Download complete 
fb814efbf4df: Download complete 
ecc97c347025: Download complete 
d32f32e5c395: Download complete 
f56201d4f627: Download complete 
24f3dbad9ace: Download complete 
2285b2b50350: Download complete 
f748483b1fec: Download complete 
2a5bf0f8f1a8: Download complete 
95486ef61dd0: Download complete 
0b2057fe41b7: Download complete 
e1ac3c04bc1d: Download complete 
4e203d55e43e: Download complete 
Status: Image is up to date for cloudrouter/bird-fedora:latest
#

 

 

For this example we will use the following topology of 3 containers. 

 

 

Lets start the 3 docker containers.

# docker run --publish-all=true -t -i cloudrouter/bird-fedora /bin/bash
# docker run --publish-all=true -t -i cloudrouter/bird-fedora /bin/bash
# docker run --publish-all=true -t -i cloudrouter/bird-fedora /bin/bash

 

Lets make sure all of our 3 containers are up and running and have the default networking in place.

# docker ps
CONTAINER ID        IMAGE                            COMMAND             CREATED             STATUS              PORTS               NAMES
02d05ac0aa07        cloudrouter/bird-fedora:latest   "/bin/bash"         28 minutes ago      Up 28 minutes                           cocky_bell          
0896588f8664        cloudrouter/bird-fedora:latest   "/bin/bash"         30 minutes ago      Up 30 minutes                           prickly_sammet      
ba136e3fdb42        cloudrouter/bird-fedora:latest   "/bin/bash"         38 minutes ago      Up 38 minutes                           evil_torvalds       
# 

 

Lets add an additional network interface (eth1) for each of our 3 docker containers. For this we will utilize the pipework script from https://github.com/jpetazzo/pipework

# sudo pipework docker0 -i eth1 02d05ac0aa07 10.0.0.1/24 
# sudo pipework docker0 -i eth1 0896588f8664 10.0.0.8/24 
# sudo pipework docker0 -i eth1 ba136e3fdb42 10.0.0.7/24 

 

Lets configure bird.conf on each of our containers and start the bird daemon.

Container 1 bird.conf ( ID: ba136e3fdb42) 

[root@ba136e3fdb42 etc]# cat /etc/bird.conf 
/* Main configuration file for BIRD. This is ony a template,
 * you will *need* to customize it according to your needs
 * Beware that only double quotes '"' are valid. No singles. */
 
log "/var/log/bird.log" all;
debug protocols all;
#debug commands 2;
router id  10.0.0.1;       # Mandatory for IPv6, may be automatic for IPv4
protocol kernel {
    persist;                # Don't remove routes on BIRD shutdown
    scan time 200;          # Scan kernel routing table every 200 seconds
    export all;
    import all;
}
protocol device {
    scan time 10;           # Scan interfaces every 10 seconds
}

/* This is a sample config that should be customized with appropriate AS numbers
 * and peers; add one section like this for each neighbor */
protocol bgp toRouteServer {
    local as 200;                      # Customize your AS number
    neighbor 10.0.0.7 as 30351;    # Customize neighbor AS number && IP
    export all;
    import all;
}
protocol direct {
	interface "*";
}

 

Container 2 bird.conf ( ID: 02d05ac0aa07)

[root@02d05ac0aa07 log]# cat /etc/bird.conf
####
##BIRD Route Server Configuration 
####
log "/var/log/bird.log" all;
debug protocols all;
#debug commands 2;
router id  10.0.0.7;    
define myas = 30351;
# This function excludes weird networks
#  rfc1918, class D, class E, too long and too short prefixes
function avoid_martians()
prefix set martians;
{
  martians = [ 169.254.0.0/16+, 172.16.0.0/12+, 192.168.0.0/16+,
	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 ~ martians then return false;
  return true;
}
# BGP output filter (based on communities)
function bgp_out(int peeras)
{
#  if ! (source = RTS_BGP ) then return false;
  if peeras > 65535 then return true; # communities does not support AS32
  if (0,peeras) ~ bgp_community then return false;
  if (myas,peeras) ~ bgp_community then return true;
  if (0, myas) ~ bgp_community then return false;
  return true;
}

protocol kernel {
    persist;                # Don't remove routes on BIRD shutdown
    scan time 200;          # Scan kernel routing table every 200 seconds
    export all;
    import all;
}
protocol device {
    scan time 10;           # Scan interfaces every 10 seconds
}

###########################################
### START CustomerA BGP Config
###########################################
table T200;
filter bgp_in_AS200
{
  if ! (avoid_martians()) then reject;
  if (bgp_path.first != 200 ) then reject;
  accept;
}
protocol pipe P200 {
  description "CustomerA AS-200";
  table master;
  mode transparent;
  peer table T200;
  import filter bgp_in_AS200;
  export where bgp_out(200);
}
protocol bgp toCustomerA {
    local as myas;              
    neighbor 10.0.0.1 as 200; 
    export all;
    import all;
    route limit 1000;
    table T200;
    rs client;
}
###########################################
# END CustomerA BGP Config
###########################################
###########################################
### START CustomerB BGP Config
###########################################
table T300;
filter bgp_in_AS300
{
  if ! (avoid_martians()) then reject;
  if (bgp_path.first != 300 ) then reject;
  accept;
}
protocol pipe P300 {
  description "CustomerB AS-300";
  table master;
  mode transparent;
  peer table T300;
  import filter bgp_in_AS300;
  export where bgp_out(300);
}
protocol bgp toCustomerB {
    local as myas;              
    neighbor 10.0.0.8 as 300; 
    export all;
    import all;
    route limit 1000;
    table T300;
    rs client;
}
###########################################
# END CustomerA BGP Config
###########################################
[root@02d05ac0aa07 log]# 

 

Container 3 bird.conf ( ID: 0896588f8664)

[root@0896588f8664 etc]# cat /etc/bird.conf
/* Main configuration file for BIRD. This is ony a template,
 * you will *need* to customize it according to your needs
 * Beware that only double quotes '"' are valid. No singles. */
 
log "/var/log/bird.log" all;
debug protocols all;
#debug commands 2;
router id  10.0.0.8;       # Mandatory for IPv6, may be automatic for IPv4
protocol kernel {
    persist;                # Don't remove routes on BIRD shutdown
    scan time 200;          # Scan kernel routing table every 200 seconds
    export all;
    import all;
}
protocol device {
    scan time 10;           # Scan interfaces every 10 seconds
}

/* This is a sample config that should be customized with appropriate AS numbers
 * and peers; add one section like this for each neighbor */
protocol bgp toRouteServer {
    local as 300;                      # Customize your AS number
    neighbor 10.0.0.7 as 30351;    # Customize neighbor AS number && IP
    export all;
    import all;
}
protocol direct {
	interface "*";
}
[root@0896588f8664 etc]# 

 

Lets start the bird daemon and ensure the BGP Sessions are ESTABLISHED.

# bird -c /etc/bird.conf
[root@02d05ac0aa07 log]# birdc 'show protocols all toCustomerA' 
BIRD 1.4.5 ready.
name     proto    table    state  since       info
toCustomerA BGP      T200     up     18:40:12    Established   
  Preference:     100
  Input filter:   ACCEPT
  Output filter:  ACCEPT
  Import limit:   1000
    Action:       restart
  Routes:         2 imported, 0 exported, 4 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              2          0          0          0          2
    Import withdraws:            0          0        ---          0          0
    Export updates:              3          2          0        ---          1
    Export withdraws:            0        ---        ---        ---          1
  BGP state:          Established
    Neighbor address: 10.0.0.1
    Neighbor AS:      200
    Neighbor ID:      10.0.0.1
    Neighbor caps:    refresh restart-aware AS4
    Session:          external route-server AS4
    Source address:   10.0.0.7
    Route limit:      2/1000
    Hold timer:       140/240
    Keepalive timer:  36/80
[root@02d05ac0aa07 log]# birdc 'show protocols all toCustomerB'
BIRD 1.4.5 ready.
name     proto    table    state  since       info
toCustomerB BGP      T300     up     18:33:54    Established   
  Preference:     100
  Input filter:   ACCEPT
  Output filter:  ACCEPT
  Import limit:   1000
    Action:       restart
  Routes:         2 imported, 1 exported, 1 preferred
  Route change stats:     received   rejected   filtered    ignored   accepted
    Import updates:              2          0          0          0          2
    Import withdraws:            0          0        ---          0          0
    Export updates:              3          2          0        ---          1
    Export withdraws:            0        ---        ---        ---          0
  BGP state:          Established
    Neighbor address: 10.0.0.8
    Neighbor AS:      300
    Neighbor ID:      10.0.0.8
    Neighbor caps:    refresh restart-aware AS4
    Session:          external route-server AS4
    Source address:   10.0.0.7
    Route limit:      2/1000
    Hold timer:       186/240
    Keepalive timer:  25/80
[root@02d05ac0aa07 log]# 

 

With this we have been able to demonstrate that we can run the bird daemon in a CloudRouter container and do some simple BGP sessions and make sure it does function as a Route Server.

#End of Article.