diff options
-rw-r--r-- | sdnvpn/artifacts/quagga_setup.sh | 110 | ||||
-rw-r--r-- | sdnvpn/lib/quagga.py | 6 | ||||
-rw-r--r-- | sdnvpn/lib/utils.py | 40 | ||||
-rw-r--r-- | sdnvpn/test/functest/config.yaml | 9 | ||||
-rw-r--r-- | sdnvpn/test/functest/testcase_3.py | 102 |
5 files changed, 203 insertions, 64 deletions
diff --git a/sdnvpn/artifacts/quagga_setup.sh b/sdnvpn/artifacts/quagga_setup.sh index a8fe9f6..fbd229f 100644 --- a/sdnvpn/artifacts/quagga_setup.sh +++ b/sdnvpn/artifacts/quagga_setup.sh @@ -1,22 +1,25 @@ #! /bin/bash set -xe - # change the password because this script is run on a passwordless cloud-image echo 'ubuntu:opnfv' | chpasswd # Wait for a floating IP # as a workaround to NAT breakage -sleep 20 +sleep 100 # Variables to be filled in with python -NEIGHBOR_IP=%s -OWN_IP=%s +NEIGHBOR_IP=$1 +OWN_IP=$2 # directly access the instance from the external net without NAT -EXT_NET_MASK=%s +EXT_NET_MASK=$3 +IP_PREFIX=$4 +RD=$5 +IRT=$6 +ERT=$7 if [[ $(getent hosts | awk '{print $2}') != *"$(cat /etc/hostname | awk '{print $1}')"* ]] -then +then echo "127.0.1.1 $(cat /etc/hostname | awk '{print $1}')" | tee -a /etc/hosts fi @@ -37,60 +40,53 @@ fi ip link set $quagga_int up ip addr add $OWN_IP/$EXT_NET_MASK dev $quagga_int -ZEBRA_CONFIG_LOCATION="/etc/quagga/zebra.conf" -DAEMONS_FILE_LOCATION="/etc/quagga/daemons" -BGPD_CONFIG_LOCATION="/etc/quagga/bgpd.conf" -BGPD_LOG_FILE="/var/log/bgpd.log" - -# Quagga is already installed to run as well in setups without inet -# dns fix -# echo "nameserver 8.8.8.8" > /etc/resolvconf/resolv.conf.d/head -# resolvconf -u -# DEBIAN_FRONTEND=noninteractive apt-get update -# DEBIAN_FRONTEND=noninteractive apt-get install quagga -y - -touch $BGPD_LOG_FILE -chown quagga:quagga $BGPD_LOG_FILE - -chown quagga:quagga $DAEMONS_FILE_LOCATION -cat <<CATEOF > $DAEMONS_FILE_LOCATION -zebra=yes -bgpd=yes -ospfd=no -ospf6d=no -ripd=no -ripngd=no -isisd=no -babeld=no -CATEOF - -touch $ZEBRA_CONFIG_LOCATION -chown quagga:quagga $ZEBRA_CONFIG_LOCATION +# Download quagga/zrpc rpms +cd /root +wget http://artifacts.opnfv.org/sdnvpn/quagga4/quagga-ubuntu-updated.tar.gz +tar -xvf quagga-ubuntu-updated.tar.gz +cd /root/quagga +dpkg -i c-capnproto_1.0.2.75f7901.Ubuntu16.04_amd64.deb +dpkg -i zmq_4.1.3.56b71af.Ubuntu16.04_amd64.deb +dpkg -i quagga_1.1.0.cd8ab40.Ubuntu16.04_amd64.deb +dpkg -i thrift_1.0.0.b2a4d4a.Ubuntu16.04_amd64.deb +dpkg -i zrpc_0.2.0efd19f.thriftv4.Ubuntu16.04_amd64.deb -cat <<CATEOF > $BGPD_CONFIG_LOCATION -! -*- bgp -*- - -hostname bgpd -password sdncbgpc +nohup /opt/quagga/sbin/bgpd & +cat > /tmp/quagga-config << EOF1 +config terminal router bgp 200 - bgp router-id ${OWN_IP} - neighbor ${NEIGHBOR_IP} remote-as 100 - no neighbor ${NEIGHBOR_IP} activate + bgp router-id $OWN_IP + no bgp log-neighbor-changes + bgp graceful-restart stalepath-time 90 + bgp graceful-restart restart-time 900 + bgp graceful-restart + bgp graceful-restart preserve-fw-state + bgp bestpath as-path multipath-relax + neighbor $NEIGHBOR_IP remote-as 100 + no neighbor $NEIGHBOR_IP activate + vrf $RD + rd $RD + rt import $IRT + rt export $ERT + exit +! +address-family vpnv4 +neighbor $NEIGHBOR_IP activate +neighbor $NEIGHBOR_IP attribute-unchanged next-hop +exit ! - address-family vpnv4 unicast - neighbor ${NEIGHBOR_IP} activate - exit-address-family +route-map map permit 1 + set ip next-hop $OWN_IP +exit ! -line vty - exec-timeout 0 0 +router bgp 200 +address-family vpnv4 +network $IP_PREFIX rd $RD tag 100 route-map map +exit ! -debug bgp events -debug bgp updates -log file ${BGPD_LOG_FILE} -end -CATEOF -chown quagga:quagga $BGPD_CONFIG_LOCATION -service quagga restart -pgrep bgpd -pgrep zebra +EOF1 + +sleep 20 + +(sleep 1;echo "sdncbgpc";sleep 1;cat /tmp/quagga-config;sleep 1; echo "exit") |nc -q1 localhost 2605 diff --git a/sdnvpn/lib/quagga.py b/sdnvpn/lib/quagga.py index e072f1c..0ea206e 100644 --- a/sdnvpn/lib/quagga.py +++ b/sdnvpn/lib/quagga.py @@ -44,12 +44,14 @@ def bootstrap_quagga(fip_addr, controller_ip): def gen_quagga_setup_script(controller_ip, fake_floating_ip, - ext_net_mask): + ext_net_mask, + ip_prefix, rd, irt, ert): with open(COMMON_CONFIG.quagga_setup_script_path) as f: template = f.read() script = template % (controller_ip, fake_floating_ip, - ext_net_mask) + ext_net_mask, + ip_prefix, rd, irt, ert) return script diff --git a/sdnvpn/lib/utils.py b/sdnvpn/lib/utils.py index 33ff594..e43750c 100644 --- a/sdnvpn/lib/utils.py +++ b/sdnvpn/lib/utils.py @@ -7,6 +7,7 @@ # # http://www.apache.org/licenses/LICENSE-2.0 # +import json import logging import os import time @@ -14,6 +15,7 @@ import requests import re import subprocess from concurrent.futures import ThreadPoolExecutor +from requests.auth import HTTPBasicAuth from opnfv.deployment.factory import Factory as DeploymentFactory @@ -942,3 +944,41 @@ def get_odl_bgp_entity_owner(controllers): if re.search(odl_bgp_owner, line): return controller return None + + +def add_quagga_external_gre_end_point(controllers, remote_tep_ip): + json_body = {'input': + {'destination-ip': remote_tep_ip, + 'tunnel-type': "odl-interface:tunnel-type-mpls-over-gre"} + } + url = ('http://{ip}:8081/restconf/operations/' + 'itm-rpc:add-external-tunnel-endpoint'.format(ip=controllers[0].ip)) + headers = {'Content-type': 'application/yang.data+json', + 'Accept': 'application/yang.data+json'} + try: + requests.post(url, data=json.dumps(json_body), + headers=headers, + auth=HTTPBasicAuth('admin', 'admin')) + except Exception as e: + logger.error("Failed to create external tunnel endpoint on" + " ODL for external tep ip %s with error %s" + % (remote_tep_ip, e)) + return None + + +def is_fib_entry_present_on_odl(controllers, ip_prefix, vrf_id): + url = ('http://admin:admin@{ip}:8081/restconf/config/odl-fib:fibEntries/' + 'vrfTables/{vrf}/'.format(ip=controllers[0].ip, vrf=vrf_id)) + logger.error("url is %s" % url) + try: + vrf_table = requests.get(url).json() + is_ipprefix_exists = False + for vrf_entry in vrf_table['vrfTables'][0]['vrfEntry']: + if vrf_entry['destPrefix'] == ip_prefix: + is_ipprefix_exists = True + break + return is_ipprefix_exists + except Exception as e: + logger.error('Failed to find ip prefix %s with error %s' + % (ip_prefix, e)) + return False diff --git a/sdnvpn/test/functest/config.yaml b/sdnvpn/test/functest/config.yaml index 360d88f..e910c77 100644 --- a/sdnvpn/test/functest/config.yaml +++ b/sdnvpn/test/functest/config.yaml @@ -86,8 +86,13 @@ testcases: quagga_instance_ip: 10.10.11.5 instance_1_name: sdnvpn-3-1 instance_1_ip: 10.10.10.5 - import_targets: '31:31' - export_targets: '32:32' + route_targets: '88:88' + import_targets: '88:88' + export_targets: '88:88' + route_distinguishers: '18:18' + external_network_name: External Network in Quagga VM + external_network_ip_prefix: 30.1.1.1/32 + external_network_ip: 30.1.1.1 sdnvpn.test.functest.testcase_4: enabled: true diff --git a/sdnvpn/test/functest/testcase_3.py b/sdnvpn/test/functest/testcase_3.py index 7f70043..a527236 100644 --- a/sdnvpn/test/functest/testcase_3.py +++ b/sdnvpn/test/functest/testcase_3.py @@ -186,7 +186,14 @@ def main(): test_utils.open_http_port(neutron_client, sg_id) test_utils.open_bgp_port(neutron_client, sg_id) - net_id, subnet_1_id, router_1_id = test_utils.create_network( + + image_id = os_utils.create_glance_image( + glance_client, TESTCASE_CONFIG.image_name, + COMMON_CONFIG.image_path, disk=COMMON_CONFIG.image_format, + container="bare", public='public') + image_ids.append(image_id) + + net_1_id, subnet_1_id, router_1_id = test_utils.create_network( neutron_client, TESTCASE_CONFIG.net_1_name, TESTCASE_CONFIG.subnet_1_name, @@ -203,7 +210,7 @@ def main(): interfaces.append(tuple((router_1_id, subnet_1_id))) interfaces.append(tuple((router_quagga_id, subnet_quagga_id))) - network_ids.extend([net_id, quagga_net_id]) + network_ids.extend([net_1_id, quagga_net_id]) router_ids.extend([router_1_id, router_quagga_id]) subnet_ids.extend([subnet_1_id, subnet_quagga_id]) @@ -250,7 +257,11 @@ def main(): quagga_bootstrap_script = quagga.gen_quagga_setup_script( controller_ext_ip, fake_fip['fip_addr'], - ext_net_mask) + ext_net_mask, + TESTCASE_CONFIG.external_network_ip_prefix, + TESTCASE_CONFIG.route_distinguishers, + TESTCASE_CONFIG.import_targets, + TESTCASE_CONFIG.export_targets) quagga_vm = test_utils.create_instance( nova_client, @@ -306,6 +317,83 @@ def main(): else: results.add_failure("Peering with quagga") + test_utils.add_quagga_external_gre_end_point(controllers, + fake_fip['fip_addr']) + test_utils.wait_before_subtest() + + msg = ("Create VPN to define a VRF") + results.record_action(msg) + vpn_name = vpn_name = "sdnvpn-3" + kwargs = { + "import_targets": TESTCASE_CONFIG.import_targets, + "export_targets": TESTCASE_CONFIG.export_targets, + "route_targets": TESTCASE_CONFIG.route_targets, + "route_distinguishers": TESTCASE_CONFIG.route_distinguishers, + "name": vpn_name + } + bgpvpn = test_utils.create_bgpvpn(neutron_client, **kwargs) + bgpvpn_id = bgpvpn['bgpvpn']['id'] + logger.debug("VPN1 created details: %s" % bgpvpn) + bgpvpn_ids.append(bgpvpn_id) + + msg = ("Associate network '%s' to the VPN." % + TESTCASE_CONFIG.net_1_name) + results.record_action(msg) + results.add_to_summary(0, "-") + + # create a vm and connect it with network1, + # which is going to be bgpvpn associated + userdata_common = test_utils.generate_ping_userdata( + [TESTCASE_CONFIG.external_network_ip]) + + compute_node = nova_client.hypervisors.list()[0] + av_zone_1 = "nova:" + compute_node.hypervisor_hostname + vm_bgpvpn = test_utils.create_instance( + nova_client, + TESTCASE_CONFIG.instance_1_name, + image_id, + net_1_id, + sg_id, + fixed_ip=TESTCASE_CONFIG.instance_1_ip, + secgroup_name=TESTCASE_CONFIG.secgroup_name, + compute_node=av_zone_1, + userdata=userdata_common) + instance_ids.append(vm_bgpvpn) + + # wait for VM to get IP + instance_up = test_utils.wait_for_instances_up(vm_bgpvpn) + if not instance_up: + logger.error("One or more instances are down") + + test_utils.create_network_association( + neutron_client, bgpvpn_id, net_1_id) + + test_utils.wait_before_subtest() + + msg = ("External IP prefix %s is exchanged with ODL" + % TESTCASE_CONFIG.external_network_ip_prefix) + fib_added = test_utils.is_fib_entry_present_on_odl( + controllers, + TESTCASE_CONFIG.external_network_ip_prefix, + TESTCASE_CONFIG.route_distinguishers) + if fib_added: + results.add_success(msg) + else: + results.add_failure(msg) + + # TODO: uncomment the following once OVS is installed with > 2.8.3 and + # underlay connectivity is established between vxlan overlay and + # external network. + # results.get_ping_status_target_ip( + # vm_bgpvpn, + # TESTCASE_CONFIG.external_network_name, + # TESTCASE_CONFIG.external_network_ip, + # expected="PASS", + # timeout=300) + + results.add_to_summary(0, "=") + logger.info("\n%s" % results.summary) + except Exception as e: logger.error("exception occurred while executing testcase_3: %s", e) raise @@ -315,6 +403,14 @@ def main(): test_utils.cleanup_neutron(neutron_client, floatingip_ids, bgpvpn_ids, interfaces, subnet_ids, router_ids, network_ids) + bgp_nbr_disconnect_cmd = ("bgp-nbr -i %s -a 200 del" + % fake_fip['fip_addr']) + bgp_server_stop_cmd = ("bgp-rtr -r %s -a 100 del" + % controller_ext_ip) + odl_zrpc_disconnect_cmd = "bgp-connect -p 7644 -h 127.0.0.1 del" + test_utils.run_odl_cmd(controller, bgp_nbr_disconnect_cmd) + test_utils.run_odl_cmd(controller, bgp_server_stop_cmd) + test_utils.run_odl_cmd(controller, odl_zrpc_disconnect_cmd) return results.compile_summary() |