IXIA traffic generator 91/38291/7
authorDeepak S <deepak.s@linux.intel.com>
Tue, 20 Jun 2017 21:18:57 +0000 (14:18 -0700)
committerRoss Brattain <ross.b.brattain@intel.com>
Tue, 8 Aug 2017 19:57:42 +0000 (12:57 -0700)
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>
22 files changed:
etc/yardstick/nodes/pod.yaml.nsb.sample.ixia [new file with mode: 0644]
samples/vnf_samples/traffic_profiles/ixia_ipv4_latency.yaml [new file with mode: 0644]
samples/vnf_samples/vnf_descriptors/ixia_rfc2544_tpl.yaml [new file with mode: 0644]
samples/vnf_samples/vnf_descriptors/tg_ixload.yaml [new file with mode: 0644]
samples/vnf_samples/vnf_descriptors/tg_ixload_4port.yaml [new file with mode: 0644]
tests/unit/common/test_utils.py
tests/unit/network_services/libs/__init__.py [new file with mode: 0644]
tests/unit/network_services/libs/ixia_libs/__init__.py [new file with mode: 0644]
tests/unit/network_services/libs/ixia_libs/test_IxNet.py [new file with mode: 0644]
tests/unit/network_services/traffic_profile/test_http_ixload.py [new file with mode: 0644]
tests/unit/network_services/traffic_profile/test_ixia_rfc2544.py [new file with mode: 0644]
tests/unit/network_services/vnf_generic/vnf/test_tg_ixload.py [new file with mode: 0644]
tests/unit/network_services/vnf_generic/vnf/test_tg_rfc2544_ixia.py [new file with mode: 0644]
yardstick/common/utils.py
yardstick/network_services/libs/__init__.py [new file with mode: 0644]
yardstick/network_services/libs/ixia_libs/IxNet/IxNet.py [new file with mode: 0644]
yardstick/network_services/libs/ixia_libs/IxNet/__init__.py [new file with mode: 0644]
yardstick/network_services/libs/ixia_libs/__init__.py [new file with mode: 0644]
yardstick/network_services/traffic_profile/http_ixload.py [new file with mode: 0644]
yardstick/network_services/traffic_profile/ixia_rfc2544.py [new file with mode: 0644]
yardstick/network_services/vnf_generic/vnf/tg_ixload.py [new file with mode: 0644]
yardstick/network_services/vnf_generic/vnf/tg_rfc2544_ixia.py [new file with mode: 0644]

diff --git a/etc/yardstick/nodes/pod.yaml.nsb.sample.ixia b/etc/yardstick/nodes/pod.yaml.nsb.sample.ixia
new file mode 100644 (file)
index 0000000..57a8305
--- /dev/null
@@ -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 (file)
index 0000000..ccd40c3
--- /dev/null
@@ -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 (file)
index 0000000..4b520f6
--- /dev/null
@@ -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 (file)
index 0000000..b430d35
--- /dev/null
@@ -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 (file)
index 0000000..ffbfbde
--- /dev/null
@@ -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)
index 53b5652..948f8fc 100644 (file)
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..9114b51
--- /dev/null
@@ -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 (file)
index 0000000..2e1b6f4
--- /dev/null
@@ -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 (file)
index 0000000..6dba64a
--- /dev/null
@@ -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 (file)
index 0000000..cda4412
--- /dev/null
@@ -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 (file)
index 0000000..8f7f057
--- /dev/null
@@ -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)
index 1059e1c..969bb4b 100644 (file)
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..815a2a2
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/yardstick/network_services/libs/ixia_libs/__init__.py b/yardstick/network_services/libs/ixia_libs/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/yardstick/network_services/traffic_profile/http_ixload.py b/yardstick/network_services/traffic_profile/http_ixload.py
new file mode 100644 (file)
index 0000000..8a4f97f
--- /dev/null
@@ -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 (file)
index 0000000..5ba0018
--- /dev/null
@@ -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 (file)
index 0000000..c15f7b9
--- /dev/null
@@ -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 (file)
index 0000000..07bbdae
--- /dev/null
@@ -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()