summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepak S <deepak.s@linux.intel.com>2017-06-20 14:18:57 -0700
committerRoss Brattain <ross.b.brattain@intel.com>2017-08-08 12:57:42 -0700
commit4545b967760ca795a3c67f043eaca60798a90570 (patch)
tree5ced218450c7fb96e1b6230080fc5cfc901b50fa
parent5ce3b6f8c8b3217091e51a6041455738603d90b8 (diff)
IXIA traffic generator
Change-Id: I09bcb3f2c4b945283070d442589d3bf00468abbc Signed-off-by: Deepak S <deepak.s@linux.intel.com> Signed-off-by: Edward MacGillivray <edward.s.macgillivray@intel.com> Signed-off-by: Ross Brattain <ross.b.brattain@intel.com>
-rw-r--r--etc/yardstick/nodes/pod.yaml.nsb.sample.ixia90
-rw-r--r--samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml121
-rw-r--r--samples/vnf_samples/vnf_descriptors/ixia_rfc2544_tpl.yaml79
-rw-r--r--samples/vnf_samples/vnf_descriptors/tg_ixload.yaml80
-rw-r--r--samples/vnf_samples/vnf_descriptors/tg_ixload_4port.yaml104
-rw-r--r--tests/unit/common/test_utils.py26
-rw-r--r--tests/unit/network_services/libs/__init__.py0
-rw-r--r--tests/unit/network_services/libs/ixia_libs/__init__.py0
-rw-r--r--tests/unit/network_services/libs/ixia_libs/test_IxNet.py882
-rw-r--r--tests/unit/network_services/traffic_profile/test_http_ixload.py250
-rw-r--r--tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py648
-rw-r--r--tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py374
-rw-r--r--tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py405
-rw-r--r--yardstick/common/utils.py26
-rw-r--r--yardstick/network_services/libs/__init__.py0
-rw-r--r--yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py335
-rw-r--r--yardstick/network_services/libs/ixia_libs/IxNet/__init__.py0
-rw-r--r--yardstick/network_services/libs/ixia_libs/__init__.py0
-rw-r--r--yardstick/network_services/traffic_profile/http_ixload.py294
-rw-r--r--yardstick/network_services/traffic_profile/ixia_rfc2544.py155
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_ixload.py176
-rw-r--r--yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py165
22 files changed, 4210 insertions, 0 deletions
diff --git a/etc/yardstick/nodes/pod.yaml.nsb.sample.ixia b/etc/yardstick/nodes/pod.yaml.nsb.sample.ixia
new file mode 100644
index 000000000..57a83058e
--- /dev/null
+++ b/etc/yardstick/nodes/pod.yaml.nsb.sample.ixia
@@ -0,0 +1,90 @@
+# Copyright (c) 2016-2017 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.
+
+nodes:
+-
+ name: trafficgen_1
+ role: IxNet
+ ip: 1.2.1.1 #ixia machine ip
+ user: user
+ password: r00t
+ key_filename: /root/.ssh/id_rsa
+ tg_config:
+ ixchassis: "1.2.1.7" #ixia chassis ip
+ tcl_port: "8009" # tcl server port
+ lib_path: "/opt/ixia/ixos-api/8.01.0.2/lib/ixTcl1.0"
+ root_dir: "/opt/ixia/ixos-api/8.01.0.2/"
+ py_bin_path: "/opt/ixia/ixload/8.01.106.3/bin/"
+ py_lib_path: "/opt/ixia/ixnetwork/8.01.1029.14/lib/PythonApi"
+ dut_result_dir: "/mnt/ixia"
+ version: 8.1
+ interfaces:
+ xe0: # logical name from topology.yaml and vnfd.yaml
+ vpci: "2:5" # Card:port
+ driver: "none"
+ dpdk_port_num: 0
+ local_ip: "152.16.100.20"
+ netmask: "255.255.0.0"
+ local_mac: "00:98:10:64:14:00"
+ xe1: # logical name from topology.yaml and vnfd.yaml
+ vpci: "2:6" # [(Card, port)]
+ driver: "none"
+ dpdk_port_num: 1
+ local_ip: "152.40.40.20"
+ netmask: "255.255.0.0"
+ local_mac: "00:98:28:28:14:00"
+-
+ name: vnf
+ role: VirtualNetworkFunction
+ ip: 192.168.100.101
+ user: root
+ password: r00t
+ host: 192.168.100.101
+ key_filename: /root/.ssh/id_rsa
+ interfaces:
+ xe0: # logical name from topology.yaml and vnfd.yaml
+ vpci: "0000:07:00.2"
+ driver: "i40e"
+ dpdk_port_num: 0
+ local_ip: "152.16.100.10"
+ netmask: "255.255.0.0"
+ local_mac: "00:00:00:00:00:03"
+
+ xe1: # logical name from topology.yaml and vnfd.yaml
+ vpci: "0000:07:00.3"
+ driver: "i40e"
+ dpdk_port_num: 1
+ local_ip: "152.40.40.10"
+ netmask: "255.255.0.0"
+ local_mac: "00:00:00:00:00:04"
+
+ routing_table:
+ - network: "152.16.100.20"
+ netmask: "255.255.0.0"
+ gateway: "152.16.100.20"
+ if: "xe0"
+ - network: "152.40.40.20"
+ netmask: "255.255.0.0"
+ gateway: "152.40.40.20"
+ if: "xe1"
+
+ 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:9828:2814"
+ netmask: "112"
+ gateway: "0064:ff9b:0:0:0:0:9828:2814"
+ if: "xe1"
diff --git a/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml
new file mode 100644
index 000000000..ccd40c33b
--- /dev/null
+++ b/samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml
@@ -0,0 +1,121 @@
+# flow definition for ACL tests - 1K flows - ipv4 only
+#
+# the number of flows defines the widest range of parameters
+# for example if srcip_range=1.0.0.1-1.0.0.255 and dst_ip_range=10.0.0.1-10.0.1.255
+# and it should define only 16 flows
+#
+#there is assumption that packets generated will have a random sequences of following addresses pairs
+# in the packets
+# 1. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512)
+# 2. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512)
+# ...
+# 512. src=1.x.x.x(x.x.x =random from 1..255) dst=10.x.x.x (random from 1..512)
+#
+# not all combination should be filled
+# Any other field with random range will be added to flow definition
+#
+# the example.yaml provides all possibilities for traffic generation
+#
+# the profile defines a public and private side to make limited traffic correlation
+# between private and public side same way as it is made by IXIA solution.
+#
+schema: "isb:traffic_profile:0.1"
+
+# This file is a template, it will be filled with values from tc.yaml before passing to the traffic generator
+
+name: rfc2544
+description: Traffic profile to run RFC2544 latency
+traffic_profile:
+ traffic_type : IXIARFC2544Profile # defines traffic behavior - constant or look for highest possible throughput
+ frame_rate : 100 # pc of linerate
+ # that specifies a range (e.g. ipv4 address, port)
+
+
+private_1:
+ ipv4:
+ outer_l2:
+ framesize:
+ 64B: "{{ get(imix, 'imix.private.imix_small', '0') }}"
+ 128B: "{{ get(imix, 'imix.private.imix_128B', '0') }}"
+ 256B: "{{ get(imix, 'imix.private.imix_256B', '0') }}"
+ 373b: "{{ get(imix, 'imix.private.imix_373B', '0') }}"
+ 570B: "{{get(imix, 'imix.private.imix_570B', '0') }}"
+ 1400B: "{{get(imix, 'imix.private.imix_1400B', '0') }}"
+ 1518B: "{{get(imix, 'imix.private.imix_1500B', '0') }}"
+
+ outer_l3v4:
+ proto: "udp"
+ srcip4: "{{get(flow, 'flow.srcip4_range', '1.1.1.1-1.15.255.255') }}"
+ dstip4: "{{get(flow, 'flow.dstip4_range', '90.90.1.1-90.105.255.255') }}"
+ count: "{{get(flow, 'flow.count', '1') }}"
+ ttl: 32
+ dscp: 0
+ outer_l4:
+ srcport: "{{get(flow, 'flow.srcport_range', '1234') }}"
+ dstport: "{{get(flow, 'flow.dstport_range', '2001') }}"
+public_1:
+ ipv4:
+ outer_l2:
+ framesize:
+ 64B: "{{ get(imix, 'imix.private.imix_small', '0') }}"
+ 128B: "{{ get(imix, 'imix.private.imix_128B', '0') }}"
+ 256B: "{{ get(imix, 'imix.private.imix_256B', '0') }}"
+ 373b: "{{ get(imix, 'imix.private.imix_373B', '0') }}"
+ 570B: "{{get(imix, 'imix.private.imix_570B', '0') }}"
+ 1400B: "{{get(imix, 'imix.private.imix_1400B', '0') }}"
+ 1518B: "{{get(imix, 'imix.private.imix_1500B', '0') }}"
+
+ outer_l3v4:
+ proto: "udp"
+ srcip4: "{{get(flow, 'flow.dstip4_range', '1.1.1.1-1.15.255.255') }}"
+ dstip4: "{{get(flow, 'flow.srcip4_range', '90.90.1.1-90.105.255.255') }}"
+ count: "{{get(flow, 'flow.count', '1') }}"
+ ttl: 32
+ dscp: 0
+ outer_l4:
+ srcport: "{{get(flow, 'flow.srcport_range', '1234') }}"
+ dstport: "{{get(flow, 'flow.dstport_range', '2001') }}"
+private_2:
+ ipv4:
+ outer_l2:
+ framesize:
+ 64B: "{{ get(imix, 'imix.private.imix_small', '0') }}"
+ 128B: "{{ get(imix, 'imix.private.imix_128B', '0') }}"
+ 256B: "{{ get(imix, 'imix.private.imix_256B', '0') }}"
+ 373b: "{{ get(imix, 'imix.private.imix_373B', '0') }}"
+ 570B: "{{get(imix, 'imix.private.imix_570B', '0') }}"
+ 1400B: "{{get(imix, 'imix.private.imix_1400B', '0') }}"
+ 1518B: "{{get(imix, 'imix.private.imix_1500B', '0') }}"
+
+ outer_l3v4:
+ proto: "udp"
+ srcip4: "{{get(flow, 'flow.srcip4_range', '1.1.1.1-1.15.255.255') }}"
+ dstip4: "{{get(flow, 'flow.dstip4_range', '90.90.1.1-90.105.255.255') }}"
+ count: "{{get(flow, 'flow.count', '1') }}"
+ ttl: 32
+ dscp: 0
+ outer_l4:
+ srcport: "{{get(flow, 'flow.srcport_range', '1234') }}"
+ dstport: "{{get(flow, 'flow.dstport_range', '2001') }}"
+public_2:
+ ipv4:
+ outer_l2:
+ framesize:
+ 64B: "{{ get(imix, 'imix.private.imix_small', '0') }}"
+ 128B: "{{ get(imix, 'imix.private.imix_128B', '0') }}"
+ 256B: "{{ get(imix, 'imix.private.imix_256B', '0') }}"
+ 373b: "{{ get(imix, 'imix.private.imix_373B', '0') }}"
+ 570B: "{{get(imix, 'imix.private.imix_570B', '0') }}"
+ 1400B: "{{get(imix, 'imix.private.imix_1400B', '0') }}"
+ 1518B: "{{get(imix, 'imix.private.imix_1500B', '0') }}"
+
+ outer_l3v4:
+ proto: "udp"
+ srcip4: "{{get(flow, 'flow.dstip4_range', '1.1.1.1-1.15.255.255') }}"
+ dstip4: "{{get(flow, 'flow.srcip4_range', '90.90.1.1-90.105.255.255') }}"
+ count: "{{get(flow, 'flow.count', '1') }}"
+ ttl: 32
+ dscp: 0
+ outer_l4:
+ srcport: "{{get(flow, 'flow.srcport_range', '1234') }}"
+ dstport: "{{get(flow, 'flow.dstport_range', '2001') }}"
diff --git a/samples/vnf_samples/vnf_descriptors/ixia_rfc2544_tpl.yaml b/samples/vnf_samples/vnf_descriptors/ixia_rfc2544_tpl.yaml
new file mode 100644
index 000000000..4b520f61b
--- /dev/null
+++ b/samples/vnf_samples/vnf_descriptors/ixia_rfc2544_tpl.yaml
@@ -0,0 +1,79 @@
+#
+# Copyright 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.
+#
+vnfd:vnfd-catalog:
+ vnfd:
+ - id: IXIATrafficGen # ISB class mapping
+ name: IXIAtrafficgen
+ short-name: ixia
+ description: IXIA stateless traffic verifier
+ mgmt-interface:
+ vdu-id: trexgen-baremetal
+ user: '{{user}}' # Value filled by vnfdgen
+ password: '{{password}}' # Value filled by vnfdgen
+ ip: '{{ip}}' # Value filled by vnfdgen
+ tg-config:
+ ixchassis: '{{tg_config.ixchassis}}' #ixia chassis ip
+ tcl_port: '{{tg_config.tcl_port}}' # tcl server port
+ lib_path: '{{tg_config.lib_path}}'
+ root_dir: '{{tg_config.root_dir}}'
+ py_lib_path: '{{tg_config.py_lib_path}}'
+ py_bin_path: '{{tg_config.py_bin_path}}'
+ dut_result_dir: '{{tg_config.dut_result_dir}}'
+ version: '{{tg_config.version}}'
+ connection-point:
+ - name: xe0
+ type: VPORT
+ - name: xe1
+ type: VPORT
+ vdu:
+ - id: trexgen-baremetal
+ name: trexgen-baremetal
+ description: IXIAstateless traffic verifier
+ external-interface:
+ - name: xe0
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ # Substitution variables MUST be quoted. Otherwise Python can misinterpet them.
+ vpci: '{{ interfaces.xe0.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe0.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe0.local_ip }}' # Value filled by vnfdgen
+ driver: '{{ interfaces.xe0.driver}}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe0.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe0.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe0.dst_mac }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe0
+ - name: xe1
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe1.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe1.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe1.local_ip }}' # Value filled by vnfdgen
+ driver: '{{ interfaces.xe1.driver}}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe1.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe1.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe1.dst_mac }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe1
+
+ benchmark:
+ kpi:
+ - rx_throughput_fps
+ - tx_throughput_fps
+ - tx_throughput_mbps
+ - rx_throughput_mbps
+ - in_packets
+ - out_packets
diff --git a/samples/vnf_samples/vnf_descriptors/tg_ixload.yaml b/samples/vnf_samples/vnf_descriptors/tg_ixload.yaml
new file mode 100644
index 000000000..b430d35bd
--- /dev/null
+++ b/samples/vnf_samples/vnf_descriptors/tg_ixload.yaml
@@ -0,0 +1,80 @@
+#
+# Copyright 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.
+#
+vnfd:vnfd-catalog:
+ vnfd:
+ - id: IxLoadTrafficGen
+ name: IxLoadTrafficGenVnfSshIntel
+ short-name: IxLoadTrafficGenVnf
+ description: IxLoad client/server connection details
+ mgmt-interface:
+ user: '{{user}}' # Value filled by vnfdgen
+ password: '{{password}}' # Value filled by vnfdgen
+ ip: '{{ip}}' # Value filled by vnfdgen
+ tg-config:
+ ixchassis: '{{tg_config.ixchassis}}' #ixia chassis ip
+ tcl_port: '{{tg_config.tcl_port}}' # tcl server port
+ lib_path: '{{tg_config.lib_path}}'
+ root_dir: '{{tg_config.root_dir}}'
+ py_lib_path: '{{tg_config.py_lib_path}}'
+ py_bin_path: '{{tg_config.py_bin_path}}'
+ dut_result_dir: '{{tg_config.dut_result_dir}}'
+ version: '{{tg_config.version}}'
+ vdu:
+ - id: abclient-baremetal
+ name: abclient-baremetal
+ description: AB client interface details
+ external-interface:
+ - name: xe0
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe0.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe0.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe0.local_ip }}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe0.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe0.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe0.dst_mac }}' # Value filled by vnfdgen
+ netmask: '{{ interfaces.xe0.netmask }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe0
+ - name: xe1
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe1.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe1.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe1.local_ip }}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe1.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe1.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe1.dst_mac }}' # Value filled by vnfdgen
+ netmask: '{{ interfaces.xe1.netmask }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe1
+ benchmark:
+ kpi:
+ - complete_requests
+ - failed_requests
+ - time_taken_for_tests [seconds]
+ - requests_per_second [#/sec] (mean)
+ - time_per_request [ms] (mean, across all concurrent requests)
+ - transfer_rate [Kbytes/sec] received
+ - requests_served_50% (ms)
+ - requests_served_66% (ms)
+ - requests_served_75% (ms)
+ - requests_served_80% (ms)
+ - requests_served_90% (ms)
+ - requests_served_95% (ms)
+ - requests_served_98% (ms)
+ - requests_served_99% (ms)
+ - requests_served_100% (ms) \ No newline at end of file
diff --git a/samples/vnf_samples/vnf_descriptors/tg_ixload_4port.yaml b/samples/vnf_samples/vnf_descriptors/tg_ixload_4port.yaml
new file mode 100644
index 000000000..ffbfbdec0
--- /dev/null
+++ b/samples/vnf_samples/vnf_descriptors/tg_ixload_4port.yaml
@@ -0,0 +1,104 @@
+#
+# Copyright 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.
+#
+vnfd:vnfd-catalog:
+ vnfd:
+ - id: IxLoadTrafficGen
+ name: IxLoadTrafficGenVnfSshIntel
+ short-name: IxLoadTrafficGenVnf
+ description: IxLoad client/server connection details
+ mgmt-interface:
+ user: '{{user}}' # Value filled by vnfdgen
+ password: '{{password}}' # Value filled by vnfdgen
+ ip: '{{ip}}' # Value filled by vnfdgen
+ tg-config:
+ ixchassis: '{{tg_config.ixchassis}}' #ixia chassis ip
+ tcl_port: '{{tg_config.tcl_port}}' # tcl server port
+ lib_path: '{{tg_config.lib_path}}'
+ root_dir: '{{tg_config.root_dir}}'
+ py_lib_path: '{{tg_config.py_lib_path}}'
+ dut_result_dir: '{{tg_config.dut_result_dir}}'
+ version: '{{tg_config.version}}'
+ vdu:
+ - id: abclient-baremetal
+ name: abclient-baremetal
+ description: AB client interface details
+ external-interface:
+ - name: xe0
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe0.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe0.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe0.local_ip }}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe0.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe0.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe0.dst_mac }}' # Value filled by vnfdgen
+ netmask: '{{ interfaces.xe0.netmask }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe0
+ - name: xe1
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe1.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe1.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe1.local_ip }}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe1.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe1.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe1.dst_mac }}' # Value filled by vnfdgen
+ netmask: '{{ interfaces.xe1.netmask }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe1
+ - name: xe2
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe2.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe2.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe2.local_ip }}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe2.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe2.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe2.dst_mac }}' # Value filled by vnfdgen
+ netmask: '{{ interfaces.xe2.netmask }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe2
+ - name: xe3
+ virtual-interface:
+ type: PCI-PASSTHROUGH
+ vpci: '{{ interfaces.xe3.vpci }}' # Value filled by vnfdgen
+ local_iface_name: '{{ interfaces.xe3.local_iface_name }}' # Value filled by vnfdgen
+ local_ip: '{{ interfaces.xe3.local_ip }}' # Value filled by vnfdgen
+ dst_ip: '{{ interfaces.xe3.dst_ip }}' # Value filled by vnfdgen
+ local_mac: '{{ interfaces.xe3.local_mac }}' # Value filled by vnfdgen
+ dst_mac: '{{ interfaces.xe3.dst_mac }}' # Value filled by vnfdgen
+ netmask: '{{ interfaces.xe3.netmask }}' # Value filled by vnfdgen
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe3
+
+ benchmark:
+ kpi:
+ - complete_requests
+ - failed_requests
+ - time_taken_for_tests [seconds]
+ - requests_per_second [#/sec] (mean)
+ - time_per_request [ms] (mean, across all concurrent requests)
+ - transfer_rate [Kbytes/sec] received
+ - requests_served_50% (ms)
+ - requests_served_66% (ms)
+ - requests_served_75% (ms)
+ - requests_served_80% (ms)
+ - requests_served_90% (ms)
+ - requests_served_95% (ms)
+ - requests_served_98% (ms)
+ - requests_served_99% (ms)
+ - requests_served_100% (ms)
diff --git a/tests/unit/common/test_utils.py b/tests/unit/common/test_utils.py
index 53b56523e..948f8fc98 100644
--- a/tests/unit/common/test_utils.py
+++ b/tests/unit/common/test_utils.py
@@ -916,6 +916,32 @@ class TestUtils(unittest.TestCase):
result = utils.parse_ini_file('my_path')
self.assertDictEqual(result, expected)
+ def test_join_non_strings(self):
+ self.assertEqual(utils.join_non_strings(':'), '')
+ self.assertEqual(utils.join_non_strings(':', 'a'), 'a')
+ self.assertEqual(utils.join_non_strings(':', 'a', 2, 'c'), 'a:2:c')
+ self.assertEqual(utils.join_non_strings(':', ['a', 2, 'c']), 'a:2:c')
+ self.assertEqual(utils.join_non_strings(':', 'abc'), 'abc')
+
+ def test_validate_non_string_sequence(self):
+ self.assertEqual(utils.validate_non_string_sequence([1, 2, 3]), [1, 2, 3])
+ self.assertIsNone(utils.validate_non_string_sequence('123'))
+ self.assertIsNone(utils.validate_non_string_sequence(1))
+
+ self.assertEqual(utils.validate_non_string_sequence(1, 2), 2)
+ self.assertEqual(utils.validate_non_string_sequence(1, default=2), 2)
+
+ with self.assertRaises(RuntimeError):
+ utils.validate_non_string_sequence(1, raise_exc=RuntimeError)
+
+ def test_error_class(self):
+ with self.assertRaises(RuntimeError):
+ utils.ErrorClass()
+
+ error_instance = utils.ErrorClass(test='')
+ with self.assertRaises(AttributeError):
+ error_instance.get_name()
+
class TestUtilsIpAddrMethods(unittest.TestCase):
diff --git a/tests/unit/network_services/libs/__init__.py b/tests/unit/network_services/libs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/unit/network_services/libs/__init__.py
diff --git a/tests/unit/network_services/libs/ixia_libs/__init__.py b/tests/unit/network_services/libs/ixia_libs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/unit/network_services/libs/ixia_libs/__init__.py
diff --git a/tests/unit/network_services/libs/ixia_libs/test_IxNet.py b/tests/unit/network_services/libs/ixia_libs/test_IxNet.py
new file mode 100644
index 000000000..9114b5163
--- /dev/null
+++ b/tests/unit/network_services/libs/ixia_libs/test_IxNet.py
@@ -0,0 +1,882 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016-2017 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.
+#
+
+# Unittest for yardstick.network_services.libs.ixia_libs.IxNet
+
+from __future__ import absolute_import
+import unittest
+import mock
+
+from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IxNextgen
+from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IP_VERSION_4
+from yardstick.network_services.libs.ixia_libs.IxNet.IxNet import IP_VERSION_6
+
+
+class TestIxNextgen(unittest.TestCase):
+
+ def test___init__(self):
+ ixnet_gen = IxNextgen()
+ self.assertIsNone(ixnet_gen._bidir)
+
+ @mock.patch("yardstick.network_services.libs.ixia_libs.IxNet.IxNet.IxNetwork")
+ @mock.patch("yardstick.network_services.libs.ixia_libs.IxNet.IxNet.sys")
+ def test_connect(self, mock_sys, mock_ix_network):
+ mock_ix_network.IxNet.return_value = mock_ixnet = mock.Mock()
+
+ ixnet_gen = IxNextgen()
+ ixnet_gen.get_config = mock.MagicMock()
+ ixnet_gen.get_ixnet = mock.MagicMock()
+
+ result = ixnet_gen._connect({"py_lib_path": "/tmp"})
+ self.assertIsNotNone(result)
+ self.assertEqual(mock_ix_network.IxNet.call_count, 1)
+ self.assertEqual(mock_ixnet.connect.call_count, 1)
+
+ def test_clear_ixia_config(self):
+ ixnet = mock.MagicMock()
+ ixnet.execute = mock.Mock()
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.clear_ixia_config()
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.execute.call_count, 1)
+
+ def test_load_ixia_profile(self):
+ ixnet = mock.MagicMock()
+ ixnet.execute = mock.Mock()
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.load_ixia_profile({})
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.execute.call_count, 1)
+
+ def test_load_ixia_config(self):
+ ixnet = mock.MagicMock()
+ ixnet.execute = mock.Mock()
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_load_config({})
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.execute.call_count, 2)
+
+ @mock.patch('yardstick.network_services.libs.ixia_libs.IxNet.IxNet.log')
+ def test_ix_assign_ports(self, mock_logger):
+ ixnet = mock.MagicMock()
+ ixnet.getList.return_value = [0, 1]
+ ixnet.getAttribute.side_effect = ['up', 'down']
+
+ config = {
+ 'chassis': '1.1.1.1',
+ 'card1': '1',
+ 'card2': '2',
+ 'port1': '2',
+ 'port2': '2',
+ }
+
+ ixnet_gen = IxNextgen(ixnet)
+ ixnet_gen._cfg = config
+
+ result = ixnet_gen.ix_assign_ports()
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.execute.call_count, 1)
+ self.assertEqual(ixnet.commit.call_count, 1)
+ self.assertEqual(ixnet.getAttribute.call_count, 2)
+ self.assertEqual(mock_logger.error.call_count, 1)
+
+ def test_ix_update_frame(self):
+ static_traffic_params = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": {
+ "64B": "100",
+ "1KB": "0",
+ },
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": False,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+
+ ixnet = mock.MagicMock()
+ ixnet.remapIds.return_value = ["0"]
+ ixnet.setMultiAttribute.return_value = [1]
+ ixnet.commit.return_value = [1]
+ ixnet.getList.side_effect = [
+ [1],
+ [1],
+ [1],
+ [
+ "ethernet.header.destinationAddress",
+ "ethernet.header.sourceAddress",
+ ],
+ ]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_update_frame(static_traffic_params)
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.setMultiAttribute.call_count, 7)
+ self.assertEqual(ixnet.commit.call_count, 2)
+
+ def test_ix_update_udp(self):
+ ixnet = mock.MagicMock()
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_update_udp({})
+ self.assertIsNone(result)
+
+ def test_ix_update_tcp(self):
+ ixnet = mock.MagicMock()
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_update_tcp({})
+ self.assertIsNone(result)
+
+ def test_ix_start_traffic(self):
+ ixnet = mock.MagicMock()
+ ixnet.getList.return_value = [0]
+ ixnet.getAttribute.return_value = 'down'
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_start_traffic()
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.getList.call_count, 1)
+ self.assertEqual(ixnet.execute.call_count, 3)
+
+ def test_ix_stop_traffic(self):
+ ixnet = mock.MagicMock()
+ ixnet.getList.return_value = [0]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_stop_traffic()
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.getList.call_count, 1)
+ self.assertEqual(ixnet.execute.call_count, 1)
+
+ def test_ix_get_statistics(self):
+ ixnet = mock.MagicMock()
+ ixnet.execute.return_value = ""
+ ixnet.getList.side_effect = [
+ [
+ '::ixNet::OBJ-/statistics/view:"Traffic Item Statistics"',
+ '::ixNet::OBJ-/statistics/view:"Port Statistics"',
+ ],
+ [
+ '::ixNet::OBJ-/statistics/view:"Flow Statistics"',
+ ],
+ ]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_get_statistics()
+ self.assertIsNotNone(result)
+ self.assertEqual(ixnet.getList.call_count, 2)
+ self.assertEqual(ixnet.execute.call_count, 20)
+
+ def test_find_view_obj_no_where(self):
+ views = ['here', 'there', 'everywhere']
+ result = IxNextgen.find_view_obj('no_where', views)
+ self.assertEqual(result, '')
+
+ def test_add_ip_header_v4(self):
+ static_traffic_params = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "count": 1024,
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+
+ ixnet = mock.MagicMock()
+ ixnet.remapIds.return_value = ["0"]
+ ixnet.setMultiAttribute.return_value = [1]
+ ixnet.commit.return_value = [1]
+ ixnet.getList.side_effect = [[1], [0], [0], ["srcIp", "dstIp"]]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_4)
+ self.assertIsNone(result)
+ self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
+ self.assertEqual(ixnet.commit.call_count, 1)
+
+ def test_add_ip_header_v4_nothing_to_do(self):
+ static_traffic_params = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "count": 1024,
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+
+ ixnet = mock.MagicMock()
+ ixnet.remapIds.return_value=["0"]
+ ixnet.setMultiAttribute.return_value = [1]
+ ixnet.commit.return_value = [1]
+ ixnet.getList.side_effect = [[1], [0, 1], [0], ["srcIp", "dstIp"]]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_4)
+ self.assertIsNone(result)
+ self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
+ self.assertEqual(ixnet.commit.call_count, 1)
+
+ def test_add_ip_header_v6(self):
+ static_traffic_profile = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+
+ ixnet = mock.MagicMock()
+ ixnet.getList.side_effect = [[1], [1], [1], ["srcIp", "dstIp"]]
+ ixnet.remapIds.return_value = ["0"]
+ ixnet.setMultiAttribute.return_value = [1]
+ ixnet.commit.return_value = [1]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.add_ip_header(static_traffic_profile, IP_VERSION_6)
+ self.assertIsNone(result)
+ self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
+ self.assertEqual(ixnet.commit.call_count, 1)
+
+ def test_add_ip_header_v6_nothing_to_do(self):
+ static_traffic_params = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "count": 1024,
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": {"64B": "100"},
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+
+ ixnet = mock.MagicMock()
+ ixnet.getList.side_effect = [[1], [0, 1], [1], ["srcIP", "dstIP"]]
+ ixnet.remapIds.return_value = ["0"]
+ ixnet.setMultiAttribute.return_value = [1]
+ ixnet.commit.return_value = [1]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.add_ip_header(static_traffic_params, IP_VERSION_6)
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.setMultiAttribute.call_count, 0)
+
+ def test_set_random_ip_multi_attributes_bad_ip_version(self):
+ bad_ip_version = object()
+ ixnet_gen = IxNextgen(mock.Mock())
+ mock1 = mock.Mock()
+ mock2 = mock.Mock()
+ mock3 = mock.Mock()
+ with self.assertRaises(ValueError):
+ ixnet_gen.set_random_ip_multi_attributes(mock1, bad_ip_version, mock2, mock3)
+
+ def test_get_config(self):
+ tg_cfg = {
+ "vdu": [
+ {
+ "external-interface": [
+ {
+ "virtual-interface": {
+ "vpci": "0000:07:00.1",
+ },
+ },
+ {
+ "virtual-interface": {
+ "vpci": "0001:08:01.2",
+ },
+ },
+ ],
+ },
+ ],
+ "mgmt-interface": {
+ "ip": "test1",
+ "tg-config": {
+ "dut_result_dir": "test2",
+ "version": "test3",
+ "ixchassis": "test4",
+ "tcl_port": "test5",
+ "py_lib_path": "test6",
+ },
+ }
+ }
+
+ expected = {
+ 'py_lib_path': 'test6',
+ 'machine': 'test1',
+ 'port': 'test5',
+ 'chassis': 'test4',
+ 'card1': '0000',
+ 'port1': '07',
+ 'card2': '0001',
+ 'port2': '08',
+ 'output_dir': 'test2',
+ 'version': 'test3',
+ 'bidir': True,
+ }
+
+ result = IxNextgen.get_config(tg_cfg)
+ self.assertDictEqual(result, expected)
+
+ def test_ix_update_ether(self):
+ static_traffic_params = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+
+ ixnet = mock.MagicMock()
+ ixnet.setMultiAttribute.return_value = [1]
+ ixnet.commit.return_value = [1]
+ ixnet.getList.side_effect = [
+ [1],
+ [1],
+ [1],
+ [
+ "ethernet.header.destinationAddress",
+ "ethernet.header.sourceAddress",
+ ],
+ ]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_update_ether(static_traffic_params)
+ self.assertIsNone(result)
+ self.assertGreater(ixnet.setMultiAttribute.call_count, 0)
+
+ def test_ix_update_ether_nothing_to_do(self):
+ static_traffic_params = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+
+ ixnet = mock.MagicMock()
+ ixnet.setMultiAttribute.return_value = [1]
+ ixnet.commit.return_value = [1]
+ ixnet.getList.side_effect=[
+ [1],
+ [1],
+ [1],
+ [
+ "ethernet.header.destinationAddress",
+ "ethernet.header.sourceAddress",
+ ],
+ ]
+
+ ixnet_gen = IxNextgen(ixnet)
+
+ result = ixnet_gen.ix_update_ether(static_traffic_params)
+ self.assertIsNone(result)
+ self.assertEqual(ixnet.setMultiAttribute.call_count, 0)
diff --git a/tests/unit/network_services/traffic_profile/test_http_ixload.py b/tests/unit/network_services/traffic_profile/test_http_ixload.py
new file mode 100644
index 000000000..2e1b6f4ff
--- /dev/null
+++ b/tests/unit/network_services/traffic_profile/test_http_ixload.py
@@ -0,0 +1,250 @@
+# Copyright (c) 2017 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.
+
+
+from __future__ import absolute_import
+import unittest
+import mock
+import runpy
+
+from oslo_serialization import jsonutils
+
+from yardstick.network_services.traffic_profile import http_ixload
+
+
+class TestIxLoadTrafficGen(unittest.TestCase):
+
+ def test_parse_run_test(self):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+ j = jsonutils.dump_as_bytes(test_input)
+ ixload = http_ixload.IXLOADHttpTest(j)
+ self.assertDictEqual(ixload.test_input, test_input)
+ self.assertIsNone(ixload.parse_run_test())
+ self.assertEqual(ixload.ports_to_reassign, [
+ ["IXIA_CHASSIS", "CARD", 1],
+ ["IXIA_CHASSIS", "CARD", 2],
+ ["IXIA_CHASSIS", "CARD", 3],
+ ])
+
+ def test_format_ports_for_reassignment(self):
+ ports = [
+ ["IXIA_CHASSIS", "CARD", 1],
+ ["IXIA_CHASSIS", "CARD", 2],
+ ["IXIA_CHASSIS", "CARD", 3],
+ ]
+ formatted = http_ixload.IXLOADHttpTest.format_ports_for_reassignment(ports)
+ self.assertEqual(formatted, [
+ "IXIA_CHASSIS;CARD;1",
+ "IXIA_CHASSIS;CARD;2",
+ "IXIA_CHASSIS;CARD;3",
+ ])
+
+ def test_reassign_ports(self):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+ j = jsonutils.dump_as_bytes(test_input)
+ ixload = http_ixload.IXLOADHttpTest(j)
+ repository = mock.Mock()
+ test = mock.MagicMock()
+ test.setPorts = mock.Mock()
+ ports_to_reassign = [(1, 2, 3), (1, 2, 4)]
+ ixload.format_ports_for_reassignment = mock.Mock(return_value=["1;2;3"])
+ self.assertIsNone(ixload.reassign_ports(test, repository, ports_to_reassign))
+
+ def test_reassign_ports_error(self):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+ j = jsonutils.dump_as_bytes(test_input)
+ ixload = http_ixload.IXLOADHttpTest(j)
+ repository = mock.Mock()
+ test = "test"
+ ports_to_reassign = [(1, 2, 3), (1, 2, 4)]
+ ixload.format_ports_for_reassignment = mock.Mock(return_value=["1;2;3"])
+ ixload.ix_load = mock.MagicMock()
+ ixload.ix_load.delete = mock.Mock()
+ ixload.ix_load.disconnect = mock.Mock()
+ with self.assertRaises(Exception):
+ ixload.reassign_ports(test, repository, ports_to_reassign)
+
+ def test_stat_collector(self):
+ args = [0, 1]
+ self.assertIsNone(
+ http_ixload.IXLOADHttpTest.stat_collector(*args))
+
+ def test_IxL_StatCollectorCommand(self):
+ args = [[0, 1, 2, 3], [0, 1, 2, 3]]
+ self.assertIsNone(
+ http_ixload.IXLOADHttpTest.IxL_StatCollectorCommand(*args))
+
+ def test_set_results_dir(self):
+ test_stat_collector = mock.MagicMock()
+ test_stat_collector.setResultDir = mock.Mock()
+ results_on_windows = "c:/Results"
+ self.assertIsNone(
+ http_ixload.IXLOADHttpTest.set_results_dir(test_stat_collector,
+ results_on_windows))
+
+ def test_set_results_dir_error(self):
+ test_stat_collector = ""
+ results_on_windows = "c:/Results"
+ with self.assertRaises(Exception):
+ http_ixload.IXLOADHttpTest.set_results_dir(test_stat_collector, results_on_windows)
+
+ def test_load_config_file(self):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+ j = jsonutils.dump_as_bytes(test_input)
+ ixload = http_ixload.IXLOADHttpTest(j)
+ ixload.ix_load = mock.MagicMock()
+ ixload.ix_load.new = mock.Mock(return_value="")
+ self.assertIsNotNone(ixload.load_config_file("ixload.cfg"))
+
+ def test_load_config_file_error(self):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+ j = jsonutils.dump_as_bytes(test_input)
+ ixload = http_ixload.IXLOADHttpTest(j)
+ ixload.ix_load = "test"
+ with self.assertRaises(Exception):
+ ixload.load_config_file("ixload.cfg")
+
+ @mock.patch('yardstick.network_services.traffic_profile.http_ixload.IxLoad')
+ @mock.patch('yardstick.network_services.traffic_profile.http_ixload.StatCollectorUtils')
+ def test_start_http_test_connect_error(self, mock_collector_type, mock_ixload_type):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+
+ j = jsonutils.dump_as_bytes(test_input)
+
+ mock_ixload = mock_ixload_type()
+ mock_ixload.connect.side_effect = RuntimeError
+
+ ixload = http_ixload.IXLOADHttpTest(j)
+ ixload.results_on_windows = 'windows_result_dir'
+ ixload.result_dir = 'my_result_dir'
+
+ with self.assertRaises(RuntimeError):
+ ixload.start_http_test()
+
+ @mock.patch('yardstick.network_services.traffic_profile.http_ixload.IxLoad')
+ @mock.patch('yardstick.network_services.traffic_profile.http_ixload.StatCollectorUtils')
+ def test_start_http_test(self, mock_collector_type, mock_ixload_type):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+
+ j = jsonutils.dump_as_bytes(test_input)
+
+ ixload = http_ixload.IXLOADHttpTest(j)
+ ixload.results_on_windows = 'windows_result_dir'
+ ixload.result_dir = 'my_result_dir'
+ ixload.load_config_file = mock.MagicMock()
+
+ self.assertIsNone(ixload.start_http_test())
+
+ @mock.patch('yardstick.network_services.traffic_profile.http_ixload.IxLoad')
+ @mock.patch('yardstick.network_services.traffic_profile.http_ixload.StatCollectorUtils')
+ def test_start_http_test_reassign_error(self, mock_collector_type, mock_ixload_type):
+ ports = [1, 2, 3]
+ test_input = {
+ "remote_server": "REMOTE_SERVER",
+ "ixload_cfg": "IXLOAD_CFG",
+ "result_dir": "RESULT_DIR",
+ "ixia_chassis": "IXIA_CHASSIS",
+ "IXIA": {
+ "card": "CARD",
+ "ports": ports,
+ },
+ }
+
+ j = jsonutils.dump_as_bytes(test_input)
+
+ ixload = http_ixload.IXLOADHttpTest(j)
+ ixload.load_config_file = mock.MagicMock()
+
+ reassign_ports = mock.Mock(side_effect=RuntimeError)
+ ixload.reassign_ports = reassign_ports
+ ixload.results_on_windows = 'windows_result_dir'
+ ixload.result_dir = 'my_result_dir'
+
+ ixload.start_http_test()
+ self.assertEqual(reassign_ports.call_count, 1)
+
+ @mock.patch("yardstick.network_services.traffic_profile.http_ixload.IXLOADHttpTest")
+ def test_main(self, IXLOADHttpTest):
+ args = ["1", "2", "3"]
+ http_ixload.main(args)
diff --git a/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py b/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py
new file mode 100644
index 000000000..6dba64af9
--- /dev/null
+++ b/tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py
@@ -0,0 +1,648 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016-2017 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.
+#
+
+from __future__ import absolute_import
+from __future__ import division
+import unittest
+import mock
+
+STL_MOCKS = {
+ 'stl': mock.MagicMock(),
+ 'stl.trex_stl_lib': mock.MagicMock(),
+ 'stl.trex_stl_lib.base64': mock.MagicMock(),
+ 'stl.trex_stl_lib.binascii': mock.MagicMock(),
+ 'stl.trex_stl_lib.collections': mock.MagicMock(),
+ 'stl.trex_stl_lib.copy': mock.MagicMock(),
+ 'stl.trex_stl_lib.datetime': mock.MagicMock(),
+ 'stl.trex_stl_lib.functools': mock.MagicMock(),
+ 'stl.trex_stl_lib.imp': mock.MagicMock(),
+ 'stl.trex_stl_lib.inspect': mock.MagicMock(),
+ 'stl.trex_stl_lib.json': mock.MagicMock(),
+ 'stl.trex_stl_lib.linecache': mock.MagicMock(),
+ 'stl.trex_stl_lib.math': mock.MagicMock(),
+ 'stl.trex_stl_lib.os': mock.MagicMock(),
+ 'stl.trex_stl_lib.platform': mock.MagicMock(),
+ 'stl.trex_stl_lib.pprint': mock.MagicMock(),
+ 'stl.trex_stl_lib.random': mock.MagicMock(),
+ 'stl.trex_stl_lib.re': mock.MagicMock(),
+ 'stl.trex_stl_lib.scapy': mock.MagicMock(),
+ 'stl.trex_stl_lib.socket': mock.MagicMock(),
+ 'stl.trex_stl_lib.string': mock.MagicMock(),
+ 'stl.trex_stl_lib.struct': mock.MagicMock(),
+ 'stl.trex_stl_lib.sys': mock.MagicMock(),
+ 'stl.trex_stl_lib.threading': mock.MagicMock(),
+ 'stl.trex_stl_lib.time': mock.MagicMock(),
+ 'stl.trex_stl_lib.traceback': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(),
+ 'stl.trex_stl_lib.types': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.collections': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.common': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.json': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.os': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.random': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.re': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.string': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.sys': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(),
+ 'stl.trex_stl_lib.warnings': mock.MagicMock(),
+ 'stl.trex_stl_lib.yaml': mock.MagicMock(),
+ 'stl.trex_stl_lib.zlib': mock.MagicMock(),
+ 'stl.trex_stl_lib.zmq': mock.MagicMock(),
+}
+
+STLClient = mock.MagicMock()
+stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
+stl_patch.start()
+
+if stl_patch:
+ from yardstick.network_services.traffic_profile.traffic_profile \
+ import TrexProfile
+ from yardstick.network_services.traffic_profile.ixia_rfc2544 import \
+ IXIARFC2544Profile
+ from yardstick.network_services.traffic_profile import ixia_rfc2544
+
+
+class TestIXIARFC2544Profile(unittest.TestCase):
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64}}
+
+ PROFILE = {'description': 'Traffic profile to run RFC2544 latency',
+ 'name': 'rfc2544',
+ 'traffic_profile': {'traffic_type': 'IXIARFC2544Profile',
+ 'frame_rate': 100},
+ 'public': {'ipv4':
+ {'outer_l2': {'framesize':
+ {'64B': '100', '1518B': '0',
+ '128B': '0', '1400B': '0',
+ '256B': '0', '373b': '0',
+ '570B': '0'}},
+ 'outer_l3v4': {'dstip4': '1.1.1.1-1.15.255.255',
+ 'proto': 'udp',
+ 'srcip4': '90.90.1.1-90.105.255.255',
+ 'dscp': 0, 'ttl': 32},
+ 'outer_l4': {'srcport': '2001',
+ 'dsrport': '1234'}}},
+ 'private': {'ipv4':
+ {'outer_l2': {'framesize':
+ {'64B': '100', '1518B': '0',
+ '128B': '0', '1400B': '0',
+ '256B': '0', '373b': '0',
+ '570B': '0'}},
+ 'outer_l3v4': {'dstip4': '9.9.1.1-90.105.255.255',
+ 'proto': 'udp',
+ 'srcip4': '1.1.1.1-1.15.255.255',
+ 'dscp': 0, 'ttl': 32},
+ 'outer_l4': {'dstport': '2001',
+ 'srcport': '1234'}}},
+ 'schema': 'isb:traffic_profile:0.1'}
+
+ def test_get_ixia_traffic_profile_error(self):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [-1]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ STATIC_TRAFFIC = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+ ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC
+
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.rate = 100
+ mac = {"src_mac_0": "00:00:00:00:00:01",
+ "src_mac_1": "00:00:00:00:00:02",
+ "src_mac_2": "00:00:00:00:00:02",
+ "dst_mac_0": "00:00:00:00:00:03",
+ "dst_mac_1": "00:00:00:00:00:04",
+ "dst_mac_2": "00:00:00:00:00:04"}
+ self.assertRaises(IOError, r_f_c2544_profile._get_ixia_traffic_profile,
+ self.PROFILE, mac, xfile="tmp",
+ static_traffic=STATIC_TRAFFIC)
+
+
+ @mock.patch("yardstick.network_services.traffic_profile.ixia_rfc2544.open")
+ def test_get_ixia_traffic_profile(self, mock_open):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [-1]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ STATIC_TRAFFIC = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+ ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC
+
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.rate = 100
+ mac = {"src_mac_0": "00:00:00:00:00:01",
+ "src_mac_1": "00:00:00:00:00:02",
+ "src_mac_2": "00:00:00:00:00:02",
+ "dst_mac_0": "00:00:00:00:00:03",
+ "dst_mac_1": "00:00:00:00:00:04",
+ "dst_mac_2": "00:00:00:00:00:04"}
+ result = r_f_c2544_profile._get_ixia_traffic_profile(
+ self.PROFILE, mac, xfile="tmp", static_traffic=STATIC_TRAFFIC)
+ self.assertIsNotNone(result)
+
+ @mock.patch("yardstick.network_services.traffic_profile.ixia_rfc2544.open")
+ def test_get_ixia_traffic_profile_v6(self, mock_open):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [-1]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ STATIC_TRAFFIC = {
+ "private": {
+ "id": 1,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:03",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "dscp": 0,
+ "dstip4": "152.16.40.20",
+ "proto": "udp",
+ "srcip4": "152.16.100.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "2001",
+ "srcport": "1234"
+ },
+ "traffic_type": "continuous"
+ },
+ "public": {
+ "id": 2,
+ "bidir": "False",
+ "duration": 60,
+ "iload": "100",
+ "outer_l2": {
+ "dstmac": "00:00:00:00:00:04",
+ "framesPerSecond": True,
+ "framesize": 64,
+ "srcmac": "00:00:00:00:00:01"
+ },
+ "outer_l3": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v4": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l3v6": {
+ "count": 1024,
+ "dscp": 0,
+ "dstip4": "152.16.100.20",
+ "proto": "udp",
+ "srcip4": "152.16.40.20",
+ "ttl": 32
+ },
+ "outer_l4": {
+ "dstport": "1234",
+ "srcport": "2001"
+ },
+ "traffic_type": "continuous"
+ }
+ }
+ ixia_rfc2544.STATIC_TRAFFIC = STATIC_TRAFFIC
+
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.rate = 100
+ mac = {"src_mac_0": "00:00:00:00:00:01",
+ "src_mac_1": "00:00:00:00:00:02",
+ "src_mac_2": "00:00:00:00:00:02",
+ "dst_mac_0": "00:00:00:00:00:03",
+ "dst_mac_1": "00:00:00:00:00:04",
+ "dst_mac_2": "00:00:00:00:00:04"}
+ profile_data = {'description': 'Traffic profile to run RFC2544',
+ 'name': 'rfc2544',
+ 'traffic_profile':
+ {'traffic_type': 'IXIARFC2544Profile',
+ 'frame_rate': 100},
+ 'public':
+ {'ipv4':
+ {'outer_l2': {'framesize':
+ {'64B': '100', '1518B': '0',
+ '128B': '0', '1400B': '0',
+ '256B': '0', '373b': '0',
+ '570B': '0'}},
+ 'outer_l3v6': {'dstip6': '1.1.1.1-1.15.255.255',
+ 'proto': 'udp',
+ 'srcip6': '90.90.1.1-90.105.255.255',
+ 'dscp': 0, 'ttl': 32},
+ 'outer_l4': {'srcport': '2001',
+ 'dsrport': '1234'}}},
+ 'private': {'ipv4':
+ {'outer_l2': {'framesize':
+ {'64B': '100', '1518B': '0',
+ '128B': '0', '1400B': '0',
+ '256B': '0', '373b': '0',
+ '570B': '0'}},
+ 'outer_l3v6':
+ {'dstip6': '9.9.1.1-90.105.255.255',
+ 'proto': 'udp',
+ 'srcip6': '1.1.1.1-1.15.255.255',
+ 'dscp': 0, 'ttl': 32},
+ 'outer_l4': {'dstport': '2001',
+ 'srcport': '1234'}}},
+ 'schema': 'isb:traffic_profile:0.1'}
+ result = r_f_c2544_profile._get_ixia_traffic_profile(
+ profile_data, mac, static_traffic=STATIC_TRAFFIC)
+ self.assertIsNotNone(result)
+
+ def test__ixia_traffic_generate(self):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [-1]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ traffic = {"public": {'iload': 10},
+ "private": {'iload': 10}}
+ ixia_obj = mock.MagicMock()
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.rate = 100
+ result = r_f_c2544_profile._ixia_traffic_generate(traffic_generator,
+ traffic, ixia_obj)
+ self.assertIsNone(result)
+
+ def test_execute(self):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [-1]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.first_run = True
+ r_f_c2544_profile.params = {"public": {'iload': 10},
+ "private": {'iload': 10}}
+
+ r_f_c2544_profile.get_streams = mock.Mock()
+ r_f_c2544_profile.full_profile = {}
+ r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
+ r_f_c2544_profile.get_multiplier = mock.Mock()
+ r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
+ ixia_obj = mock.MagicMock()
+ self.assertEqual(None, r_f_c2544_profile.execute(traffic_generator,
+ ixia_obj))
+
+ def test_get_drop_percentage(self):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [0]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.params = self.PROFILE
+ ixia_obj = mock.MagicMock()
+ r_f_c2544_profile.execute = mock.Mock()
+ r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
+ r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
+ r_f_c2544_profile.get_multiplier = mock.Mock()
+ r_f_c2544_profile.tmp_throughput = 0
+ r_f_c2544_profile.tmp_drop = 0
+ r_f_c2544_profile.full_profile = {}
+ samples = {}
+ for ifname in range(1):
+ name = "xe{}".format(ifname)
+ samples[name] = {"rx_throughput_fps": 20,
+ "tx_throughput_fps": 20,
+ "rx_throughput_mbps": 10,
+ "tx_throughput_mbps": 10,
+ "RxThroughput": 10,
+ "TxThroughput": 10,
+ "in_packets": 1000,
+ "out_packets": 1000}
+ tol_min = 100.0
+ tolerance = 0.0
+ self.assertIsNotNone(r_f_c2544_profile.get_drop_percentage(
+ traffic_generator, samples,
+ tol_min, tolerance, ixia_obj))
+
+ def test_get_drop_percentage_update(self):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [0]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.params = self.PROFILE
+ ixia_obj = mock.MagicMock()
+ r_f_c2544_profile.execute = mock.Mock()
+ r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
+ r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
+ r_f_c2544_profile.get_multiplier = mock.Mock()
+ r_f_c2544_profile.tmp_throughput = 0
+ r_f_c2544_profile.tmp_drop = 0
+ r_f_c2544_profile.full_profile = {}
+ samples = {}
+ for ifname in range(1):
+ name = "xe{}".format(ifname)
+ samples[name] = {"rx_throughput_fps": 20,
+ "tx_throughput_fps": 20,
+ "rx_throughput_mbps": 10,
+ "tx_throughput_mbps": 10,
+ "RxThroughput": 10,
+ "TxThroughput": 10,
+ "in_packets": 1000,
+ "out_packets": 1002}
+ tol_min = 0.0
+ tolerance = 1.0
+ self.assertIsNotNone(r_f_c2544_profile.get_drop_percentage(
+ traffic_generator, samples,
+ tol_min, tolerance, ixia_obj))
+
+ def test_get_drop_percentage_div_zero(self):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [0]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.params = self.PROFILE
+ ixia_obj = mock.MagicMock()
+ r_f_c2544_profile.execute = mock.Mock()
+ r_f_c2544_profile._get_ixia_traffic_profile = mock.Mock()
+ r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
+ r_f_c2544_profile.get_multiplier = mock.Mock()
+ r_f_c2544_profile.tmp_throughput = 0
+ r_f_c2544_profile.tmp_drop = 0
+ r_f_c2544_profile.full_profile = {}
+ samples = {}
+ for ifname in range(1):
+ name = "xe{}".format(ifname)
+ samples[name] = {"rx_throughput_fps": 20,
+ "tx_throughput_fps": 20,
+ "rx_throughput_mbps": 10,
+ "tx_throughput_mbps": 10,
+ "RxThroughput": 10,
+ "TxThroughput": 10,
+ "in_packets": 1000,
+ "out_packets": 0}
+ tol_min = 0.0
+ tolerance = 0.0
+ r_f_c2544_profile.tmp_throughput = 0
+ self.assertIsNotNone(r_f_c2544_profile.get_drop_percentage(
+ traffic_generator, samples,
+ tol_min, tolerance, ixia_obj))
+
+ def test_get_multiplier(self):
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.max_rate = 100
+ r_f_c2544_profile.min_rate = 100
+ self.assertEqual("1.0", r_f_c2544_profile.get_multiplier())
+
+ def test_start_ixia_latency(self):
+ traffic_generator = mock.Mock(autospec=TrexProfile)
+ traffic_generator.my_ports = [0, 1]
+ traffic_generator.priv_ports = [0]
+ traffic_generator.pub_ports = [1]
+ traffic_generator.client = \
+ mock.Mock(return_value=True)
+ r_f_c2544_profile = IXIARFC2544Profile(self.TRAFFIC_PROFILE)
+ r_f_c2544_profile.max_rate = 100
+ r_f_c2544_profile.min_rate = 100
+ ixia_obj = mock.MagicMock()
+ r_f_c2544_profile._get_ixia_traffic_profile = \
+ mock.Mock(return_value={})
+ r_f_c2544_profile.full_profile = {}
+ r_f_c2544_profile._ixia_traffic_generate = mock.Mock()
+ self.assertEqual(
+ None,
+ r_f_c2544_profile.start_ixia_latency(traffic_generator,
+ ixia_obj))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py
new file mode 100644
index 000000000..cda44127e
--- /dev/null
+++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py
@@ -0,0 +1,374 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016-2017 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.
+#
+
+from __future__ import absolute_import
+import unittest
+import mock
+import subprocess
+
+STL_MOCKS = {
+ 'stl': mock.MagicMock(),
+ 'stl.trex_stl_lib': mock.MagicMock(),
+ 'stl.trex_stl_lib.base64': mock.MagicMock(),
+ 'stl.trex_stl_lib.binascii': mock.MagicMock(),
+ 'stl.trex_stl_lib.collections': mock.MagicMock(),
+ 'stl.trex_stl_lib.copy': mock.MagicMock(),
+ 'stl.trex_stl_lib.datetime': mock.MagicMock(),
+ 'stl.trex_stl_lib.functools': mock.MagicMock(),
+ 'stl.trex_stl_lib.imp': mock.MagicMock(),
+ 'stl.trex_stl_lib.inspect': mock.MagicMock(),
+ 'stl.trex_stl_lib.json': mock.MagicMock(),
+ 'stl.trex_stl_lib.linecache': mock.MagicMock(),
+ 'stl.trex_stl_lib.math': mock.MagicMock(),
+ 'stl.trex_stl_lib.os': mock.MagicMock(),
+ 'stl.trex_stl_lib.platform': mock.MagicMock(),
+ 'stl.trex_stl_lib.pprint': mock.MagicMock(),
+ 'stl.trex_stl_lib.random': mock.MagicMock(),
+ 'stl.trex_stl_lib.re': mock.MagicMock(),
+ 'stl.trex_stl_lib.scapy': mock.MagicMock(),
+ 'stl.trex_stl_lib.socket': mock.MagicMock(),
+ 'stl.trex_stl_lib.string': mock.MagicMock(),
+ 'stl.trex_stl_lib.struct': mock.MagicMock(),
+ 'stl.trex_stl_lib.sys': mock.MagicMock(),
+ 'stl.trex_stl_lib.threading': mock.MagicMock(),
+ 'stl.trex_stl_lib.time': mock.MagicMock(),
+ 'stl.trex_stl_lib.traceback': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(),
+ 'stl.trex_stl_lib.types': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.collections': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.common': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.json': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.os': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.random': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.re': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.string': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.sys': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(),
+ 'stl.trex_stl_lib.warnings': mock.MagicMock(),
+ 'stl.trex_stl_lib.yaml': mock.MagicMock(),
+ 'stl.trex_stl_lib.zlib': mock.MagicMock(),
+ 'stl.trex_stl_lib.zmq': mock.MagicMock(),
+}
+
+STLClient = mock.MagicMock()
+stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
+stl_patch.start()
+
+if stl_patch:
+ from yardstick.network_services.vnf_generic.vnf.tg_ixload import IxLoadTrafficGen
+ from yardstick.network_services.vnf_generic.vnf.tg_ixload import IxLoadResourceHelper
+ from yardstick.network_services.traffic_profile.base import TrafficProfile
+
+
+NAME = "tg__1"
+
+
+class TestIxLoadTrafficGen(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.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64}}
+
+ def test___init__(self):
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ self.assertIsNone(ixload_traffic_gen.data)
+
+ def test_collect_kpi(self):
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ ixload_traffic_gen.data = {}
+ restult = ixload_traffic_gen.collect_kpi()
+ self.assertEqual({}, restult)
+
+ def test_listen_traffic(self):
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ self.assertEqual(None, ixload_traffic_gen.listen_traffic({}))
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.makedirs")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
+ def test_instantiate(self, call, shutil, mock_makedirs):
+ 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]
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ scenario_cfg = {'tc': "nsb_test_case",
+ 'ixia_profile': "ixload.cfg"}
+ ixload_traffic_gen.RESULTS_MOUNT = "/tmp/result"
+ shutil.copy = mock.Mock()
+ scenario_cfg.update({'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}}
+ }})
+ self.assertRaises(IOError,
+ ixload_traffic_gen.instantiate(scenario_cfg, {}))
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len")
+ def test_run_traffic(self, call, shutil, main_open, min, max, len):
+ mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ 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]
+ vnfd["mgmt-interface"].update({"tg-config": {}})
+ vnfd["mgmt-interface"]["tg-config"].update({"ixchassis":
+ "1.1.1.1"})
+ vnfd["mgmt-interface"]["tg-config"].update({"py_bin_path":
+ "/root"})
+ sut = IxLoadTrafficGen(NAME, vnfd)
+ sut.connection = mock.Mock()
+ sut.connection.run = mock.Mock()
+ sut._traffic_runner = mock.Mock(return_value=0)
+ shutil.copy = mock.Mock()
+ result = sut.run_traffic(mock_traffic_profile)
+ self.assertIsNone(result)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.shutil")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.open")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.min")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.max")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.len")
+ def test_run_traffic_csv(self, call, shutil, main_open, min, max, len):
+ mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+ 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]
+ vnfd["mgmt-interface"].update({"tg-config": {}})
+ vnfd["mgmt-interface"]["tg-config"].update({"ixchassis":
+ "1.1.1.1"})
+ vnfd["mgmt-interface"]["tg-config"].update({"py_bin_path":
+ "/root"})
+ sut = IxLoadTrafficGen(NAME, vnfd)
+ sut.connection = mock.Mock()
+ sut.connection.run = mock.Mock()
+ sut._traffic_runner = mock.Mock(return_value=0)
+ shutil.copy = mock.Mock()
+ subprocess.call(["touch", "/tmp/1.csv"])
+ sut.rel_bin_path = mock.Mock(return_value="/tmp/*.csv")
+ result = sut.run_traffic(mock_traffic_profile)
+ self.assertIsNone(result)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ def test_terminate(self, call):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh.from_node.return_value = ssh_mock
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ self.assertEqual(None, ixload_traffic_gen.terminate())
+
+ @mock.patch("yardstick.ssh.SSH")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ def test_parse_csv_read(self, mock_call, mock_ssh):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ kpi_data = {
+ 'HTTP Total Throughput (Kbps)': 1,
+ 'HTTP Simulated Users': 2,
+ 'HTTP Concurrent Connections': '3',
+ 'HTTP Connection Rate': 4.3,
+ 'HTTP Transaction Rate': True,
+ }
+ http_reader = [kpi_data]
+
+ mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_type.execute.return_value = 0, "", ""
+ mock_ssh.from_node.return_value = mock_ssh_type
+
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ result = ixload_traffic_gen.resource_helper.result
+
+ ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
+ for key_left, key_right in IxLoadResourceHelper.KPI_LIST.items():
+ self.assertEqual(result[key_left][-1], int(kpi_data[key_right]))
+
+ @mock.patch("yardstick.ssh.SSH")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ def test_parse_csv_read_value_error(self, mock_call, mock_ssh):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ http_reader = [{
+ 'HTTP Total Throughput (Kbps)': 1,
+ 'HTTP Simulated Users': 2,
+ 'HTTP Concurrent Connections': "not a number",
+ 'HTTP Connection Rate': 4,
+ 'HTTP Transaction Rate': 5,
+ }]
+
+ mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_type.execute.return_value = 0, "", ""
+ mock_ssh.from_node.return_value = mock_ssh_type
+
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+ init_value = ixload_traffic_gen.resource_helper.result
+
+ ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
+ self.assertDictEqual(ixload_traffic_gen.resource_helper.result, init_value)
+
+ @mock.patch("yardstick.ssh.SSH")
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_ixload.call")
+ def test_parse_csv_read_error(self, mock_call, mock_ssh):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ http_reader = [{
+ 'HTTP Total Throughput (Kbps)': 1,
+ 'HTTP Simulated Users': 2,
+ 'HTTP Concurrent Connections': 3,
+ 'HTTP Transaction Rate': 5,
+ }]
+
+ mock_ssh_type = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_type.execute.return_value = 0, "", ""
+ mock_ssh.from_node.return_value = mock_ssh_type
+
+ ixload_traffic_gen = IxLoadTrafficGen(NAME, vnfd)
+
+ with self.assertRaises(KeyError):
+ ixload_traffic_gen.resource_helper.parse_csv_read(http_reader)
diff --git a/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py
new file mode 100644
index 000000000..8f7f05772
--- /dev/null
+++ b/tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py
@@ -0,0 +1,405 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2016-2017 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.
+#
+
+from __future__ import absolute_import
+import os
+import unittest
+import mock
+STL_MOCKS = {
+ 'stl': mock.MagicMock(),
+ 'stl.trex_stl_lib': mock.MagicMock(),
+ 'stl.trex_stl_lib.base64': mock.MagicMock(),
+ 'stl.trex_stl_lib.binascii': mock.MagicMock(),
+ 'stl.trex_stl_lib.collections': mock.MagicMock(),
+ 'stl.trex_stl_lib.copy': mock.MagicMock(),
+ 'stl.trex_stl_lib.datetime': mock.MagicMock(),
+ 'stl.trex_stl_lib.functools': mock.MagicMock(),
+ 'stl.trex_stl_lib.imp': mock.MagicMock(),
+ 'stl.trex_stl_lib.inspect': mock.MagicMock(),
+ 'stl.trex_stl_lib.json': mock.MagicMock(),
+ 'stl.trex_stl_lib.linecache': mock.MagicMock(),
+ 'stl.trex_stl_lib.math': mock.MagicMock(),
+ 'stl.trex_stl_lib.os': mock.MagicMock(),
+ 'stl.trex_stl_lib.platform': mock.MagicMock(),
+ 'stl.trex_stl_lib.pprint': mock.MagicMock(),
+ 'stl.trex_stl_lib.random': mock.MagicMock(),
+ 'stl.trex_stl_lib.re': mock.MagicMock(),
+ 'stl.trex_stl_lib.scapy': mock.MagicMock(),
+ 'stl.trex_stl_lib.socket': mock.MagicMock(),
+ 'stl.trex_stl_lib.string': mock.MagicMock(),
+ 'stl.trex_stl_lib.struct': mock.MagicMock(),
+ 'stl.trex_stl_lib.sys': mock.MagicMock(),
+ 'stl.trex_stl_lib.threading': mock.MagicMock(),
+ 'stl.trex_stl_lib.time': mock.MagicMock(),
+ 'stl.trex_stl_lib.traceback': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_async_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_exceptions': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_ext': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_jsonrpc_client': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_packet_builder_interface': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_packet_builder_scapy': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_port': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_stats': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_streams': mock.MagicMock(),
+ 'stl.trex_stl_lib.trex_stl_types': mock.MagicMock(),
+ 'stl.trex_stl_lib.types': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.argparse': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.collections': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.common': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.json': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.os': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.parsing_opts': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.pwd': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.random': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.re': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.string': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.sys': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.text_opts': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.text_tables': mock.MagicMock(),
+ 'stl.trex_stl_lib.utils.texttable': mock.MagicMock(),
+ 'stl.trex_stl_lib.warnings': mock.MagicMock(),
+ 'stl.trex_stl_lib.yaml': mock.MagicMock(),
+ 'stl.trex_stl_lib.zlib': mock.MagicMock(),
+ 'stl.trex_stl_lib.zmq': mock.MagicMock(),
+}
+
+STLClient = mock.MagicMock()
+stl_patch = mock.patch.dict("sys.modules", STL_MOCKS)
+stl_patch.start()
+
+if stl_patch:
+ from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia import IxiaTrafficGen
+ from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia import IxiaRfc2544Helper
+ from yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia import IxiaResourceHelper
+ from yardstick.network_services.traffic_profile.base import TrafficProfile
+
+TEST_FILE_YAML = 'nsb_test_case.yaml'
+
+
+NAME = "tg__1"
+
+
+@mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.IxNextgen")
+class TestIxiaResourceHelper(unittest.TestCase):
+
+ def test___init___with_custom_rfc_helper(self, mock_ix_nextgen):
+ class MyRfcHelper(IxiaRfc2544Helper):
+ pass
+
+ ixia_resource_helper = IxiaResourceHelper(mock.Mock(), MyRfcHelper)
+ self.assertIsInstance(ixia_resource_helper.rfc_helper, MyRfcHelper)
+
+ def test_stop_collect_with_client(self, mock_ix_nextgen):
+ mock_client = mock.Mock()
+
+ ixia_resource_helper = IxiaResourceHelper(mock.Mock())
+
+ ixia_resource_helper.client = mock_client
+ ixia_resource_helper.stop_collect()
+ self.assertEqual(mock_client.ix_stop_traffic.call_count, 1)
+
+
+@mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.IxNextgen")
+class TestIXIATrafficGen(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.1.1.1',
+ 'password': 'r00t',
+ 'user': 'root',
+ 'ip': '1.1.1.1'},
+ 'benchmark':
+ {'kpi': ['packets_in', 'packets_fwd', 'packets_dropped']},
+ 'connection-point': [{'type': 'VPORT', 'name': 'xe0'},
+ {'type': 'VPORT', 'name': 'xe1'}],
+ 'id': 'VpeApproxVnf', 'name': 'VPEVnfSsh'}]}}
+
+ TRAFFIC_PROFILE = {
+ "schema": "isb:traffic_profile:0.1",
+ "name": "fixed",
+ "description": "Fixed traffic profile to run UDP traffic",
+ "traffic_profile": {
+ "traffic_type": "FixedTraffic",
+ "frame_rate": 100, # pps
+ "flow_number": 10,
+ "frame_size": 64}}
+
+ TC_YAML = {'scenarios': [{'tc_options':
+ {'rfc2544': {'allowed_drop_rate': '0.8 - 1'}},
+ 'runner': {'duration': 400,
+ 'interval': 35, 'type': 'Duration'},
+ 'traffic_options':
+ {'flow': 'ipv4_1flow_Packets_vpe.yaml',
+ 'imix': 'imix_voice.yaml'},
+ 'vnf_options': {'vpe': {'cfg': 'vpe_config'}},
+ 'traffic_profile': 'ipv4_throughput_vpe.yaml',
+ 'type': 'NSPerf',
+ 'nodes': {'tg__1': 'trafficgen_1.yardstick',
+ 'vnf__1': 'vnf.yardstick'},
+ 'topology': 'vpe_vnf_topology.yaml'}],
+ 'context': {'nfvi_type': 'baremetal', 'type': 'Node',
+ 'name': 'yardstick',
+ 'file': '/etc/yardstick/nodes/pod.yaml'},
+ 'schema': 'yardstick:task:0.1'}
+
+ def test___init__(self, mock_ixnextgen):
+ 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]
+ ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd)
+
+ def test_listen_traffic(self, mock_ixnextgen):
+ 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]
+ ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd)
+ self.assertEqual(None, ixnet_traffic_gen.listen_traffic({}))
+
+ def test_instantiate(self, mock_ixnextgen):
+ 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]
+ ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd)
+ scenario_cfg = {'tc': "nsb_test_case", "topology": "",
+ 'ixia_profile': "ixload.cfg"}
+ scenario_cfg.update({'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}}
+ }})
+ ixnet_traffic_gen.topology = ""
+ ixnet_traffic_gen.get_ixobj = mock.MagicMock()
+ ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock()
+ ixnet_traffic_gen._ixia_traffic_gen._connect = mock.Mock()
+ self.assertRaises(
+ IOError,
+ ixnet_traffic_gen.instantiate(scenario_cfg, {}))
+
+ def test_collect_kpi(self, mock_ixnextgen):
+ 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]
+ ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd)
+ ixnet_traffic_gen.data = {}
+ restult = ixnet_traffic_gen.collect_kpi()
+ self.assertEqual({}, restult)
+
+ def test_terminate(self, mock_ixnextgen):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ ssh_mock.execute = \
+ mock.Mock(return_value=(0, "", ""))
+ ssh.from_node.return_value = ssh_mock
+ ixnet_traffic_gen = IxiaTrafficGen(NAME, vnfd)
+ ixnet_traffic_gen._terminated = mock.MagicMock()
+ ixnet_traffic_gen._terminated.value = 0
+ ixnet_traffic_gen._ixia_traffic_gen = mock.MagicMock()
+ ixnet_traffic_gen._ixia_traffic_gen.ix_stop_traffic = mock.Mock()
+ ixnet_traffic_gen._traffic_process = mock.MagicMock()
+ ixnet_traffic_gen._traffic_process.terminate = mock.Mock()
+ self.assertEqual(None, ixnet_traffic_gen.terminate())
+
+ def _get_file_abspath(self, filename):
+ curr_path = os.path.dirname(os.path.abspath(__file__))
+ file_path = os.path.join(curr_path, filename)
+ return file_path
+
+ def test_scale(self, mock_ix_nextgen):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sut = IxiaTrafficGen('vnf1', vnfd)
+ sut.scale()
+
+ def test__check_status(self, mock_ix_nextgen):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ sut = IxiaTrafficGen('vnf1', vnfd)
+ sut._check_status()
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.tg_rfc2544_ixia.time")
+ @mock.patch("yardstick.ssh.SSH")
+ def test_traffic_runner(self, mock_ixnextgen, mock_ssh, mock_time):
+ mock_traffic_profile = mock.Mock(autospec=TrafficProfile)
+ mock_traffic_profile.get_traffic_definition.return_value = "64"
+ mock_traffic_profile.params = self.TRAFFIC_PROFILE
+
+ mock_ssh_instance = mock.Mock(autospec=mock_ssh.SSH)
+ mock_ssh_instance.execute.return_value = 0, "", ""
+ mock_ssh_instance.run.return_value = 0, "", ""
+
+ mock_ssh.from_node.return_value = mock_ssh_instance
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnfd["mgmt-interface"].update({
+ 'tg-config': {
+ "ixchassis": "1.1.1.1",
+ "py_bin_path": "/root",
+ }
+ })
+
+ samples = {}
+ name = ''
+ for ifname in range(1):
+ name = "xe{}".format(ifname)
+ samples[name] = {
+ "Rx_Rate_Kbps": 20,
+ "Tx_Rate_Kbps": 20,
+ "Rx_Rate_Mbps": 10,
+ "Tx_Rate_Mbps": 10,
+ "RxThroughput": 10,
+ "TxThroughput": 10,
+ "Valid_Frames_Rx": 1000,
+ "Frames_Tx": 1000,
+ "in_packets": 1000,
+ "out_packets": 1000,
+ }
+
+ samples.update({"CurrentDropPercentage": 0.0})
+
+ last_res = [
+ 0,
+ {
+ "Rx_Rate_Kbps": [20, 20],
+ "Tx_Rate_Kbps": [20, 20],
+ "Rx_Rate_Mbps": [10, 10],
+ "Tx_Rate_Mbps": [10, 10],
+ "CurrentDropPercentage": [0, 0],
+ "RxThroughput": [10, 10],
+ "TxThroughput": [10, 10],
+ "Frames_Tx": [1000, 1000],
+ "in_packets": [1000, 1000],
+ "Valid_Frames_Rx": [1000, 1000],
+ "out_packets": [1000, 1000],
+ },
+ ]
+
+ mock_traffic_profile.execute.return_value = ['Completed', samples]
+ mock_traffic_profile.get_drop_percentage.return_value = ['Completed', samples]
+
+ sut = IxiaTrafficGen(name, vnfd)
+ sut.tg_port_pairs = [[[0], [1]]]
+ sut.vnf_port_pairs = [[[0], [1]]]
+ sut.tc_file_name = self._get_file_abspath(TEST_FILE_YAML)
+ sut.topology = ""
+
+ sut.ssh_helper = mock.Mock()
+ sut._traffic_process = mock.MagicMock()
+ sut.generate_port_pairs = mock.Mock()
+
+ sut._ixia_traffic_gen = mock.MagicMock()
+ sut._ixia_traffic_gen.ix_get_statistics.return_value = last_res
+
+ sut.resource_helper.client = mock.MagicMock()
+ sut.resource_helper.client_started = mock.MagicMock()
+ sut.resource_helper.client_started.value = 1
+
+ sut.scenario_helper.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,
+ },
+ },
+ },
+ 'ixia_profile': {}
+ }
+
+ result = sut._traffic_runner(mock_traffic_profile)
+ self.assertIsNone(result)
diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py
index 1059e1ce4..969bb4b38 100644
--- a/yardstick/common/utils.py
+++ b/yardstick/common/utils.py
@@ -370,3 +370,29 @@ def parse_cpuinfo(cpuinfo):
def config_to_dict(config):
return {section: dict(config.items(section)) for section in
config.sections()}
+
+
+def validate_non_string_sequence(value, default=None, raise_exc=None):
+ if isinstance(value, collections.Sequence) and not isinstance(value, str):
+ return value
+ if raise_exc:
+ raise raise_exc
+ return default
+
+
+def join_non_strings(separator, *non_strings):
+ try:
+ non_strings = validate_non_string_sequence(non_strings[0], raise_exc=RuntimeError)
+ except (IndexError, RuntimeError):
+ pass
+ return str(separator).join(str(non_string) for non_string in non_strings)
+
+
+class ErrorClass(object):
+
+ def __init__(self, *args, **kwargs):
+ if 'test' not in kwargs:
+ raise RuntimeError
+
+ def __getattr__(self, item):
+ raise AttributeError
diff --git a/yardstick/network_services/libs/__init__.py b/yardstick/network_services/libs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/libs/__init__.py
diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py
new file mode 100644
index 000000000..815a2a21c
--- /dev/null
+++ b/yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py
@@ -0,0 +1,335 @@
+# Copyright (c) 2016-2017 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.
+
+from __future__ import absolute_import
+from __future__ import print_function
+import sys
+import logging
+
+import re
+from itertools import product
+
+from yardstick.common.utils import ErrorClass
+
+try:
+ import IxNetwork
+except ImportError:
+ IxNetwork = ErrorClass
+
+log = logging.getLogger(__name__)
+
+IP_VERSION_4 = 4
+IP_VERSION_6 = 6
+
+
+class TrafficStreamHelper(object):
+
+ TEMPLATE = '{0.traffic_item}/{0.stream}:{0.param_id}/{1}'
+
+ def __init__(self, traffic_item, stream, param_id):
+ super(TrafficStreamHelper, self).__init__()
+ self.traffic_item = traffic_item
+ self.stream = stream
+ self.param_id = param_id
+
+ def __getattr__(self, item):
+ return self.TEMPLATE.format(self, item)
+
+
+class FramesizeHelper(object):
+
+ def __init__(self):
+ super(FramesizeHelper, self).__init__()
+ self.weighted_pairs = []
+ self.weighted_range_pairs = []
+
+ @property
+ def weighted_pairs_arg(self):
+ return '-weightedPairs', self.weighted_pairs
+
+ @property
+ def weighted_range_pairs_arg(self):
+ return '-weightedRangePairs', self.weighted_range_pairs
+
+ def make_args(self, *args):
+ return self.weighted_pairs_arg + self.weighted_range_pairs_arg + args
+
+ def populate_data(self, framesize_data):
+ for key, value in framesize_data.items():
+ if value == '0':
+ continue
+
+ replaced = re.sub('[Bb]', '', key)
+ self.weighted_pairs.extend([
+ replaced,
+ value,
+ ])
+ pairs = [
+ replaced,
+ replaced,
+ value,
+ ]
+ self.weighted_range_pairs.append(pairs)
+
+
+class IxNextgen(object):
+
+ STATS_NAME_MAP = {
+ "traffic_item": 'Traffic Item',
+ "Tx_Frames": 'Tx Frames',
+ "Rx_Frames": 'Rx Frames',
+ "Tx_Frame_Rate": 'Tx Frame Rate',
+ "Rx_Frame_Rate": 'Tx Frame Rate',
+ "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
+ "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
+ "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
+ }
+
+ PORT_STATS_NAME_MAP = {
+ "stat_name": 'Stat Name',
+ "Frames_Tx": 'Frames Tx.',
+ "Valid_Frames_Rx": 'Valid Frames Rx.',
+ "Frames_Tx_Rate": 'Frames Tx. Rate',
+ "Valid_Frames_Rx_Rate": 'Valid Frames Rx. Rate',
+ "Tx_Rate_Kbps": 'Tx. Rate (Kbps)',
+ "Rx_Rate_Kbps": 'Rx. Rate (Kbps)',
+ "Tx_Rate_Mbps": 'Tx. Rate (Mbps)',
+ "Rx_Rate_Mbps": 'Rx. Rate (Mbps)',
+ }
+
+ LATENCY_NAME_MAP = {
+ "Store-Forward_Avg_latency_ns": 'Store-Forward Avg Latency (ns)',
+ "Store-Forward_Min_latency_ns": 'Store-Forward Min Latency (ns)',
+ "Store-Forward_Max_latency_ns": 'Store-Forward Max Latency (ns)',
+ }
+
+ RANDOM_MASK_MAP = {
+ IP_VERSION_4: '0.0.0.255',
+ IP_VERSION_6: '0:0:0:0:0:0:0:ff',
+ }
+
+ MODE_SEEDS_MAP = {
+ 0: ('private', ['256', '2048']),
+ }
+
+ MODE_SEEDS_DEFAULT = 'public', ['2048', '256']
+
+ @staticmethod
+ def find_view_obj(view_name, views):
+ edited_view_name = '::ixNet::OBJ-/statistics/view:"{}"'.format(view_name)
+ return next((view for view in views if edited_view_name == view), '')
+
+ @staticmethod
+ def get_config(tg_cfg):
+ external_interface = tg_cfg["vdu"][0]["external-interface"]
+ card_port0 = external_interface[0]["virtual-interface"]["vpci"]
+ card_port1 = external_interface[1]["virtual-interface"]["vpci"]
+ card0, port0 = card_port0.split(':')[:2]
+ card1, port1 = card_port1.split(':')[:2]
+ cfg = {
+ 'py_lib_path': tg_cfg["mgmt-interface"]["tg-config"]["py_lib_path"],
+ 'machine': tg_cfg["mgmt-interface"]["ip"],
+ 'port': tg_cfg["mgmt-interface"]["tg-config"]["tcl_port"],
+ 'chassis': tg_cfg["mgmt-interface"]["tg-config"]["ixchassis"],
+ 'card1': card0,
+ 'port1': port0,
+ 'card2': card1,
+ 'port2': port1,
+ 'output_dir': tg_cfg["mgmt-interface"]["tg-config"]["dut_result_dir"],
+ 'version': tg_cfg["mgmt-interface"]["tg-config"]["version"],
+ 'bidir': True,
+ }
+ return cfg
+
+ def __init__(self, ixnet=None):
+ self.ixnet = ixnet
+ self._objRefs = dict()
+ self._cfg = None
+ self._logger = logging.getLogger(__name__)
+ self._params = None
+ self._bidir = None
+
+ def iter_over_get_lists(self, x1, x2, y2, offset=0):
+ for x in self.ixnet.getList(x1, x2):
+ y_list = self.ixnet.getList(x, y2)
+ for i, y in enumerate(y_list, offset):
+ yield x, y, i
+
+ def set_random_ip_multi_attribute(self, ipv4, seed, fixed_bits, random_mask, l3_count):
+ self.ixnet.setMultiAttribute(
+ ipv4,
+ '-seed', str(seed),
+ '-fixedBits', str(fixed_bits),
+ '-randomMask', str(random_mask),
+ '-valueType', 'random',
+ '-countValue', str(l3_count))
+
+ def set_random_ip_multi_attributes(self, ip, version, seeds, l3):
+ try:
+ random_mask = self.RANDOM_MASK_MAP[version]
+ except KeyError:
+ raise ValueError('Unknown version %s' % version)
+
+ l3_count = l3['count']
+ if "srcIp" in ip:
+ fixed_bits = l3['srcip4']
+ self.set_random_ip_multi_attribute(ip, seeds[0], fixed_bits, random_mask, l3_count)
+ if "dstIp" in ip:
+ fixed_bits = l3['dstip4']
+ self.set_random_ip_multi_attribute(ip, seeds[1], fixed_bits, random_mask, l3_count)
+
+ def add_ip_header(self, params, version):
+ for it, ep, i in self.iter_over_get_lists('/traffic', 'trafficItem', "configElement"):
+ mode, seeds = self.MODE_SEEDS_MAP.get(i, self.MODE_SEEDS_DEFAULT)
+ l3 = params[mode]['outer_l3']
+
+ for ip, ip_bits, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
+ self.set_random_ip_multi_attributes(ip_bits, version, seeds, l3)
+
+ self.ixnet.commit()
+
+ def _connect(self, tg_cfg):
+ self._cfg = self.get_config(tg_cfg)
+
+ sys.path.append(self._cfg["py_lib_path"])
+ self.ixnet = IxNetwork.IxNet()
+
+ machine = self._cfg['machine']
+ port = str(self._cfg['port'])
+ version = str(self._cfg['version'])
+ result = self.ixnet.connect(machine, '-port', port, '-version', version)
+ return result
+
+ def clear_ixia_config(self):
+ self.ixnet.execute('newConfig')
+
+ def load_ixia_profile(self, profile):
+ self.ixnet.execute('loadConfig', self.ixnet.readFrom(profile))
+
+ def ix_load_config(self, profile):
+ self.clear_ixia_config()
+ self.load_ixia_profile(profile)
+
+ def ix_assign_ports(self):
+ vports = self.ixnet.getList(self.ixnet.getRoot(), 'vport')
+ ports = [
+ (self._cfg['chassis'], self._cfg['card1'], self._cfg['port1']),
+ (self._cfg['chassis'], self._cfg['card2'], self._cfg['port2']),
+ ]
+
+ vport_list = self.ixnet.getList("/", "vport")
+ self.ixnet.execute('assignPorts', ports, [], vport_list, True)
+ self.ixnet.commit()
+
+ for vport in vports:
+ if self.ixnet.getAttribute(vport, '-state') != 'up':
+ log.error("Both thr ports are down...")
+
+ def ix_update_frame(self, params):
+ streams = ["configElement"]
+
+ for param in params.values():
+ framesize_data = FramesizeHelper()
+ traffic_items = self.ixnet.getList('/traffic', 'trafficItem')
+ param_id = param['id']
+ for traffic_item, stream in product(traffic_items, streams):
+ helper = TrafficStreamHelper(traffic_item, stream, param_id)
+
+ self.ixnet.setMultiAttribute(helper.transmissionControl,
+ '-type', '{0}'.format(param['traffic_type']),
+ '-duration', '{0}'.format(param['duration']))
+
+ stream_frame_rate_path = helper.frameRate
+ self.ixnet.setMultiAttribute(stream_frame_rate_path, '-rate', param['iload'])
+ if param['outer_l2']['framesPerSecond']:
+ self.ixnet.setMultiAttribute(stream_frame_rate_path,
+ '-type', 'framesPerSecond')
+
+ framesize_data.populate_data(param['outer_l2']['framesize'])
+
+ make_attr_args = framesize_data.make_args('-incrementFrom', '66',
+ '-randomMin', '66',
+ '-quadGaussian', [],
+ '-type', 'weightedPairs',
+ '-presetDistribution', 'cisco',
+ '-incrementTo', '1518')
+
+ self.ixnet.setMultiAttribute(helper.frameSize, *make_attr_args)
+
+ self.ixnet.commit()
+
+ def update_ether_multi_attribute(self, ether, mac_addr):
+ self.ixnet.setMultiAttribute(ether,
+ '-singleValue', mac_addr,
+ '-fieldValue', mac_addr,
+ '-valueType', 'singleValue')
+
+ def update_ether_multi_attributes(self, ether, l2):
+ if "ethernet.header.destinationAddress" in ether:
+ self.update_ether_multi_attribute(ether, str(l2['dstmac']))
+
+ if "ethernet.header.sourceAddress" in ether:
+ self.update_ether_multi_attribute(ether, str(l2['srcmac']))
+
+ def ix_update_ether(self, params):
+ for ti, ep, index in self.iter_over_get_lists('/traffic', 'trafficItem',
+ "configElement", 1):
+ iter1 = (v['outer_l2'] for v in params.values() if str(v['id']) == str(index))
+ try:
+ l2 = next(iter1, {})
+ except KeyError:
+ continue
+
+ for ip, ether, _ in self.iter_over_get_lists(ep, 'stack', 'field'):
+ self.update_ether_multi_attributes(ether, l2)
+
+ self.ixnet.commit()
+
+ def ix_update_udp(self, params):
+ pass
+
+ def ix_update_tcp(self, params):
+ pass
+
+ def ix_start_traffic(self):
+ tis = self.ixnet.getList('/traffic', 'trafficItem')
+ for ti in tis:
+ self.ixnet.execute('generate', [ti])
+ self.ixnet.execute('apply', '/traffic')
+ self.ixnet.execute('start', '/traffic')
+
+ def ix_stop_traffic(self):
+ tis = self.ixnet.getList('/traffic', 'trafficItem')
+ for _ in tis:
+ self.ixnet.execute('stop', '/traffic')
+
+ def build_stats_map(self, view_obj, name_map):
+ return {kl: self.execute_get_column_values(view_obj, kr) for kl, kr in name_map.items()}
+
+ def execute_get_column_values(self, view_obj, name):
+ return self.ixnet.execute('getColumnValues', view_obj, name)
+
+ def ix_get_statistics(self):
+ views = self.ixnet.getList('/statistics', 'view')
+ view_obj = self.find_view_obj("Traffic Item Statistics", views)
+ stats = self.build_stats_map(view_obj, self.STATS_NAME_MAP)
+
+ self.find_view_obj("Port Statistics", views)
+ ports_stats = self.build_stats_map(view_obj, self.PORT_STATS_NAME_MAP)
+
+ views = self.ixnet.getList('/statistics', 'view')
+ view_obj = self.find_view_obj("Flow Statistics", views)
+ stats["latency"] = self.build_stats_map(view_obj, self.LATENCY_NAME_MAP)
+
+ return stats, ports_stats
diff --git a/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py b/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/libs/ixia_libs/IxNet/__init__.py
diff --git a/yardstick/network_services/libs/ixia_libs/__init__.py b/yardstick/network_services/libs/ixia_libs/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/libs/ixia_libs/__init__.py
diff --git a/yardstick/network_services/traffic_profile/http_ixload.py b/yardstick/network_services/traffic_profile/http_ixload.py
new file mode 100644
index 000000000..8a4f97f04
--- /dev/null
+++ b/yardstick/network_services/traffic_profile/http_ixload.py
@@ -0,0 +1,294 @@
+# Copyright (c) 2016-2017 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.
+
+from __future__ import absolute_import
+from __future__ import print_function
+
+import sys
+import os
+import logging
+
+# ixload uses its own py2. So importing jsonutils fails. So adding below
+# workaround to support call from yardstick
+try:
+ from oslo_serialization import jsonutils
+except ImportError:
+ import json as jsonutils
+
+from yardstick.common.utils import join_non_strings
+from yardstick.common.utils import ErrorClass
+
+try:
+ from IxLoad import IxLoad, StatCollectorUtils
+except ImportError:
+ IxLoad = ErrorClass
+ StatCollectorUtils = ErrorClass
+
+LOG = logging.getLogger(__name__)
+CSV_FILEPATH_NAME = 'IxL_statResults.csv'
+
+STATS_TO_GET = (
+ 'HTTP_Client.csv',
+ 'HTTP_Server.csv',
+ 'L2-3 Stats for Client Ports.csv',
+ 'L2-3 Stats for Server Ports.csv',
+ 'IxLoad Detailed Report.html',
+ 'IxLoad Detailed Report.pdf'
+)
+
+HTTP_CLIENT_STATS = [
+ ["HTTP Client", "TCP Connections Established", "kSum"],
+ ["HTTP Client", "TCP Connection Requests Failed", "kSum"],
+ ["HTTP Client", "HTTP Simulated Users", "kSum"],
+ ["HTTP Client", "HTTP Concurrent Connections", "kSum"],
+ ["HTTP Client", "HTTP Connections", "kSum"],
+ ["HTTP Client", "HTTP Transactions", "kSum"],
+ ["HTTP Client", "HTTP Connection Attempts", "kSum"]
+]
+
+HTTP_SERVER_STATS = [
+ ["HTTP Server", "TCP Connections Established", "kSum"],
+ ["HTTP Server", "TCP Connection Requests Failed", "kSum"]
+]
+
+
+INCOMING_STAT_RECORD_TEMPLATE = """
+=====================================
+INCOMING STAT RECORD >>> %s
+Len = %s
+%s
+%s
+=====================================
+"""
+
+INCOMING_STAT_INTERVAL_TEMPLATE = """
+=====================================
+Incoming stats: Time interval: %s
+Incoming stats: Time interval: %s
+=====================================
+"""
+
+
+class IXLOADHttpTest(object):
+
+ def __init__(self, test_input):
+ self.test_input = jsonutils.loads(test_input)
+ self.parse_run_test()
+ self.ix_load = None
+ self.stat_utils = None
+ self.remote_server = None
+ self.config_file = None
+ self.results_on_windows = None
+ self.result_dir = None
+ self.chassis = None
+ self.card = None
+ self.ports_to_reassign = None
+
+ @staticmethod
+ def format_ports_for_reassignment(ports):
+ formatted = [join_non_strings(';', p) for p in ports if len(p) == 3]
+ LOG.debug('for client ports:%s', os.linesep.join(formatted))
+ return formatted
+
+ def reassign_ports(self, test, repository, ports_to_reassign):
+ LOG.debug('ReassignPorts: %s %s', test, repository)
+
+ chassis_chain = repository.cget('chassisChain')
+ LOG.debug('chassischain: %s', chassis_chain)
+ client_ports = ports_to_reassign[0::2]
+ server_ports = ports_to_reassign[1::2]
+
+ client_ports = self.format_ports_for_reassignment(client_ports)
+ LOG.debug('Reassigning client ports: %s', client_ports)
+ server_ports = self.format_ports_for_reassignment(server_ports)
+ LOG.debug('Reassigning server ports: %s', server_ports)
+ ports_to_set = client_ports + server_ports
+
+ try:
+ LOG.debug('Reassigning ports: %s', ports_to_set)
+ test.setPorts(ports_to_set)
+ except Exception:
+ LOG.error('Error: Could not remap port assignment for: %s',
+ ports_to_set)
+ self.ix_load.delete(repository)
+ self.ix_load.disconnect()
+ raise
+
+ @staticmethod
+ def stat_collector(*args):
+ LOG.debug(INCOMING_STAT_RECORD_TEMPLATE, args, len(args), args[0], args[1])
+
+ @staticmethod
+ def IxL_StatCollectorCommand(*args):
+ stats = args[1][3]
+ timestamp = args[1][1]
+ LOG.debug(INCOMING_STAT_INTERVAL_TEMPLATE, timestamp, stats)
+
+ @staticmethod
+ def set_results_dir(test_controller, results_on_windows):
+ """
+ If the folder doesn't exists on the Windows Client PC,
+ IxLoad will automatically create it.
+ """
+ try:
+ test_controller.setResultDir(results_on_windows)
+ except Exception:
+ LOG.error('Error creating results dir on Win: %s',
+ results_on_windows)
+ raise
+
+ def load_config_file(self, config_file):
+ try:
+ LOG.debug(config_file)
+ repository = self.ix_load.new("ixRepository", name=config_file)
+ return repository
+ except Exception:
+ LOG.error('Error: IxLoad config file not found: %s', config_file)
+ raise
+
+ def start_http_test(self):
+ self.ix_load = IxLoad()
+
+ LOG.debug('--- ixLoad obj: %s', self.ix_load)
+ try:
+ self.ix_load.connect(self.remote_server)
+ except Exception:
+ raise
+
+ log_tag = "IxLoad-api"
+ log_name = "reprun"
+ logger = self.ix_load.new("ixLogger", log_tag, 1)
+ log_engine = logger.getEngine()
+ log_engine.setLevels(self.ix_load.ixLogger.kLevelDebug,
+ self.ix_load.ixLogger.kLevelInfo)
+ log_engine.setFile(log_name, 2, 256, 1)
+
+ # Initialize stat collection utilities
+ self.stat_utils = StatCollectorUtils()
+
+ test_controller = self.ix_load.new("ixTestController", outputDir=1)
+
+ repository = self.load_config_file(self.config_file)
+
+ # Get the first test on the testList
+ test_name = repository.testList[0].cget("name")
+ test = repository.testList.getItem(test_name)
+
+ self.set_results_dir(test_controller, self.results_on_windows)
+
+ test.config(statsRequired=1, enableResetPorts=1, csvInterval=2,
+ enableForceOwnership=True)
+
+ # ---- Remap ports ----
+ try:
+ self.reassign_ports(test, repository, self.ports_to_reassign)
+ except Exception:
+ LOG.exception("Exception occurred during reassign_ports")
+
+ # -----------------------------------------------------------------------
+ # Set up stat Collection
+ # -----------------------------------------------------------------------
+ test_server_handle = test_controller.getTestServerHandle()
+ self.stat_utils.Initialize(test_server_handle)
+
+ # Clear any stats that may have been registered previously
+ self.stat_utils.ClearStats()
+
+ # Define the stats we would like to collect
+ self.stat_utils.AddStat(caption="Watch_Stat_1",
+ statSourceType="HTTP Client",
+ statName="TCP Connections Established",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.AddStat(caption="Watch_Stat_2",
+ statSourceType="HTTP Client",
+ statName="TCP Connection Requests Failed",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.AddStat(caption="Watch_Stat_3",
+ statSourceType="HTTP Server",
+ statName="TCP Connections Established",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.AddStat(caption="Watch_Stat_4",
+ statSourceType="HTTP Server",
+ statName="TCP Connection Requests Failed",
+ aggregationType="kSum",
+ filterList={})
+
+ self.stat_utils.StartCollector(self.IxL_StatCollectorCommand)
+
+ test_controller.run(test)
+ self.ix_load.waitForTestFinish()
+
+ test_controller.releaseConfigWaitFinish()
+
+ # Stop the collector (running in the tcl event loop)
+ self.stat_utils.StopCollector()
+
+ # Cleanup
+ test_controller.generateReport(detailedReport=1, format="PDF;HTML")
+ test_controller.releaseConfigWaitFinish()
+
+ self.ix_load.delete(test)
+ self.ix_load.delete(test_controller)
+ self.ix_load.delete(logger)
+ self.ix_load.delete(log_engine)
+
+ LOG.debug('Retrieving CSV stats from Windows Client PC ...')
+ for stat_file in STATS_TO_GET:
+ enhanced_stat_file = stat_file.replace('-', '')
+ enhanced_stat_file = enhanced_stat_file.replace(' ', '_')
+ enhanced_stat_file = enhanced_stat_file.replace('__', '_')
+
+ LOG.debug('Getting csv stat file: %s', stat_file)
+ src_file = os.path.join(self.results_on_windows, stat_file)
+ dst_file = os.path.join(self.result_dir, '_'.join(['ixLoad', enhanced_stat_file]))
+ self.ix_load.retrieveFileCopy(src_file, dst_file)
+
+ self.ix_load.disconnect()
+
+ def parse_run_test(self):
+ self.remote_server = self.test_input["remote_server"]
+ LOG.debug("remote tcl server: %s", self.remote_server)
+
+ self.config_file = self.test_input["ixload_cfg"]
+ LOG.debug("ixload config: %s", self.remote_server)
+
+ self.results_on_windows = 'C:/Results'
+ self.result_dir = self.test_input["result_dir"]
+ self.chassis = self.test_input["ixia_chassis"]
+ LOG.debug("remote ixia chassis: %s", self.chassis)
+
+ self.card = self.test_input["IXIA"]["card"]
+ self.ports_to_reassign = [
+ [self.chassis, self.card, port] for port in
+ self.test_input["IXIA"]["ports"]
+ ]
+
+ LOG.debug("Ports to be reassigned: %s", self.ports_to_reassign)
+
+
+def main(args):
+ # Get the args from cmdline and parse and run the test
+ test_input = "".join(args[1:])
+ if test_input:
+ ixload_obj = IXLOADHttpTest(test_input)
+ ixload_obj.start_http_test()
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/yardstick/network_services/traffic_profile/ixia_rfc2544.py b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
new file mode 100644
index 000000000..5ba00180b
--- /dev/null
+++ b/yardstick/network_services/traffic_profile/ixia_rfc2544.py
@@ -0,0 +1,155 @@
+# Copyright (c) 2016-2017 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.
+
+from __future__ import absolute_import
+import logging
+import json
+
+from yardstick.network_services.traffic_profile.traffic_profile import \
+ TrexProfile
+
+LOG = logging.getLogger(__name__)
+
+
+class IXIARFC2544Profile(TrexProfile):
+ def _get_ixia_traffic_profile(self, profile_data, mac={},
+ xfile=None, static_traffic={}):
+ result = {}
+ if xfile:
+ with open(xfile, 'r') as stream:
+ try:
+ static_traffic = json.load(stream)
+ except Exception as exc:
+ LOG.debug(exc)
+
+ for traffickey, trafficvalue in static_traffic.items():
+ traffic = static_traffic[traffickey]
+ # outer_l2
+ index = 0
+ for key, value in profile_data[traffickey].items():
+ framesize = value['outer_l2']['framesize']
+ traffic['outer_l2']['framesize'] = framesize
+ traffic['framesPerSecond'] = True
+ traffic['bidir'] = False
+ traffic['outer_l2']['srcmac'] = \
+ mac["src_mac_{}".format(traffic['id'])]
+ traffic['outer_l2']['dstmac'] = \
+ mac["dst_mac_{}".format(traffic['id'])]
+ # outer_l3
+ if "outer_l3v6" in list(value.keys()):
+ traffic['outer_l3'] = value['outer_l3v6']
+ srcip4 = value['outer_l3v6']['srcip6']
+ traffic['outer_l3']['srcip4'] = srcip4.split("-")[0]
+ dstip4 = value['outer_l3v6']['dstip6']
+ traffic['outer_l3']['dstip4'] = dstip4.split("-")[0]
+ else:
+ traffic['outer_l3'] = value['outer_l3v4']
+ srcip4 = value['outer_l3v4']['srcip4']
+ traffic['outer_l3']['srcip4'] = srcip4.split("-")[0]
+ dstip4 = value['outer_l3v4']['dstip4']
+ traffic['outer_l3']['dstip4'] = dstip4.split("-")[0]
+
+ traffic['outer_l3']['type'] = key
+ # outer_l4
+ traffic['outer_l4'] = value['outer_l4']
+ index = index + 1
+ result.update({traffickey: traffic})
+
+ return result
+
+ def _ixia_traffic_generate(self, traffic_generator, traffic, ixia_obj):
+ for key, value in traffic.items():
+ if "public" in key or "private" in key:
+ traffic[key]["iload"] = str(self.rate)
+ ixia_obj.ix_update_frame(traffic)
+ ixia_obj.ix_update_ether(traffic)
+ # ixia_obj.ix_update_ipv4(traffic)
+ ixia_obj.ix_start_traffic()
+ self.tmp_drop = 0
+ self.tmp_throughput = 0
+
+ def execute(self, traffic_generator, ixia_obj, mac={}, xfile=None):
+ if self.first_run:
+ self.full_profile = {}
+ self.pg_id = 0
+ self.profile = 'private_1'
+ for key, value in self.params.items():
+ if "private" in key or "public" in key:
+ self.profile_data = self.params[key]
+ self.get_streams(self.profile_data)
+ self.full_profile.update({key: self.profile_data})
+ traffic = \
+ self._get_ixia_traffic_profile(self.full_profile, mac, xfile)
+ self.max_rate = self.rate
+ self.min_rate = 0
+ self.get_multiplier()
+ self._ixia_traffic_generate(traffic_generator, traffic, ixia_obj)
+
+ def get_multiplier(self):
+ self.rate = round((self.max_rate + self.min_rate) / 2.0, 2)
+ multiplier = round(self.rate / self.pps, 2)
+ return str(multiplier)
+
+ def start_ixia_latency(self, traffic_generator, ixia_obj,
+ mac={}, xfile=None):
+ traffic = self._get_ixia_traffic_profile(self.full_profile, mac)
+ self._ixia_traffic_generate(traffic_generator, traffic,
+ ixia_obj, xfile)
+
+ def get_drop_percentage(self, traffic_generator, samples, tol_min,
+ tolerance, ixia_obj, mac={}, xfile=None):
+ status = 'Running'
+ drop_percent = 100
+ in_packets = sum([samples[iface]['in_packets'] for iface in samples])
+ out_packets = sum([samples[iface]['out_packets'] for iface in samples])
+ rx_throughput = \
+ sum([samples[iface]['RxThroughput'] for iface in samples])
+ tx_throughput = \
+ sum([samples[iface]['TxThroughput'] for iface in samples])
+ packet_drop = abs(out_packets - in_packets)
+ try:
+ drop_percent = round((packet_drop / float(out_packets)) * 100, 2)
+ except ZeroDivisionError:
+ LOG.info('No traffic is flowing')
+ samples['TxThroughput'] = round(tx_throughput / 1.0, 2)
+ samples['RxThroughput'] = round(rx_throughput / 1.0, 2)
+ samples['CurrentDropPercentage'] = drop_percent
+ samples['Throughput'] = self.tmp_throughput
+ samples['DropPercentage'] = self.tmp_drop
+ if drop_percent > tolerance and self.tmp_throughput == 0:
+ samples['Throughput'] = round(rx_throughput / 1.0, 2)
+ samples['DropPercentage'] = drop_percent
+ if self.first_run:
+ max_supported_rate = out_packets / 30.0
+ self.rate = max_supported_rate
+ self.first_run = False
+ if drop_percent <= tolerance:
+ status = 'Completed'
+ if drop_percent > tolerance:
+ self.max_rate = self.rate
+ elif drop_percent < tol_min:
+ self.min_rate = self.rate
+ if drop_percent >= self.tmp_drop:
+ self.tmp_drop = drop_percent
+ self.tmp_throughput = round((rx_throughput / 1.0), 2)
+ samples['Throughput'] = round(rx_throughput / 1.0, 2)
+ samples['DropPercentage'] = drop_percent
+ else:
+ samples['Throughput'] = round(rx_throughput / 1.0, 2)
+ samples['DropPercentage'] = drop_percent
+ return status, samples
+ self.get_multiplier()
+ traffic = self._get_ixia_traffic_profile(self.full_profile, mac, xfile)
+ self._ixia_traffic_generate(traffic_generator, traffic, ixia_obj)
+ return status, samples
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_ixload.py b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py
new file mode 100644
index 000000000..c15f7b954
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_ixload.py
@@ -0,0 +1,176 @@
+# Copyright (c) 2016-2017 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.
+
+from __future__ import absolute_import
+import csv
+import glob
+import logging
+import os
+import shutil
+
+from collections import OrderedDict
+from subprocess import call
+
+import six
+
+from yardstick.common.utils import makedirs
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNFTrafficGen
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ClientResourceHelper
+
+LOG = logging.getLogger(__name__)
+
+VNF_PATH = os.path.dirname(os.path.realpath(__file__))
+
+MOUNT_CMD = """\
+mount.cifs //{0[ip]}/Results {1.RESULTS_MOUNT} \
+-o username={0[user]},password={0[password]}\
+"""
+
+IXLOAD_CONFIG_TEMPLATE = '''\
+{
+ "ixia_chassis": "%s",
+ "IXIA": {
+ "ports": %s,
+ "card": %s
+ },
+ "remote_server": "%s",
+ "result_dir": "%s",
+ "ixload_cfg": '"C:/Results/%s"
+}'''
+
+IXLOAD_CMD = "{ixloadpy} {http_ixload} {args}"
+
+
+class ResourceDataHelper(list):
+
+ def get_aggregates(self):
+ return {
+ "min": min(self),
+ "max": max(self),
+ "avg": sum(self) / len(self),
+ }
+
+
+class IxLoadResourceHelper(ClientResourceHelper):
+
+ RESULTS_MOUNT = "/mnt/Results"
+
+ KPI_LIST = OrderedDict((
+ ('http_throughput', 'HTTP Total Throughput (Kbps)'),
+ ('simulated_users', 'HTTP Simulated Users'),
+ ('concurrent_connections', 'HTTP Concurrent Connections'),
+ ('connection_rate', 'HTTP Connection Rate'),
+ ('transaction_rate', 'HTTP Transaction Rate'),
+ ))
+
+ def __init__(self, setup_helper):
+ super(IxLoadResourceHelper, self).__init__(setup_helper)
+ self.result = OrderedDict((key, ResourceDataHelper()) for key in self.KPI_LIST)
+ self.resource_file_name = ''
+
+ def parse_csv_read(self, reader):
+ for row in reader:
+ try:
+ new_data = {key_left: int(row[key_right])
+ for key_left, key_right in self.KPI_LIST.items()}
+ except (TypeError, ValueError):
+ continue
+ else:
+ for key, value in new_data.items():
+ self.result[key].append(value)
+
+ def setup(self):
+ # TODO: fixupt scenario_helper to hanlde ixia
+ self.resource_file_name = str(self.scenario_helper.scenario_cfg['ixia_profile'])
+ makedirs(self.RESULTS_MOUNT)
+ cmd = MOUNT_CMD.format(self.vnfd_helper.mgmt_interface, self)
+ LOG.debug(cmd)
+
+ if not os.path.ismount(self.RESULTS_MOUNT):
+ call(cmd, shell=True)
+
+ shutil.rmtree(self.RESULTS_MOUNT, ignore_errors=True)
+ makedirs(self.RESULTS_MOUNT)
+ shutil.copy(self.resource_file_name, self.RESULTS_MOUNT)
+
+ def make_aggregates(self):
+ return {key_right: self.result[key_left].get_aggregates()
+ for key_left, key_right in self.KPI_LIST.items()}
+
+ def log(self):
+ for key in self.KPI_LIST:
+ LOG.debug(self.result[key])
+
+
+class IxLoadTrafficGen(SampleVNFTrafficGen):
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = IxLoadResourceHelper
+
+ super(IxLoadTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+ self._result = {}
+ self.done = False
+ self.data = None
+
+ def run_traffic(self, traffic_profile):
+ ports = []
+ card = None
+ for interface in self.vnfd_helper.interfaces:
+ vpci_list = interface['virtual-interface']["vpci"].split(":")
+ card = vpci_list[0]
+ ports.append(vpci_list[1])
+
+ for csv_file in glob.iglob(self.ssh_helper.join_bin_path('*.csv')):
+ os.unlink(csv_file)
+
+ ixia_config = self.vnfd_helper.mgmt_interface["tg-config"]
+ ixload_config = IXLOAD_CONFIG_TEMPLATE % (
+ ixia_config["ixchassis"], ports, card,
+ self.vnfd_helper.mgmt_interface["ip"], self.ssh_helper.bin_path,
+ os.path.basename(self.resource_helper.resource_file_name))
+
+ http_ixload_path = os.path.join(VNF_PATH, "../../traffic_profile")
+ cmd = IXLOAD_CMD.format(
+ ixloadpy=os.path.join(ixia_config["py_bin_path"], "ixloadpython"),
+ http_ixload=os.path.join(http_ixload_path, "http_ixload.py"),
+ args="'%s'" % ixload_config)
+
+ LOG.debug(cmd)
+ call(cmd, shell=True)
+
+ with open(self.ssh_helper.join_bin_path("ixLoad_HTTP_Client.csv")) as csv_file:
+ lines = csv_file.readlines()[10:]
+
+ with open(self.ssh_helper.join_bin_path("http_result.csv"), 'wb+') as result_file:
+ result_file.writelines(six.text_type(lines[:-1]))
+ result_file.flush()
+ result_file.seek(0)
+ reader = csv.DictReader(result_file)
+ self.resource_helper.parse_csv_read(reader)
+
+ self.resource_helper.log()
+ self.data = self.resource_helper.make_aggregates()
+
+ def listen_traffic(self, traffic_profile):
+ pass
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ super(IxLoadTrafficGen, self).instantiate(scenario_cfg, context_cfg)
+ self.done = False
+
+ def terminate(self):
+ call(["pkill", "-9", "http_ixload.py"])
+ super(IxLoadTrafficGen, self).terminate()
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
new file mode 100644
index 000000000..07bbdae95
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py
@@ -0,0 +1,165 @@
+# Copyright (c) 2016-2017 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.
+
+from __future__ import absolute_import
+import time
+import os
+import logging
+import sys
+
+from yardstick.common.utils import ErrorClass
+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 Rfc2544ResourceHelper
+
+try:
+ from IxNet import IxNextgen
+except ImportError:
+ IxNextgen = ErrorClass
+
+LOG = logging.getLogger(__name__)
+
+WAIT_AFTER_CFG_LOAD = 10
+WAIT_FOR_TRAFFIC = 30
+IXIA_LIB = os.path.dirname(os.path.realpath(__file__))
+IXNET_LIB = os.path.join(IXIA_LIB, "../../libs/ixia_libs/IxNet")
+sys.path.append(IXNET_LIB)
+
+
+class IxiaRfc2544Helper(Rfc2544ResourceHelper):
+
+ pass
+
+
+class IxiaResourceHelper(ClientResourceHelper):
+
+ def __init__(self, setup_helper, rfc_helper_type=None):
+ super(IxiaResourceHelper, self).__init__(setup_helper)
+ self.scenario_helper = setup_helper.scenario_helper
+
+ self.client = IxNextgen()
+
+ if rfc_helper_type is None:
+ rfc_helper_type = IxiaRfc2544Helper
+
+ self.rfc_helper = rfc_helper_type(self.scenario_helper)
+ self.tg_port_pairs = []
+ self.priv_ports = None
+ self.pub_ports = None
+
+ def _connect(self, client=None):
+ self.client.connect(self.vnfd_helper)
+
+ def _build_ports(self):
+ # self.generate_port_pairs(self.topology)
+ self.priv_ports = [int(x[0][-1]) for x in self.tg_port_pairs]
+ self.pub_ports = [int(x[1][-1]) for x in self.tg_port_pairs]
+ self.my_ports = list(set(self.priv_ports).union(set(self.pub_ports)))
+
+ def get_stats(self, *args, **kwargs):
+ return self.client.ix_get_statistics()[1]
+
+ def stop_collect(self):
+ self._terminated.value = 0
+ if self.client:
+ self.client.ix_stop_traffic()
+
+ def generate_samples(self, key=None, default=None):
+ last_result = self.get_stats()
+
+ samples = {}
+ for vpci_idx, interface in enumerate(self.vnfd_helper.interfaces):
+ name = "xe{0}".format(vpci_idx)
+ samples[name] = {
+ "rx_throughput_kps": float(last_result["Rx_Rate_Kbps"][vpci_idx]),
+ "tx_throughput_kps": float(last_result["Tx_Rate_Kbps"][vpci_idx]),
+ "rx_throughput_mbps": float(last_result["Rx_Rate_Mbps"][vpci_idx]),
+ "tx_throughput_mbps": float(last_result["Tx_Rate_Mbps"][vpci_idx]),
+ "in_packets": int(last_result["Valid_Frames_Rx"][vpci_idx]),
+ "out_packets": int(last_result["Frames_Tx"][vpci_idx]),
+ "RxThroughput": int(last_result["Valid_Frames_Rx"][vpci_idx]) / 30,
+ "TxThroughput": int(last_result["Frames_Tx"][vpci_idx]) / 30,
+ }
+
+ return samples
+
+ def run_traffic(self, traffic_profile):
+ min_tol = self.rfc_helper.tolerance_low
+ max_tol = self.rfc_helper.tolerance_high
+
+ self._build_ports()
+ self._connect()
+
+ # we don't know client_file_name until runtime as instantiate
+ client_file_name = self.scenario_helper.scenario_cfg['ixia_profile']
+ self.client.ix_load_config(client_file_name)
+ time.sleep(WAIT_AFTER_CFG_LOAD)
+
+ self.client.ix_assign_ports()
+
+ mac = {}
+ for index, interface in enumerate(self.vnfd_helper.interfaces):
+ virt_intf = interface["virtual-interface"]
+ mac.update({
+ "src_mac_{}".format(index): virt_intf["local_mac"],
+ "dst_mac_{}".format(index): virt_intf["dst_mac"],
+ })
+
+ samples = {}
+ ixia_file = os.path.join(os.getcwd(), "ixia_traffic.cfg")
+ # Generate ixia traffic config...
+ while not self._terminated.value:
+ traffic_profile.execute(self, self.client, mac, ixia_file)
+ self.client_started.value = 1
+ time.sleep(WAIT_FOR_TRAFFIC)
+ self.client.ix_stop_traffic()
+ samples = self.generate_samples()
+ self._queue.put(samples)
+ status, samples = traffic_profile.get_drop_percentage(self, samples, min_tol,
+ max_tol, self.client, mac,
+ ixia_file)
+
+ current = samples['CurrentDropPercentage']
+ if min_tol <= current <= max_tol or status == 'Completed':
+ self._terminated.value = 1
+
+ self.client.ix_stop_traffic()
+ self._queue.put(samples)
+
+
+class IxiaTrafficGen(SampleVNFTrafficGen):
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None, resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = IxiaResourceHelper
+
+ super(IxiaTrafficGen, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+ self._ixia_traffic_gen = None
+ self.ixia_file_name = ''
+ self.tg_port_pairs = []
+ self.vnf_port_pairs = []
+
+ def _check_status(self):
+ pass
+
+ def scale(self, flavor=""):
+ pass
+
+ def listen_traffic(self, traffic_profile):
+ pass
+
+ def terminate(self):
+ self.resource_helper.stop_collect()
+ super(IxiaTrafficGen, self).terminate()