From d3ee35dc0015e073b7138f3b02508b40fc6288b1 Mon Sep 17 00:00:00 2001 From: Martin Banszel Date: Wed, 19 Jul 2017 19:35:02 +0000 Subject: Add fixes for heat deployed UDP_Replay and TRex - Added a PROTOCOL_MAP to map the protocol names to codes -- the scapy requires the code, it fails if the proto is set e.g. to 'udp' - ip addresses must be str, not unicode -- explicit conversion to str added - removed unittest for setup_vnf_environment in test_tg_trex.py as it is the same function as already tested in test_sample_vnf.py - traffic_profile refactored -- code repetition decreased, unittest adapted Known issues: - there is a an attempt to stop already stopped trex. It fires an exception that stop command is issued on the disconnected client. Change-Id: I87e9029630f48b30e8f5b4f9d88ab3b25fd65f03 Signed-off-by: Martin Banszel --- .../tc_heat_rfc2544_ipv4_1flow_64B_trex.yaml | 79 +++ .../traffic_profile/test_traffic_profile.py | 150 ++-- .../vnf_generic/vnf/test_tg_rfc2544_trex.py | 5 +- .../vnf_generic/vnf/test_tg_trex.py | 223 +++++- .../vnf_generic/vnf/test_udp_replay.py | 785 ++++++++++++--------- .../network_services/helpers/samplevnf_helper.py | 9 +- yardstick/network_services/nfvi/resource.py | 1 + .../traffic_profile/traffic_profile.py | 385 +++++----- .../network_services/vnf_generic/vnf/sample_vnf.py | 10 +- .../network_services/vnf_generic/vnf/tg_trex.py | 19 +- .../network_services/vnf_generic/vnf/udp_replay.py | 65 +- 11 files changed, 1016 insertions(+), 715 deletions(-) create mode 100644 samples/vnf_samples/nsut/udp_replay/tc_heat_rfc2544_ipv4_1flow_64B_trex.yaml diff --git a/samples/vnf_samples/nsut/udp_replay/tc_heat_rfc2544_ipv4_1flow_64B_trex.yaml b/samples/vnf_samples/nsut/udp_replay/tc_heat_rfc2544_ipv4_1flow_64B_trex.yaml new file mode 100644 index 000000000..09a20c33d --- /dev/null +++ b/samples/vnf_samples/nsut/udp_replay/tc_heat_rfc2544_ipv4_1flow_64B_trex.yaml @@ -0,0 +1,79 @@ +# Copyright (c) 2016 Intel Corporation +# +# 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. + +--- +schema: yardstick:task:0.1 +scenarios: +- type: NSPerf + traffic_profile: ../../traffic_profiles/ipv4_throughput.yaml + topology: udp_replay-vnf-topology.yaml + nodes: + tg__1: trafficgen_1.yardstick + vnf__1: vnf.yardstick + options: + packetsize: 64 + traffic_type: 4 + vnf__1: + hw_csum: false + tg__1: + hw_csum: false + rfc2544: + allowed_drop_rate: 0.0001 - 0.0001 + runner: + type: Iteration + iterations: 10 + interval: 35 + traffic_options: + flow: ../../traffic_profiles/ipv4_1flow_Packets.yaml + imix: ../../traffic_profiles/imix_voice.yaml +context: + name: yardstick + image: yardstick-samplevnfs + user: ubuntu + nfvi_type: heat + flavor: + vcpus: 10 + ram: 20480 + disk: 4 + extra_specs: + hw:cpu_sockets: 1 + hw:cpu_cores: 10 + hw:cpu_threads: 1 + placement_groups: + pgrp1: + policy: "availability" + + servers: + vnf: + floating_ip: true + placement: "pgrp1" + trafficgen_1: + floating_ip: true + placement: "pgrp1" + + networks: + mgmt: + cidr: '10.0.1.0/24' + xe0: + cidr: '10.0.2.0/24' + vld_id: public + enable_dhcp: False + gateway_ip: null + port_security_enabled: False + xe1: + cidr: '10.0.3.0/24' + vld_id: private + enable_dhcp: False + gateway_ip: null + port_security_enabled: False diff --git a/tests/unit/network_services/traffic_profile/test_traffic_profile.py b/tests/unit/network_services/traffic_profile/test_traffic_profile.py index 9a78c36a3..55e7d483a 100644 --- a/tests/unit/network_services/traffic_profile/test_traffic_profile.py +++ b/tests/unit/network_services/traffic_profile/test_traffic_profile.py @@ -29,8 +29,16 @@ stl_patch.start() if stl_patch: from yardstick.network_services.traffic_profile.base import TrafficProfile - from yardstick.network_services.traffic_profile.traffic_profile import \ - TrexProfile + from yardstick.network_services.traffic_profile.traffic_profile import TrexProfile + from yardstick.network_services.traffic_profile.traffic_profile import SRC + from yardstick.network_services.traffic_profile.traffic_profile import DST + from yardstick.network_services.traffic_profile.traffic_profile import ETHERNET + from yardstick.network_services.traffic_profile.traffic_profile import IP + from yardstick.network_services.traffic_profile.traffic_profile import IPv6 + from yardstick.network_services.traffic_profile.traffic_profile import UDP + from yardstick.network_services.traffic_profile.traffic_profile import SRC_PORT + from yardstick.network_services.traffic_profile.traffic_profile import DST_PORT + from yardstick.network_services.traffic_profile.traffic_profile import TYPE_OF_SERVICE class TestTrexProfile(unittest.TestCase): @@ -44,6 +52,10 @@ class TestTrexProfile(unittest.TestCase): "flow_number": 10, "frame_size": 64}} + EXAMPLE_ETHERNET_ADDR = "00:00:00:00:00:01" + EXAMPLE_IP_ADDR = "10.0.0.1" + EXAMPLE_IPv6_ADDR = "0064:ff9b:0:0:0:0:9810:6414" + PROFILE = {'description': 'Traffic profile to run RFC2544 latency', 'name': 'rfc2544', 'traffic_profile': {'traffic_type': 'RFC2544Profile', @@ -129,87 +141,6 @@ class TestTrexProfile(unittest.TestCase): TrexProfile(TrafficProfile) self.assertEqual(None, trex_profile.execute({})) - def test_set_src_mac(self): - src_mac = "00:00:00:00:00:01" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_src_mac(src_mac)) - - src_mac = "00:00:00:00:00:01-00:00:00:00:00:02" - self.assertEqual(None, trex_profile.set_src_mac(src_mac)) - - def test_set_dst_mac(self): - dst_mac = "00:00:00:00:00:03" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_dst_mac(dst_mac)) - - dst_mac = "00:00:00:00:00:03-00:00:00:00:00:04" - self.assertEqual(None, trex_profile.set_dst_mac(dst_mac)) - - def test_set_src_ip4(self): - src_ipv4 = "152.16.100.20" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_src_ip4(src_ipv4)) - - src_ipv4 = "152.16.100.20-152.16.100.30" - self.assertEqual(None, trex_profile.set_src_ip4(src_ipv4)) - - def test_set_dst_ip4(self): - dst_ipv4 = "152.16.100.20" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_dst_ip4(dst_ipv4)) - - dst_ipv4 = "152.16.100.20-152.16.100.30" - self.assertEqual(None, trex_profile.set_dst_ip4(dst_ipv4)) - - def test_set_src_ip6(self): - src_ipv6 = "0064:ff9b:0:0:0:0:9810:6414" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_src_ip6(src_ipv6)) - - src_ipv6 = "0064:ff9b:0:0:0:0:9810:6414-0064:ff9b:0:0:0:0:9810:6420" - self.assertEqual(None, trex_profile.set_src_ip6(src_ipv6)) - - def test_set_dst_ip6(self): - dst_ipv6 = "0064:ff9b:0:0:0:0:9810:6414" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_dst_ip6(dst_ipv6)) - - dst_ipv6 = "0064:ff9b:0:0:0:0:9810:6414-0064:ff9b:0:0:0:0:9810:6420" - self.assertEqual(None, trex_profile.set_dst_ip6(dst_ipv6)) - - def test_dscp(self): - dscp = "0" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_dscp(dscp)) - - dscp = "0-1" - self.assertEqual(None, trex_profile.set_dscp(dscp)) - - def test_src_port(self): - port = "1234" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_src_port(port)) - - port = "1234-5678" - self.assertEqual(None, trex_profile.set_src_port(port)) - - def test_dst_port(self): - port = "1234" - trex_profile = \ - TrexProfile(TrafficProfile) - self.assertEqual(None, trex_profile.set_dst_port(port)) - - port = "1234-5678" - self.assertEqual(None, trex_profile.set_dst_port(port)) - def test_qinq(self): qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0}, "C-VLAN": {"id": 512, "priority": 0, "cfi": 0}} @@ -222,36 +153,36 @@ class TestTrexProfile(unittest.TestCase): "C-VLAN": {"id": "512-515", "priority": 0, "cfi": 0}} self.assertEqual(None, trex_profile.set_qinq(qinq)) - def test_set_outer_l2_fields(self): + def test__set_outer_l2_fields(self): trex_profile = \ TrexProfile(TrafficProfile) qinq = {"S-VLAN": {"id": 128, "priority": 0, "cfi": 0}, "C-VLAN": {"id": 512, "priority": 0, "cfi": 0}} outer_l2 = self.PROFILE['private']['ipv4']['outer_l2'] outer_l2['QinQ'] = qinq - self.assertEqual(None, trex_profile.set_outer_l2_fields(outer_l2)) + self.assertEqual(None, trex_profile._set_outer_l2_fields(outer_l2)) - def test_set_outer_l3v4_fields(self): + def test__set_outer_l3v4_fields(self): trex_profile = \ TrexProfile(TrafficProfile) outer_l3v4 = self.PROFILE['private']['ipv4']['outer_l3v4'] outer_l3v4['proto'] = 'tcp' - self.assertEqual(None, trex_profile.set_outer_l3v4_fields(outer_l3v4)) + self.assertEqual(None, trex_profile._set_outer_l3v4_fields(outer_l3v4)) - def test_set_outer_l3v6_fields(self): + def test__set_outer_l3v6_fields(self): trex_profile = \ TrexProfile(TrafficProfile) outer_l3v6 = self.PROFILE_v6['private']['ipv6']['outer_l3v4'] outer_l3v6['proto'] = 'tcp' outer_l3v6['tc'] = 1 outer_l3v6['hlim'] = 10 - self.assertEqual(None, trex_profile.set_outer_l3v6_fields(outer_l3v6)) + self.assertEqual(None, trex_profile._set_outer_l3v6_fields(outer_l3v6)) - def test_set_outer_l4_fields(self): + def test__set_outer_l4_fields(self): trex_profile = \ TrexProfile(TrafficProfile) outer_l4 = self.PROFILE['private']['ipv4']['outer_l4'] - self.assertEqual(None, trex_profile.set_outer_l4_fields(outer_l4)) + self.assertEqual(None, trex_profile._set_outer_l4_fields(outer_l4)) def test_get_streams(self): trex_profile = \ @@ -284,3 +215,40 @@ class TestTrexProfile(unittest.TestCase): TrexProfile(TrafficProfile) self.assertRaises(SystemExit, trex_profile._get_start_end_ipv6, "1.1.1.3", "1.1.1.1") + + def test__general_single_action_partial(self): + trex_profile = TrexProfile(TrafficProfile) + + trex_profile._general_single_action_partial(ETHERNET)(SRC)(self.EXAMPLE_ETHERNET_ADDR) + self.assertEqual(self.EXAMPLE_ETHERNET_ADDR, trex_profile.ether_packet.src) + + trex_profile._general_single_action_partial(IP)(DST)(self.EXAMPLE_IP_ADDR) + self.assertEqual(self.EXAMPLE_IP_ADDR, trex_profile.ip_packet.dst) + + trex_profile._general_single_action_partial(IPv6)(DST)(self.EXAMPLE_IPv6_ADDR) + self.assertEqual(self.EXAMPLE_IPv6_ADDR, trex_profile.ip6_packet.dst) + + trex_profile._general_single_action_partial(UDP)(SRC_PORT)(5060) + self.assertEqual(5060, trex_profile.udp_packet.sport) + + trex_profile._general_single_action_partial(IP)(TYPE_OF_SERVICE)(0) + self.assertEqual(0, trex_profile.ip_packet.tos) + + def test__set_proto_addr(self): + trex_profile = TrexProfile(TrafficProfile) + + ether_range = "00:00:00:00:00:01-00:00:00:00:00:02" + ip_range = "1.1.1.2-1.1.1.10" + ipv6_range = '0064:ff9b:0:0:0:0:9810:6414-0064:ff9b:0:0:0:0:9810:6420' + + trex_profile._set_proto_addr(ETHERNET, SRC, ether_range) + trex_profile._set_proto_addr(ETHERNET, DST, ether_range) + trex_profile._set_proto_addr(IP, SRC, ip_range) + trex_profile._set_proto_addr(IP, DST, ip_range) + trex_profile._set_proto_addr(IPv6, SRC, ipv6_range) + trex_profile._set_proto_addr(IPv6, DST, ipv6_range) + trex_profile._set_proto_addr(UDP, SRC_PORT, "5060-5090") + trex_profile._set_proto_addr(UDP, DST_PORT, "5060") + + + diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py index ad8c6494e..6f2a9445f 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_trex.py @@ -21,9 +21,9 @@ import unittest import mock from tests.unit import STL_MOCKS +SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' -SSH_HELPER = "yardstick.ssh.SSH" STLClient = mock.MagicMock() stl_patch = mock.patch.dict("sys.modules", STL_MOCKS) @@ -252,6 +252,8 @@ class TestTrexTrafficGenRFC(unittest.TestCase): trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) trex_traffic_gen._start_server = mock.Mock(return_value=0) trex_traffic_gen.resource_helper = mock.MagicMock() + trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() + scenario_cfg = { "tc": "tc_baremetal_rfc2544_ipv4_1flow_64B", "topology": 'nsb_test_case.yaml', @@ -286,6 +288,7 @@ class TestTrexTrafficGenRFC(unittest.TestCase): trex_traffic_gen = TrexTrafficGenRFC('vnf1', self.VNFD_0) trex_traffic_gen.resource_helper = mock.MagicMock() + trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() scenario_cfg = { "tc": "tc_baremetal_rfc2544_ipv4_1flow_64B", "nodes": [ diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py index 65370dfa5..9d1ce1520 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_trex.py @@ -20,6 +20,8 @@ from __future__ import absolute_import import unittest import mock +SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' + from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh from tests.unit import STL_MOCKS @@ -112,16 +114,197 @@ class TestTrexTrafficGen(unittest.TestCase): "traffic_type": "FixedTraffic", "frame_rate": 100, # pps "flow_number": 10, - "frame_size": 64}} + "frame_size": 64 + }, + } + + SCENARIO_CFG = { + "options": { + "packetsize": 64, + "traffic_type": 4, + "rfc2544": { + "allowed_drop_rate": "0.8 - 1", + }, + "vnf__1": { + "rules": "acl_1rule.yaml", + "vnf_config": { + "lb_config": "SW", + "lb_count": 1, + "worker_config": "1C/1T", + "worker_threads": 1, + } + } + }, + "task_id": "a70bdf4a-8e67-47a3-9dc1-273c14506eb7", + "tc": "tc_ipv4_1Mflow_64B_packetsize", + "runner": { + "object": "NetworkServiceTestCase", + "interval": 35, + "output_filename": "/tmp/yardstick.out", + "runner_id": 74476, "duration": 400, + "type": "Duration" + }, + "traffic_profile": "ipv4_throughput_acl.yaml", + "traffic_options": { + "flow": "ipv4_Packets_acl.yaml", + "imix": "imix_voice.yaml" + }, + "type": "ISB", + "nodes": { + "tg__2": "trafficgen_2.yardstick", + "tg__1": "trafficgen_1.yardstick", + "vnf__1": "vnf.yardstick" + }, + "topology": "udpreplay-tg-topology-baremetal.yaml" + } + + CONTEXT_CFG = { + "nodes": { + "vnf__1": { + "vnfd-id-ref": "vnf__1", + "ip": "1.2.1.1", + "interfaces": { + "xe0": { + "local_iface_name": "ens786f0", + "vld_id": "private", + "netmask": "255.255.255.0", + "vpci": "0000:05:00.0", + "local_ip": "152.16.100.19", + "driver": "i40e", + "dst_ip": "152.16.100.20", + "local_mac": "00:00:00:00:00:02", + "dst_mac": "00:00:00:00:00:04", + "dpdk_port_num": 0 + }, + "xe1": { + "local_iface_name": "ens786f1", + "vld_id": "public", + "netmask": "255.255.255.0", + "vpci": "0000:05:00.1", + "local_ip": "152.16.40.19", + "driver": "i40e", + "dst_ip": "152.16.40.20", + "local_mac": "00:00:00:00:00:01", + "dst_mac": "00:00:00:00:00:03", + "dpdk_port_num": 1 + } + }, + "host": "1.2.1.1", + "user": "root", + "nd_route_tbl": [ + { + "netmask": "112", + "if": "xe0", + "gateway": "0064:ff9b:0:0:0:0:9810:6414", + "network": "0064:ff9b:0:0:0:0:9810:6414" + }, + { + "netmask": "112", + "if": "xe1", + "gateway": "0064:ff9b:0:0:0:0:9810:2814", + "network": "0064:ff9b:0:0:0:0:9810:2814" + } + ], + "password": "r00t", + "VNF model": "udp_replay.yaml", + "name": "vnf.yardstick", + "member-vnf-index": "2", + "routing_table": [ + { + "netmask": "255.255.255.0", + "if": "xe0", + "gateway": "152.16.100.20", + "network": "152.16.100.20" + }, + { + "netmask": "255.255.255.0", + "if": "xe1", + "gateway": "152.16.40.20", + "network": "152.16.40.20" + } + ], + "role": "vnf" + }, + "trafficgen_2.yardstick": { + "member-vnf-index": "3", + "role": "TrafficGen", + "name": "trafficgen_2.yardstick", + "vnfd-id-ref": "tg__2", + "ip": "1.2.1.1", + "interfaces": { + "xe0": { + "local_iface_name": "ens513f0", + "vld_id": "public", + "netmask": "255.255.255.0", + "vpci": "0000:02:00.0", + "local_ip": "152.16.40.20", + "driver": "ixgbe", + "dst_ip": "152.16.40.19", + "local_mac": "00:00:00:00:00:03", + "dst_mac": "00:00:00:00:00:01", + "dpdk_port_num": 0 + }, + "xe1": { + "local_iface_name": "ens513f1", + "netmask": "255.255.255.0", + "network": "202.16.100.0", + "local_ip": "202.16.100.20", + "driver": "ixgbe", + "local_mac": "00:1e:67:d0:60:5d", + "vpci": "0000:02:00.1", + "dpdk_port_num": 1 + } + }, + "password": "r00t", + "VNF model": "l3fwd_vnf.yaml", + "user": "root" + }, + "trafficgen_1.yardstick": { + "member-vnf-index": "1", + "role": "TrafficGen", + "name": "trafficgen_1.yardstick", + "vnfd-id-ref": "tg__1", + "ip": "1.2.1.1", + "interfaces": { + "xe0": { + "local_iface_name": "ens785f0", + "vld_id": "private", + "netmask": "255.255.255.0", + "vpci": "0000:05:00.0", + "local_ip": "152.16.100.20", + "driver": "i40e", + "dst_ip": "152.16.100.19", + "local_mac": "00:00:00:00:00:04", + "dst_mac": "00:00:00:00:00:02", + "dpdk_port_num": 0 + }, + "xe1": { + "local_ip": "152.16.100.21", + "driver": "i40e", + "vpci": "0000:05:00.1", + "dpdk_port_num": 1, + "local_iface_name": "ens785f1", + "netmask": "255.255.255.0", + "local_mac": "00:00:00:00:00:01" + } + }, + "password": "r00t", + "VNF model": "tg_rfc2544_tpl.yaml", + "user": "root" + } + } + } + + - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test___init__(self, ssh): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] trex_traffic_gen = TrexTrafficGen(NAME, vnfd) self.assertIsInstance(trex_traffic_gen.resource_helper, TrexResourceHelper) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test_collect_kpi(self, ssh): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] @@ -130,14 +313,14 @@ class TestTrexTrafficGen(unittest.TestCase): result = trex_traffic_gen.collect_kpi() self.assertEqual({}, result) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test_listen_traffic(self, ssh): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] trex_traffic_gen = TrexTrafficGen(NAME, vnfd) self.assertIsNone(trex_traffic_gen.listen_traffic({})) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test_instantiate(self, ssh): mock_ssh(ssh) @@ -150,9 +333,11 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen._tg_process._is_alive = mock.Mock(return_value=1) trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.instantiate({}, {})) + trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() - @mock.patch("yardstick.ssh.SSH") + self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)) + + @mock.patch(SSH_HELPER) def test_instantiate_error(self, ssh): mock_ssh(ssh, exec_result=(1, "", "")) @@ -164,9 +349,10 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen._tg_process._is_alive = mock.Mock(return_value=0) trex_traffic_gen.ssh_helper = mock.MagicMock() trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() - self.assertIsNone(trex_traffic_gen.instantiate({}, {})) + trex_traffic_gen.setup_helper.setup_vnf_environment = mock.MagicMock() + self.assertIsNone(trex_traffic_gen.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test__start_server(self, ssh): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] @@ -175,7 +361,7 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() self.assertIsNone(trex_traffic_gen._start_server()) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test__traffic_runner(self, ssh): mock_ssh(ssh) @@ -195,7 +381,7 @@ class TestTrexTrafficGen(unittest.TestCase): self.sut.resource_helper.QUEUE_WAIT_TIME = 0 self.sut._traffic_runner(mock_traffic_profile) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test__generate_trex_cfg(self, ssh): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] @@ -203,7 +389,7 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() self.assertIsNone(trex_traffic_gen.resource_helper.generate_cfg()) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test_run_traffic(self, ssh): mock_ssh(ssh) @@ -221,21 +407,14 @@ class TestTrexTrafficGen(unittest.TestCase): self.sut._traffic_process.terminate() self.assertIsNotNone(result) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test_scale(self, ssh): mock_ssh(ssh, exec_result=(1, "", "")) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] trex_traffic_gen = TrexTrafficGen(NAME, vnfd) trex_traffic_gen.scale('') - @mock.patch("yardstick.ssh.SSH") - def test_setup_vnf_environment(self, ssh): - mock_ssh(ssh, exec_result=(1, "", "")) - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - trex_traffic_gen = TrexTrafficGen(NAME, vnfd) - self.assertIsNone(trex_traffic_gen.setup_helper.setup_vnf_environment()) - - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test_terminate(self, ssh): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] @@ -244,7 +423,7 @@ class TestTrexTrafficGen(unittest.TestCase): trex_traffic_gen.resource_helper.ssh_helper = mock.MagicMock() self.assertIsNone(trex_traffic_gen.terminate()) - @mock.patch("yardstick.ssh.SSH") + @mock.patch(SSH_HELPER) def test__connect_client(self, ssh): mock_ssh(ssh) vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] diff --git a/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py b/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py index f0d75d57b..c4ced30fe 100644 --- a/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py +++ b/tests/unit/network_services/vnf_generic/vnf/test_udp_replay.py @@ -22,6 +22,7 @@ import mock import os from tests.unit import STL_MOCKS +SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper' STLClient = mock.MagicMock() @@ -30,269 +31,347 @@ stl_patch.start() if stl_patch: from yardstick.network_services.vnf_generic.vnf.udp_replay import UdpReplayApproxVnf - from yardstick.network_services.vnf_generic.vnf import udp_replay + from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper + +from tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh TEST_FILE_YAML = 'nsb_test_case.yaml' -NAME = "tg__1" +NAME = "vnf__1" @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process") -class TestAclApproxVnf(unittest.TestCase): - VNFD = {'vnfd:vnfd-catalog': - {'vnfd': - [{'short-name': 'VpeVnf', - 'vdu': - [{'routing_table': - [{'network': '152.16.100.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.100.20', - 'if': 'xe0'}, - {'network': '152.16.40.20', - 'netmask': '255.255.255.0', - 'gateway': '152.16.40.20', - 'if': 'xe1'}], - 'description': 'VPE approximation using DPDK', - 'name': 'vpevnf-baremetal', - 'nd_route_tbl': - [{'network': '0064:ff9b:0:0:0:0:9810:6414', - 'netmask': '112', - 'gateway': '0064:ff9b:0:0:0:0:9810:6414', - 'if': 'xe0'}, - {'network': '0064:ff9b:0:0:0:0:9810:2814', - 'netmask': '112', - 'gateway': '0064:ff9b:0:0:0:0:9810:2814', - 'if': 'xe1'}], - 'id': 'vpevnf-baremetal', - 'external-interface': - [{'virtual-interface': - {'dst_mac': '00:00:00:00:00:04', - 'vpci': '0000:05:00.0', - 'local_ip': '152.16.100.19', - 'type': 'PCI-PASSTHROUGH', - 'netmask': '255.255.255.0', - 'dpdk_port_num': '0', - 'bandwidth': '10 Gbps', - 'driver': "i40e", - 'dst_ip': '152.16.100.20', - 'local_iface_name': 'xe0', - 'local_mac': '00:00:00:00:00:02'}, - 'vnfd-connection-point-ref': 'xe0', - 'name': 'xe0'}, - {'virtual-interface': - {'dst_mac': '00:00:00:00:00:03', - 'vpci': '0000:05:00.1', - 'local_ip': '152.16.40.19', - 'type': 'PCI-PASSTHROUGH', - 'driver': "i40e", - 'netmask': '255.255.255.0', - 'dpdk_port_num': '1', - 'bandwidth': '10 Gbps', - 'dst_ip': '152.16.40.20', - 'local_iface_name': 'xe1', - 'local_mac': '00:00:00:00:00:01'}, - 'vnfd-connection-point-ref': 'xe1', - 'name': 'xe1'}]}], - 'description': 'Vpe approximation using DPDK', - 'mgmt-interface': - {'vdu-id': 'vpevnf-baremetal', - 'host': '1.2.1.1', - 'password': 'r00t', - 'user': 'root', - 'ip': '1.2.1.1'}, - 'benchmark': - {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']}, - 'connection-point': [{'type': 'VPORT', 'name': 'xe0'}, - {'type': 'VPORT', 'name': 'xe1'}], - 'id': 'UdpReplayApproxVnf', 'name': 'VPEVnfSsh'}]}} - - scenario_cfg = {'options': {'packetsize': 64, 'traffic_type': 4, - 'rfc2544': {'allowed_drop_rate': '0.8 - 1'}, - 'vnf__1': {'rules': 'acl_1rule.yaml', - 'vnf_config': {'lb_config': 'SW', - 'lb_count': 1, - 'worker_config': - '1C/1T', - 'worker_threads': 1}} - }, - 'task_id': 'a70bdf4a-8e67-47a3-9dc1-273c14506eb7', - 'tc': 'tc_ipv4_1Mflow_64B_packetsize', - 'runner': {'object': 'NetworkServiceTestCase', - 'interval': 35, - 'output_filename': '/tmp/yardstick.out', - 'runner_id': 74476, 'duration': 400, - 'type': 'Duration'}, - 'traffic_profile': 'ipv4_throughput_acl.yaml', - 'traffic_options': {'flow': 'ipv4_Packets_acl.yaml', - 'imix': 'imix_voice.yaml'}, - 'type': 'ISB', - 'nodes': {'tg__2': 'trafficgen_2.yardstick', - 'tg__1': 'trafficgen_1.yardstick', - 'vnf__1': 'vnf.yardstick'}, - 'topology': 'vpe-tg-topology-baremetal.yaml'} - - context_cfg = {'nodes': {'trafficgen_2.yardstick': - {'member-vnf-index': '3', - 'role': 'TrafficGen', - 'name': 'trafficgen_2.yardstick', - 'vnfd-id-ref': 'tg__2', - 'ip': '1.2.1.1', - 'interfaces': - {'xe0': {'local_iface_name': 'ens513f0', - 'vld_id': 'public', - 'netmask': '255.255.255.0', - 'local_ip': '152.16.40.20', - 'dst_mac': '00:00:00:00:00:01', - 'local_mac': '00:00:00:00:00:03', - 'dst_ip': '152.16.40.19', - 'driver': 'ixgbe', - 'vpci': '0000:02:00.0', - 'dpdk_port_num': 0}, - 'xe1': {'local_iface_name': 'ens513f1', - 'netmask': '255.255.255.0', - 'network': '202.16.100.0', - 'local_ip': '202.16.100.20', - 'local_mac': '00:1e:67:d0:60:5d', - 'driver': 'ixgbe', - 'vpci': '0000:02:00.1', - 'dpdk_port_num': 1}}, - 'password': 'r00t', - 'VNF model': 'l3fwd_vnf.yaml', - 'user': 'root'}, - 'trafficgen_1.yardstick': - {'member-vnf-index': '1', - 'role': 'TrafficGen', - 'name': 'trafficgen_1.yardstick', - 'vnfd-id-ref': 'tg__1', - 'ip': '1.2.1.1', - 'interfaces': - {'xe0': {'local_iface_name': 'ens785f0', - 'vld_id': 'private', - 'netmask': '255.255.255.0', - 'local_ip': '152.16.100.20', - 'dst_mac': '00:00:00:00:00:02', - 'local_mac': '00:00:00:00:00:04', - 'dst_ip': '152.16.100.19', - 'driver': 'i40e', - 'vpci': '0000:05:00.0', - 'dpdk_port_num': 0}, - 'xe1': {'local_iface_name': 'ens785f1', - 'netmask': '255.255.255.0', - 'local_ip': '152.16.100.21', - 'local_mac': '00:00:00:00:00:01', - 'driver': 'i40e', - 'vpci': '0000:05:00.1', - 'dpdk_port_num': 1}}, - 'password': 'r00t', - 'VNF model': 'tg_rfc2544_tpl.yaml', - 'user': 'root'}, - 'vnf__1': - {'name': 'vnf.yardstick', - 'vnfd-id-ref': 'vnf__1', - 'ip': '1.2.1.1', - 'interfaces': - {'xe0': {'local_iface_name': 'ens786f0', - 'vld_id': 'private', - 'netmask': '255.255.255.0', - 'local_ip': '152.16.100.19', - 'dst_mac': '00:00:00:00:00:04', - 'local_mac': '00:00:00:00:00:02', - 'dst_ip': '152.16.100.20', - 'driver': 'i40e', - 'vpci': '0000:05:00.0', - 'dpdk_port_num': 0}, - 'xe1': {'local_iface_name': 'ens786f1', - 'vld_id': 'public', - 'netmask': '255.255.255.0', - 'local_ip': '152.16.40.19', - 'dst_mac': '00:00:00:00:00:03', - 'local_mac': '00:00:00:00:00:01', - 'dst_ip': '152.16.40.20', - 'driver': 'i40e', - 'vpci': '0000:05:00.1', - 'dpdk_port_num': 1}}, - 'routing_table': - [{'netmask': '255.255.255.0', - 'gateway': '152.16.100.20', - 'network': '152.16.100.20', - 'if': 'xe0'}, - {'netmask': '255.255.255.0', - 'gateway': '152.16.40.20', - 'network': '152.16.40.20', - 'if': 'xe1'}], - 'member-vnf-index': '2', - 'host': '1.2.1.1', - 'role': 'vnf', - 'user': 'root', - 'nd_route_tbl': - [{'netmask': '112', - 'gateway': '0064:ff9b:0:0:0:0:9810:6414', - 'network': '0064:ff9b:0:0:0:0:9810:6414', - 'if': 'xe0'}, - {'netmask': '112', - 'gateway': '0064:ff9b:0:0:0:0:9810:2814', - 'network': '0064:ff9b:0:0:0:0:9810:2814', - 'if': 'xe1'}], - 'password': 'r00t', - 'VNF model': 'udp_replay.yaml'}}} - - def test___init__(self, mock_process): - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - self.assertIsNone(udp_approx_vnf._vnf_process) +class TestUdpReplayApproxVnf(unittest.TestCase): + + VNFD_0 = { + 'short-name': 'UdpReplayVnf', + 'vdu': [ + { + 'description': 'UDPReplay approximation using DPDK', + 'routing_table': [ + { + 'netmask': '255.255.255.0', + 'if': 'xe0', + 'network': '152.16.100.20', + 'gateway': '152.16.100.20', + }, + { + 'netmask': '255.255.255.0', + 'if': 'xe1', + 'network': '152.16.40.20', + 'gateway': '152.16.40.20', + } + ], + 'external-interface': [ + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:04', + 'driver': 'i40e', + 'local_iface_name': 'xe0', + 'bandwidth': '10 Gbps', + 'local_ip': '152.16.100.19', + 'local_mac': '00:00:00:00:00:02', + 'vpci': '0000:05:00.0', + 'dpdk_port_num': '0', + 'netmask': '255.255.255.0', + 'dst_ip': '152.16.100.20', + 'type': 'PCI-PASSTHROUGH', + }, + 'vnfd-connection-point-ref': 'xe0', + 'name': 'xe0', + }, + { + 'virtual-interface': { + 'dst_mac': '00:00:00:00:00:03', + 'driver': 'i40e', + 'local_iface_name': 'xe1', + 'bandwidth': '10 Gbps', + 'local_ip': '152.16.40.19', + 'local_mac': '00:00:00:00:00:01', + 'vpci': '0000:05:00.1', + 'dpdk_port_num': '1', + 'netmask': '255.255.255.0', + 'dst_ip': '152.16.40.20', + 'type': 'PCI-PASSTHROUGH', + }, + 'vnfd-connection-point-ref': 'xe1', + 'name': 'xe1', + } + ], + 'nd_route_tbl': [ + { + 'netmask': '112', + 'if': 'xe0', + 'network': '0064:ff9b:0:0:0:0:9810:6414', + 'gateway': '0064:ff9b:0:0:0:0:9810:6414', + }, + { + 'netmask': '112', + 'if': 'xe1', + 'network': '0064:ff9b:0:0:0:0:9810:2814', + 'gateway': '0064:ff9b:0:0:0:0:9810:2814', + } + ], + 'id': 'udpreplayvnf-baremetal', + 'name': 'udpreplayvnf-baremetal', + } + ], + 'description': 'UDPReplay approximation using DPDK', + 'name': 'VPEVnfSsh', + 'mgmt-interface': { + 'vdu-id': 'udpreplay-baremetal', + 'host': '1.2.1.1', + 'password': 'r00t', + 'user': 'root', + 'ip': '1.2.1.1', + }, + 'benchmark': { + 'kpi': [ + 'packets_in', + 'packets_fwd', + 'packets_dropped', + ] + }, + 'connection-point': [ + { + 'type': 'VPORT', + 'name': 'xe0', + }, + { + 'type': 'VPORT', + 'name': 'xe1', + } + ], + 'id': 'UdpReplayApproxVnf', + } + + SCENARIO_CFG = { + "options": { + "packetsize": 64, + "traffic_type": 4, + "rfc2544": { + "allowed_drop_rate": "0.8 - 1", + }, + "vnf__1": { + "rules": "acl_1rule.yaml", + "vnf_config": { + "lb_config": "SW", + "lb_count": 1, + "worker_config": "1C/1T", + "worker_threads": 1, + }, + "hw_csum": "false", + } + }, + "task_id": "a70bdf4a-8e67-47a3-9dc1-273c14506eb7", + "tc": "tc_ipv4_1Mflow_64B_packetsize", + "runner": { + "object": "NetworkServiceTestCase", + "interval": 35, + "output_filename": "/tmp/yardstick.out", + "runner_id": 74476, "duration": 400, + "type": "Duration" + }, + "traffic_profile": "ipv4_throughput_acl.yaml", + "traffic_options": { + "flow": "ipv4_Packets_acl.yaml", + "imix": "imix_voice.yaml" + }, + "type": "ISB", + "nodes": { + "tg__2": "trafficgen_2.yardstick", + "tg__1": "trafficgen_1.yardstick", + "vnf__1": "vnf.yardstick" + }, + "topology": "udpreplay-tg-topology-baremetal.yaml" + } + + CONTEXT_CFG = { + "nodes": { + "vnf__1": { + "vnfd-id-ref": "vnf__1", + "ip": "1.2.1.1", + "interfaces": { + "xe0": { + "local_iface_name": "ens786f0", + "vld_id": "private", + "netmask": "255.255.255.0", + "vpci": "0000:05:00.0", + "local_ip": "152.16.100.19", + "driver": "i40e", + "dst_ip": "152.16.100.20", + "local_mac": "00:00:00:00:00:02", + "dst_mac": "00:00:00:00:00:04", + "dpdk_port_num": 0 + }, + "xe1": { + "local_iface_name": "ens786f1", + "vld_id": "public", + "netmask": "255.255.255.0", + "vpci": "0000:05:00.1", + "local_ip": "152.16.40.19", + "driver": "i40e", + "dst_ip": "152.16.40.20", + "local_mac": "00:00:00:00:00:01", + "dst_mac": "00:00:00:00:00:03", + "dpdk_port_num": 1 + } + }, + "host": "1.2.1.1", + "user": "root", + "nd_route_tbl": [ + { + "netmask": "112", + "if": "xe0", + "gateway": "0064:ff9b:0:0:0:0:9810:6414", + "network": "0064:ff9b:0:0:0:0:9810:6414" + }, + { + "netmask": "112", + "if": "xe1", + "gateway": "0064:ff9b:0:0:0:0:9810:2814", + "network": "0064:ff9b:0:0:0:0:9810:2814" + } + ], + "password": "r00t", + "VNF model": "udp_replay.yaml", + "name": "vnf.yardstick", + "member-vnf-index": "2", + "routing_table": [ + { + "netmask": "255.255.255.0", + "if": "xe0", + "gateway": "152.16.100.20", + "network": "152.16.100.20" + }, + { + "netmask": "255.255.255.0", + "if": "xe1", + "gateway": "152.16.40.20", + "network": "152.16.40.20" + } + ], + "role": "vnf" + }, + "trafficgen_2.yardstick": { + "member-vnf-index": "3", + "role": "TrafficGen", + "name": "trafficgen_2.yardstick", + "vnfd-id-ref": "tg__2", + "ip": "1.2.1.1", + "interfaces": { + "xe0": { + "local_iface_name": "ens513f0", + "vld_id": "public", + "netmask": "255.255.255.0", + "vpci": "0000:02:00.0", + "local_ip": "152.16.40.20", + "driver": "ixgbe", + "dst_ip": "152.16.40.19", + "local_mac": "00:00:00:00:00:03", + "dst_mac": "00:00:00:00:00:01", + "dpdk_port_num": 0 + }, + "xe1": { + "local_iface_name": "ens513f1", + "netmask": "255.255.255.0", + "network": "202.16.100.0", + "local_ip": "202.16.100.20", + "driver": "ixgbe", + "local_mac": "00:1e:67:d0:60:5d", + "vpci": "0000:02:00.1", + "dpdk_port_num": 1 + } + }, + "password": "r00t", + "VNF model": "l3fwd_vnf.yaml", + "user": "root" + }, + "trafficgen_1.yardstick": { + "member-vnf-index": "1", + "role": "TrafficGen", + "name": "trafficgen_1.yardstick", + "vnfd-id-ref": "tg__1", + "ip": "1.2.1.1", + "interfaces": { + "xe0": { + "local_iface_name": "ens785f0", + "vld_id": "private", + "netmask": "255.255.255.0", + "vpci": "0000:05:00.0", + "local_ip": "152.16.100.20", + "driver": "i40e", + "dst_ip": "152.16.100.19", + "local_mac": "00:00:00:00:00:04", + "dst_mac": "00:00:00:00:00:02", + "dpdk_port_num": 0 + }, + "xe1": { + "local_ip": "152.16.100.21", + "driver": "i40e", + "vpci": "0000:05:00.1", + "dpdk_port_num": 1, + "local_iface_name": "ens785f1", + "netmask": "255.255.255.0", + "local_mac": "00:00:00:00:00:01" + } + }, + "password": "r00t", + "VNF model": "tg_rfc2544_tpl.yaml", + "user": "root" + } + } + } + + def test___init__(self, _): + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + self.assertIsNone(udp_replay_approx_vnf._vnf_process) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") - def test_collect_kpi(self, mock_time, mock_process): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - result = "stats\r\r\n\r\nUDP_Replay stats:\r\n--------------\r\n" \ - "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop \r\n"\ - "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\r\n" \ - "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>" - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - udp_approx_vnf.q_in = mock.MagicMock() - udp_approx_vnf.q_out = mock.MagicMock() - udp_approx_vnf.q_out.qsize = mock.Mock(return_value=0) - udp_approx_vnf.all_ports = [0, 1] - udp_approx_vnf.interfaces = vnfd["vdu"][0]['external-interface'] - udp_approx_vnf.get_stats = mock.Mock(return_value=result) - result = {'collect_stats': {}, 'packets_dropped': 0, - 'packets_fwd': 14748451, 'packets_in': 14748472} - self.assertEqual(result, udp_approx_vnf.collect_kpi()) + @mock.patch(SSH_HELPER) + def test_collect_kpi(self, ssh, mock_time, _): + mock_ssh(ssh) + + vnfd = self.VNFD_0 + result = "stats\r\r\n\r\nUDP_Replay stats:\r\n--------------\r\n" \ + "Port\t\tRx Packet\t\tTx Packet\t\tRx Pkt Drop\t\tTx Pkt Drop \r\n"\ + "0\t\t7374156\t\t7374136\t\t\t0\t\t\t0\r\n" \ + "1\t\t7374316\t\t7374315\t\t\t0\t\t\t0\r\n\r\nReplay>\r\r\nReplay>" + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) + udp_replay_approx_vnf.q_in = mock.MagicMock() + udp_replay_approx_vnf.q_out = mock.MagicMock() + udp_replay_approx_vnf.q_out.qsize = mock.Mock(return_value=0) + udp_replay_approx_vnf.all_ports = [0, 1] + udp_replay_approx_vnf.get_stats = mock.Mock(return_value=result) + result = {'collect_stats': {}, 'packets_dropped': 0, + 'packets_fwd': 14748451, 'packets_in': 14748472} + self.assertEqual(result, udp_replay_approx_vnf.collect_kpi()) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") - def test_vnf_execute_command(self, mock_time, mock_process): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - cmd = "quit" - self.assertEqual("", udp_approx_vnf.vnf_execute(cmd)) - - def test_get_stats(self, mock_process): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - udp_approx_vnf.q_in = mock.MagicMock() - udp_approx_vnf.q_out = mock.MagicMock() - udp_approx_vnf.q_out.qsize = mock.Mock(return_value=0) - mock_result = \ - "CG-NAPT(.*\n)*Received 100, Missed 0, Dropped 0,Translated 100,ingress" - udp_approx_vnf.vnf_execute = mock.Mock(return_value=mock_result) - self.assertEqual(mock_result, - udp_approx_vnf.get_stats()) + @mock.patch(SSH_HELPER) + def test_vnf_execute_command(self, ssh, mock_time, _): + mock_ssh(ssh) + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + cmd = "quit" + self.assertEqual("", udp_replay_approx_vnf.vnf_execute(cmd)) + + @mock.patch(SSH_HELPER) + def test_get_stats(self, ssh, _): + mock_ssh(ssh) + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf.q_in = mock.MagicMock() + udp_replay_approx_vnf.q_out = mock.MagicMock() + udp_replay_approx_vnf.q_out.qsize = mock.Mock(return_value=0) + mock_result = \ + "CG-NAPT(.*\n)*Received 100, Missed 0, Dropped 0,Translated 100,ingress" + + udp_replay_approx_vnf.vnf_execute = mock.Mock(return_value=mock_result) + + self.assertEqual(mock_result, + udp_replay_approx_vnf.get_stats()) def _get_file_abspath(self, filename): curr_path = os.path.dirname(os.path.abspath(__file__)) @@ -300,111 +379,115 @@ class TestAclApproxVnf(unittest.TestCase): return file_path @mock.patch('yardstick.network_services.vnf_generic.vnf.udp_replay.open') - def test__build_pipeline_kwargs(self, mock_open, mock_process): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - udp_approx_vnf._build_config = mock.MagicMock() - udp_approx_vnf.queue_wrapper = mock.MagicMock() - udp_approx_vnf.nfvi_type = "baremetal" - udp_approx_vnf.bound_pci = [] - udp_approx_vnf.all_ports = [0, 1] - udp_approx_vnf.ssh_helper = mock.MagicMock( - **{"provision_tool.return_value": "tool_path"}) - udp_approx_vnf.vnf_cfg = {'lb_config': 'SW', - 'lb_count': 1, - 'worker_config': '1C/1T', - 'worker_threads': 1} - udp_approx_vnf.options = {'traffic_type': '4', - 'topology': 'nsb_test_case.yaml'} - - udp_approx_vnf._build_pipeline_kwargs() - self.assertEqual(udp_approx_vnf.pipeline_kwargs, { - 'config': '(0, 0, 1)(1, 0, 2)', - 'cpu_mask_hex': '0x6', - 'hw_csum': '', - 'ports_len_hex': '0x3', - 'tool_path': 'tool_path', - 'whitelist': '' - }) - - @mock.patch("yardstick.network_services.vnf_generic.vnf.udp_replay.hex") - @mock.patch("yardstick.network_services.vnf_generic.vnf.udp_replay.eval") + @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch(SSH_HELPER) + def test__build_config(self, ssh, mock_context, *_): + mock_ssh(ssh) + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf.queue_wrapper = mock.MagicMock() + udp_replay_approx_vnf.nfvi_context = mock_context + udp_replay_approx_vnf.nfvi_context.attrs = {'nfvi_type': 'baremetal'} + udp_replay_approx_vnf.setup_helper.bound_pci = [] + udp_replay_approx_vnf.all_ports = [0, 1] + udp_replay_approx_vnf.ssh_helper.provision_tool = mock.MagicMock(return_value="tool_path") + udp_replay_approx_vnf.scenario_helper = ScenarioHelper(name='vnf__1') + udp_replay_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG + + cmd_line = udp_replay_approx_vnf._build_config() + + expected = "sudo tool_path -c 0x7 -n 4 -w -- -p 0x3 --config='(0, 0, 1)(1, 0, 2)'" + self.assertEqual(cmd_line, expected) + @mock.patch('yardstick.network_services.vnf_generic.vnf.udp_replay.open') - def test_run_udp_replay(self, mock_open, eval, hex, mock_process): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh_mock.run = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - udp_approx_vnf._build_config = mock.MagicMock() - udp_approx_vnf.queue_wrapper = mock.MagicMock() - udp_approx_vnf.ssh_helper = mock.MagicMock() - udp_approx_vnf.ssh_helper.run = mock.MagicMock() - udp_approx_vnf.vnf_cfg = {'lb_config': 'SW', - 'lb_count': 1, - 'worker_config': '1C/1T', - 'worker_threads': 1} - udp_approx_vnf.options = {'traffic_type': '4', - 'topology': 'nsb_test_case.yaml'} - - udp_approx_vnf._run() - udp_approx_vnf.ssh_helper.run.assert_called_once() + @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch(SSH_HELPER) + def test__build_pipeline_kwargs(self, ssh, mock_context, *_): + mock_ssh(ssh) + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf._build_config = mock.MagicMock() + udp_replay_approx_vnf.queue_wrapper = mock.MagicMock() + udp_replay_approx_vnf.nfvi_context = mock_context + udp_replay_approx_vnf.nfvi_context.attrs = {'nfvi_type': 'baremetal'} + udp_replay_approx_vnf.setup_helper.bound_pci = [] + udp_replay_approx_vnf.all_ports = [0, 1] + udp_replay_approx_vnf.ssh_helper.provision_tool = mock.MagicMock(return_value="tool_path") + udp_replay_approx_vnf.scenario_helper = ScenarioHelper(name='vnf__1') + udp_replay_approx_vnf.scenario_helper.scenario_cfg = self.SCENARIO_CFG + + udp_replay_approx_vnf._build_pipeline_kwargs() + + self.assertEqual(udp_replay_approx_vnf.pipeline_kwargs, { + 'config': '(0, 0, 1)(1, 0, 2)', + 'cpu_mask_hex': '0x7', + 'hw_csum': '', + 'ports_len_hex': '0x3', + 'tool_path': 'tool_path', + 'whitelist': '' + }) + + @mock.patch(SSH_HELPER) + def test_run_udp_replay(self, ssh, _): + mock_ssh(ssh) + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf._build_config = mock.MagicMock() + udp_replay_approx_vnf.queue_wrapper = mock.MagicMock() + + udp_replay_approx_vnf._run() + + udp_replay_approx_vnf.ssh_helper.run.assert_called_once() @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") - def test_instantiate(self, Context, mock_process): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - self.scenario_cfg['vnf_options'] = {'cgnapt': {'cfg': "", - 'rules': ""}} - udp_approx_vnf._run_udp_replay = mock.Mock(return_value=0) - udp_approx_vnf._parse_rule_file = mock.Mock(return_value={}) - udp_approx_vnf.deploy_udp_replay_vnf = mock.Mock(return_value=1) - udp_approx_vnf.q_out.put("Replay>") - udp_approx_vnf.get_my_ports = mock.Mock(return_value=[0, 1]) - udp_replay.WAIT_TIME = 3 - udp_approx_vnf.get_nfvi_type = mock.Mock(return_value="baremetal") - - udp_approx_vnf._vnf_process = mock.MagicMock() - udp_approx_vnf._vnf_process.is_alive = \ - mock.Mock(return_value=1) - self.assertIsNone(udp_approx_vnf.instantiate(self.scenario_cfg, - self.context_cfg)) - - def test_scale(self, mock_process): - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) + @mock.patch(SSH_HELPER) + def test_instantiate(self, ssh, *_): + mock_ssh(ssh) + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf.q_out.put("Replay>") + udp_replay_approx_vnf.WAIT_TIME = 0 + udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock() + + self.assertIsNone(udp_replay_approx_vnf.instantiate(self.SCENARIO_CFG, + self.CONTEXT_CFG)) + + udp_replay_approx_vnf._vnf_process.is_alive = mock.Mock(return_value=1) + udp_replay_approx_vnf._vnf_process.exitcode = 0 + + self.assertEquals(udp_replay_approx_vnf.wait_for_instantiate(), 0) + + @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Context") + @mock.patch('yardstick.ssh.SSH') + @mock.patch(SSH_HELPER) + def test_instantiate_panic(self, ssh, resource_ssh, *_): + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf.WAIT_TIME = 0 + udp_replay_approx_vnf.q_out.put("some text PANIC some text") + udp_replay_approx_vnf.setup_helper.setup_vnf_environment = mock.Mock() + + self.assertIsNone(udp_replay_approx_vnf.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)) + with self.assertRaises(RuntimeError): + udp_replay_approx_vnf.wait_for_instantiate() + + def test_scale(self, _): + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) flavor = "" - self.assertRaises(NotImplementedError, udp_approx_vnf.scale, flavor) + + self.assertRaises(NotImplementedError, udp_replay_approx_vnf.scale, flavor) @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.time") - def test_terminate(self, mock_time, mock_process): - with mock.patch("yardstick.ssh.SSH") as ssh: - ssh_mock = mock.Mock(autospec=ssh.SSH) - ssh_mock.execute = \ - mock.Mock(return_value=(0, "", "")) - ssh.from_node.return_value = ssh_mock - vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0] - udp_approx_vnf = UdpReplayApproxVnf(NAME, vnfd) - udp_approx_vnf._vnf_process = mock.MagicMock() - udp_approx_vnf._vnf_process.terminate = mock.Mock() - udp_approx_vnf.used_drivers = {"01:01.0": "i40e", - "01:01.1": "i40e"} - udp_approx_vnf.execute_command = mock.Mock() - udp_approx_vnf.ssh_helper = ssh_mock - udp_approx_vnf.dpdk_nic_bind = "dpdk_nic_bind.py" - self.assertEqual(None, udp_approx_vnf.terminate()) + @mock.patch(SSH_HELPER) + def test_terminate(self, ssh, mock_time, _): + mock_ssh(ssh) + + udp_replay_approx_vnf = UdpReplayApproxVnf(NAME, self.VNFD_0) + udp_replay_approx_vnf._vnf_process = mock.MagicMock() + udp_replay_approx_vnf._vnf_process.terminate = mock.Mock() + udp_replay_approx_vnf.used_drivers = {"01:01.0": "i40e", + "01:01.1": "i40e"} + udp_replay_approx_vnf.dpdk_nic_bind = "dpdk_nic_bind.py" + self.assertEqual(None, udp_replay_approx_vnf.terminate()) if __name__ == '__main__': unittest.main() diff --git a/yardstick/network_services/helpers/samplevnf_helper.py b/yardstick/network_services/helpers/samplevnf_helper.py index dfc5cb972..9d89d4188 100644 --- a/yardstick/network_services/helpers/samplevnf_helper.py +++ b/yardstick/network_services/helpers/samplevnf_helper.py @@ -229,10 +229,15 @@ class MultiPortConfig(object): @staticmethod def get_port_pairs(interfaces): port_pair_list = [] - networks = defaultdict(list) + networks = {} for private_intf in interfaces: vintf = private_intf['virtual-interface'] - networks[vintf['vld_id']].append(vintf) + try: + vld_id = vintf['vld_id'] + except KeyError: + pass + else: + networks.setdefault(vld_id, []).append(vintf) for name, net in networks.items(): # partition returns a tuple diff --git a/yardstick/network_services/nfvi/resource.py b/yardstick/network_services/nfvi/resource.py index f0ae67616..055fdba7e 100644 --- a/yardstick/network_services/nfvi/resource.py +++ b/yardstick/network_services/nfvi/resource.py @@ -203,6 +203,7 @@ class ResourceProfile(object): self._provide_config_file(bin_path, 'collectd.conf', kwargs) def _start_collectd(self, connection, bin_path): + LOG.debug("Starting collectd to collect NFVi stats") connection.execute('sudo pkill -9 collectd') bin_path = get_nsb_option("bin_path") collectd_path = os.path.join(bin_path, "collectd", "collectd") diff --git a/yardstick/network_services/traffic_profile/traffic_profile.py b/yardstick/network_services/traffic_profile/traffic_profile.py index 7bbe89268..4c6595d94 100644 --- a/yardstick/network_services/traffic_profile/traffic_profile.py +++ b/yardstick/network_services/traffic_profile/traffic_profile.py @@ -33,203 +33,86 @@ from trex_stl_lib.trex_stl_packet_builder_scapy import STLScVmRaw from trex_stl_lib.trex_stl_packet_builder_scapy import STLVmFixIpv4 from trex_stl_lib import api as Pkt +SRC = 'src' +DST = 'dst' +ETHERNET = 'Ethernet' +IP = 'IP' +IPv6 = 'IPv6' +UDP = 'UDP' +DSCP = 'DSCP' +SRC_PORT = 'sport' +DST_PORT = 'dport' +TYPE_OF_SERVICE = 'tos' + class TrexProfile(TrafficProfile): """ This class handles Trex Traffic profile generation and execution """ - def __init__(self, yaml_data): - super(TrexProfile, self).__init__(yaml_data) - self.flows = 100 - self.pps = 100 - self.pg_id = 0 - self.first_run = True - self.streams = 1 - self.profile_data = [] - self.profile = None - self.base_pkt = None - self.fsize = None - self.trex_vm = None - self.vms = [] - self.rate = None - self.ip_packet = None - self.ip6_packet = None - self.udp_packet = None - self.udp_dport = '' - self.udp_sport = '' - self.qinq_packet = None - self.qinq = False - self.vm_flow_vars = [] - self.packets = [] - self.ether_packet = [] - - def execute(self, traffic_generator): - """ Generate the stream and run traffic on the given ports """ - pass - - def _set_ether_fields(self, **kwargs): - """ set ethernet protocol fields """ - if not self.ether_packet: - self.ether_packet = Pkt.Ether() - for key, value in six.iteritems(kwargs): - setattr(self.ether_packet, key, value) - - def _set_ip_fields(self, **kwargs): - """ set l3 ipv4 protocol fields """ - - if not self.ip_packet: - self.ip_packet = Pkt.IP() - for key in kwargs: - setattr(self.ip_packet, key, kwargs[key]) - - def _set_ip6_fields(self, **kwargs): - """ set l3 ipv6 protocol fields """ - if not self.ip6_packet: - self.ip6_packet = Pkt.IPv6() - for key in kwargs: - setattr(self.ip6_packet, key, kwargs[key]) - - def _set_udp_fields(self, **kwargs): - """ set l4 udp ports fields """ - if not self.udp_packet: - self.udp_packet = Pkt.UDP() - for key in kwargs: - setattr(self.udp_packet, key, kwargs[key]) - - def set_src_mac(self, src_mac): - """ set source mac address fields """ - src_macs = src_mac.split('-') - min_value = src_macs[0] - if len(src_macs) == 1: - src_mac = min_value - self._set_ether_fields(src=src_mac) - else: - stl_vm_flow_var = STLVmFlowVar(name="mac_src", + PROTO_MAP = { + ETHERNET: ('ether_packet', Pkt.Ether), + IP: ('ip_packet', Pkt.IP), + IPv6: ('ip6_packet', Pkt.IPv6), + UDP: ('udp_packet', Pkt.UDP), + } + + def _general_single_action_partial(self, protocol): + def f(field): + def partial(value): + kwargs = { + field: value + } + self._set_proto_fields(protocol, **kwargs) + return partial + return f + + def _ethernet_range_action_partial(self, direction, _): + def partial(min_value, max_value): + stl_vm_flow_var = STLVmFlowVar(name="mac_{}".format(direction), min_value=1, max_value=30, size=4, op='inc', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_src', - pkt_offset='Ether.src') + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_{}'.format(direction), + pkt_offset='Ether.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) + return partial - def set_dst_mac(self, dst_mac): - """ set destination mac address fields """ - dst_macs = dst_mac.split('-') - min_value = dst_macs[0] - if len(dst_macs) == 1: - dst_mac = min_value - self._set_ether_fields(dst=dst_mac) - else: - stl_vm_flow_var = STLVmFlowVar(name="mac_dst", - min_value=1, - max_value=30, - size=4, - op='inc', - step=1) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='mac_dst', - pkt_offset='Ether.dst') - self.vm_flow_vars.append(stl_vm_wr_flow_var) - - def set_src_ip4(self, src_ip4, count=1): - """ set source ipv4 address fields """ - src_ips = src_ip4.split('-') - min_value = src_ips[0] - max_value = src_ips[1] if len(src_ips) == 2 else src_ips[0] - if len(src_ips) == 1: - src_ip4 = min_value - self._set_ip_fields(src=src_ip4) - else: - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="ip4_src", + def _ip_range_action_partial(self, direction, count=1): + def partial(min_value, max_value): + stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="ip4_{}".format(direction), min_value=min_value, max_value=max_value, size=4, limit=int(count), seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip4_src', - pkt_offset='IP.src') + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip4_{}'.format(direction), + pkt_offset='IP.{}'.format(direction)) self.vm_flow_vars.append(stl_vm_wr_flow_var) stl_vm_fix_ipv4 = STLVmFixIpv4(offset="IP") self.vm_flow_vars.append(stl_vm_fix_ipv4) + return partial - def set_dst_ip4(self, dst_ip4, count=1): - """ set destination ipv4 address fields """ - dst_ips = dst_ip4.split('-') - min_value = dst_ips[0] - max_value = dst_ips[1] if len(dst_ips) == 2 else dst_ips[0] - if len(dst_ips) == 1: - dst_ip4 = min_value - self._set_ip_fields(dst=dst_ip4) - else: - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="dst_ip4", - min_value=min_value, - max_value=max_value, - size=4, - limit=int(count), - seed=0x1235) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='dst_ip4', - pkt_offset='IP.dst') - self.vm_flow_vars.append(stl_vm_wr_flow_var) - stl_vm_fix_ipv4 = STLVmFixIpv4(offset="IP") - self.vm_flow_vars.append(stl_vm_fix_ipv4) - - def set_src_ip6(self, src_ip6): - """ set source ipv6 address fields """ - src_ips = src_ip6.split('-') - min_value = src_ips[0] - max_value = src_ips[1] if len(src_ips) == 2 else src_ips[0] - src_ip6 = min_value - self._set_ip6_fields(src=src_ip6) - if len(src_ips) == 2: - min_value, max_value = \ - self._get_start_end_ipv6(min_value, max_value) - stl_vm_flow_var = STLVmFlowVar(name="ip6_src", + def _ip6_range_action_partial(self, direction, _): + def partial(min_value, max_value): + min_value, max_value = self._get_start_end_ipv6(min_value, max_value) + stl_vm_flow_var = STLVmFlowVar(name="ip6_{}".format(direction), min_value=min_value, max_value=max_value, size=8, op='random', step=1) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip6_src', - pkt_offset='IPv6.src', + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='ip6_{}'.format(direction), + pkt_offset='IPv6.{}'.format(direction), offset_fixup=8) self.vm_flow_vars.append(stl_vm_wr_flow_var) + return partial - def set_dst_ip6(self, dst_ip6): - """ set destination ipv6 address fields """ - dst_ips = dst_ip6.split('-') - min_value = dst_ips[0] - max_value = dst_ips[1] if len(dst_ips) == 2 else dst_ips[0] - dst_ip6 = min_value - self._set_ip6_fields(dst=dst_ip6) - if len(dst_ips) == 2: - min_value, max_value = \ - self._get_start_end_ipv6(min_value, max_value) - stl_vm_flow_var = STLVmFlowVar(name="dst_ip6", - min_value=min_value, - max_value=max_value, - size=8, - op='random', - step=1) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='dst_ip6', - pkt_offset='IPv6.dst', - offset_fixup=8) - self.vm_flow_vars.append(stl_vm_wr_flow_var) - - def set_dscp(self, dscp): - """ set dscp for trex """ - dscps = str(dscp).split('-') - min_value = int(dscps[0]) - max_value = int(dscps[1]) if len(dscps) == 2 else int(dscps[0]) - if len(dscps) == 1: - dscp = min_value - self._set_ip_fields(tos=dscp) - else: + def _dscp_range_action_partial(self, *_): + def partial(min_value, max_value): stl_vm_flow_var = STLVmFlowVar(name="dscp", min_value=min_value, max_value=max_value, @@ -241,54 +124,110 @@ class TrexProfile(TrafficProfile): pkt_offset='IP.tos') self.vm_flow_vars.append(stl_vm_wr_flow_var) - def set_src_port(self, src_port, count=1): - """ set packet source port """ - src_ports = str(src_port).split('-') - min_value = int(src_ports[0]) - if len(src_ports) == 1: - max_value = int(src_ports[0]) - src_port = min_value - self._set_udp_fields(sport=src_port) - else: - max_value = int(src_ports[1]) - stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="port_src", + def _udp_range_action_partial(self, field, count=1): + def partial(min_value, max_value): + stl_vm_flow_var = STLVmFlowVarRepeatableRandom(name="port_{}".format(field), min_value=min_value, max_value=max_value, size=2, limit=int(count), seed=0x1235) self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_src', + stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_{}'.format(field), pkt_offset=self.udp_sport) self.vm_flow_vars.append(stl_vm_wr_flow_var) + return partial - def set_dst_port(self, dst_port, count=1): - """ set packet destnation port """ - dst_ports = str(dst_port).split('-') - min_value = int(dst_ports[0]) - if len(dst_ports) == 1: - max_value = int(dst_ports[0]) - dst_port = min_value - self._set_udp_fields(dport=dst_port) + def __init__(self, yaml_data): + super(TrexProfile, self).__init__(yaml_data) + self.flows = 100 + self.pps = 100 + self.pg_id = 0 + self.first_run = True + self.streams = 1 + self.profile_data = [] + self.profile = None + self.base_pkt = None + self.fsize = None + self.trex_vm = None + self.vms = [] + self.rate = None + self.ether_packet = None + self.ip_packet = None + self.ip6_packet = None + self.udp_packet = None + self.udp_dport = '' + self.udp_sport = '' + self.qinq_packet = None + self.qinq = False + self.vm_flow_vars = [] + self.packets = [] + + self._map_proto_actions = { + # the tuple is (single value function, range value function, if the values should be + # converted to integer). + ETHERNET: (self._general_single_action_partial(ETHERNET), + self._ethernet_range_action_partial, + False, + ), + IP: (self._general_single_action_partial(IP), + self._ip_range_action_partial, + False, + ), + IPv6: (self._general_single_action_partial(IPv6), + self._ip6_range_action_partial, + False, + ), + DSCP: (self._general_single_action_partial(IP), + self._dscp_range_action_partial, + True, + ), + UDP: (self._general_single_action_partial(UDP), + self._udp_range_action_partial, + True, + ), + } + + def execute(self, traffic_generator): + """ Generate the stream and run traffic on the given ports """ + pass + + def _call_on_range(self, range, single_action, range_action, count=1, to_int=False): + def convert_to_int(val): + return int(val) if to_int else val + + range_iter = iter(str(range).split('-')) + min_value = convert_to_int(next(range_iter)) + try: + max_value = convert_to_int(next(range_iter)) + except StopIteration: + single_action(min_value) else: - max_value = int(dst_ports[1]) - stl_vm_flow_var = \ - STLVmFlowVarRepeatableRandom(name="port_dst", - min_value=min_value, - max_value=max_value, - size=2, - limit=int(count), - seed=0x1235) - self.vm_flow_vars.append(stl_vm_flow_var) - stl_vm_wr_flow_var = STLVmWrFlowVar(fv_name='port_dst', - pkt_offset=self.udp_dport) - self.vm_flow_vars.append(stl_vm_wr_flow_var) + range_action(min_value=min_value, max_value=max_value) + + def _set_proto_addr(self, protocol, field, address, count=1): + single_action, range_action, to_int = self._map_proto_actions[protocol] + self._call_on_range(address, + single_action(field), + range_action(field, count), + to_int=to_int, + ) + + def _set_proto_fields(self, protocol, **kwargs): + _attr_name, _class = self.PROTO_MAP[protocol] + + if not getattr(self, _attr_name): + setattr(self, _attr_name, _class()) + + _attr = getattr(self, _attr_name) + for key, value in six.iteritems(kwargs): + setattr(_attr, key, value) def set_svlan_cvlan(self, svlan, cvlan): """ set svlan & cvlan """ self.qinq = True ether_params = {'type': 0x8100} - self._set_ether_fields(**ether_params) + self._set_proto_fields(ETHERNET, **ether_params) svlans = str(svlan['id']).split('-') svlan_min = int(svlans[0]) svlan_max = int(svlans[1]) if len(svlans) == 2 else int(svlans[0]) @@ -309,42 +248,42 @@ class TrexProfile(TrafficProfile): """ set qinq in packet """ self.set_svlan_cvlan(qinq['S-VLAN'], qinq['C-VLAN']) - def set_outer_l2_fields(self, outer_l2): + def _set_outer_l2_fields(self, outer_l2): """ setup outer l2 fields from traffic profile """ ether_params = {'type': 0x800} - self._set_ether_fields(**ether_params) + self._set_proto_fields(ETHERNET, **ether_params) if 'srcmac' in outer_l2: - self.set_src_mac(outer_l2['srcmac']) + self._set_proto_addr(ETHERNET, SRC, outer_l2['srcmac']) if 'dstmac' in outer_l2: - self.set_dst_mac(outer_l2['dstmac']) + self._set_proto_addr(ETHERNET, DST, outer_l2['dstmac']) if 'QinQ' in outer_l2: self.set_qinq(outer_l2['QinQ']) - def set_outer_l3v4_fields(self, outer_l3v4): + def _set_outer_l3v4_fields(self, outer_l3v4): """ setup outer l3v4 fields from traffic profile """ ip_params = {} if 'proto' in outer_l3v4: - ip_params['proto'] = outer_l3v4['proto'] + ip_params['proto'] = socket.getprotobyname(outer_l3v4['proto']) if outer_l3v4['proto'] == 'tcp': self.udp_packet = Pkt.TCP() self.udp_dport = 'TCP.dport' self.udp_sport = 'TCP.sport' tcp_params = {'flags': '', 'window': 0} - self._set_udp_fields(**tcp_params) + self._set_proto_fields(UDP, **tcp_params) if 'ttl' in outer_l3v4: ip_params['ttl'] = outer_l3v4['ttl'] - self._set_ip_fields(**ip_params) + self._set_proto_fields(IP, **ip_params) if 'dscp' in outer_l3v4: - self.set_dscp(outer_l3v4['dscp']) + self._set_proto_addr(DSCP, TYPE_OF_SERVICE, outer_l3v4['dscp']) if 'srcip4' in outer_l3v4: - self.set_src_ip4(outer_l3v4['srcip4'], outer_l3v4['count']) + self._set_proto_addr(IP, SRC, outer_l3v4['srcip4'], outer_l3v4['count']) if 'dstip4' in outer_l3v4: - self.set_dst_ip4(outer_l3v4['dstip4'], outer_l3v4['count']) + self._set_proto_addr(IP, DST, outer_l3v4['dstip4'], outer_l3v4['count']) - def set_outer_l3v6_fields(self, outer_l3v6): + def _set_outer_l3v6_fields(self, outer_l3v6): """ setup outer l3v6 fields from traffic profile """ ether_params = {'type': 0x86dd} - self._set_ether_fields(**ether_params) + self._set_proto_fields(ETHERNET, **ether_params) ip6_params = {} if 'proto' in outer_l3v6: ip6_params['proto'] = outer_l3v6['proto'] @@ -353,25 +292,25 @@ class TrexProfile(TrafficProfile): self.udp_dport = 'TCP.dport' self.udp_sport = 'TCP.sport' tcp_params = {'flags': '', 'window': 0} - self._set_udp_fields(**tcp_params) + self._set_proto_fields(UDP, **tcp_params) if 'ttl' in outer_l3v6: ip6_params['ttl'] = outer_l3v6['ttl'] if 'tc' in outer_l3v6: ip6_params['tc'] = outer_l3v6['tc'] if 'hlim' in outer_l3v6: ip6_params['hlim'] = outer_l3v6['hlim'] - self._set_ip6_fields(**ip6_params) + self._set_proto_fields(IPv6, **ip6_params) if 'srcip6' in outer_l3v6: - self.set_src_ip6(outer_l3v6['srcip6']) + self._set_proto_addr(IPv6, SRC, outer_l3v6['srcip6']) if 'dstip6' in outer_l3v6: - self.set_dst_ip6(outer_l3v6['dstip6']) + self._set_proto_addr(IPv6, DST, outer_l3v6['dstip6']) - def set_outer_l4_fields(self, outer_l4): + def _set_outer_l4_fields(self, outer_l4): """ setup outer l4 fields from traffic profile """ if 'srcport' in outer_l4: - self.set_src_port(outer_l4['srcport'], outer_l4['count']) + self._set_proto_addr(UDP, SRC_PORT, outer_l4['srcport'], outer_l4['count']) if 'dstport' in outer_l4: - self.set_dst_port(outer_l4['dstport'], outer_l4['count']) + self._set_proto_addr(UDP, DST_PORT, outer_l4['dstport'], outer_l4['count']) def generate_imix_data(self, packet_definition): """ generate packet size for a given traffic profile """ @@ -434,13 +373,13 @@ class TrexProfile(TrafficProfile): outer_l3v6 = packet_definition.get('outer_l3v6', None) outer_l4 = packet_definition.get('outer_l4', None) if outer_l2: - self.set_outer_l2_fields(outer_l2) + self._set_outer_l2_fields(outer_l2) if outer_l3v4: - self.set_outer_l3v4_fields(outer_l3v4) + self._set_outer_l3v4_fields(outer_l3v4) if outer_l3v6: - self.set_outer_l3v6_fields(outer_l3v6) + self._set_outer_l3v6_fields(outer_l3v6) if outer_l4: - self.set_outer_l4_fields(outer_l4) + self._set_outer_l4_fields(outer_l4) self.trex_vm = STLScVmRaw(self.vm_flow_vars) def generate_packets(self): diff --git a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py index 9a7d39913..1b2533aad 100644 --- a/yardstick/network_services/vnf_generic/vnf/sample_vnf.py +++ b/yardstick/network_services/vnf_generic/vnf/sample_vnf.py @@ -680,19 +680,19 @@ class ScenarioHelper(object): @property def task_path(self): - return self.scenario_cfg["task_path"] + return self.scenario_cfg['task_path'] @property def nodes(self): - return self.scenario_cfg['nodes'] + return self.scenario_cfg.get('nodes') @property def all_options(self): - return self.scenario_cfg["options"] + return self.scenario_cfg.get('options', {}) @property def options(self): - return self.all_options[self.name] + return self.all_options.get(self.name, {}) @property def vnf_cfg(self): @@ -742,7 +742,6 @@ class SampleVNF(GenericVNF): self.q_out = Queue() self.queue_wrapper = None self.run_kwargs = {} - self.scenario_cfg = None self.tg_port_pairs = None self.used_drivers = {} self.vnf_port_pairs = None @@ -937,7 +936,6 @@ class SampleVNFTrafficGen(GenericTrafficGen): def instantiate(self, scenario_cfg, context_cfg): self.scenario_helper.scenario_cfg = scenario_cfg self.resource_helper.generate_cfg() - self.setup_helper.setup_vnf_environment() self.resource_helper.setup() LOG.info("Starting %s server...", self.APP_NAME) diff --git a/yardstick/network_services/vnf_generic/vnf/tg_trex.py b/yardstick/network_services/vnf_generic/vnf/tg_trex.py index 616b331ba..1fe790f08 100644 --- a/yardstick/network_services/vnf_generic/vnf/tg_trex.py +++ b/yardstick/network_services/vnf_generic/vnf/tg_trex.py @@ -25,10 +25,19 @@ from yardstick.common.utils import mac_address_to_hex_list from yardstick.network_services.utils import get_nsb_option from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper LOG = logging.getLogger(__name__) +class TrexDpdkVnfSetupEnvHelper(DpdkVnfSetupEnvHelper): + APP_NAME = "t-rex-64" + CFG_CONFIG = "" + CFG_SCRIPT = "" + PIPELINE_COMMAND = "" + VNF_TYPE = "TG" + + class TrexResourceHelper(ClientResourceHelper): CONF_FILE = '/tmp/trex_cfg.yaml' @@ -36,16 +45,14 @@ class TrexResourceHelper(ClientResourceHelper): RESOURCE_WORD = 'trex' RUN_DURATION = 0 - SYNC_PORT = 4500 - ASYNC_PORT = 4501 + ASYNC_PORT = 4500 + SYNC_PORT = 4501 def generate_cfg(self): ext_intf = self.vnfd_helper.interfaces vpci_list = [] port_list = [] trex_cfg = { - 'port_limit': 0, - 'version': '2', 'interfaces': vpci_list, 'port_info': port_list, "port_limit": len(ext_intf), @@ -79,6 +86,7 @@ class TrexResourceHelper(ClientResourceHelper): DISABLE_DEPLOY = True def setup(self): + super(TrexResourceHelper, self).setup() if self.DISABLE_DEPLOY: return @@ -130,6 +138,9 @@ class TrexTrafficGen(SampleVNFTrafficGen): if resource_helper_type is None: resource_helper_type = TrexResourceHelper + if setup_env_helper_type is None: + setup_env_helper_type = TrexDpdkVnfSetupEnvHelper + super(TrexTrafficGen, self).__init__(name, vnfd, setup_env_helper_type, resource_helper_type) diff --git a/yardstick/network_services/vnf_generic/vnf/udp_replay.py b/yardstick/network_services/vnf_generic/vnf/udp_replay.py index 6e206f2b2..a9bc204d5 100644 --- a/yardstick/network_services/vnf_generic/vnf/udp_replay.py +++ b/yardstick/network_services/vnf_generic/vnf/udp_replay.py @@ -16,6 +16,8 @@ from __future__ import absolute_import import logging from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF +from yardstick.network_services.vnf_generic.vnf.sample_vnf import DpdkVnfSetupEnvHelper +from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper LOG = logging.getLogger(__name__) @@ -27,38 +29,65 @@ REPLAY_PIPELINE_COMMAND = ( # {tool_path} -p {ports_len_hex} -f {cfg_file} -s {script}' +class UdpReplaySetupEnvHelper(DpdkVnfSetupEnvHelper): + + APP_NAME = "UDP_Replay" + + +class UdpReplayResourceHelper(ClientResourceHelper): + pass + + class UdpReplayApproxVnf(SampleVNF): APP_NAME = "UDP_Replay" APP_WORD = "UDP_Replay" - PIPELINE_COMMAND = REPLAY_PIPELINE_COMMAND VNF_PROMPT = 'Replay>' - CSUM_MAP = { - 'baremetal': '', - 'sriov': '', - } + VNF_TYPE = 'UdpReplay' + + HW_OFFLOADING_NFVI_TYPES = {'baremetal', 'sriov'} + + PIPELINE_COMMAND = REPLAY_PIPELINE_COMMAND + + def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None): + if resource_helper_type is None: + resource_helper_type = UdpReplayResourceHelper + + if setup_env_helper_type is None: + setup_env_helper_type = UdpReplaySetupEnvHelper + + super(UdpReplayApproxVnf, self).__init__(name, vnfd, setup_env_helper_type, + resource_helper_type) + + def _start_server(self): + super(UdpReplayApproxVnf, self)._start_server() + self.resource_helper.start() def scale(self, flavor=""): """ scale vnfbased on flavor input """ raise NotImplementedError - def _build_config(self): - pass - def _deploy(self): self.generate_port_pairs() super(UdpReplayApproxVnf, self)._deploy() def _build_pipeline_kwargs(self): - tool_path = self.ssh_helper.provision_tool(self.APP_NAME) - ports_mask = 2 ** len(self.all_ports) - 1 + all_ports = [i for i, _ in enumerate(self.vnfd_helper.interfaces)] + number_of_ports = len(all_ports) + + tool_path = self.ssh_helper.provision_tool(tool_file=self.APP_NAME) + ports_mask = 2 ** number_of_ports - 1 ports_mask_hex = hex(ports_mask) - cpu_mask_hex = hex(ports_mask * 2) - hw_csum = self.CSUM_MAP.get(self.nfvi_type, "--no-hw-csum") - config_value = "".join(str((port, 0, port + 1)) for port in self.all_ports) + cpu_mask_hex = hex(2 ** (number_of_ports + 1) - 1) + hw_csum = "" + if (not self.scenario_helper.options.get('hw_csum', False) or + self.nfvi_context.attrs.get('nfvi_type') not in self.HW_OFFLOADING_NFVI_TYPES): + hw_csum = '--no-hw-csum' + + config_value = "".join(str((port, 0, port + 1)) for port in all_ports) - whitelist = " -w ".join(self.bound_pci) + whitelist = " -w ".join(self.setup_helper.bound_pci) self.pipeline_kwargs = { 'ports_len_hex': ports_mask_hex, 'tool_path': tool_path, @@ -68,13 +97,19 @@ class UdpReplayApproxVnf(SampleVNF): 'config': config_value, } + def _build_config(self): + self._build_pipeline_kwargs() + return self.PIPELINE_COMMAND.format(**self.pipeline_kwargs) + def collect_kpi(self): def get_sum(offset): return sum(int(i) for i in split_stats[offset::5]) + number_of_ports = len(self.vnfd_helper.interfaces) + stats = self.get_stats() stats_words = stats.split() - split_stats = stats_words[stats_words.index('0'):][:len(self.all_ports) * 5] + split_stats = stats_words[stats_words.index('0'):][:number_of_ports * 5] result = { "packets_in": get_sum(1), "packets_fwd": get_sum(2), -- cgit 1.2.3-korg