Jump to: navigation, search

Neutron/DynamicRouting/TestingDynamicRouting

Tutorial to test Dynamic Routing

This page explains how to test the Dynamic Routing functionality. Currently this feature is not merged yet and it should be ready for Juno. This tutorial explains how to build and use the under-review code.

Environment to Test

We want to test how Dynamic Routing Agent (dr_agent) is able to exchange routes from Neutron to a uplink Quagga instance. To do so, we are going to deploy a Virtual Machine with devstack and another Virtual Machine with a quagga instance. It will not be a real scenario deployment because we will need to do a trick in the neutron gateway router, but the purpose of this tutorial is just see how the dr_agent works advertising and discovering routes as well as the exposed neutron resources through the python-neutronclient tool.

An ugly schema of the environment would be the following:

Dynamic routing test.jpg


Prepare devstack

Just deploy a devstack in a Virtual Machine with a bridged interface. Let's supose this bridged interface gets the 192.168.2.38 address. There is a WIP patch in gerrit to allow depoy the dr-agent here. Cherry pick-it over master. Should work without problems.

To let devstack clone the under-review BGP code (neutron and python-neutronclient), use the following local.conf:

 !/usr/bin/env bash
 
 [[local|localrc]]
 
 THE_PASSWORD=dummy
 DATABASE_PASSWORD=${DATABASE_PASSWORD:-$THE_PASSWORD}
 RABBIT_PASSWORD=${RABBIT_PASSWORD:-$THE_PASSWORD}
 SERVICE_TOKEN=${SERVICE_TOKEN:-$THE_PASSWORD}
 SERVICE_PASSWORD=${SERVICE_PASSWORD:-$THE_PASSWORD}
 ADMIN_PASSWORD=${ADMIN_PASSWORD:-$THE_PASSWORD}
 
 SCREEN_LOGDIR=/tmp
 
 NEUTRON_REPO=https://review.openstack.org/openstack/neutron
 NEUTRON_BRANCH=refs/changes/38/115938/1
 NEUTRONCLIENT_REPO=https://review.openstack.org/openstack/python-neutronclient
 NEUTRONCLIENT_BRANCH=refs/changes/18/111318/5
 
 #disable heat, too much time for the Fedora image
 disable_service h-eng
 disable_service h-api
 disable_service h-api-cfn
 disable_service h-api-cw
  
 # enable neutron
 disable_service n-net
 enable_service q-svc
 enable_service q-dhcp
 enable_service q-meta
 enable_service q-lbaas
 enable_service q-agt
 enable_service q-l3
 
 # enable dynamic routing agent (NEW!)
 enable_service q-dragent
 
 HOST_IP=192.168.2.38

please note the enable_service q-dragent line is the one that deploys the dr-agent and the branches used in gerrit mention the patchset. So for check the last version you should see if the last part of the branch name is the last patchset available.

Before run devstack, you should install Ryu BGP driver. Ryu uses olso.config for declare and load configuration options and last version throws a conflict exception. You'd rather install last version from source:

 $ git clone https://github.com/osrg/ryu
 $ cd ryu && sudo python setup.py install

now you can run devstack.

Configure Quagga

Install Quagga in another virtual machine with a bridged interface. Let's say this interface gets IP address 192.168.2.65.

 $ sudo apt-get install quagga

configure the following files:

in /etc/quagga/daemons
 zebra=yes
 bgpd=yes
 ospfd=no
 ospf6d=no
 ripd=no
 ripngd=no
 isisd=no

in /etc/quagga/zebra.conf

 # Zebra configuration
 
 # name of the router
 hostname quagga_1
 password zebra
 
 # log
 log file /var/log/quagga/zebra.log

in /etc/quagga/bgpd.conf

 # declare a router with local-as 1000
 router bgp 1000
 
 # expose networks
 neighbor 192.168.2.38 remote-as 12345
 network 10.100.0.0/24
 network 10.200.0.0/24
 
 log file /var/log/quagga/bgpd.log
 debug bgp events
 debug bgp filters
 debug bgp fsm
 debug bgp keepalives
 debug bgp updates

according to this files, one the test is finished, the Neutron router should have learned the routes 10.100.0.0/24 and 10.200.0.0/24 through the nexthop 192.168.2.65.

Now you can restart quagga:

 sudo service quagga restart

Execute Neutron calls

You should run all the calls using the admin user, so load the openrc as it is needed:

 $ source devstack/openrc admin

First step is create the routing instance entity:

 $ neutron routinginstance-create test_dynamicrouting

Neutron works with the configuration attribute dynamic_routing_auto_schedule = True by default. So after create a routing instance, a dr_agent will take care of it and will synchronise to it periodically. So that means that after declare a peer in this routing instance or an advertise route, the agent will do the actions needed. In this approach, a dr_agent only can synchronise with a single Routing Instance to avoid conflicts.

So you have to update the routing instance with the Quagga remote peer values:

 $ neutron routinginstance-update test_dynamicrouting --peers type=dict list=true peer=192.168.2.65,remote_as=1000
 Updated routinginstance: test_dynamicrouting
 $ neutron routinginstance-show test_dynamicrouting
 
  +-----------------+-------------------------------------------------------------+
  | Field           | Value                                                       |
  +-----------------+-------------------------------------------------------------+
  | advertiseroutes |                                                             |
  | id              | e316b071-2a13-454c-9b2f-f1c15d4a6d9d                        |
  | name            | test_dynamicrouting                                         |
  | peers           | {"peer": "192.168.2.65", "password": "", "remote_as": 1000} |
  | tenant_id       | 157aff04848b43d19c6c4e4a8f78003e                            |
  +-----------------+-------------------------------------------------------------+
  

