Neutron/DynamicRouting/TestingDynamicRouting
Contents
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:
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.
Advertise routes
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!