Merge "Add tempest scenario tests"
This commit is contained in:
commit
aeec382d24
neutron_dynamic_routing/tests
@ -7,9 +7,91 @@ GATE_DEST=$BASE/new
|
||||
NEUTRON_PATH=$GATE_DEST/neutron
|
||||
DR_PATH=$GATE_DEST/$PROJECT_NAME
|
||||
DEVSTACK_PATH=$GATE_DEST/devstack
|
||||
APPARMOR_PROFILE_PATH=/etc/apparmor.d
|
||||
QUAGGA_CONFIG_PATH=/tmp/ctn_docker
|
||||
|
||||
VENV=${1:-"dsvm-functional"}
|
||||
|
||||
# NOTE(kakuma)
|
||||
# Check apparmor to avoid the following error for docker operation.
|
||||
# "oci runtime error: apparmor failed to apply profile: no such file or directory"
|
||||
# This is a temporary solution. This needs to be fixed in a better way.
|
||||
function check_apparmor_for_docker {
|
||||
if [[ -d $APPARMOR_PROFILE_PATH ]]
|
||||
then
|
||||
if [[ ! -f $APPARMOR_PROFILE_PATH/docker ]]
|
||||
then
|
||||
cat << EOF > /tmp/docker
|
||||
#include <tunables/global>
|
||||
|
||||
|
||||
profile docker-default flags=(attach_disconnected,mediate_deleted) {
|
||||
|
||||
#include <abstractions/base>
|
||||
|
||||
|
||||
network,
|
||||
capability,
|
||||
file,
|
||||
umount,
|
||||
|
||||
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir)
|
||||
# deny write to files not in /proc/<number>/** or /proc/sys/**
|
||||
deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,
|
||||
deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
|
||||
deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/
|
||||
deny @{PROC}/sysrq-trigger rwklx,
|
||||
deny @{PROC}/mem rwklx,
|
||||
deny @{PROC}/kmem rwklx,
|
||||
deny @{PROC}/kcore rwklx,
|
||||
|
||||
deny mount,
|
||||
|
||||
deny /sys/[^f]*/** wklx,
|
||||
deny /sys/f[^s]*/** wklx,
|
||||
deny /sys/fs/[^c]*/** wklx,
|
||||
deny /sys/fs/c[^g]*/** wklx,
|
||||
deny /sys/fs/cg[^r]*/** wklx,
|
||||
deny /sys/firmware/efi/efivars/** rwklx,
|
||||
deny /sys/kernel/security/** rwklx,
|
||||
|
||||
|
||||
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
|
||||
ptrace (trace,read) peer=docker-default,
|
||||
|
||||
}
|
||||
EOF
|
||||
chmod 0644 /tmp/docker
|
||||
sudo chown root:root /tmp/docker
|
||||
sudo mv /tmp/docker $APPARMOR_PROFILE_PATH/docker
|
||||
sudo service apparmor restart
|
||||
sudo service docker restart
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function configure_docker_test_env {
|
||||
if ! pip freeze | grep ryu > /dev/null
|
||||
then
|
||||
sudo pip install -c https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt ryu
|
||||
fi
|
||||
RYU_PATH=`pip show ryu | grep Location | cut -d' ' -f2`/ryu
|
||||
sudo usermod -aG sudo tempest
|
||||
bash $RYU_PATH/tests/integrated/common/install_docker_test_pkg.sh --sudo-pip
|
||||
}
|
||||
|
||||
function do_devstack_gate {
|
||||
local gate_retval
|
||||
set +e
|
||||
$GATE_DEST/devstack-gate/devstack-vm-gate.sh
|
||||
gate_retval=$?
|
||||
if [[ -d $QUAGGA_CONFIG_PATH ]]
|
||||
then
|
||||
sudo cp -r $QUAGGA_CONFIG_PATH /opt/stack/logs/bgp_dr_docker
|
||||
fi
|
||||
set -e
|
||||
return $gate_retval
|
||||
}
|
||||
|
||||
if [[ "$VENV" == dsvm-functional* ]]
|
||||
then
|
||||
@ -26,7 +108,24 @@ then
|
||||
|
||||
# Make the workspace owned by the stack user
|
||||
sudo chown -R $STACK_USER:$STACK_USER $BASE
|
||||
|
||||
elif [[ "$VENV" == dsvm-api* ]]
|
||||
then
|
||||
configure_docker_test_env
|
||||
|
||||
$GATE_DEST/devstack-gate/devstack-vm-gate.sh
|
||||
|
||||
elif [[ "$VENV" == dsvm-scenario* ]]
|
||||
then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --reinstall apparmor
|
||||
configure_docker_test_env
|
||||
check_apparmor_for_docker
|
||||
export DEVSTACK_LOCAL_CONFIG+=$'\n'"BGP_SCHEDULER_DRIVER=neutron_dynamic_routing.services.bgp.scheduler.bgp_dragent_scheduler.ChanceScheduler"
|
||||
|
||||
do_devstack_gate
|
||||
|
||||
else
|
||||
echo "Unrecognized environment $VENV".
|
||||
exit 1
|
||||
fi
|
||||
|
@ -117,3 +117,12 @@ class BgpSpeakerClientJSON(rest_client.RestClient):
|
||||
body = jsonutils.loads(body)
|
||||
self.expected_success(200, resp.status)
|
||||
return rest_client.ResponseBody(resp, body)
|
||||
|
||||
def add_bgp_speaker_to_dragent(self, agent_id, bgp_speaker_id):
|
||||
uri = 'v2.0/agents/%s/bgp-drinstances' % agent_id
|
||||
update_body = {"bgp_speaker_id": bgp_speaker_id}
|
||||
update_body = jsonutils.dumps(update_body)
|
||||
resp, body = self.post(uri, update_body)
|
||||
self.expected_success(201, resp.status)
|
||||
body = jsonutils.loads(body)
|
||||
return rest_client.ResponseBody(resp, body)
|
||||
|
36
neutron_dynamic_routing/tests/tempest/scenario/README
Normal file
36
neutron_dynamic_routing/tests/tempest/scenario/README
Normal file
@ -0,0 +1,36 @@
|
||||
scenario tests use the following environment.
|
||||
|
||||
diagram:
|
||||
|
||||
----------------------+--------------- tenant
|
||||
| network
|
||||
+--------+
|
||||
| router |
|
||||
+--------+
|
||||
|
|
||||
-----+----------------+--------------- provider
|
||||
| | network
|
||||
+---------+ |
|
||||
| dragent | |
|
||||
+---------+ |
|
||||
| |
|
||||
| +--------------+
|
||||
| |
|
||||
+--------+
|
||||
| docker |
|
||||
| bridge |
|
||||
+--------+
|
||||
|
|
||||
+-----------+------------+-------
|
||||
| |
|
||||
+---------+ +---------+
|
||||
docker | quagga1 | | quagga2 | ...
|
||||
container +---------+ +---------+
|
||||
|
||||
|
||||
docker container environment is provided by test tool of ryu.
|
||||
It has the following functions:
|
||||
- build and remove a container image.
|
||||
- run, stop and remove a container.
|
||||
- some operations to quagga container.
|
||||
- get some information from quagga container.
|
369
neutron_dynamic_routing/tests/tempest/scenario/base.py
Normal file
369
neutron_dynamic_routing/tests/tempest/scenario/base.py
Normal file
@ -0,0 +1,369 @@
|
||||
# Copyright (C) 2016 VA Linux Systems Japan K.K.
|
||||
# Copyright (C) 2016 Fumihiko Kakuma <kakuma at valinux co jp>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
import threading
|
||||
import time
|
||||
|
||||
import netaddr
|
||||
|
||||
from tempest import config
|
||||
from tempest import test
|
||||
|
||||
from neutron.tests.tempest.api import base
|
||||
from neutron_dynamic_routing.tests.tempest import bgp_client
|
||||
from ryu.tests.integrated.common import docker_base as ctn_base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
Scope = collections.namedtuple('Scope', 'name')
|
||||
Pool = collections.namedtuple('Pool', 'name, prefixlen, prefixes')
|
||||
Net = collections.namedtuple('Net', 'name, net, mask, cidr, router')
|
||||
SubNet = collections.namedtuple('SubNet', 'name, cidr, mask')
|
||||
Router = collections.namedtuple('Router', 'name, gw, dist')
|
||||
AS = collections.namedtuple('AS', 'asn, router_id, adv_net')
|
||||
CHECKTIME = 180
|
||||
CHECKTIME_INFO = 60
|
||||
CHECKTIME_INT = 1
|
||||
|
||||
|
||||
def _setup_client_args(auth_provider):
|
||||
"""Set up ServiceClient arguments using config settings. """
|
||||
service = CONF.network.catalog_type or 'network'
|
||||
region = CONF.network.region or 'regionOne'
|
||||
endpoint_type = CONF.network.endpoint_type
|
||||
build_interval = CONF.network.build_interval
|
||||
build_timeout = CONF.network.build_timeout
|
||||
|
||||
# The disable_ssl appears in identity
|
||||
disable_ssl_certificate_validation = (
|
||||
CONF.identity.disable_ssl_certificate_validation)
|
||||
ca_certs = None
|
||||
|
||||
# Trace in debug section
|
||||
trace_requests = CONF.debug.trace_requests
|
||||
|
||||
return [auth_provider, service, region, endpoint_type,
|
||||
build_interval, build_timeout,
|
||||
disable_ssl_certificate_validation, ca_certs,
|
||||
trace_requests]
|
||||
|
||||
|
||||
class BgpSpeakerScenarioTestJSONBase(base.BaseAdminNetworkTest):
|
||||
|
||||
def setUp(self):
|
||||
self.addCleanup(self.net_resource_cleanup)
|
||||
super(BgpSpeakerScenarioTestJSONBase, self).setUp()
|
||||
|
||||
@classmethod
|
||||
def _setup_bgp_non_admin_client(cls):
|
||||
mgr = cls.get_client_manager()
|
||||
auth_provider = mgr.auth_provider
|
||||
client_args = _setup_client_args(auth_provider)
|
||||
cls.bgp_client = bgp_client.BgpSpeakerClientJSON(*client_args)
|
||||
|
||||
@classmethod
|
||||
def _setup_bgp_admin_client(cls):
|
||||
mgr = cls.get_client_manager(credential_type='admin')
|
||||
auth_provider = mgr.auth_provider
|
||||
client_args = _setup_client_args(auth_provider)
|
||||
cls.bgp_adm_client = bgp_client.BgpSpeakerClientJSON(*client_args)
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(BgpSpeakerScenarioTestJSONBase, cls).resource_setup()
|
||||
if not test.is_extension_enabled('bgp', 'network'):
|
||||
msg = "BGP Speaker extension is not enabled."
|
||||
raise cls.skipException(msg)
|
||||
|
||||
cls.images = []
|
||||
cls.containers = []
|
||||
cls.r_ass = []
|
||||
cls.r_as_ip = []
|
||||
cls.bridges = []
|
||||
cls.admin_routerports = []
|
||||
cls.admin_floatingips = []
|
||||
cls.admin_routers = []
|
||||
cls.admin_router_ip = []
|
||||
cls.resource_setup_container()
|
||||
cls._setup_bgp_admin_client()
|
||||
cls._setup_bgp_non_admin_client()
|
||||
cls.lock = threading.Lock()
|
||||
|
||||
@classmethod
|
||||
def resource_cleanup(cls):
|
||||
for ctn in cls.containers:
|
||||
try:
|
||||
ctn.stop()
|
||||
except ctn_base.CommandError:
|
||||
pass
|
||||
ctn.remove()
|
||||
for br in cls.bridges:
|
||||
br.delete()
|
||||
super(BgpSpeakerScenarioTestJSONBase, cls).resource_cleanup()
|
||||
|
||||
@classmethod
|
||||
def get_subnet(self, start='10.10.1.0', end='10.10.255.0', step=256):
|
||||
subnet_gen = netaddr.iter_iprange(start, end, step=step)
|
||||
i = 1
|
||||
while True:
|
||||
with self.lock:
|
||||
try:
|
||||
yield (i, str(subnet_gen.next()))
|
||||
except StopIteration:
|
||||
subnet_gen = netaddr.iter_iprange(start, end, step=step)
|
||||
yield (i, str(subnet_gen.next()))
|
||||
i += 1
|
||||
|
||||
def net_resource_cleanup(self):
|
||||
for floatingip in self.admin_floatingips:
|
||||
self._try_delete_resource(self.admin_client.delete_floatingip,
|
||||
floatingip['id'])
|
||||
for routerport in self.admin_routerports:
|
||||
self._try_delete_resource(
|
||||
self.admin_client.remove_router_interface_with_subnet_id,
|
||||
routerport['router_id'], routerport['subnet_id'])
|
||||
for router in self.admin_routers:
|
||||
self._try_delete_resource(self.admin_client.delete_router,
|
||||
router['id'])
|
||||
|
||||
def create_bgp_speaker(self, auto_delete=True, **args):
|
||||
data = {'bgp_speaker': args}
|
||||
bgp_speaker = self.bgp_adm_client.create_bgp_speaker(data)
|
||||
bgp_speaker_id = bgp_speaker['bgp_speaker']['id']
|
||||
if auto_delete:
|
||||
self.addCleanup(self.bgp_adm_client.delete_bgp_speaker,
|
||||
bgp_speaker_id)
|
||||
return bgp_speaker['bgp_speaker']
|
||||
|
||||
def delete_bgp_speaker(self, id):
|
||||
return self.bgp_adm_client.delete_bgp_speaker(id)
|
||||
|
||||
def create_bgp_peer(self, auto_delete=True, **args):
|
||||
bgp_peer = self.bgp_adm_client.create_bgp_peer({'bgp_peer': args})
|
||||
bgp_peer_id = bgp_peer['bgp_peer']['id']
|
||||
if auto_delete:
|
||||
self.addCleanup(self.bgp_adm_client.delete_bgp_peer,
|
||||
bgp_peer_id)
|
||||
return bgp_peer['bgp_peer']
|
||||
|
||||
def delete_bgp_peer(self, id):
|
||||
return self.bgp_adm_client.delete_bgp_peer(id)
|
||||
|
||||
def get_dragent_id(self):
|
||||
agents = self.admin_client.list_agents(
|
||||
agent_type="BGP dynamic routing agent")
|
||||
self.assertTrue(agents['agents'][0]['alive'])
|
||||
return agents['agents'][0]['id']
|
||||
|
||||
def add_bgp_speaker_to_dragent(self, agent_id, speaker_id):
|
||||
self.bgp_adm_client.add_bgp_speaker_to_dragent(agent_id, speaker_id)
|
||||
|
||||
# tnets[[net1, subnet1, router1], [net2, subnet2, router2], ...]
|
||||
def create_bgp_network(self, ip_version, scope,
|
||||
exnet, expool, exsubnet,
|
||||
tpool, tnets):
|
||||
addr_scope = self.create_address_scope(scope.name,
|
||||
ip_version=ip_version)
|
||||
# external network
|
||||
ext_net = self.create_shared_network(**{'router:external': True})
|
||||
ext_net_id = ext_net['id']
|
||||
ext_subnetpool = self.create_subnetpool(
|
||||
expool.name,
|
||||
is_admin=True,
|
||||
default_prefixlen=expool.prefixlen,
|
||||
address_scope_id=addr_scope['id'],
|
||||
prefixes=expool.prefixes)
|
||||
self.create_subnet(
|
||||
{'id': ext_net_id},
|
||||
cidr=netaddr.IPNetwork(exsubnet.cidr),
|
||||
mask_bits=exsubnet.mask,
|
||||
ip_version=ip_version,
|
||||
client=self.admin_client,
|
||||
subnetpool_id=ext_subnetpool['id'])
|
||||
# tenant network
|
||||
tenant_subnetpool = self.create_subnetpool(
|
||||
tpool.name,
|
||||
default_prefixlen=tpool.prefixlen,
|
||||
address_scope_id=addr_scope['id'],
|
||||
prefixes=tpool.prefixes)
|
||||
for tnet, tsubnet, router in tnets:
|
||||
tenant_net = self.create_network()
|
||||
tenant_subnet = self.create_subnet(
|
||||
{'id': tenant_net['id']},
|
||||
cidr=netaddr.IPNetwork(tsubnet.cidr),
|
||||
mask_bits=tsubnet.mask,
|
||||
ip_version=ip_version,
|
||||
subnetpool_id=tenant_subnetpool['id'])
|
||||
# router
|
||||
ext_gw_info = {'network_id': ext_net_id}
|
||||
router_cr = self.admin_client.create_router(
|
||||
router.name,
|
||||
external_gateway_info=ext_gw_info,
|
||||
distributed=router.dist)['router']
|
||||
self.admin_routers.append(router_cr)
|
||||
self.admin_client.add_router_interface_with_subnet_id(
|
||||
router_cr['id'],
|
||||
tenant_subnet['id'])
|
||||
self.admin_routerports.append({'router_id': router_cr['id'],
|
||||
'subnet_id': tenant_subnet['id']})
|
||||
router = self.admin_client.show_router(router_cr['id'])['router']
|
||||
fixed_ips = router['external_gateway_info']['external_fixed_ips']
|
||||
self.admin_router_ip.append(fixed_ips[0]['ip_address'])
|
||||
return ext_net_id
|
||||
|
||||
def create_and_add_peers_to_speaker(self, ext_net_id,
|
||||
speaker_info, peer_infos,
|
||||
auto_delete=True):
|
||||
speaker = self.create_bgp_speaker(auto_delete=auto_delete,
|
||||
**speaker_info)
|
||||
speaker_id = speaker['id']
|
||||
self.bgp_adm_client.add_bgp_gateway_network(speaker_id,
|
||||
ext_net_id)
|
||||
peer_ids = []
|
||||
for peer_args in peer_infos:
|
||||
peer = self.create_bgp_peer(auto_delete=auto_delete,
|
||||
**peer_args)
|
||||
peer_id = peer['id']
|
||||
peer_ids.append(peer_id)
|
||||
self.bgp_adm_client.add_bgp_peer_with_id(speaker_id,
|
||||
peer_id)
|
||||
return (speaker_id, peer_ids)
|
||||
|
||||
def get_remote_as_state(self, l_as, r_as,
|
||||
expected_state,
|
||||
init_state=ctn_base.BGP_FSM_IDLE,
|
||||
checktime=CHECKTIME,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
neighbor_state = init_state
|
||||
for i in range(0, checktime):
|
||||
neighbor_state = r_as.get_neighbor_state(l_as)
|
||||
if neighbor_state == expected_state:
|
||||
break
|
||||
time.sleep(checktime_int)
|
||||
return neighbor_state
|
||||
|
||||
def check_remote_as_state(self, l_as, r_as,
|
||||
expected_state,
|
||||
init_state=ctn_base.BGP_FSM_IDLE,
|
||||
checktime=CHECKTIME,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
neighbor_state = self.get_remote_as_state(l_as, r_as,
|
||||
expected_state,
|
||||
init_state=init_state,
|
||||
checktime=checktime,
|
||||
checktime_int=checktime_int)
|
||||
self.assertEqual(neighbor_state, expected_state)
|
||||
|
||||
def get_remote_as_of_state_ok(self, l_as, r_ass,
|
||||
expected_state,
|
||||
init_state=ctn_base.BGP_FSM_IDLE,
|
||||
checktime=CHECKTIME,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
neighbor_state = init_state
|
||||
ras_list = []
|
||||
ras_max = len(r_ass)
|
||||
for r_as in r_ass:
|
||||
ras_list.append({'as': r_as, 'check': False})
|
||||
ok_ras = []
|
||||
for i in range(0, checktime):
|
||||
for ras in ras_list:
|
||||
if ras['check']:
|
||||
continue
|
||||
neighbor_state = ras['as'].get_neighbor_state(l_as)
|
||||
if neighbor_state == expected_state:
|
||||
ras['check'] = True
|
||||
ok_ras.append(ras['as'])
|
||||
if len(ok_ras) >= ras_max:
|
||||
break
|
||||
time.sleep(checktime_int)
|
||||
return ok_ras
|
||||
|
||||
def check_multi_remote_as_state(self, l_as, r_ass,
|
||||
expected_state,
|
||||
init_state=ctn_base.BGP_FSM_IDLE,
|
||||
checktime=CHECKTIME,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
ok_ras = self.get_remote_as_of_state_ok(
|
||||
l_as, r_ass,
|
||||
expected_state,
|
||||
init_state=init_state,
|
||||
checktime=checktime,
|
||||
checktime_int=checktime_int)
|
||||
self.assertEqual(len(ok_ras), len(r_ass))
|
||||
|
||||
def get_remote_as_rib(self, r_as, prefix, rf, key, expected_item,
|
||||
checktime=CHECKTIME_INFO,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
item = None
|
||||
for i in range(0, checktime):
|
||||
rib = r_as.get_global_rib(prefix=prefix, rf=rf)
|
||||
if rib and key in rib[0]:
|
||||
if expected_item == rib[0][key]:
|
||||
item = rib[0][key]
|
||||
break
|
||||
time.sleep(checktime_int)
|
||||
return item
|
||||
|
||||
def check_remote_as_rib(self, r_as, prefix, rf, key, expected_item,
|
||||
checktime=CHECKTIME_INFO,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
item = self.get_remote_as_rib(r_as=r_as, prefix=prefix, rf=rf,
|
||||
key=key, expected_item=expected_item,
|
||||
checktime=checktime,
|
||||
checktime_int=checktime_int)
|
||||
self.assertEqual(expected_item, item)
|
||||
|
||||
def get_remote_as_of_rib_ok(self, r_ass, prefix, rf, key, expected_item,
|
||||
checktime=CHECKTIME_INFO,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
ras_list = []
|
||||
ras_max = len(r_ass)
|
||||
for r_as in r_ass:
|
||||
ras_list.append({'as': r_as, 'check': False})
|
||||
ok_ras = []
|
||||
for i in range(0, checktime):
|
||||
for ras in ras_list:
|
||||
if ras['check']:
|
||||
continue
|
||||
rib = r_as.get_global_rib(prefix=prefix, rf=rf)
|
||||
if rib and key in rib[0]:
|
||||
if expected_item == rib[0][key]:
|
||||
ras['check'] = True
|
||||
ok_ras.append(ras['as'])
|
||||
if len(ok_ras) >= ras_max:
|
||||
break
|
||||
time.sleep(checktime_int)
|
||||
return ok_ras
|
||||
|
||||
def check_multi_remote_as_rib(self, r_ass, prefix, rf, key, expected_item,
|
||||
checktime=CHECKTIME_INFO,
|
||||
checktime_int=CHECKTIME_INT):
|
||||
ok_ras = self.get_remote_as_of_rib_ok(
|
||||
r_ass=r_ass, prefix=prefix, rf=rf,
|
||||
key=key, expected_item=expected_item,
|
||||
checktime=checktime,
|
||||
checktime_int=checktime_int)
|
||||
self.assertEqual(len(ok_ras), len(r_ass))
|
||||
|
||||
def get_next_hop(self, speaker_id, dest_addr):
|
||||
routes = self.bgp_adm_client.get_bgp_advertised_routes(speaker_id)
|
||||
next_hop = ''
|
||||
for route in routes['advertised_routes']:
|
||||
if route['destination'] == dest_addr:
|
||||
next_hop = route['next_hop']
|
||||
break
|
||||
return next_hop
|
@ -0,0 +1,146 @@
|
||||
# Copyright (C) 2016 VA Linux Systems Japan K.K.
|
||||
# Copyright (C) 2016 Fumihiko Kakuma <kakuma at valinux co jp>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import config
|
||||
|
||||
from neutron_dynamic_routing.tests.tempest.scenario import base
|
||||
|
||||
from ryu.tests.integrated.common import docker_base as ctn_base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class BgpSpeakerProtoTestBase(base.BgpSpeakerScenarioTestJSONBase):
|
||||
|
||||
def _test_check_neighbor_established(self, ip_version):
|
||||
self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
|
||||
num, subnet = self.tnet_gen.next()
|
||||
mask = '/' + str(self.TPool.prefixlen)
|
||||
TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
|
||||
cidr=subnet + mask, router=None)
|
||||
TSubNet = base.SubNet(name='', cidr=TNet.cidr, mask=TNet.mask)
|
||||
MyRouter = base.Router(name='my-router' + str(num), gw='', dist=False)
|
||||
ext_net_id = self.create_bgp_network(
|
||||
ip_version, self.MyScope,
|
||||
self.PNet, self.PPool, self.PSubNet,
|
||||
self.TPool, [[TNet, TSubNet, MyRouter]])
|
||||
speaker_id, peers_ids = self.create_and_add_peers_to_speaker(
|
||||
ext_net_id,
|
||||
self.bgp_speaker_args,
|
||||
[self.bgp_peer_args[0]])
|
||||
self.check_remote_as_state(self.dr, self.r_ass[0],
|
||||
ctn_base.BGP_FSM_ESTABLISHED)
|
||||
|
||||
def _test_check_advertised_tenant_network(self, ip_version):
|
||||
self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
|
||||
num, subnet = self.tnet_gen.next()
|
||||
mask = '/' + str(self.TPool.prefixlen)
|
||||
TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
|
||||
cidr=subnet + mask, router=None)
|
||||
TSubNet = base.SubNet(name='', cidr=TNet.cidr, mask=TNet.mask)
|
||||
MyRouter = base.Router(name='my-router' + str(num), gw='', dist=False)
|
||||
ext_net_id = self.create_bgp_network(
|
||||
ip_version, self.MyScope,
|
||||
self.PNet, self.PPool, self.PSubNet,
|
||||
self.TPool, [[TNet, TSubNet, MyRouter]])
|
||||
speaker_id, peers_ids = self.create_and_add_peers_to_speaker(
|
||||
ext_net_id,
|
||||
self.bgp_speaker_args,
|
||||
[self.bgp_peer_args[0]])
|
||||
self.check_remote_as_state(self.dr, self.r_ass[0],
|
||||
ctn_base.BGP_FSM_ESTABLISHED)
|
||||
rf = 'ipv' + str(ip_version)
|
||||
self.check_remote_as_rib(self.r_ass[0], TNet.cidr, rf,
|
||||
'nexthop',
|
||||
self.get_next_hop(speaker_id, TNet.cidr))
|
||||
|
||||
def _test_check_advertised_multiple_tenant_network(self, ip_version):
|
||||
self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
|
||||
tnets = []
|
||||
tnets_cidr = []
|
||||
for i in range(0, 3):
|
||||
num, subnet = self.tnet_gen.next()
|
||||
mask = '/' + str(self.TPool.prefixlen)
|
||||
TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
|
||||
cidr=subnet + mask, router=None)
|
||||
TSubNet = base.SubNet(name='', cidr=TNet.cidr, mask=TNet.mask)
|
||||
MyRouter = base.Router(name='my-router' + str(num),
|
||||
gw='', dist=False)
|
||||
tnets.append([TNet, TSubNet, MyRouter])
|
||||
tnets_cidr.append(TNet.cidr)
|
||||
ext_net_id = self.create_bgp_network(
|
||||
ip_version, self.MyScope,
|
||||
self.PNet, self.PPool, self.PSubNet,
|
||||
self.TPool, tnets)
|
||||
speaker_id, peers_ids = self.create_and_add_peers_to_speaker(
|
||||
ext_net_id,
|
||||
self.bgp_speaker_args,
|
||||
[self.bgp_peer_args[0]])
|
||||
self.check_remote_as_state(self.dr, self.r_ass[0],
|
||||
ctn_base.BGP_FSM_ESTABLISHED)
|
||||
rf = 'ipv' + str(ip_version)
|
||||
for cidr in tnets_cidr:
|
||||
self.check_remote_as_rib(self.r_ass[0], cidr, rf,
|
||||
'nexthop',
|
||||
self.get_next_hop(speaker_id, cidr))
|
||||
|
||||
def _test_check_neighbor_established_with_multiple_peers(
|
||||
self, ip_version):
|
||||
for (bgp_peer_args, r_as_ip) in zip(self.bgp_peer_args,
|
||||
self.r_as_ip):
|
||||
bgp_peer_args['peer_ip'] = r_as_ip.split('/')[0]
|
||||
num, subnet = self.tnet_gen.next()
|
||||
mask = '/' + str(self.TPool.prefixlen)
|
||||
TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
|
||||
cidr=subnet + mask, router=None)
|
||||
TSubNet = base.SubNet(name='', cidr=TNet.cidr, mask=TNet.mask)
|
||||
MyRouter = base.Router(name='my-router' + str(num), gw='', dist=False)
|
||||
ext_net_id = self.create_bgp_network(
|
||||
ip_version, self.MyScope,
|
||||
self.PNet, self.PPool, self.PSubNet,
|
||||
self.TPool, [[TNet, TSubNet, MyRouter]])
|
||||
speaker_id, peers_ids = self.create_and_add_peers_to_speaker(
|
||||
ext_net_id,
|
||||
self.bgp_speaker_args,
|
||||
self.bgp_peer_args)
|
||||
self.check_multi_remote_as_state(self.dr, self.r_ass,
|
||||
ctn_base.BGP_FSM_ESTABLISHED)
|
||||
|
||||
def _test_check_advertised_tenant_network_with_multiple_peers(
|
||||
self, ip_version):
|
||||
for (bgp_peer_args, r_as_ip) in zip(self.bgp_peer_args,
|
||||
self.r_as_ip):
|
||||
bgp_peer_args['peer_ip'] = r_as_ip.split('/')[0]
|
||||
num, subnet = self.tnet_gen.next()
|
||||
mask = '/' + str(self.TPool.prefixlen)
|
||||
TNet = base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
|
||||
cidr=subnet + mask, router=None)
|
||||
TSubNet = base.SubNet(name='', cidr=TNet.cidr, mask=TNet.mask)
|
||||
MyRouter = base.Router(name='my-router' + str(num), gw='', dist=False)
|
||||
ext_net_id = self.create_bgp_network(
|
||||
ip_version, self.MyScope,
|
||||
self.PNet, self.PPool, self.PSubNet,
|
||||
self.TPool, [[TNet, TSubNet, MyRouter]])
|
||||
speaker_id, peers_ids = self.create_and_add_peers_to_speaker(
|
||||
ext_net_id,
|
||||
self.bgp_speaker_args,
|
||||
self.bgp_peer_args)
|
||||
self.check_multi_remote_as_state(self.dr, self.r_ass,
|
||||
ctn_base.BGP_FSM_ESTABLISHED)
|
||||
rf = 'ipv' + str(ip_version)
|
||||
next_hop = self.get_next_hop(speaker_id, TNet.cidr)
|
||||
self.check_multi_remote_as_rib(self.r_ass, TNet.cidr, rf,
|
||||
'nexthop', next_hop)
|
101
neutron_dynamic_routing/tests/tempest/scenario/basic/base.py
Normal file
101
neutron_dynamic_routing/tests/tempest/scenario/basic/base.py
Normal file
@ -0,0 +1,101 @@
|
||||
# Copyright (C) 2016 VA Linux Systems Japan K.K.
|
||||
# Copyright (C) 2016 Fumihiko Kakuma <kakuma at valinux co jp>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron_dynamic_routing.tests.tempest.scenario import base
|
||||
from ryu.tests.integrated.common import docker_base as ctn_base
|
||||
from ryu.tests.integrated.common import quagga
|
||||
|
||||
|
||||
class BgpSpeakerBasicTestJSONBase(base.BgpSpeakerScenarioTestJSONBase):
|
||||
|
||||
RAS_MAX = 3
|
||||
public_gw = '192.168.10.1'
|
||||
MyScope = base.Scope(name='my-scope')
|
||||
PNet = base.Net(name='', net='172.24.6.0', mask=24,
|
||||
cidr='172.24.6.0/24', router=None)
|
||||
PPool = base.Pool(name='test-pool-ext', prefixlen=PNet.mask,
|
||||
prefixes=[PNet.net + '/8'])
|
||||
PSubNet = base.SubNet(name='', cidr=PNet.cidr, mask=PNet.mask)
|
||||
TPool = base.Pool(name='tenant-test-pool', prefixlen=28,
|
||||
prefixes=['10.10.0.0/16'])
|
||||
L_AS = base.AS(asn='64512', router_id='192.168.0.2', adv_net='')
|
||||
ras_l = [
|
||||
base.AS(asn='64522', router_id='192.168.0.12',
|
||||
adv_net='192.168.162.0/24'),
|
||||
base.AS(asn='64523', router_id='192.168.0.13',
|
||||
adv_net='192.168.163.0/24'),
|
||||
base.AS(asn='64524', router_id='192.168.0.14',
|
||||
adv_net='192.168.164.0/24')
|
||||
]
|
||||
|
||||
bgp_speaker_args = {
|
||||
'local_as': L_AS.asn,
|
||||
'ip_version': 4,
|
||||
'name': 'my-bgp-speaker1',
|
||||
'advertise_floating_ip_host_routes': True,
|
||||
'advertise_tenant_networks': True
|
||||
}
|
||||
bgp_peer_args = [
|
||||
{'remote_as': ras_l[0].asn,
|
||||
'name': 'my-bgp-peer1',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'},
|
||||
{'remote_as': ras_l[1].asn,
|
||||
'name': 'my-bgp-peer2',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'},
|
||||
{'remote_as': ras_l[2].asn,
|
||||
'name': 'my-bgp-peer3',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'}
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(BgpSpeakerBasicTestJSONBase, self).setUp()
|
||||
|
||||
@classmethod
|
||||
def resource_setup_container(cls):
|
||||
cls.brdc = ctn_base.Bridge(name='br-docker',
|
||||
subnet='192.168.10.0/24',
|
||||
start_ip='192.168.10.128',
|
||||
end_ip='192.168.10.254',
|
||||
self_ip=True,
|
||||
fixed_ip=cls.public_gw + '/24',
|
||||
br_type=ctn_base.BRIDGE_TYPE_OVS)
|
||||
cls.bridges.append(cls.brdc)
|
||||
# This is dummy container object for a dr service.
|
||||
# This keeps data which passes to a quagga container.
|
||||
cls.dr = ctn_base.BGPContainer(name='dr', asn=int(cls.L_AS.asn),
|
||||
router_id=cls.L_AS.router_id)
|
||||
cls.dr.set_addr_info(bridge='br-docker', ipv4=cls.public_gw)
|
||||
# quagga container
|
||||
cls.dockerimg = ctn_base.DockerImage()
|
||||
cls.q_img = cls.dockerimg.create_quagga(check_exist=True)
|
||||
cls.images.append(cls.q_img)
|
||||
for i in range(cls.RAS_MAX):
|
||||
qg = quagga.QuaggaBGPContainer(name='q' + str(i + 1),
|
||||
asn=int(cls.ras_l[i].asn),
|
||||
router_id=cls.ras_l[i].router_id,
|
||||
ctn_image_name=cls.q_img)
|
||||
cls.containers.append(qg)
|
||||
cls.r_ass.append(qg)
|
||||
qg.add_route(cls.ras_l[i].adv_net)
|
||||
qg.run(wait=True)
|
||||
cls.r_as_ip.append(cls.brdc.addif(qg))
|
||||
qg.add_peer(cls.dr, bridge=cls.brdc.name,
|
||||
peer_info={'passive': True})
|
||||
cls.tnet_gen = cls.get_subnet(start='10.10.1.0', end='10.10.255.0',
|
||||
step=256)
|
@ -0,0 +1,76 @@
|
||||
# Copyright (C) 2016 VA Linux Systems Japan K.K.
|
||||
# Copyright (C) 2016 Fumihiko Kakuma <kakuma at valinux co jp>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
|
||||
from neutron_dynamic_routing.tests.tempest.scenario import base as s_base
|
||||
from neutron_dynamic_routing.tests.tempest.scenario.basic import base
|
||||
|
||||
from ryu.tests.integrated.common import docker_base as ctn_base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class BgpSpeakerBasicTest(base.BgpSpeakerBasicTestJSONBase):
|
||||
|
||||
@decorators.idempotent_id('cc615252-c6cb-4d75-a70e-608fb2c3736a')
|
||||
def test_schedule_added_speaker(self):
|
||||
self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
|
||||
num, subnet = self.tnet_gen.next()
|
||||
mask = '/' + str(self.TPool.prefixlen)
|
||||
TNet = s_base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
|
||||
cidr=subnet + mask, router=None)
|
||||
TSubNet = s_base.SubNet(name='', cidr=TNet.cidr, mask=TNet.mask)
|
||||
MyRouter = s_base.Router(name='my-router' + str(num), gw='',
|
||||
dist=False)
|
||||
ext_net_id = self.create_bgp_network(
|
||||
4, self.MyScope,
|
||||
self.PNet, self.PPool, self.PSubNet,
|
||||
self.TPool, [[TNet, TSubNet, MyRouter]])
|
||||
speaker_id, peers_ids = self.create_and_add_peers_to_speaker(
|
||||
ext_net_id,
|
||||
self.bgp_speaker_args,
|
||||
[self.bgp_peer_args[0]])
|
||||
self.check_remote_as_state(self.dr, self.r_ass[0],
|
||||
ctn_base.BGP_FSM_ESTABLISHED)
|
||||
|
||||
@decorators.idempotent_id('ce98c33c-0ffa-49ae-b365-da836406793b')
|
||||
def test_unschedule_deleted_speaker(self):
|
||||
self.bgp_peer_args[0]['peer_ip'] = self.r_as_ip[0].split('/')[0]
|
||||
num, subnet = self.tnet_gen.next()
|
||||
mask = '/' + str(self.TPool.prefixlen)
|
||||
TNet = s_base.Net(name='', net=subnet, mask=self.TPool.prefixlen,
|
||||
cidr=subnet + mask, router=None)
|
||||
TSubNet = s_base.SubNet(name='', cidr=TNet.cidr, mask=TNet.mask)
|
||||
MyRouter = s_base.Router(name='my-router' + str(num), gw='',
|
||||
dist=False)
|
||||
ext_net_id = self.create_bgp_network(
|
||||
4, self.MyScope,
|
||||
self.PNet, self.PPool, self.PSubNet,
|
||||
self.TPool, [[TNet, TSubNet, MyRouter]])
|
||||
speaker_id, peers_ids = self.create_and_add_peers_to_speaker(
|
||||
ext_net_id,
|
||||
self.bgp_speaker_args,
|
||||
[self.bgp_peer_args[0]],
|
||||
auto_delete=False)
|
||||
self.check_remote_as_state(self.dr, self.r_ass[0],
|
||||
ctn_base.BGP_FSM_ESTABLISHED)
|
||||
self.delete_bgp_speaker(speaker_id)
|
||||
self.delete_bgp_peer(peers_ids[0])
|
||||
self.check_remote_as_state(self.dr, self.r_ass[0],
|
||||
ctn_base.BGP_FSM_ACTIVE,
|
||||
init_state=ctn_base.BGP_FSM_ESTABLISHED)
|
131
neutron_dynamic_routing/tests/tempest/scenario/ipv4/test_ipv4.py
Normal file
131
neutron_dynamic_routing/tests/tempest/scenario/ipv4/test_ipv4.py
Normal file
@ -0,0 +1,131 @@
|
||||
# Copyright (C) 2016 VA Linux Systems Japan K.K.
|
||||
# Copyright (C) 2016 Fumihiko Kakuma <kakuma at valinux co jp>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
|
||||
from neutron_dynamic_routing.tests.tempest.scenario import base
|
||||
from neutron_dynamic_routing.tests.tempest.scenario import base_test_proto as test_base # noqa
|
||||
|
||||
from ryu.tests.integrated.common import docker_base as ctn_base
|
||||
from ryu.tests.integrated.common import quagga
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class BgpSpeakerIpv4Test(test_base.BgpSpeakerProtoTestBase):
|
||||
|
||||
RAS_MAX = 3
|
||||
ip_version = 4
|
||||
public_gw = '192.168.10.1'
|
||||
MyScope = base.Scope(name='my-scope')
|
||||
PNet = base.Net(name='', net='172.24.6.0', mask=24,
|
||||
cidr='172.24.6.0/24', router=None)
|
||||
PPool = base.Pool(name='test-pool-ext', prefixlen=PNet.mask,
|
||||
prefixes=[PNet.net + '/8'])
|
||||
PSubNet = base.SubNet(name='', cidr=PNet.cidr, mask=PNet.mask)
|
||||
TPool = base.Pool(name='tenant-test-pool', prefixlen=28,
|
||||
prefixes=['10.10.0.0/16'])
|
||||
L_AS = base.AS(asn='64512', router_id='192.168.0.2', adv_net='')
|
||||
ras_l = [
|
||||
base.AS(asn='64522', router_id='192.168.0.12',
|
||||
adv_net='192.168.162.0/24'),
|
||||
base.AS(asn='64523', router_id='192.168.0.13',
|
||||
adv_net='192.168.163.0/24'),
|
||||
base.AS(asn='64524', router_id='192.168.0.14',
|
||||
adv_net='192.168.164.0/24')
|
||||
]
|
||||
|
||||
bgp_speaker_args = {
|
||||
'local_as': L_AS.asn,
|
||||
'ip_version': ip_version,
|
||||
'name': 'my-bgp-speaker1',
|
||||
'advertise_floating_ip_host_routes': True,
|
||||
'advertise_tenant_networks': True
|
||||
}
|
||||
bgp_peer_args = [
|
||||
{'remote_as': ras_l[0].asn,
|
||||
'name': 'my-bgp-peer1',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'},
|
||||
{'remote_as': ras_l[1].asn,
|
||||
'name': 'my-bgp-peer2',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'},
|
||||
{'remote_as': ras_l[2].asn,
|
||||
'name': 'my-bgp-peer3',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'}
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(BgpSpeakerIpv4Test, self).setUp()
|
||||
|
||||
@classmethod
|
||||
def resource_setup_container(cls):
|
||||
cls.brdc = ctn_base.Bridge(name='br-docker',
|
||||
subnet='192.168.10.0/24',
|
||||
start_ip='192.168.10.128',
|
||||
end_ip='192.168.10.254',
|
||||
self_ip=True,
|
||||
fixed_ip=cls.public_gw + '/24',
|
||||
br_type=ctn_base.BRIDGE_TYPE_OVS)
|
||||
cls.bridges.append(cls.brdc)
|
||||
# This is dummy container object for a dr service.
|
||||
# This keeps data which passes to a quagga container.
|
||||
cls.dr = ctn_base.BGPContainer(name='dr', asn=int(cls.L_AS.asn),
|
||||
router_id=cls.L_AS.router_id)
|
||||
cls.dr.set_addr_info(bridge='br-docker', ipv4=cls.public_gw)
|
||||
# quagga container
|
||||
cls.dockerimg = ctn_base.DockerImage()
|
||||
cls.q_img = cls.dockerimg.create_quagga(check_exist=True)
|
||||
cls.images.append(cls.q_img)
|
||||
for i in range(cls.RAS_MAX):
|
||||
qg = quagga.QuaggaBGPContainer(name='q' + str(i + 1),
|
||||
asn=int(cls.ras_l[i].asn),
|
||||
router_id=cls.ras_l[i].router_id,
|
||||
ctn_image_name=cls.q_img)
|
||||
cls.containers.append(qg)
|
||||
cls.r_ass.append(qg)
|
||||
qg.add_route(cls.ras_l[i].adv_net)
|
||||
qg.run(wait=True)
|
||||
cls.r_as_ip.append(cls.brdc.addif(qg))
|
||||
qg.add_peer(cls.dr, bridge=cls.brdc.name,
|
||||
peer_info={'passive': True})
|
||||
cls.tnet_gen = cls.get_subnet(start='10.10.1.0', end='10.10.255.0',
|
||||
step=256)
|
||||
|
||||
@decorators.idempotent_id('7f2acbc2-ff88-4a63-aa02-a2f9feb3f5b0')
|
||||
def test_check_neighbor_established(self):
|
||||
self._test_check_neighbor_established(self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('f32245fc-aeab-4244-acfa-3af9dd662e8d')
|
||||
def test_check_advertised_tenant_network(self):
|
||||
self._test_check_advertised_tenant_network(self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('a5c238de-b750-499c-aaa2-b44a057e9ed3')
|
||||
def test_check_advertised_multiple_tenant_network(self):
|
||||
self._test_check_advertised_multiple_tenant_network(self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('e4961cc1-0c47-4081-a896-caaa9342ca75')
|
||||
def test_check_neighbor_established_with_multiple_peers(self):
|
||||
self._test_check_neighbor_established_with_multiple_peers(
|
||||
self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('91971dfb-c129-4744-9fbb-ac4f9e8d56c0')
|
||||
def test_check_advertised_tenant_network_with_multiple_peers(self):
|
||||
self._test_check_advertised_tenant_network_with_multiple_peers(
|
||||
self.ip_version)
|
132
neutron_dynamic_routing/tests/tempest/scenario/ipv6/test_ipv6.py
Normal file
132
neutron_dynamic_routing/tests/tempest/scenario/ipv6/test_ipv6.py
Normal file
@ -0,0 +1,132 @@
|
||||
# Copyright (C) 2016 VA Linux Systems Japan K.K.
|
||||
# Copyright (C) 2016 Fumihiko Kakuma <kakuma at valinux co jp>
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import config
|
||||
from tempest.lib import decorators
|
||||
|
||||
from neutron_dynamic_routing.tests.tempest.scenario import base
|
||||
from neutron_dynamic_routing.tests.tempest.scenario import base_test_proto as test_base # noqa
|
||||
|
||||
from ryu.tests.integrated.common import docker_base as ctn_base
|
||||
from ryu.tests.integrated.common import quagga
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class BgpSpeakerIpv6Test(test_base.BgpSpeakerProtoTestBase):
|
||||
|
||||
RAS_MAX = 3
|
||||
ip_version = 6
|
||||
public_gw = '2001:db8:a000::1'
|
||||
MyScope = base.Scope(name='my-scope')
|
||||
PNet = base.Net(name='', net='2001:db8::', mask=64,
|
||||
cidr='2001:db8::/64', router=None)
|
||||
PPool = base.Pool(name='test-pool-ext', prefixlen=PNet.mask,
|
||||
prefixes=[PNet.net + '/8'])
|
||||
PSubNet = base.SubNet(name='', cidr=PNet.cidr, mask=PNet.mask)
|
||||
TPool = base.Pool(name='tenant-test-pool', prefixlen=64,
|
||||
prefixes=['2001:db8:8000::/48'])
|
||||
L_AS = base.AS(asn='64512', router_id='192.168.0.2', adv_net='')
|
||||
ras_l = [
|
||||
base.AS(asn='64522', router_id='192.168.0.12',
|
||||
adv_net='2001:db8:9002::/48'),
|
||||
base.AS(asn='64523', router_id='192.168.0.13',
|
||||
adv_net='2001:db8:9003::/48'),
|
||||
base.AS(asn='64524', router_id='192.168.0.14',
|
||||
adv_net='2001:db8:9004::/48')
|
||||
]
|
||||
|
||||
bgp_speaker_args = {
|
||||
'local_as': L_AS.asn,
|
||||
'ip_version': ip_version,
|
||||
'name': 'my-bgp-speaker1',
|
||||
'advertise_floating_ip_host_routes': True,
|
||||
'advertise_tenant_networks': True
|
||||
}
|
||||
bgp_peer_args = [
|
||||
{'remote_as': ras_l[0].asn,
|
||||
'name': 'my-bgp-peer1',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'},
|
||||
{'remote_as': ras_l[1].asn,
|
||||
'name': 'my-bgp-peer2',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'},
|
||||
{'remote_as': ras_l[2].asn,
|
||||
'name': 'my-bgp-peer3',
|
||||
'peer_ip': None,
|
||||
'auth_type': 'none'}
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super(BgpSpeakerIpv6Test, self).setUp()
|
||||
|
||||
@classmethod
|
||||
def resource_setup_container(cls):
|
||||
cls.brdc = ctn_base.Bridge(name='br-docker',
|
||||
subnet='2001:db8:a000::/64',
|
||||
start_ip='2001:db8:a000::8000',
|
||||
end_ip='2001:db8:a000::fffe',
|
||||
self_ip=True,
|
||||
fixed_ip=cls.public_gw + '/64',
|
||||
br_type=ctn_base.BRIDGE_TYPE_OVS)
|
||||
cls.bridges.append(cls.brdc)
|
||||
# This is dummy container object for a dr service.
|
||||
# This keeps data which passes to a quagga container.
|
||||
cls.dr = ctn_base.BGPContainer(name='dr', asn=int(cls.L_AS.asn),
|
||||
router_id=cls.L_AS.router_id)
|
||||
cls.dr.set_addr_info(bridge='br-docker', ipv6=cls.public_gw)
|
||||
# quagga container
|
||||
cls.dockerimg = ctn_base.DockerImage()
|
||||
cls.q_img = cls.dockerimg.create_quagga(check_exist=True)
|
||||
cls.images.append(cls.q_img)
|
||||
for i in range(cls.RAS_MAX):
|
||||
qg = quagga.QuaggaBGPContainer(name='q' + str(i + 1),
|
||||
asn=int(cls.ras_l[i].asn),
|
||||
router_id=cls.ras_l[i].router_id,
|
||||
ctn_image_name=cls.q_img)
|
||||
cls.containers.append(qg)
|
||||
cls.r_ass.append(qg)
|
||||
qg.add_route(cls.ras_l[i].adv_net, route_info={'rf': 'ipv6'})
|
||||
qg.run(wait=True)
|
||||
cls.r_as_ip.append(cls.brdc.addif(qg))
|
||||
qg.add_peer(cls.dr, bridge=cls.brdc.name, v6=True,
|
||||
peer_info={'passive': True})
|
||||
cls.tnet_gen = cls.get_subnet(start='2001:db8:8000:1::',
|
||||
end='2001:db8:8000:ffff::',
|
||||
step=65536 * 65536 * 65536 * 65536)
|
||||
|
||||
@decorators.idempotent_id('5194a8e2-95bd-49f0-872d-1e3e875ede32')
|
||||
def test_check_neighbor_established(self):
|
||||
self._test_check_neighbor_established(self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('6a3483fc-8c8a-4387-bda6-c7061410e04b')
|
||||
def test_check_advertised_tenant_network(self):
|
||||
self._test_check_advertised_tenant_network(self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('aca5d678-c249-4de5-921b-6b6ba621e4f7')
|
||||
def test_check_advertised_multiple_tenant_network(self):
|
||||
self._test_check_advertised_multiple_tenant_network(self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('f81012f3-2f7e-4b3c-8c1d-b1778146d712')
|
||||
def test_check_neighbor_established_with_multiple_peers(self):
|
||||
self._test_check_neighbor_established_with_multiple_peers(
|
||||
self.ip_version)
|
||||
|
||||
@decorators.idempotent_id('be710ec1-a338-44c9-8b89-31c3532aae65')
|
||||
def test_check_advertised_tenant_network_with_multiple_peers(self):
|
||||
self._test_check_advertised_tenant_network_with_multiple_peers(
|
||||
self.ip_version)
|
Loading…
x
Reference in New Issue
Block a user