2015/12/11

Using exaBGP to control your routers

ExaBGP is a python implementation of the BGP protocol. You can run exaBGP on the server and establish BGP sessions to your routers. You can find the exaBGP source on the github.

https://github.com/Exa-Networks/exabgp

What you can do with it? You can for example use it to monitor the state of your network or to manipulate routes. You can find many use cases on the following link:

https://github.com/Exa-Networks/exabgp/wiki/Related-articles

To install exaBGP on your server use python pip.

pip install exabgp

The advantage of exaBGP is that it is very programmable. It transform BGP messages to text or JSON files. You can communicate with exaBGP with the API. To send commands to the exaBGP write these commands to STDOUT. To receive the data read the STDIN.

To begin with the exaBGP you need a configuration file. The configuration file specify the basic BGP settings for the server and basic neighbor settings. The example of the file is:

neighbor 192.168.1.1 {
    router-id 192.168.1.2;
    local-address 192.168.1.2;
    local-as 1;
    peer-as 1;
    graceful-restart;

    process routes {
        run ./routes.py
    }
}

With the neighbor command you specify the IP address of the neighbor. Inside the neighbor configuration you specify the router-id of the server, the IP address, which will be used by the server, local and remote AS number (you can use iBGP or eBGP session). The process command is mandatory. With process command you specify which external script will exaBGP run. You can run any script you want. You can use this script to write to the STDOUT, which will be captured by exaBGP and use this command to execute some tasks. You can run multiple scripts by using multiple process commands.

The example of the routes.py is:

import sys
import time

routes = [
'announce route 1.1.1.1/32 next-hop 192.168.1.10',
]

time.sleep(1)

for route in routes:
    sys.stdout.write(route + '\n')
    sys.stdout.flush()
    time.sleep(1)

while True:
    time.sleep(1)


The exaBGP will execute this script and this script will write the ‘announce …’ command to the STDOUT. This command will tell the exaBGP to announce this route to the BGP peer. And if you check your router after announcing this route, you can see this route in the BGP table.

You can also construct your configuration with the group parameters:

group DEMO {
    router-id 192.168.1.2;
    local-address 192.168.1.2;
    graceful-restart;

    neighbor 192.168.1.10 {
        local-as 65010;
        peer-as 65010;
    }

    neighbor 192.168.1.11 {
        local-as 65011;
        peer-as 65011;
    }

    process routes {
         run ./routes.py;
    }
}

As you can see, you can use different AS numbers on the BGP server. That is really the advantage of using exaBGP.

To run an exaBGP server use the following command:

exabgp demo.conf

This command will run the server and establish the BGP sessions with your routers.

ExaBGP is a great tool, if you want to have the programmable BGP implementation. The only thing that I am missing is the lack of documentation, and examples.

2015/08/11

Use ansible to update host file on the servers

I had some time to play around with Ansible. Ansible is a great tool, which allows you to automate your environment.

I came to a problem, where I need to distribute host file to all machines in inventory and update this host file with host specific variables, which are located in inventory as well. Here is the guide that shows you how to create host file and distribute this file to all hosts that are located in the inventory.

To achieve the goal, I have created the ansible host file, with all hosts in my network. I have grouped the the servers based on server roles. It looks like this:

$cat ansible_hosts
[controller]
controller

[network]
network

[compute]
compute1
compute2

I have also created the subfolder, which is located in the same folder as ansible_hosts file. I have named this folder host_vars. Ansible automatically load files located in that folder and associate variables with the host in inventory file. The name of the file must be the same as name of the host in inventory. I put the following variables in the file:

$cat host_vars/controller
---
hostname: controller
ip_address: 10.0.0.101

You can use ansible template module, which takes file and update file with variables. Ansible uses Jinja2 templating system. I took the default ubuntu hosts file and updated file with the following lines:

127.0.0.1 localhost
127.0.1.1 {{ hostname }}

{% for host in groups['all'] %}
{{ hostvars[host]['ip_address']  }} {{ hostvars[host]['hostname']  }}
{% endfor %}

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

The Jinja2 templating system replace {{ hostname }} with the variable hostname of the current host. Another interesting block is for loop. The for loop goes through all hosts that are listed in ansible inventory file. You can also replace the 'all' with the specific group, which will be used to go only through hosts listed in that group. The hostvars is reserved dictionary, which holds all variables for all hosts. You can access specific variable with correct keys.

Now I have created the playbook which will use this template.

---
- hosts: all
  remote_user: ansible
  tasks:

   # Create hosts file from variables and copy file to remote destination /etc/hosts
   - template: src=./templates/hosts dest=/etc/hosts
     become: yes
     become_method: sudo

You should run this playbook with the command:

$ ansible-playbook openstack_install.yml
...
TASK [template dest=/etc/hosts src=./templates/hosts] **************************
changed: [compute1]
changed: [compute2]
changed: [controller]
changed: [network]
...

If you display the host file on one of the server, the hosts file is updated correctly.

ansible@controller:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 controller

10.0.0.131 compute1
10.0.0.132 compute2
10.0.0.101 controller
10.0.0.111 network

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

This is the example of the usage of the Jinja2 templating system with ansible. The templating system is very powerful which allows you to create complex template and updated these templates with correct variables.