Now you are ready to advertise and discovery routes from this peer.

You want to advertise the floating ip range through the eth1 interface, so the route's discovery value is : 174.24.4.0/24 and and nexthop is 192.168.2.38. Update the advertiseroute accordingly:

 $ neutron routinginstance-update test_dynamicrouting --advertiseroutes type=dict list=true destination=174.24.4.0/24,nexthop=192.168.2.38
 Updated routinginstance: test_dynamicrouting
 $ neutron routinginstance-show test_dynamicrouting
 
  +-----------------+-------------------------------------------------------------+
  | Field           | Value                                                       |
  +-----------------+-------------------------------------------------------------+
  | advertiseroutes | {"destination": "174.24.4.0/24", "nexthop": "192.168.2.38"} |
  | id              | e316b071-2a13-454c-9b2f-f1c15d4a6d9d                        |
  | name            | test_dynamicrouting                                         |
  | peers           | {"peer": "192.168.2.65", "password": "", "remote_as": 1000} |
  | tenant_id       | 157aff04848b43d19c6c4e4a8f78003e                            |
  +-----------------+-------------------------------------------------------------+
  

After a while, you should see the following in the Quagga virtual machine:

 $ ip r | grep 174.24.4.0
 174.24.4.0/24 via 192.168.2.38 dev eth1  proto zebra

Learning Routes

Neutron routers don't allow learning routes where the nexthop is outside the range of the external subnet. Current subnet is 174.24.4.0/24 and hence, learning routes from 192.168.2.65 will raise and error when updating the router. This is because br-ex is not plugged into 192.168.2.0/24 network and actually it makes sense. We need to do a trick to see how dynamic routing works learning routes. We'll create a 192.168.2.0/24 fake subnet in Neutron external's network and associate an interface to a router's port to avoid error raising.

 $ neutron subnet-create --name test_dynamicrouting_subnet 9ef55f14-b7ab-4646-aac9-c24ba4bf8876 192.168.2.0/24 --gateway 192.168.2.200
 Created a new subnet:
 +-------------------+----------------------------------------------------+
 | Field             | Value                                              |
 +-------------------+----------------------------------------------------+
 | allocation_pools  | {"start": "192.168.2.1", "end": "192.168.2.199"}   |
 |                   | {"start": "192.168.2.201", "end": "192.168.2.254"} |
 | cidr              | 192.168.2.0/24                                     |
 | dns_nameservers   |                                                    |
 | enable_dhcp       | True                                               |
 | gateway_ip        | 192.168.2.200                                      |
 | host_routes       |                                                    |
 | id                | c0365ee9-7688-4589-a763-8e81fa29aedd               |
 | ip_version        | 4                                                  |
 | ipv6_address_mode |                                                    | 
 | ipv6_ra_mode      |                                                    |
 | name              | test_dynamicrouting_subnet                         |
 | network_id        | 9ef55f14-b7ab-4646-aac9-c24ba4bf8876               |
 | tenant_id         | 157aff04848b43d19c6c4e4a8f78003e                   |
 +-------------------+----------------------------------------------------+
 $ neutron router-list
 +--------------------------------------+---------+-----------------------------------------------------------------------------+-------------+
 | id                                   | name    | external_gateway_info                                                       | distributed |
 +--------------------------------------+---------+-----------------------------------------------------------------------------+-------------+
 | 11c199ef-0025-4185-b523-f2d7537090f8 | router1 | {"network_id": "9ef55f14-b7ab-4646-aac9-c24ba4bf8876", "enable_snat": true} | False       |
 +--------------------------------------+---------+-----------------------------------------------------------------------------+-------------+
 $ neutron router-interface-add router1 test_dynamicrouting_subnet

You are ready to add the router to the routing instance:

 $ neutron routinginstance-list
 +--------------------------------------+---------------------+----------------------------------+
 | id                                   | name                | tenant_id                        |
 +--------------------------------------+---------------------+----------------------------------+
 | e316b071-2a13-454c-9b2f-f1c15d4a6d9d | test_dynamicrouting | 157aff04848b43d19c6c4e4a8f78003e |
 +--------------------------------------+---------------------+----------------------------------+
 $ neutron routinginstance-router-add e316b071-2a13-454c-9b2f-f1c15d4a6d9d router1 (i've just realised that routinginstance name does not work here... bug to fix)

After a while, you will see how the router learns the Quagga's exposed networks:

 $ neutron router-show router1
 +-----------------------+-----------------------------------------------------------------------------+
 | Field                 | Value                                                                       |
 +-----------------------+-----------------------------------------------------------------------------+
 | admin_state_up        | True                                                                        |
 | distributed           | False                                                                       |
 | external_gateway_info | {"network_id": "9ef55f14-b7ab-4646-aac9-c24ba4bf8876", "enable_snat": true} |
 | id                    | 11c199ef-0025-4185-b523-f2d7537090f8                                        |
 | name                  | router1                                                                     |
 | routes                | {"destination": "10.100.0.0/24", "nexthop": "192.168.2.65"}                 |
 |                       | {"destination": "10.200.0.0/24", "nexthop": "192.168.2.65"}                 |
 | status                | ACTIVE                                                                      |
 | tenant_id             | 157aff04848b43d19c6c4e4a8f78003e                                            |
 +-----------------------+-----------------------------------------------------------------------------+

And that's all!