diff options
24 files changed, 765 insertions, 785 deletions
diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 00000000000..271514c669f --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,6 @@ +/env +/outputs +/output.xml +/log.html +/report.html +*.pyc diff --git a/test/README b/test/README new file mode 100644 index 00000000000..862541a67a6 --- /dev/null +++ b/test/README @@ -0,0 +1,17 @@ +# STEPS TO START DEVELOPING TESTS LOCALLY + - install virtualenv + - generate environment using virtualenv: + # cd $ROOT + # virtualenv env + # source env/bin/activate + - install python requirements for this project by executing: + # pip install -r requirements.txt + - make sure user mentioned in topology.py has NOPASSWD sudo access to + vpe_api_test + + + Done. + +# STEPS TO START THE TESTS +export PYTHONPATH=. +pybot -L TRACE -V resources/libraries/python/topology.py tests diff --git a/test/main.py b/test/main.py new file mode 100644 index 00000000000..f18c6dba35c --- /dev/null +++ b/test/main.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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 os +import robot +from robot.run import RobotFramework +from robot.conf.settings import RobotSettings +from robot.running.builder import TestSuiteBuilder +from robot.running.model import TestSuite + + +def get_suite_list(*datasources, **options): + class _MyRobotFramework(RobotFramework): + def main(self, datasources, **options): + # copied from robot.run.RobotFramework.main + settings = RobotSettings(options) + suite = TestSuiteBuilder(settings['SuiteNames'], + settings['WarnOnSkipped']).build(*datasources) + suite.configure(**settings.suite_config) + + return suite + + # Options are in robot.conf.settings + suite = _MyRobotFramework().execute(*datasources, **options) + if isinstance(suite, TestSuite): + suites = [] + suites.append(suite) + append_new = True + while append_new: + append_new = False + tmp = [] + for s in suites: + if len(s.suites._items) > 0: + for i in s.suites._items: + tmp.append(i) + append_new = True + else: + tmp.append(s) + suites = tmp + return suites + else: + # TODO: add from robot.errors typ error + return [] + + +def run_suites(test_dir, suites, out_dir="./outputs", **options): + # TODO: add logic + + try: + for f in os.listdir(out_dir): + os.remove('/'.join((out_dir, f))) + except OSError: + pass + if not os.path.exists(out_dir): + os.makedirs(out_dir) + + for s in suites: + longname = s.longname + varfile=[] + varfile.append('resources/libraries/python/topology.py') + + # TODO: check testcases Tags + + with open('{}/{}.out'.format(out_dir, longname), 'w') as out, \ + open('{}/{}.log'.format(out_dir, longname), 'w') as debug: + robot.run(test_dir, + suite=[longname], + output='{}/{}.xml'.format(out_dir, longname), + debugfile=debug, + log=None, + report=None, + stdout=out, + variablefile=varfile, + **options) + + +def parse_outputs(out_dir='./'): + outs = ['/'.join((out_dir, file)) for file in os.listdir(out_dir) if file.endswith('.xml')] + robot.rebot(*outs, merge=True) + + +if __name__ == "__main__": + i = [] + e = [] + # i = ['bd', 'ip'] + # i = ['hw'] + # e = ['hw'] + test_dir = "./tests" + out_dir = "./outputs" + + suite_list = get_suite_list(test_dir, include=i, exclude=e, output=None, dryrun=True) + run_suites(test_dir, suite_list, include=i, exclude=e, out_dir=out_dir) + parse_outputs(out_dir=out_dir) diff --git a/test/requirements.txt b/test/requirements.txt new file mode 100644 index 00000000000..0850b3d9488 --- /dev/null +++ b/test/requirements.txt @@ -0,0 +1,3 @@ +robotframework +paramiko +scp diff --git a/test/resources/libraries/bash/dut_setup.sh b/test/resources/libraries/bash/dut_setup.sh new file mode 100644 index 00000000000..c6cbd031f1a --- /dev/null +++ b/test/resources/libraries/bash/dut_setup.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +echo vpe process +ps aux | grep vpe + +echo Free memory +free -m + +echo List vpp packages +dpkg -l \*vpp\* + + +echo List /proc/meminfo +cat /proc/meminfo + + diff --git a/test/resources/libraries/python/DUTSetup.py b/test/resources/libraries/python/DUTSetup.py new file mode 100644 index 00000000000..c09975f29ce --- /dev/null +++ b/test/resources/libraries/python/DUTSetup.py @@ -0,0 +1,40 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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 robot.api import logger +from topology import NodeType +from ssh import SSH + +class DUTSetup(object): + + def __init__(self): + pass + + def setup_all_duts(self, nodes): + """Prepare all DUTs in given topology for test execution.""" + for node in nodes.values(): + if node['type'] == NodeType.DUT: + self.setup_dut(node) + + def setup_dut(self, node): + ssh = SSH() + ssh.connect(node) + + ssh.scp('resources/libraries/bash/dut_setup.sh', '/tmp/dut_setup.sh') + (ret_code, stdout, stderr) = \ + ssh.exec_command('sudo -Sn bash /tmp/dut_setup.sh') + logger.trace(stdout) + if 0 != int(ret_code): + logger.error('DUT {0} setup script failed: "{1}"'. + format(node['host'], stdout + stderr)) + raise Exception('DUT test setup script failed at node {}'. + format(node['host'])) diff --git a/test/resources/libraries/python/SetupFramework.py b/test/resources/libraries/python/SetupFramework.py new file mode 100644 index 00000000000..8fd712f5388 --- /dev/null +++ b/test/resources/libraries/python/SetupFramework.py @@ -0,0 +1,92 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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 shlex +from ssh import SSH +from subprocess import Popen, PIPE, call +from tempfile import NamedTemporaryFile +from os.path import basename +from constants import Constants as con +from robot.api import logger + +__all__ = ["SetupFramework"] + +class SetupFramework(object): + """Setup suite run on topology nodes. + + Many VAT/CLI based tests need the scripts at remote hosts before executing + them. This class packs the whole testing directory and copies it over + to all nodes in topology under /tmp/ + + """ + + def __init__(self): + pass + + def __pack_framework_dir(self): + """Pack the testing WS into temp file, return its name.""" + + tmpfile = NamedTemporaryFile(suffix=".tgz", prefix="openvpp-testing-") + file_name = tmpfile.name + tmpfile.close() + + proc = Popen(shlex.split("tar -zcf {0} .".format(file_name)), + stdout=PIPE, stderr=PIPE) + (stdout, stderr) = proc.communicate() + + logger.debug(stdout) + logger.debug(stderr) + + return_code = proc.wait() + if 0 != return_code: + raise Exception("Could not pack testing framework.") + + return file_name + + def __copy_tarball_to_node(self, tarball, node): + logger.console('Copying tarball to {0}'.format(node['host'])) + ssh = SSH() + ssh.connect(node) + + ssh.scp(tarball, "/tmp/") + + def __extract_tarball_at_node(self, tarball, node): + logger.console('Extracting tarball to {0} on {1}'.format( + con.REMOTE_FW_DIR, node['host'])) + ssh = SSH() + ssh.connect(node) + + cmd = 'rm -rf {1}; mkdir {1} ; sudo -Sn tar -zxf {0} -C {1};'.format( + tarball, con.REMOTE_FW_DIR) + (ret_code, stdout, stderr) = ssh.exec_command(cmd, timeout=30) + if 0 != ret_code: + logger.error('Unpack error: {0}'.format(stderr)) + raise Exception('Failed to unpack {0} at node {1}'.format( + tarball, node['host'])) + + def __delete_local_tarball(self, tarball): + call(shlex.split('sh -c "rm {0} > /dev/null 2>&1"'.format(tarball))) + + def setup_framework(self, nodes): + """Pack the whole directory and extract in temp on each node.""" + + tarball = self.__pack_framework_dir() + logger.console('Framework packed to {0}'.format(tarball)) + remote_tarball = "/tmp/{0}".format(basename(tarball)) + + for node in nodes.values(): + self.__copy_tarball_to_node(tarball, node) + self.__extract_tarball_at_node(remote_tarball, node) + + logger.trace('Test framework copied to all topology nodes') + self.__delete_local_tarball(tarball) + diff --git a/test/resources/libraries/python/VatExecutor.py b/test/resources/libraries/python/VatExecutor.py new file mode 100644 index 00000000000..55a0454bcb5 --- /dev/null +++ b/test/resources/libraries/python/VatExecutor.py @@ -0,0 +1,84 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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 os +from ssh import SSH +from robot.api import logger + +__all__ = [] + +class VatExecutor(object): + + __TMP_DIR = "/tmp/" + __VAT_BIN = "vpe_api_test" + + def __init__(self): + self._stdout = None + self._stderr = None + self._ret_code = None + + def execute_script(self, local_path, node, timeout=10, json_out=True): + """Copy local_path script to node, execute it and return result. + + Returns (rc, stdout, stderr tuple). + """ + + ssh = SSH() + ssh.connect(node) + + local_basename = os.path.basename(local_path) + remote_file_path = self.__TMP_DIR + local_basename + remote_file_out = remote_file_path + ".out" + + ssh.scp(local_path, remote_file_path) + + cmd = "sudo -S {vat} {json} < {input}".format(vat=self.__VAT_BIN, + json="json" if json_out == True else "", + input=remote_file_path) + (ret_code, stdout, stderr) = ssh.exec_command(cmd, timeout) + self._ret_code = ret_code + self._stdout = stdout + self._stderr = stderr + + logger.trace("Command '{0}' returned {1}'".format(cmd, self._ret_code)) + logger.trace("stdout: '{0}'".format(self._stdout)) + logger.trace("stderr: '{0}'".format(self._stderr)) + + #TODO: download vpe_api_test output file + self._delete_files(node, remote_file_path, remote_file_out) + + def _delete_files(self, node, *files): + ssh = SSH() + ssh.connect(node) + files = " ".join([str(x) for x in files]) + ssh.exec_command("rm {0}".format(files)) + + def script_should_have_failed(self): + if self._ret_code is None: + raise Exception("First execute the script!") + if self._ret_code == 0: + raise AssertionError( + "Script execution passed, but failure was expected") + + def script_should_have_passed(self): + if self._ret_code is None: + raise Exception("First execute the script!") + if self._ret_code != 0: + raise AssertionError( + "Script execution failed, but success was expected") + + def get_script_stdout(self): + return self._stdout + + def get_script_stderr(self): + return self._stderr + diff --git a/test/resources/libraries/python/constants.py b/test/resources/libraries/python/constants.py new file mode 100644 index 00000000000..8c92993c7cf --- /dev/null +++ b/test/resources/libraries/python/constants.py @@ -0,0 +1,15 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +class Constants(object): + #OpenVPP testing directory location at topology nodes + REMOTE_FW_DIR = '/tmp/openvpp-testing' diff --git a/test/resources/libraries/python/ssh.py b/test/resources/libraries/python/ssh.py new file mode 100644 index 00000000000..0887a765ba5 --- /dev/null +++ b/test/resources/libraries/python/ssh.py @@ -0,0 +1,127 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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 paramiko +from scp import SCPClient +from time import time +from robot.api import logger + +__all__ = ["exec_cmd"] + +# TODO: Attempt to recycle SSH connections +# TODO: load priv key + +class SSH(object): + + __MAX_RECV_BUF = 10*1024*1024 + __existing_connections = {} + + def __init__(self): + self._ssh = paramiko.SSHClient() + self._ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self._hostname = None + + def _node_hash(self, node): + return hash(frozenset([node['host'], node['port']])) + + def connect(self, node): + """Connect to node prior to running exec_command or scp. + + If there already is a connection to the node, this method reuses it. + """ + self._hostname = node['host'] + node_hash = self._node_hash(node) + if node_hash in self.__existing_connections: + self._ssh = self.__existing_connections[node_hash] + else: + start = time() + self._ssh.connect(node['host'], username=node['username'], + password=node['password']) + self.__existing_connections[node_hash] = self._ssh + logger.trace('connect took {} seconds'.format(time() - start)) + + def exec_command(self, cmd, timeout=10): + """Execute SSH command on a new channel on the connected Node. + + Returns (return_code, stdout, stderr). + """ + start = time() + chan = self._ssh.get_transport().open_session() + if timeout is not None: + chan.settimeout(int(timeout)) + chan.exec_command(cmd) + end = time() + logger.trace('exec_command "{0}" on {1} took {2} seconds'.format(cmd, + self._hostname, end-start)) + + + stdout = "" + while True: + buf = chan.recv(self.__MAX_RECV_BUF) + stdout += buf + if not buf: + break + + stderr = "" + while True: + buf = chan.recv_stderr(self.__MAX_RECV_BUF) + stderr += buf + if not buf: + break + + return_code = chan.recv_exit_status() + logger.trace('chan_recv/_stderr took {} seconds'.format(time()-end)) + + return (return_code, stdout, stderr) + + def scp(self, local_path, remote_path): + """Copy files from local_path to remote_path. + + connect() method has to be called first! + """ + logger.trace('SCP {0} to {1}:{2}'.format( + local_path, self._hostname, remote_path)) + # SCPCLient takes a paramiko transport as its only argument + scp = SCPClient(self._ssh.get_transport()) + start = time() + scp.put(local_path, remote_path) + scp.close() + end = time() + logger.trace('SCP took {0} seconds'.format(end-start)) + +def exec_cmd(node, cmd, timeout=None): + """Convenience function to ssh/exec/return rc & out. + + Returns (rc, stdout). + """ + if node is None: + raise TypeError('Node parameter is None') + if cmd is None: + raise TypeError('Command parameter is None') + if len(cmd) == 0: + raise ValueError('Empty command parameter') + + ssh = SSH() + try: + ssh.connect(node) + except Exception, e: + logger.error("Failed to connect to node" + e) + return None + + try: + (ret_code, stdout, stderr) = ssh.exec_command(cmd, timeout=timeout) + except Exception, e: + logger.error(e) + return None + + return (ret_code, stdout, stderr) + diff --git a/test/resources/libraries/python/topology.py b/test/resources/libraries/python/topology.py new file mode 100644 index 00000000000..16b8f317394 --- /dev/null +++ b/test/resources/libraries/python/topology.py @@ -0,0 +1,50 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. + +#Defines nodes and topology structure. + +__all__ = ["DICT__nodes"] + + +class NodeType(object): + DUT = 'DUT' + TG = 'TG' + +MOCK_DATA_FOR_NOW = { + 'nodes' : { + 'DUT1' : { + 'type' : NodeType.DUT, + 'host' : 'wasa-ucs-14', + 'port' : 22, + 'username' : '', + 'password' : '', + }, + 'DUT2' : { + 'type' : NodeType.DUT, + 'host' : 'wasa-ucs-13', + 'port' : 22, + 'username' : '', + 'password' : '', + }, + 'TG' : { + 'type' : NodeType.TG, + 'host' : 'wasa-ucs-12', + 'port' : 22, + 'username' : '', + 'password' : '', + }, + } + } + +DICT__nodes = MOCK_DATA_FOR_NOW['nodes'] + diff --git a/test/resources/libraries/robot/default.robot b/test/resources/libraries/robot/default.robot new file mode 100644 index 00000000000..4b102f5525a --- /dev/null +++ b/test/resources/libraries/robot/default.robot @@ -0,0 +1,20 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Library | resources/libraries/python/DUTSetup.py + +*** Keywords *** +| Setup all DUTs before test +| | [Documentation] | Setup all DUTs in topology before test execution +| | Setup All DUTs | ${nodes} + diff --git a/test/resources/libraries/robot/interfaces.robot b/test/resources/libraries/robot/interfaces.robot new file mode 100644 index 00000000000..924d98f141b --- /dev/null +++ b/test/resources/libraries/robot/interfaces.robot @@ -0,0 +1,20 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Resource | resources/libraries/robot/vat/interfaces.robot + +*** Keywords *** +| VPP reports interfaces on | [Arguments] | ${node} +| | VPP reports interfaces through VAT on | ${node} +#| | VPP reports interfaces through ODL on | ${node} +#| | VPP reports interfaces through DEBUGCLI on | ${node} diff --git a/test/resources/libraries/robot/vat/interfaces.robot b/test/resources/libraries/robot/vat/interfaces.robot new file mode 100644 index 00000000000..37c9ffbbbd1 --- /dev/null +++ b/test/resources/libraries/robot/vat/interfaces.robot @@ -0,0 +1,23 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Library | resources/libraries/python/VatExecutor.py + +*** Variables *** +| ${VAT_DUMP_INTERFACES} | resources/templates/vat/dump_interfaces.vat + +*** Keywords *** +| VPP reports interfaces through VAT on +| | [Arguments] | ${node} +| | Execute Script | ${VAT_DUMP_INTERFACES} | ${node} +| | Script Should Have Passed diff --git a/test/resources/templates/vat/dump_interfaces.vat b/test/resources/templates/vat/dump_interfaces.vat new file mode 100644 index 00000000000..dfc5e6939df --- /dev/null +++ b/test/resources/templates/vat/dump_interfaces.vat @@ -0,0 +1,3 @@ +sw_interface_dump +dump_interface_table +quit diff --git a/test/tests/suites/__init__.robot b/test/tests/suites/__init__.robot new file mode 100644 index 00000000000..5959befce1d --- /dev/null +++ b/test/tests/suites/__init__.robot @@ -0,0 +1,15 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Library | resources/libraries/python/SetupFramework.py +| Suite Setup | Setup Framework | ${nodes} diff --git a/test/tests/suites/bridge_domain/test.robot b/test/tests/suites/bridge_domain/test.robot new file mode 100644 index 00000000000..06b05cd5f97 --- /dev/null +++ b/test/tests/suites/bridge_domain/test.robot @@ -0,0 +1,26 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Resource | resources/libraries/robot/default.robot +| Resource | resources/libraries/robot/interfaces.robot +| Test Setup | Setup all DUTs before test + +*** Test Cases *** +| VPP reports interfaces +| | VPP reports interfaces on | ${nodes['DUT1']} + + +| Loop the test +| | : FOR | ${INDEX} | in range | 10 +| | | VPP reports interfaces on | ${nodes['DUT1']} + diff --git a/test/tests/suites/vhost_user_dummy/__init__.robot b/test/tests/suites/vhost_user_dummy/__init__.robot new file mode 100644 index 00000000000..f1b637aaf6d --- /dev/null +++ b/test/tests/suites/vhost_user_dummy/__init__.robot @@ -0,0 +1,14 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Documentation | Dummy test suite to test suite execution diff --git a/test/tests/suites/vhost_user_dummy/test1.robot b/test/tests/suites/vhost_user_dummy/test1.robot new file mode 100644 index 00000000000..b5ad24cc12e --- /dev/null +++ b/test/tests/suites/vhost_user_dummy/test1.robot @@ -0,0 +1,18 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Force Tags | vhost-user | hw + +*** Test Cases *** +| Create vhost user interface on hw +| | Log | interface created diff --git a/test/tests/suites/vhost_user_dummy/test2.robot b/test/tests/suites/vhost_user_dummy/test2.robot new file mode 100644 index 00000000000..742f409c741 --- /dev/null +++ b/test/tests/suites/vhost_user_dummy/test2.robot @@ -0,0 +1,18 @@ +# Copyright (c) 2015 Cisco and/or its affiliates. +# 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. +*** Settings *** +| Force Tags | vhost-user | virl + +*** Test Cases *** +| Create vhost user interface on virl +| | Log | interface created diff --git a/vnet/vnet/map/examples/gen-rules.py b/vnet/vnet/map/examples/gen-rules.py index d6746f79af4..ba6dde09aa8 100755 --- a/vnet/vnet/map/examples/gen-rules.py +++ b/vnet/vnet/map/examples/gen-rules.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.4 +#!/usr/bin/env python3 # Copyright (c) 2015 Cisco and/or its affiliates. # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,194 +20,83 @@ import sys # map add domain ip4-pfx <pfx> ip6-pfx ::/0 ip6-src <ip6-src> ea-bits-len 0 psid-offset 6 psid-len 6 # map add rule index <0> psid <psid> ip6-dst <ip6-dst> +def_ip4_pfx = '192.0.2.0/24' +def_ip6_pfx = '2001:db8::/32' +def_ip6_src = '2001:db8::1' +def_psid_offset = 6 +def_psid_len = 6 +def_ea_bits_len = 14 + + parser = argparse.ArgumentParser(description='MAP VPP configuration generator') parser.add_argument('-t', action="store", dest="mapmode") +parser.add_argument('--ip4-prefix', action="store", dest="ip4_pfx", default=def_ip4_pfx) +parser.add_argument('--ip6-prefix', action="store", dest="ip6_pfx", default=def_ip6_pfx) +parser.add_argument('--ip6-src', action="store", dest="ip6_src", default=def_ip6_src) +parser.add_argument('--psid-len', action="store", dest="psid_len", default=def_psid_len) +parser.add_argument('--psid-offset', action="store", dest="psid_offset", default=def_psid_offset) +parser.add_argument('--ea-bits-len', action="store", dest="ea_bits_len", default=def_ea_bits_len) args = parser.parse_args() -# -# 1:1 Shared IPv4 address, shared BR, Terastream -# -def terastream(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/22') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 6 - ip6_src = ipaddress.ip_address('cccc:bbbb::') - for i in range(ip4_pfx.num_addresses): - if not i % 64: - ip6_src = ip6_src + 1 - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-src " + str(ip6_src) + - " ea-bits-len 0 psid-offset 0 psid-len", psid_len) - for psid in range(0x1 << psid_len): - print("map add rule index", i, "psid", psid, "ip6-dst", ip6_dst[(i * (0x1<<psid_len)) + psid]) # -# 1:1 Shared IPv4 address, shared BR, OTE +# Algorithmic mapping Shared IPv4 address # -def oteshared11(): - ip4_pfx = ipaddress.ip_network('2.84.63.0/24') - dst = list(ipaddress.ip_network('2a02:580:8c00::/40').subnets(new_prefix=56)) - psid_len = 6 - ip6_src = ipaddress.ip_address('2a02::') - for i in range(ip4_pfx.num_addresses): - if not i % 64: - ip6_src = ip6_src + 1 - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-src " + str(ip6_src) + - " ea-bits-len 0 psid-offset 6 psid-len", psid_len) - for psid in range(0x1 << psid_len): - enduserprefix = list(dst.pop(0).subnets(new_prefix=64))[255-1] - print("map add rule index", i, "psid", psid, "ip6-dst", enduserprefix[(i * (0x1<<psid_len)) + psid]) - +def algo(ip4_pfx_str, ip6_pfx_str, ip6_src_str, psid_len, ea_bits_len, ip6_src_ecmp = False): + print("map add domain ip4-pfx " + ip4_pfx_str + " ip6-pfx " + ip6_pfx_str + " ip6-src " + ip6_src_str + + " ea-bits-len " + str(ea_bits_len) + " psid-offset 6 psid-len " + str(psid_len)) # -# 1:1 Shared IPv4 address, shared BR, Terastream +# 1:1 Full IPv4 address # -def confdterastream(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/22') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 6 - ip6_src = ipaddress.ip_address('cccc:bbbb::') - for i in range(ip4_pfx.num_addresses): - if not i % 64: - ip6_src = ip6_src + 1 - print("vpp softwire softwire-instances softwire-instance", i, "br-ipv6 " + str(ip6_src) + " ipv6-prefix ::/0" + " ipv4-prefix " + str(ip4_pfx[i]) + - "/32 ea-len 0 psid-offset 6 psid-len", psid_len) -# print("vpp softwire softwire-instances softwire-instance", i, "ipv4-pfx " + str(ip4_pfx[i]) + "/32 ipv6-pfx ::/0 br-ipv6 " + str(ip6_src) + -# " ea-len 0 psid-offset 6 psid-len", psid_len) - for psid in range(0x1 << psid_len): - print("binding", psid, "ipv6-addr", ip6_dst[(i * (0x1<<psid_len)) + psid]) - -def shared11br_yang(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/16') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 6 - for i in range(ip4_pfx.num_addresses): - print("vpp softwire softwire-instances softwire-instance " + str(i) + " ipv4-prefix " + str(ip4_pfx[i]) + "/32 " + - "ipv6-prefix ::/0 ea-len 0 psid-offset 6 tunnel-mtu 1234 psid-len", psid_len) - #print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-shared-src cccc:bbbb::1", - # "ea-bits-len 0 psid-offset 6 psid-len", psid_len) - for psid in range(0x1 << psid_len): - # print("map add rule index", i, "psid", psid, "ip6-dst", ip6_dst[(i * (0x1<<psid_len)) + psid]) - print("binding", psid, "ipv6-addr", ip6_dst[(i * (0x1<<psid_len)) + psid]) +def lw46(ip4_pfx_str, ip6_pfx_str, ip6_src_str, psid_len, ea_bits_len, ip6_src_ecmp = False): + ip4_pfx = ipaddress.ip_network(ip4_pfx_str) + ip6_src = ipaddress.ip_address(ip6_src_str) + ip6_dst = ipaddress.ip_network(ip6_pfx_str) + psid_len = 0 + mod = ip4_pfx.num_addresses / 1024 -def shared11br_xml(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/32') - ip6_dst = ipaddress.ip_network('bbbb::/32') - ip6_src = ipaddress.ip_address('cccc:bbbb::') - psid_len = 6 - print('<vpp xmlns="http://www.cisco.com/yang/cisco-vpp"><softwire><softwire-instances>'); - count = 1024; for i in range(ip4_pfx.num_addresses): - if not i % 64: + print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx " + str(ip6_dst[i]) + "/128 ip6-src", + ip6_src, "ea-bits-len 0 psid-offset 0 psid-len 0") + if ip6_src_ecmp and not i % mod: ip6_src = ip6_src + 1 - if count == 0: - break; - count = count - 1; - print('<softwire-instance>') - print(' <id>'+ str(i)+ '</id>') - print(' <ipv4-prefix>'+ str(ip4_pfx[i])+ '/32</ipv4-prefix>') - print(' <ipv6-prefix>::/0</ipv6-prefix>') - print(' <ea-len>0</ea-len>') - print(' <psid-offset>0</psid-offset>') - print(' <psid-len>'+ str(psid_len) + '</psid-len>') - for psid in range(0x1 << psid_len): - print(' <binding>') - print(' <psid>', psid, '</psid>') - print(' <ipv6-addr>'+ str(ip6_dst[(i * (0x1<<psid_len)) + psid]) + '</ipv6-addr>') - print(' </binding>') - print('</softwire-instance>') - print('</softwire-instances></softwire>') - print('</vpp>') - -# -# 1:1 Shared IPv4 address, shared BR -# -def shared11br(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/16') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 6 - for i in range(ip4_pfx.num_addresses): - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-shared-src cccc:bbbb::1", - "ea-bits-len 0 psid-offset 6 psid-len", psid_len) - for psid in range(0x1 << psid_len): - print("map add rule index", i, "psid", psid, "ip6-dst", ip6_dst[(i * (0x1<<psid_len)) + psid]) # -# 1:1 Shared IPv4 address, shared BR +# 1:1 Shared IPv4 address, shared BR (16) VPP CLI # -def shared11br(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/16') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 6 - for i in range(ip4_pfx.num_addresses): - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-shared-src cccc:bbbb::1", - "ea-bits-len 0 psid-offset 6 psid-len", psid_len) - for psid in range(0x1 << psid_len): - print("map add rule index", i, "psid", psid, "ip6-dst", ip6_dst[(i * (0x1<<psid_len)) + psid]) +def lw46_shared(ip4_pfx_str, ip6_pfx_str, ip6_src_str, psid_len, ea_bits_len, ip6_src_ecmp = False): + ip4_pfx = ipaddress.ip_network(ip4_pfx_str) + ip6_src = ipaddress.ip_address(ip6_src_str) + ip6_dst = ipaddress.ip_network(ip6_pfx_str) + mod = ip4_pfx.num_addresses / 1024 -# -# 1:1 Shared IPv4 address -# -def shared11(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/16') - ip6_src = ipaddress.ip_network('cccc:bbbb::/64') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 6 for i in range(ip4_pfx.num_addresses): - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-src", ip6_src[i], - "ea-bits-len 0 psid-offset 6 psid-len", psid_len) + print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-src " + str(ip6_src) + + " ea-bits-len 0 psid-offset 0 psid-len", psid_len) for psid in range(0x1 << psid_len): print("map add rule index", i, "psid", psid, "ip6-dst", ip6_dst[(i * (0x1<<psid_len)) + psid]) + if ip6_src_ecmp and not i % mod: + ip6_src = ip6_src + 1 # -# 1:1 Shared IPv4 address small +# 1:1 Shared IPv4 address, shared BR # -def smallshared11(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/24') - ip6_src = ipaddress.ip_network('cccc:bbbb::/64') - ip6_dst = ipaddress.ip_network('bbbb::/32') +def lw46_shared_b(ip4_pfx_str, ip6_pfx_str, ip6_src_str, psid_len, ea_bits_len, ip6_src_ecmp = False): + ip4_pfx = ipaddress.ip_network(ip4_pfx_str) + ip6_src = ipaddress.ip_address(ip6_src_str) + ip6_dst = list(ipaddress.ip_network(ip6_pfx_str).subnets(new_prefix=56)) psid_len = 6 - for i in range(ip4_pfx.num_addresses): - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-src", ip6_src[i], - "ea-bits-len 0 psid-offset 6 psid-len", psid_len) - for psid in range(0x1 << psid_len): - print("map add rule index", i, "psid", psid, "ip6-dst", ip6_dst[(i * (0x1<<psid_len)) + psid]) -# -# 1:1 Full IPv4 address -# -def full11(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/16') - ip6_src = ipaddress.ip_network('cccc:bbbb::/64') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 0 - for i in range(ip4_pfx.num_addresses): - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx " + str(ip6_dst[i]) + "/128 ip6-src", ip6_src[i], - "ea-bits-len 0 psid-offset 0 psid-len 0") -def full11br(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/16') - ip6_dst = ipaddress.ip_network('bbbb::/32') - psid_len = 0 - for i in range(ip4_pfx.num_addresses): - print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx " + str(ip6_dst[i]) + "/128 ip6-shared-src cccc:bbbb::1", - "ea-bits-len 0 psid-offset 0 psid-len 0") - -# -# Algorithmic mapping Shared IPv4 address -# -def algo(): - print("map add domain ip4-pfx 20.0.0.0/24 ip6-pfx bbbb::/32 ip6-src cccc:bbbb::1 ea-bits-len 16 psid-offset 6 psid-len 8") - print("map add domain ip4-pfx 20.0.1.0/24 ip6-pfx bbbb:1::/32 ip6-src cccc:bbbb::2 ea-bits-len 8 psid-offset 0 psid-len 0") - -# -# IP4 forwarding -# -def ip4(): - ip4_pfx = ipaddress.ip_network('20.0.0.0/16') for i in range(ip4_pfx.num_addresses): - print("ip route add " + str(ip4_pfx[i]) + "/32 via 172.16.0.2") - - -globals()[args.mapmode]() - + if not i % 64: + ip6_src = ip6_src + 1 + print("map add domain ip4-pfx " + str(ip4_pfx[i]) + "/32 ip6-pfx ::/0 ip6-src " + str(ip6_src) + + " ea-bits-len 0 psid-offset 6 psid-len", psid_len) + for psid in range(0x1 << psid_len): + enduserprefix = list(ip6_dst.pop(0).subnets(new_prefix=64))[255-1] + print("map add rule index", i, "psid", psid, "ip6-dst", enduserprefix[(i * (0x1<<psid_len)) + psid]) +globals()[args.mapmode](args.ip4_pfx, args.ip6_pfx, args.ip6_src, args.psid_len, args.psid_offset, + args.ea_bits_len) diff --git a/vnet/vnet/map/examples/map-test.py b/vnet/vnet/map/examples/map-test.py deleted file mode 100755 index 01f377fb6ee..00000000000 --- a/vnet/vnet/map/examples/map-test.py +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env python -# Copyright (c) 2015 Cisco and/or its affiliates. -# 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 sys, time -from scapy.all import * - -import mapalgs - - -ifname = "vpp-tap" - -loc_v4_mac = "aa:aa:aa:aa:aa:a4" -loc_v6_mac = "aa:aa:aa:aa:aa:a6" -vpp_mac = "aa:aa:aa:aa:00:00" - -map_t = 1 - -fragsize = 0 -map_mtu = 200 - -def mac_to_vppmac(mac): - mac = mac.replace(':', '') - return mac[0:4]+"."+mac[4:8]+"."+mac[8:12] - - -map = mapalgs.MapCalc( rulev6 = 'bbbb::/32', - rulev4 = '20.0.0.0/24', - ratio = 256); - -dmr = mapalgs.DmrCalc('cccc:bbbb::/96') - - -ICMP_TYPES_CODES = { - 0: 0, - 3: 15, - 4: 0, - 5: 3, - 6: 0, - 8: 0, - 9: 0, - 10: 0, - 11: 1, - 12: 2, - 13: 0, - 14: 0, - 15: 0, - 16: 0, - 17: 0, - 18: 0 -} - -ICMP6_TYPES_CODES = { - 1: 7, - 2: 0, - 3: 1, - 4: 3, -} - -def net_conf(): - c = "" - c += "tap connect "+ifname+" hwaddr "+mac_to_vppmac(vpp_mac)+" \n" - c += "set int state tap-0 up \n" - c += "set ip6 neighbor tap-0 2001:f00d::1 "+mac_to_vppmac(loc_v6_mac)+" \n" - c += "set ip arp tap-0 10.0.0.1 "+mac_to_vppmac(loc_v4_mac)+" \n" - c += "ip route add ::/0 via 2001:f00d::1 tap-0 \n" - c += "ip route add 0.0.0.0/0 via 10.0.0.1 tap-0 \n" - return c - -def conf(): - c = net_conf() - c += "map add domain ip4-pfx 20.0.0.0/24 ip6-pfx bbbb::/32 ea-bits-len 16 psid-offset 6 psid-len 8" - if map_mtu != 0: - c += " mtu "+str(map_mtu) - if map_t: - c += " ip6-src cccc:bbbb::/96 map-t" - else: - c += " ip6-src cccc:bbbb::ffff" - - c += "\n" - return c - -def send_packet(ip_header, ip_content): - print("Send packet") - if fragsize != 0: - if ip_header.version == 4: - frags = fragment(ip_header/ip_content, fragsize=fragsize) - for f in frags: - print("Fragmented IPv4 packet") - sendp(Ether(dst=vpp_mac, src=loc_v4_mac)/f, iface=ifname) - elif ip_header.version == 6: - frags = fragment6(ip_header/IPv6ExtHdrFragment()/ip_content, fragsize) - for f in frags: - print("Fragmented IPv6 packet") - sendp(Ether(dst=vpp_mac, src=loc_v6_mac)/f, iface=ifname) - else: - sendp(Ether(dst=vpp_mac)/ip_header/ip_content, iface=ifname) - -def send_packet_frag_inner(packet, inner_header, inner_content): - print("Send packet with inner ICMP packet") - if fragsize != 0: - if packet.version == 4: - frags = fragment(inner_header/inner_content, fragsize=fragsize) - for f in frags: - print("Fragmented IPv4 inner packet") - sendp(Ether(dst=vpp_mac, src=loc_v4_mac)/packet/f, iface=ifname) - elif packet.version == 6: - frags = fragment6(inner_header/IPv6ExtHdrFragment()/inner_content, fragsize) - for f in frags: - print("Fragmented IPv6 inner packet") - sendp(Ether(dst=vpp_mac, src=loc_v6_mac)/packet/f, iface=ifname) - else: - sendp(Ether(dst=vpp_mac)/packet/inner_header/inner_content, iface=ifname) - - -def sendv6udp(src, dst, port): - psid = map.gen_psid(port) - ceaddr = str(map.get_mapce_addr(src, psid)) - dst = str(dmr.embed_6052addr(dst)) - send_packet(IPv6(dst=dst, src=ceaddr), UDP(sport=port)/('X'*900)) - -def sendv6tcp(src, dst, port): - psid = map.gen_psid(port) - ceaddr = str(map.get_mapce_addr(src, psid)) - dst = str(dmr.embed_6052addr(dst)) - send_packet(IPv6(dst=dst, src=ceaddr), TCP(sport=port)/('X'*900)) - -def sendv4udp(src, dst, port): - send_packet(IP(dst=dst, src=src), UDP(dport=port)/('X'*900)) - -def sendv4tcp(src, dst, port): - send_packet(IP(dst=dst, src=src), TCP(dport=port)/('X'*900)) - -def sendv6ping(src, dst, id): - psid = map.gen_psid(id) - ceaddr = str(map.get_mapce_addr(src, psid)) - dst = str(dmr.embed_6052addr(dst)) - send_packet(IPv6(dst=dst, src=ceaddr), ICMPv6EchoRequest(id=id, data='A'*500)) - send_packet(IPv6(dst=dst, src=ceaddr), ICMPv6EchoReply(id=id, data='A'*500)) - -def sendv4ping(src, dst, id): - send_packet(IP(dst=dst, src=src), ICMP(id=id, type=0)/('X'*500)) - send_packet(IP(dst=dst, src=src), ICMP(id=id, type=8)/('X'*500)) - -def sendv4icmperr(src, dst, type, code, port, inner_src, inner_dst, payload_length): - inner = IP(dst=inner_dst, src=inner_src)/TCP(sport=port, dport=8888)/('X'*payload_length) - send_packet_frag_inner(IP(dst=dst, src=src)/ICMP(type=type, code=code), IP(dst=inner_dst, src=inner_src), TCP(sport=port, dport=8888)/('X'*payload_length)) - #send_packet(IP(dst=dst, src=src)/ICMP(type=type, code=code)/inner) - -def sendv6icmperr(src, dst, type, code, port, payload_length): - psid = map.gen_psid(port) - src = str(map.get_mapce_addr(src, psid)) - dst = str(dmr.embed_6052addr(dst)) - inner_header = IPv6(dst=src, src=dst) - inner_content = TCP(sport=8888, dport=port)/('X'*payload_length) - send_packet_frag_inner(IPv6(dst=dst, src=src)/ICMPv6DestUnreach(type=type, code=code), inner_header, inner_content) - #send_packet(IPv6(dst=dst, src=src)/ICMPv6DestUnreach(type=type, code=code)/inner) - -def sendv4icmp_errors(src, dst, port, inner_src, inner_dst, payload_length): - for type in ICMP_TYPES_CODES: - for code in range(0, ICMP_TYPES_CODES[type] + 1): - sendv4icmperr(src, dst, type, code, port, inner_src, inner_dst, payload_length) - #sendv4icmperr(src, dst, type, ICMP_TYPES_CODES[type] + 2, port, inner_src, inner_dst, payload_length) - #sendv4icmperr(src, dst, type, 255, port, inner_src, inner_dst, payload_length) - #sendv4icmperr(src, dst, 1, 0, port, inner_src, inner_dst, payload_length) - #sendv4icmperr(src, dst, 2, 10, port, inner_src, inner_dst, payload_length) - #sendv4icmperr(src, dst, 255, 255, port, inner_src, inner_dst, payload_length) - - #TODO: Check wrong paramater with different pointer values - -def sendv6icmp_errors(src, dst, port, payload_length): - for type in ICMP6_TYPES_CODES: - for code in range(0, ICMP6_TYPES_CODES[type] + 1): - sendv6icmperr(src, dst, type, code, port, payload_length) - #sendv6icmperr(src, dst, type, ICMP6_TYPES_CODES[type] + 2, port, payload_length) - #sendv6icmperr(src, dst, type, 255, port, payload_length) - - -def traffic(): - delay = 2.0 - while 1: - #sendp(Ether(dst="bb:bb:bb:bb:bb:b4")/IP(dst="20.0.0.1")/UDP(chksum=0)/('X'*900), iface="vpp-tapv4") - #sendp(Ether(dst="bb:bb:bb:bb:bb:b6")/IPv6(dst="cccc:bbbb::a000:0001")/ICMPv6EchoRequest()/('X'*900), iface="vpp-tapv6") - #sendp(Ether(dst="bb:bb:bb:bb:bb:b6")/IPv6(dst="cccc:bbbb::a000:0001")/UDP()/('X'*900), iface="vpp-tapv6") - sendv6udp("20.0.0.1", "10.0.0.1", 12001) - sendv6tcp("20.0.0.1", "10.0.0.1", 12002) - sendv4udp("10.0.0.1", "20.0.0.1", 12003) - sendv4tcp("10.0.0.1", "20.0.0.1", 12004) - sendv6ping("20.0.0.1", "10.0.0.1", 12005) - sendv4ping("10.0.0.1", "20.0.0.1", 12006) - sendv4icmp_errors("10.0.0.1", "20.0.0.1", 12006, "20.0.0.1", "10.0.0.1", 500) - sendv4icmp_errors("10.0.0.1", "20.0.0.1", 12006, "20.0.0.1", "10.0.0.1", 1500) - sendv6icmp_errors("20.0.0.1", "10.0.0.1", 12006, 500) - time.sleep(delay) - delay *= 0.9 - -if len(sys.argv) <= 1: - print("Usage: conf|traffic") - exit(1) - -if sys.argv[1] == "conf": - print(conf()) -elif sys.argv[1] == "traffic": - traffic()
\ No newline at end of file diff --git a/vnet/vnet/map/examples/mapalgs.py b/vnet/vnet/map/examples/mapalgs.py deleted file mode 100644 index 50a0ed0a3ee..00000000000 --- a/vnet/vnet/map/examples/mapalgs.py +++ /dev/null @@ -1,327 +0,0 @@ -#!/usr/bin/env python3 - -# The MIT License (MIT) -# -# Copyright (c) 2015 -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# File included from https://github.com/ejordangottlieb/pyswmap -# Thanks to jordan ;) -# - Pierre -# - -# There is still a great deal of work required on this module. Please -# use with caution. -# -Jordan - -import sys -from ipaddress import ( - IPv6Address, - IPv6Network, - ip_network, - ip_address, - ) -from math import ( - log, - ) - -class MapCalc(object): - - def __init__(self,**bmr): - #rulev6,rulev4): - self.portranges = False - - # Validate and set BMR and BMR derived values - self._check_bmr_values(bmr) - - def _check_bmr_values(self,bmr): - # Assume these values have not been supplied. Validate later. - self.ealen = False - self.ratio = False - - # Validate that a proper PSID Offset has been set - if 'psidoffset' not in bmr: - # Set Default PSID Offset of 6 if it is not set - self.psidoffset = 6 - else: - self.psidoffset = self._psid_offset(bmr['psidoffset']) - - # Validate that a proper IPv4 rule prefix is defined - if 'rulev4' not in bmr: - print("The rule IPv4 prefix has not been set") - sys.exit(1) - else: - self.rulev4 = self._ipv4_rule(bmr['rulev4']) - - # Validate that a proper IPv6 rule prefix is defined - if 'rulev6' not in bmr: - print("The rule IPv6 prefix has not been set") - sys.exit(1) - else: - self.rulev6 = self._ipv6_rule(bmr['rulev6']) - - # Check if EA length was passed - if 'ealen' not in bmr: - self.ealen = False - else: - self.ealen = bmr['ealen'] - self.ratio = self._calc_ratio(bmr['ealen']) - - # Check if sharing ratio was passed or calculated by _calc_ratio - if 'ratio' not in bmr: - # Skip if we have already calculated ratio - if not (self.ratio): - self.ratio = False - else: - if (self.ealen): - # Check to see if supplied EA length contradicts supplied ratio - if ( bmr['ratio'] != self.ratio ): - eavalue = "EA value {}".format(self.ealen) - sharingratio = "sharing ratio {}".format(bmr['ratio']) - print("Supplied {} and {} are contradictory".format( - eavalue, - sharingratio) - ) - sys.exit(1) - else: - self.ratio = bmr['ratio'] - self.ealen = self._calc_ea(bmr['ratio']) - - # EA length or sharing ratio must be set - if not ( self.ealen or self.ratio): - print("The BMR must include an EA length or sharing ratio") - sys.exit(1) - - # Since we have not hit an exception we can calculate the port bits - self.portbits = self._calc_port_bits() - - def _ipv4_rule(self,rulev4): - try: - self.rulev4mask = ip_network( - rulev4, - strict=False - ).prefixlen - except ValueError: - print("Invalid IPv4 prefix {}".format(rulev4)) - sys.exit(1) - - self.rulev4object = ip_network(rulev4) - - return rulev4 - - def _ipv6_rule(self,rulev6): - try: - self.rulev6mask = IPv6Network( - rulev6, - strict=False - ).prefixlen - except ValueError: - print("Invalid IPv6 prefix {}".format(rulev6)) - sys.exit(1) - - return rulev6 - - def _psid_offset(self,psidoffset): - PSIDOFFSET_MAX = 6 - if psidoffset in range(0,PSIDOFFSET_MAX+1): - return psidoffset - else: - print("Invalid PSID Offset value: {}".format(psidoffset)) - sys.exit(1) - - def _psid_range(self,x): - rset = [] - for i in range(0,x+1): - rset.append(2**i) - return rset - - def _calc_port_bits(self): - portbits = 16 - self.psidoffset - self.psidbits - return portbits - - def _calc_ea(self,ratio): - if ratio not in ( self._psid_range(16) ): - print("Invalid ratio {}".format(ratio)) - print("Ratio between 2 to the power of 0 thru 16") - sys.exit(1) - - if ( 1 == ratio): - self.psidbits = 0 - else: - self.psidbits = int(log(ratio,2)) - ealen = self.psidbits + ( 32 - self.rulev4mask ) - return ealen - - def _calc_ratio(self,ealen): - maskbits = 32 - self.rulev4mask - if ( ealen < maskbits ): - print("EA of {} incompatible with rule IPv4 prefix {}".format( - ealen, - self.rulev4, - ) - ) - print("EA length must be at least {} bits".format( - maskbits, - ) - ) - sys.exit(1) - - self.psidbits = ealen - ( 32 - self.rulev4mask ) - if ( self.psidbits > 16): - print("EA length of {} is too large".format( - ealen, - ) - ) - print("EA should not exceed {} for rule IPv4 prefix {}".format( - maskbits + 16, - self.rulev4, - ) - ) - sys.exit(1) - ratio = 2**self.psidbits - return ratio - - def gen_psid(self,portnum): - if ( portnum < self.start_port() ): - print("port value is less than allowed by PSID Offset") - sys.exit(1) - psid = (portnum & ((2**self.psidbits - 1) << self.portbits)) - psid = psid >> self.portbits - return psid - - def port_ranges(self): - return 2**self.psidoffset - 1 - - def start_port(self): - if self.psidoffset == 0: return 0 - return 2**(16 - self.psidoffset) - - def port_list(self,psid): - startrange = psid * (2**self.portbits) + self.start_port() - increment = (2**self.psidbits) * (2**self.portbits) - portlist = [ ] - for port in range(startrange,startrange + 2**self.portbits): - if port >= 65536: continue - portlist.append(port) - for x in range(1,self.port_ranges()): - startrange += increment - for port in range(startrange,startrange + 2**self.portbits): - portlist.append(port) - return portlist - - def ipv4_index(self,ipv4addr): - if ip_address(ipv4addr) in ip_network(self.rulev4): - x = ip_address(ipv4addr) - y = ip_network(self.rulev4,strict=False).network_address - self.ipv4addr = x - return ( int(x) - int(y) ) - else: - print("Error: IPv4 address {} not in Rule IPv4 subnet {}".format( - ipv4add, - ip_network(self.rulev4,strict=False).network_address)) - sys.exit(1) - - def _calc_ipv6bit_pos(self): - addroffset = 128 - (self.rulev6mask + ( self.ealen - self.psidbits)) - psidshift = 128 - ( self.rulev6mask + self.ealen ) - return [addroffset,psidshift] - - def _append_map_eabits(self,ipv4index,addroffset,psidshift,psid): - rulev6base = IPv6Network(self.rulev6,strict=False).network_address - map_prefix = int(rulev6base) | ( ipv4index << addroffset ) - map_fullprefix = map_prefix | ( psid << psidshift) - return map_fullprefix - - - def get_mapce_addr(self,ipv4addr,psid): - ipv4index = self.ipv4_index(ipv4addr) - (addroffset,psidshift) = self._calc_ipv6bit_pos() - map_fullprefix = self._append_map_eabits(ipv4index, - addroffset, - psidshift, - psid) - mapv4iid = map_fullprefix | ( int(self.ipv4addr) << 16 ) - map_full_address = mapv4iid | psid - mapce_address = "{}".format(IPv6Address(map_full_address)) - return mapce_address - - def get_mapce_prefix(self,ipv4addr,psid): - ipv4index = self.ipv4_index(ipv4addr) - (addroffset,psidshift) = self._calc_ipv6bit_pos() - map_fullprefix = self._append_map_eabits(ipv4index, - addroffset, - psidshift, - psid) - mapce_prefix = "{}/{}".format( - IPv6Address(map_fullprefix), - self.rulev6mask + self.ealen - ) - return mapce_prefix - - def get_map_ipv4(self,mapce_address): - ipv4 = (int(IPv6Address(mapce_address)) & ( 0xffffffff << 16 )) >> 16 - return ip_address(ipv4) - - - -class DmrCalc(object): - - def __init__(self,dmr): - - # Validate and set BMR and BMR derived values - self.dmrprefix = self._check_dmr_prefix(dmr) - - def embed_6052addr(self,ipv4addr): - - try: - ipv4addrint = int(ip_address(ipv4addr)) - except ValueError: - print("Invalid IPv4 address {}".format(ipv4addr)) - sys.exit(1) - - if ( self.dmrprefix.prefixlen == 64 ): - ipv6int = ipv4addrint << 24 - ipv6int += int(self.dmrprefix.network_address) - return IPv6Address(ipv6int) - - if ( self.dmrprefix.prefixlen == 96 ): - ipv6int = ipv4addrint - ipv6int += int(self.dmrprefix.network_address) - return IPv6Address(ipv6int) - - def _check_dmr_prefix(self,dmrprefix): - try: - self.dmrmask = IPv6Network( - dmrprefix, - strict=False - ).prefixlen - except ValueError: - print("Invalid IPv6 prefix {}".format(prefix)) - sys.exit(1) - - if self.dmrmask not in (32,40,48,56,64,96): - print("Invalid prefix mask /{}".format(self.dmrmask)) - sys.exit(1) - - return IPv6Network(dmrprefix) - -if __name__ == "__main__": - m = DmrCalc('fd80::/48') - print(m.dmrprefix) diff --git a/vnet/vnet/map/examples/mt-test.py b/vnet/vnet/map/examples/mt-test.py deleted file mode 100644 index 62d269c7a13..00000000000 --- a/vnet/vnet/map/examples/mt-test.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2009-2014 Cisco and/or its affiliates. -# 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 threading -import time -from scapy.all import * -from Queue import * - -iface = 'veth1' - -class SnifferThread(threading.Thread) : - def __init__(self,q,iface,flt,timeout) : - threading.Thread.__init__(self) - self.q = q - self.iface = iface - self.timeout = timeout - self.flt = flt - print("Sniffers reporting for service on ",self.iface) - - def run(self) : - conf.iface=self.iface - conf.iface6=self.iface - - r = sniff(filter=self.flt,iface=self.iface,timeout=self.timeout,prn=lambda x: x.summary()) - self.q.put(r) - - - -# New "SR" function -# Fire off thread with filter and expected answer packet(s). -# Fire off sniffer thread, main thread sends packet -# Returns true if found - -def sr2(answer, *args, **kwargs): - q = Queue() - print("Creating SnifferThreadWorkerThread") - flt='ip proto 41' - iface='veth1' - sniffer = SnifferThread(q,iface,flt,1) - sniffer.setDaemon(True) - sniffer.start() - - print "Sending packet:" - send(*args, **kwargs) - sniffer.join() - ps = q.get() - -# ps.summary() - print "Number of packets sniffed:", len(ps) - - for p in ps: - ip = p.getlayer(1) - print "Comparing", ip.summary(), "and", answer.summary() - if ip == answer: - print "We have a match!!" - return True - return False - -aip6 = IPv6(dst='2002:0a0a:0a0a::12')/ICMPv6EchoRequest() -answer= IP(src="10.0.0.100",dst="10.10.10.10",ttl=63)/aip6 -packet = IPv6(dst='2002:0a0a:0a0a::12')/ICMPv6EchoRequest() - -# From IPv6 -sr2(answer, packet,iface='veth1') - -#From IPv4 -packet = IP(src='10.10.10.10',dst='10.0.0.100')/IPv6(src='2002:0a0a:0a0a::12',dst='1::2')/ICMPv6EchoRequest() -sr2(answer, packet,iface='veth1') |