aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ansible/build_vm.yml44
-rw-r--r--ansible/group_vars/all.yml9
-rw-r--r--ansible/install-inventory.ini20
-rw-r--r--ansible/install.yaml79
-rw-r--r--ansible/roles/build_yardstick_image/tasks/post_build.yml21
-rw-r--r--ansible/roles/build_yardstick_image/tasks/pre_build.yml12
-rw-r--r--ansible/roles/download_civetweb/tasks/main.yml4
-rw-r--r--ansible/roles/download_dpdk/tasks/main.yml4
-rw-r--r--ansible/roles/download_drivers/tasks/i40evf.yml4
-rw-r--r--ansible/roles/download_l2fwd/tasks/main.yml4
-rw-r--r--ansible/roles/download_pktgen/tasks/main.yml4
-rw-r--r--ansible/roles/download_trex/tasks/main.yml4
-rw-r--r--ansible/roles/install_image_dependencies/defaults/main.yml2
-rw-r--r--dashboard/RFC2544_2Port.json76
-rw-r--r--dashboard/RFC2544_2Port_Multiframesize.json63
-rw-r--r--docs/testing/user/userguide/13-nsb-installation.rst252
-rw-r--r--docs/testing/user/userguide/14-nsb-operation.rst34
-rw-r--r--docs/testing/user/userguide/nsb/nsb-list-of-tcs.rst1
-rw-r--r--docs/testing/user/userguide/nsb/tc_vpp_baremetal_crypto_ipsec.rst113
-rwxr-xr-xsamples/vnf_samples/nsut/cmts/k8s_vcmts_topology.yaml36
-rwxr-xr-xsamples/vnf_samples/nsut/cmts/tc_vcmts_k8s_pktgen.yaml360
-rw-r--r--samples/vnf_samples/traffic_profiles/ipv4_throughput_latency_vpp.yaml1
-rwxr-xr-xsamples/vnf_samples/vnf_descriptors/tg_vcmts_tpl.yaml77
-rwxr-xr-xsamples/vnf_samples/vnf_descriptors/vnf_vcmts_tpl.yaml77
-rwxr-xr-xsetup.py3
-rw-r--r--yardstick/network_services/helpers/cpu.py86
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/__init__.py0
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py53
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py688
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py68
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py88
-rw-r--r--yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py58
-rw-r--r--yardstick/network_services/traffic_profile/vpp_rfc2544.py34
-rw-r--r--yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py293
-rwxr-xr-xyardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py215
-rwxr-xr-xyardstick/network_services/vnf_generic/vnf/vcmts_vnf.py273
-rw-r--r--yardstick/network_services/vnf_generic/vnf/vims_vnf.py105
-rw-r--r--yardstick/network_services/vnf_generic/vnf/vpp_helpers.py617
-rw-r--r--yardstick/resources/templates/add_ip_address.vat1
-rw-r--r--yardstick/resources/templates/add_ip_neighbor.vat1
-rw-r--r--yardstick/resources/templates/add_route.vat1
-rw-r--r--yardstick/resources/templates/del_route.vat1
-rw-r--r--yardstick/resources/templates/flush_ip_addresses.vat1
-rw-r--r--yardstick/resources/templates/hw_interface_set_mtu.vat1
-rw-r--r--yardstick/resources/templates/interface_dump.vat1
-rw-r--r--yardstick/resources/templates/set_if_state.vat1
-rw-r--r--yardstick/tests/unit/network_services/helpers/test_cpu.py72
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py0
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py2164
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py91
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py100
-rw-r--r--yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py44
-rw-r--r--yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py77
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py801
-rwxr-xr-xyardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py652
-rwxr-xr-xyardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py651
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py713
-rw-r--r--yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py1274
58 files changed, 10378 insertions, 151 deletions
diff --git a/ansible/build_vm.yml b/ansible/build_vm.yml
new file mode 100644
index 000000000..9774f9ff5
--- /dev/null
+++ b/ansible/build_vm.yml
@@ -0,0 +1,44 @@
+- name: Prepare to build VM
+ hosts: jumphost
+ become: yes
+ vars:
+ img_prop_item: "{{ IMG_PROPERTY }}"
+ img_arch: "{{ YARD_IMG_ARCH }}"
+
+ tasks:
+ - name: Include pre-build
+ include_role:
+ name: build_yardstick_image
+ tasks_from: pre_build.yml
+ when:
+ - installation_mode != inst_mode_container
+
+
+- name: Build VM in chroot
+ hosts: chroot_image
+ connection: chroot
+ become: yes
+ vars:
+ img_property: "{{ IMG_PROPERTY }}"
+ environment: "{{ proxy_env }}"
+
+ tasks:
+ - name: Include image build
+ include_role:
+ name: build_yardstick_image
+ tasks_from: "cloudimg_modify_{{ img_property }}.yml"
+ when:
+ - installation_mode != inst_mode_container
+
+
+- name: Clear up after VM is built
+ hosts: jumphost
+ become: yes
+
+ tasks:
+ - name: Include post-build
+ include_role:
+ name: build_yardstick_image
+ tasks_from: post_build.yml
+ when:
+ - installation_mode != inst_mode_container
diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index cd12bf02e..e94d24023 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -7,7 +7,16 @@ release: "{{ OS_RELEASE | default('xenial') }}"
normal_image_file: "{{ workspace }}/yardstick-image.img"
nsb_image_file: "{{ workspace }}/yardstick-nsb-image.img"
ubuntu_image_file: /tmp/workspace/yardstick/yardstick-trusty-server.raw
+arch_amd64: "amd64"
+arch_arm64: "arm64"
+inst_mode_baremetal: "baremetal"
+inst_mode_container: "container"
+inst_mode_container_pull: "container_pull"
+ubuntu_archive:
+ "amd64": "http://archive.ubuntu.com/ubuntu/"
+ "arm64": "http://ports.ubuntu.com/ubuntu-ports/"
installation_mode: "{{ INSTALLATION_MODE | default('baremetal') }}"
+yardstick_dir: "{{ YARDSTICK_DIR | default('/home/opnfv/repos/yardstick') }}"
proxy_env:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/bin
http_proxy: "{{ lookup('env', 'http_proxy') }}"
diff --git a/ansible/install-inventory.ini b/ansible/install-inventory.ini
index bcd57db65..07d2c13f4 100644
--- a/ansible/install-inventory.ini
+++ b/ansible/install-inventory.ini
@@ -8,24 +8,20 @@ localhost ansible_connection=local
[yardstick:children]
jumphost
-[yardstick-standalone]
-# standalone-node ansible_host=192.168.2.51 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh
-
[yardstick-baremetal]
-# baremetal-node ansible_host=192.168.2.52 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh
+# baremetal-node ansible_host=192.168.2.51 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh
+
+[yardstick-standalone]
+# standalone-node ansible_host=192.168.2.52 ansible_user=ubuntu ansible_ssh_pass=password ansible_connection=ssh
[all:vars]
-arch_amd64=amd64
-arch_arm64=arm64
-inst_mode_baremetal=baremetal
-inst_mode_container=container
-inst_mode_container_pull=container_pull
-ubuntu_archive={"amd64": "http://archive.ubuntu.com/ubuntu/", "arm64": "http://ports.ubuntu.com/ubuntu-ports/"}
-# When IMG_PROPERTY is passed neither normal nor nsb set "path_to_vm=/path/to/image" to add it to OpenStack
-# path_to_img=/tmp/workspace/yardstick-image.img
# Uncomment credentials below if needed
# ansible_user=root
# ansible_ssh_pass=root
+# ansible_ssh_private_key_file=/root/.ssh/id_rsa
+
+# When IMG_PROPERTY is passed neither normal nor nsb set "path_to_vm=/path/to/image" to add it to OpenStack
+# path_to_img=/tmp/workspace/yardstick-image.img
# List of CPUs to be isolated (not used by default)
# Grub line will be extended with: "isolcpus=<ISOL_CPUS> nohz=on nohz_full=<ISOL_CPUS> rcu_nocbs=1<ISOL_CPUS>"
diff --git a/ansible/install.yaml b/ansible/install.yaml
index 558c48609..a78a11f68 100644
--- a/ansible/install.yaml
+++ b/ansible/install.yaml
@@ -15,7 +15,6 @@
- hosts: jumphost
become: yes
vars:
- yardstick_dir: "{{ YARDSTICK_DIR | default('/home/opnfv/repos/yardstick') }}"
virtual_environment: "{{ VIRTUAL_ENVIRONMENT | default(False) }}"
nsb_dir: "{{ NSB_DIR | default('/opt/nsb_bin/') }}"
@@ -105,54 +104,59 @@
- docker
- barometer_collectd
-
- name: Prepare to build VM
- hosts: jumphost
+ hosts: yardstick-standalone
become: yes
vars:
img_prop_item: "{{ IMG_PROPERTY }}"
img_arch: "{{ YARD_IMG_ARCH }}"
-
- tasks:
- - name: Include pre-build
- include_role:
- name: build_yardstick_image
- tasks_from: pre_build.yml
- when:
- - installation_mode != inst_mode_container
- - IMG_PROPERTY == 'nsb' or IMG_PROPERTY == 'normal'
-
-
-- name: Build VM in chroot
- hosts: chroot_image
- connection: chroot
- become: yes
- vars:
- img_property: "{{ IMG_PROPERTY }}"
environment: "{{ proxy_env }}"
tasks:
- - name: Include image build
- include_role:
- name: build_yardstick_image
- tasks_from: "cloudimg_modify_{{ img_property }}.yml"
+ - file:
+ dest: /tmp/ansible
+ state: directory
+ mode: 0755
+
+ - name: Copy ansible folder to remote DUT
+ copy:
+ src: "."
+ dest: /tmp/ansible
+
+ - name: Install DUT related packages
+ apt:
+ name: "{{ packages }}"
+ vars:
+ packages:
+ - qemu-kvm
+ - libvirt-bin
+ - bridge-utils
+ - fping
+ - genisoimage
+
+ # There is a bug with the easy install ansible module in Ubuntu 16.04 linux.
+ # Refer https://github.com/ansible/ansible/issues/23534
+ - name: Install pip
+ shell: easy_install -U pip
when:
- - installation_mode != inst_mode_container
- - IMG_PROPERTY == 'nsb' or IMG_PROPERTY == 'normal'
+ - ansible_distribution == 'Ubuntu'
+ - ansible_distribution_major_version|int <= 16
+ - name: Install python-pip
+ action: "{{ ansible_pkg_mgr }} name=python-pip state=present"
+ when:
+ - ansible_distribution == 'Ubuntu'
+ - ansible_distribution_major_version|int >= 17
-- name: Clear up after VM is built
- hosts: jumphost
- become: yes
+ - name: Update pip ansible docker
+ pip:
+ name: "ansible==2.5.5"
- tasks:
- - name: Include post-build
- include_role:
- name: build_yardstick_image
- tasks_from: post_build.yml
- when:
- - installation_mode != inst_mode_container
- - IMG_PROPERTY == 'nsb' or IMG_PROPERTY == 'normal'
+ # This is used as workaround as ansible doesn't support chroot on remote server
+ - name: Run ansible on remote
+ shell: "ansible-playbook -e OS_RELEASE={{ OS_RELEASE }} -e IMAGE_PROPERTY={{ IMAGE_PROPERTY }} -e YARD_IMAGE_ARCH={{ YARD_IMAGE_ARCH }} -i install-inventory.ini build_vm.yml -vv"
+ args:
+ chdir: "/tmp/ansible"
- name: Add OpenStack variables, image
@@ -216,6 +220,5 @@
volumes:
- "{{ openrc_file|default('/dev/null') }}:/etc/yardstick/openstack.creds:ro"
- /var/run/docker.sock:/var/run/docker.sock
- - /opt:/opt
- /etc/localtime:/etc/localtime:ro
when: installation_mode == inst_mode_container_pull
diff --git a/ansible/roles/build_yardstick_image/tasks/post_build.yml b/ansible/roles/build_yardstick_image/tasks/post_build.yml
index c6888f8df..abbf57c03 100644
--- a/ansible/roles/build_yardstick_image/tasks/post_build.yml
+++ b/ansible/roles/build_yardstick_image/tasks/post_build.yml
@@ -35,6 +35,10 @@
state: unmounted
- mount:
+ name: "{{ mountdir }}/run"
+ state: unmounted
+
+- mount:
name: "{{ mountdir }}"
state: unmounted
@@ -44,3 +48,20 @@
- debug:
msg: "yardstick image = {{ imgfile }}"
+
+- set_fact:
+ imgdest: "/var/lib/libvirt/images/{{ imgfile | basename}}"
+ name: "{{ (imgfile | basename | splitext)[0] }}"
+ ext: "{{ (imgfile | basename | splitext)[1] }}"
+
+- name: Verify if imgfile exists in libvirt images
+ stat:
+ path: "{{ imgdest }}"
+ register: imgdest_stat
+
+- set_fact:
+ imgdest: "/var/lib/libvirt/images/{{ name }}_autogen{{ ext }}"
+ when: imgdest_stat.stat.exists
+
+- name: Copy image to libvirt images
+ shell: "cp {{ imgfile }} {{ imgdest }}"
diff --git a/ansible/roles/build_yardstick_image/tasks/pre_build.yml b/ansible/roles/build_yardstick_image/tasks/pre_build.yml
index 2dae38060..3ac8e90e9 100644
--- a/ansible/roles/build_yardstick_image/tasks/pre_build.yml
+++ b/ansible/roles/build_yardstick_image/tasks/pre_build.yml
@@ -45,6 +45,7 @@
with_items:
# order matters
- "{{ mountdir }}/proc"
+ - "{{ mountdir }}/run"
- "{{ mountdir }}"
- "/mnt/{{ release }}"
@@ -178,6 +179,17 @@
fstab: "{{ fake_fstab }}"
state: mounted
+- name: mount chroot /run
+ mount:
+ src: /run
+ name: "{{ mountdir }}/run"
+ fstype: tmpfs
+ opts: bind
+ # !!!!!!! this is required otherwise we add entries to /etc/fstab
+ # and prevent the system from booting
+ fstab: "{{ fake_fstab }}"
+ state: mounted
+
- name: if arm copy qemu-aarch64-static into chroot
copy:
src: /usr/bin/qemu-aarch64-static
diff --git a/ansible/roles/download_civetweb/tasks/main.yml b/ansible/roles/download_civetweb/tasks/main.yml
index 03dd3ccd3..b6a475774 100644
--- a/ansible/roles/download_civetweb/tasks/main.yml
+++ b/ansible/roles/download_civetweb/tasks/main.yml
@@ -18,6 +18,10 @@
dest: "{{ clone_dest }}/"
validate_certs: False
checksum: "{{ civetweb_sha256s }}"
+ register: package_result
+ until: package_result is succeeded
+ retries: 10
+ delay: 5
- name: unarchive civetweb
unarchive:
diff --git a/ansible/roles/download_dpdk/tasks/main.yml b/ansible/roles/download_dpdk/tasks/main.yml
index 55b466cb7..e434536a3 100644
--- a/ansible/roles/download_dpdk/tasks/main.yml
+++ b/ansible/roles/download_dpdk/tasks/main.yml
@@ -26,6 +26,10 @@
dest: "{{ dpdk_dest }}"
validate_certs: False
checksum: "{{ dpdk_md5[dpdk_version] }}"
+ register: package_result
+ until: package_result is succeeded
+ retries: 10
+ delay: 5
- unarchive:
src: "{{ dpdk_dest }}/{{ dpdk_file }}"
diff --git a/ansible/roles/download_drivers/tasks/i40evf.yml b/ansible/roles/download_drivers/tasks/i40evf.yml
index cb8a09d6c..48a0330ab 100644
--- a/ansible/roles/download_drivers/tasks/i40evf.yml
+++ b/ansible/roles/download_drivers/tasks/i40evf.yml
@@ -23,6 +23,10 @@
dest: "{{ i40evf_dest }}/{{ i40evf_gzfile }}"
validate_certs: False
checksum: "{{ i40evf_checksum[i40evf_version] }}"
+ register: package_result
+ until: package_result is succeeded
+ retries: 10
+ delay: 5
- name: Unarchive the i40evf file
unarchive:
diff --git a/ansible/roles/download_l2fwd/tasks/main.yml b/ansible/roles/download_l2fwd/tasks/main.yml
index 7f2ea25c4..43b0ec366 100644
--- a/ansible/roles/download_l2fwd/tasks/main.yml
+++ b/ansible/roles/download_l2fwd/tasks/main.yml
@@ -20,6 +20,10 @@
get_url:
url: "{{ l2fwd_url }}"
dest: "{{ l2fwd_dest }}"
+ register: package_result
+ until: package_result is succeeded
+ retries: 10
+ delay: 5
- unarchive:
src: "{{ l2fwd_dest }}/{{ l2fwd_file }}"
diff --git a/ansible/roles/download_pktgen/tasks/main.yml b/ansible/roles/download_pktgen/tasks/main.yml
index ff71f207d..b5ac8cfe8 100644
--- a/ansible/roles/download_pktgen/tasks/main.yml
+++ b/ansible/roles/download_pktgen/tasks/main.yml
@@ -22,6 +22,10 @@
dest: "{{ pktgen_dest }}"
validate_certs: False
checksum: "{{ pktgen_sha256s[pktgen_version] }}"
+ register: package_result
+ until: package_result is succeeded
+ retries: 10
+ delay: 5
- unarchive:
src: "{{ pktgen_dest }}/{{ pktgen_file }}"
diff --git a/ansible/roles/download_trex/tasks/main.yml b/ansible/roles/download_trex/tasks/main.yml
index 9df67d939..44449a9c0 100644
--- a/ansible/roles/download_trex/tasks/main.yml
+++ b/ansible/roles/download_trex/tasks/main.yml
@@ -23,6 +23,10 @@
dest: "{{ trex_dest }}"
validate_certs: False
checksum: "{{ trex_sha256s[trex_version] }}"
+ register: package_result
+ until: package_result is succeeded
+ retries: 10
+ delay: 5
- name: unarchive Trex
unarchive:
diff --git a/ansible/roles/install_image_dependencies/defaults/main.yml b/ansible/roles/install_image_dependencies/defaults/main.yml
index 42951bf6d..558e68a9b 100644
--- a/ansible/roles/install_image_dependencies/defaults/main.yml
+++ b/ansible/roles/install_image_dependencies/defaults/main.yml
@@ -30,6 +30,7 @@ install_dependencies:
- libxss-dev
- expect
- libnuma-dev
+ - curl
RedHat:
- bc
- fio
@@ -50,3 +51,4 @@ install_dependencies:
- sysstat
- unzip
- python-devel
+ - curl
diff --git a/dashboard/RFC2544_2Port.json b/dashboard/RFC2544_2Port.json
index e6f3265f9..de9448cee 100644
--- a/dashboard/RFC2544_2Port.json
+++ b/dashboard/RFC2544_2Port.json
@@ -1,14 +1,50 @@
{
+ "__inputs": [
+ {
+ "name": "DS_YARDSTICK",
+ "label": "yardstick",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "influxdb",
+ "pluginName": "InfluxDB"
+ }
+ ],
+ "__requires": [
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "4.4.3"
+ },
+ {
+ "type": "panel",
+ "id": "graph",
+ "name": "Graph",
+ "version": ""
+ },
+ {
+ "type": "datasource",
+ "id": "influxdb",
+ "name": "InfluxDB",
+ "version": "1.0.0"
+ },
+ {
+ "type": "panel",
+ "id": "table",
+ "name": "Table",
+ "version": ""
+ }
+ ],
"annotations": {
"list": [
{
- "datasource": "yardstick",
+ "datasource": "${DS_YARDSTICK}",
"enable": true,
"hide": false,
"iconColor": "rgb(248, 255, 0)",
"limit": 100,
"name": "status",
- "query": "SELECT tg__0.collect_stats.Status FROM \"tc_heat_rfc2544_ipv4_1rule_1flow_trex\" WHERE \"tg__0.collect_stats.Status\"='Success' AND task_id='$task_id'",
+ "query": "SELECT tg__0.collect_stats.Status FROM $test_name WHERE \"tg__0.collect_stats.Status\"='Success' AND task_id='$task_id'",
"showIn": 0,
"titleColumn": "Status",
"type": "alert"
@@ -19,7 +55,7 @@
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
- "id": 6,
+ "id": null,
"links": [],
"refresh": false,
"rows": [
@@ -32,7 +68,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
- "datasource": "yardstick",
+ "datasource": "${DS_YARDSTICK}",
"fill": 0,
"hideTimeOverride": true,
"id": 3,
@@ -66,8 +102,8 @@
"measurement": "/^$test_name$/",
"orderByTime": "ASC",
"policy": "default",
- "query": "SELECT \"tg__0.collect_stats.xe0.InBytes\", \"tg__0.collect_stats.xe0.OutBytes\", \"tg__0.collect_stats.xe1.InBytes\", \"tg__0.collect_stats.xe1.OutBytes\" FROM /^$test_name$/ WHERE \"task_id\" =~ /^$task_id$/ AND \"tg__0.collect_stats.PktSize\" =~ /^$framesize$/ AND $timeFilter",
- "rawQuery": false,
+ "query": "SELECT \"tg__0.collect_stats.xe0.InBytes\", \"tg__0.collect_stats.xe0.OutBytes\", \"tg__0.collect_stats.xe1.InBytes\", \"tg__0.collect_stats.xe1.OutBytes\" FROM /^$test_name$/ WHERE \"task_id\" =~ /^$task_id$/ AND $timeFilter",
+ "rawQuery": true,
"refId": "A",
"resultFormat": "time_series",
"select": [
@@ -166,7 +202,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
- "datasource": "yardstick",
+ "datasource": "${DS_YARDSTICK}",
"fill": 1,
"id": 1,
"legend": {
@@ -196,7 +232,7 @@
"alias": "$col",
"dsType": "influxdb",
"groupBy": [],
- "measurement": "tc_heat_rfc2544_ipv4_1rule_1flow_trex",
+ "measurement": "/^$test_name$/",
"orderByTime": "ASC",
"policy": "default",
"refId": "A",
@@ -273,7 +309,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
- "datasource": null,
+ "datasource": "${DS_YARDSTICK}",
"fill": 1,
"id": 5,
"legend": {
@@ -528,11 +564,8 @@
"list": [
{
"allValue": null,
- "current": {
- "text": "tc_heat_rfc2544_ipv4_1rule_1flow_trex",
- "value": "tc_heat_rfc2544_ipv4_1rule_1flow_trex"
- },
- "datasource": "yardstick",
+ "current": {},
+ "datasource": "${DS_YARDSTICK}",
"hide": 0,
"includeAll": false,
"label": "test_name",
@@ -551,18 +584,15 @@
},
{
"allValue": null,
- "current": {
- "text": "004b5387-74b3-4cf0-9597-5198db9e2731",
- "value": "004b5387-74b3-4cf0-9597-5198db9e2731"
- },
- "datasource": "yardstick",
+ "current": {},
+ "datasource": "${DS_YARDSTICK}",
"hide": 0,
"includeAll": false,
"label": "task_id",
"multi": false,
"name": "task_id",
"options": [],
- "query": "SHOW TAG VALUES FROM $test_name WITH KEY = \"task_id\" ",
+ "query": "SHOW TAG VALUES FROM $test_name WITH KEY = \"task_id\" ",
"refresh": 2,
"regex": "",
"sort": 0,
@@ -575,8 +605,8 @@
]
},
"time": {
- "from": "2019-03-05T12:44:02.829Z",
- "to": "2019-03-05T13:32:27.585Z"
+ "from": "2019-03-06T13:54:13.610Z",
+ "to": "2019-03-06T13:56:59.693Z"
},
"timepicker": {
"refresh_intervals": [
@@ -605,5 +635,5 @@
},
"timezone": "",
"title": "RFC2544",
- "version": 2
+ "version": 4
}
diff --git a/dashboard/RFC2544_2Port_Multiframesize.json b/dashboard/RFC2544_2Port_Multiframesize.json
index f08cf3d47..2d8e9522f 100644
--- a/dashboard/RFC2544_2Port_Multiframesize.json
+++ b/dashboard/RFC2544_2Port_Multiframesize.json
@@ -1,14 +1,44 @@
{
+ "__inputs": [
+ {
+ "name": "DS_YARDSTICK",
+ "label": "yardstick",
+ "description": "",
+ "type": "datasource",
+ "pluginId": "influxdb",
+ "pluginName": "InfluxDB"
+ }
+ ],
+ "__requires": [
+ {
+ "type": "grafana",
+ "id": "grafana",
+ "name": "Grafana",
+ "version": "4.4.3"
+ },
+ {
+ "type": "panel",
+ "id": "graph",
+ "name": "Graph",
+ "version": ""
+ },
+ {
+ "type": "datasource",
+ "id": "influxdb",
+ "name": "InfluxDB",
+ "version": "1.0.0"
+ }
+ ],
"annotations": {
"list": [
{
- "datasource": "yardstick",
+ "datasource": "${DS_YARDSTICK}",
"enable": true,
"hide": false,
"iconColor": "rgb(248, 255, 0)",
"limit": 100,
"name": "status",
- "query": "SELECT tg__0.collect_stats.Status FROM \"tc_heat_rfc2544_ipv4_1rule_1flow_trex\" WHERE \"tg__0.collect_stats.Status\"='Success' AND task_id='$task_id'",
+ "query": "SELECT tg__0.collect_stats.Status FROM $test_name WHERE \"tg__0.collect_stats.Status\"='Success' AND task_id='$task_id'",
"showIn": 0,
"titleColumn": "Status",
"type": "alert"
@@ -19,7 +49,7 @@
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
- "id": 2,
+ "id": null,
"links": [],
"refresh": false,
"rows": [
@@ -32,7 +62,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
- "datasource": "yardstick",
+ "datasource": "${DS_YARDSTICK}",
"fill": 0,
"hideTimeOverride": true,
"id": 3,
@@ -172,7 +202,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
- "datasource": "yardstick",
+ "datasource": "${DS_YARDSTICK}",
"fill": 1,
"id": 1,
"legend": {
@@ -202,7 +232,7 @@
"alias": "$col",
"dsType": "influxdb",
"groupBy": [],
- "measurement": "tc_heat_rfc2544_ipv4_1rule_1flow_trex",
+ "measurement": "/^$test_name$/",
"orderByTime": "ASC",
"policy": "default",
"refId": "A",
@@ -285,7 +315,7 @@
"bars": false,
"dashLength": 10,
"dashes": false,
- "datasource": null,
+ "datasource": "${DS_YARDSTICK}",
"fill": 1,
"id": 5,
"legend": {
@@ -408,7 +438,7 @@
"bars": true,
"dashLength": 10,
"dashes": false,
- "datasource": null,
+ "datasource": "${DS_YARDSTICK}",
"fill": 1,
"id": 4,
"legend": {
@@ -723,11 +753,8 @@
"list": [
{
"allValue": null,
- "current": {
- "text": "tc_heat_rfc2544_ipv4_1rule_1flow_trex",
- "value": "tc_heat_rfc2544_ipv4_1rule_1flow_trex"
- },
- "datasource": "yardstick",
+ "current": {},
+ "datasource": "${DS_YARDSTICK}",
"hide": 0,
"includeAll": false,
"label": "test_name",
@@ -746,11 +773,8 @@
},
{
"allValue": null,
- "current": {
- "text": "fdb337ec-11ea-410f-b45e-83f30edb7590",
- "value": "fdb337ec-11ea-410f-b45e-83f30edb7590"
- },
- "datasource": "yardstick",
+ "current": {},
+ "datasource": "${DS_YARDSTICK}",
"hide": 0,
"includeAll": false,
"label": "task_id",
@@ -770,7 +794,6 @@
{
"allValue": null,
"current": {
- "tags": [],
"text": "64B + 128B + 512B",
"value": [
"64B",
@@ -881,5 +904,5 @@
},
"timezone": "",
"title": "RFC2544 Multi framesize",
- "version": 14
+ "version": 15
}
diff --git a/docs/testing/user/userguide/13-nsb-installation.rst b/docs/testing/user/userguide/13-nsb-installation.rst
index 0487dad9a..694521d2b 100644
--- a/docs/testing/user/userguide/13-nsb-installation.rst
+++ b/docs/testing/user/userguide/13-nsb-installation.rst
@@ -21,6 +21,7 @@ NSB Installation
.. _OVS-DPDK: http://docs.openvswitch.org/en/latest/intro/install/dpdk/
.. _devstack: https://docs.openstack.org/devstack/pike/>
+.. _OVS-DPDK-versions: http://docs.openvswitch.org/en/latest/faq/releases/
Abstract
--------
@@ -95,9 +96,10 @@ The ``nsb_setup.sh`` allows to:
1. Install Yardstick in specified mode: bare metal or container.
Refer :doc:`04-installation`.
2. Install package dependencies on remote servers used as traffic generator or
- sample VNF. Add such servers to ``install-inventory.ini`` file to either
+ sample VNF. Install DPDK, sample VNFs, TREX, collectd.
+ Add such servers to ``install-inventory.ini`` file to either
``yardstick-standalone`` or ``yardstick-baremetal`` server groups.
- Configures IOMMU, hugepages, open file limits, CPU isolation, etc.
+ It configures IOMMU, hugepages, open file limits, CPU isolation, etc.
3. Build VM image either nsb or normal. The nsb VM image is used to run
Yardstick sample VNF tests, like vFW, vACL, vCGNAPT, etc.
The normal VM image is used to run Yardstick ping tests in OpenStack context.
@@ -136,21 +138,25 @@ Modify the Yardstick installation inventory used by Ansible::
[yardstick:children]
jumphost
- [yardstick-standalone]
- standalone ansible_host=192.168.2.51 ansible_connection=ssh
-
[yardstick-baremetal]
- baremetal ansible_host=192.168.2.52 ansible_connection=ssh
+ baremetal ansible_host=192.168.2.51 ansible_connection=ssh
+
+ [yardstick-standalone]
+ standalone ansible_host=192.168.2.52 ansible_connection=ssh
[all:vars]
- arch_amd64=amd64
- arch_arm64=arm64
- inst_mode_baremetal=baremetal
- inst_mode_container=container
- inst_mode_container_pull=container_pull
- ubuntu_archive={"amd64": "http://archive.ubuntu.com/ubuntu/", "arm64": "http://ports.ubuntu.com/ubuntu-ports/"}
- ansible_user=root
- ansible_ssh_pass=root # OR ansible_ssh_private_key_file=/root/.ssh/id_rsa
+ # Uncomment credentials below if needed
+ ansible_user=root
+ ansible_ssh_pass=root
+ # ansible_ssh_private_key_file=/root/.ssh/id_rsa
+ # When IMG_PROPERTY is passed neither normal nor nsb set
+ # "path_to_vm=/path/to/image" to add it to OpenStack
+ # path_to_img=/tmp/workspace/yardstick-image.img
+
+ # List of CPUs to be isolated (not used by default)
+ # Grub line will be extended with:
+ # "isolcpus=<ISOL_CPUS> nohz=on nohz_full=<ISOL_CPUS> rcu_nocbs=1<ISOL_CPUS>"
+ # ISOL_CPUS=2-27,30-55 # physical cpu's for all NUMA nodes, four cpu's reserved
.. warning::
@@ -178,14 +184,18 @@ Modify the Yardstick installation inventory used by Ansible::
.. note::
CPU isolation can be applied to the remote servers, like:
- ISOL_CPUS=2-27,30-55
- Uncomment and modify accordingly in ``install-inventory.ini`` file.
+ ISOL_CPUS=2-27,30-55. Uncomment and modify accordingly in
+ ``install-inventory.ini`` file.
By default ``nsb_setup.sh`` pulls Yardstick image based on Ubuntu 16.04 from
docker hub and starts container, builds NSB VM image based on Ubuntu 16.04,
installs packages to the servers given in ``yardstick-standalone`` and
``yardstick-baremetal`` host groups.
+To pull Yardstick built based on Ubuntu 18 run::
+
+ ./nsb_setup.sh -i opnfv/yardstick-ubuntu-18.04:latest
+
To change default behavior modify parameters for ``install.yaml`` in
``nsb_setup.sh`` file.
@@ -196,11 +206,15 @@ To execute an installation for a **BareMetal** or a **Standalone context**::
./nsb_setup.sh
-
To execute an installation for an **OpenStack** context::
./nsb_setup.sh <path to admin-openrc.sh>
+.. note::
+
+ Yardstick may not be operational after distributive linux kernel update if
+ it has been installed before. Run ``nsb_setup.sh`` again to resolve this.
+
.. warning::
The Yardstick VM image (NSB or normal) cannot be built inside a VM.
@@ -217,11 +231,75 @@ execute::
docker exec -it yardstick bash
+.. note::
+
+ It may be needed to configure tty in docker container to extend commandline
+ character length, for example:
+
+ stty size rows 58 cols 234
+
It will also automatically download all the packages needed for NSB Testing
-setup. Refer chapter :doc:`04-installation` for more on Docker
+setup. Refer chapter :doc:`04-installation` for more on Docker.
**Install Yardstick using Docker (recommended)**
+Bare Metal context example
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Let's assume there are three servers acting as TG, sample VNF DUT and jump host.
+
+Perform following steps to install NSB:
+
+1. Clone Yardstick repo to jump host.
+2. Add TG and DUT servers to ``yardstick-baremetal`` group in
+ ``install-inventory.ini`` file to install NSB and dependencies. Install
+ python on servers.
+3. Start deployment using docker image based on Ubuntu 16:
+
+.. code-block:: console
+
+ ./nsb_setup.sh
+
+4. Reboot bare metal servers.
+5. Enter to yardstick container and modify pod yaml file and run tests.
+
+Standalone context example for Ubuntu 18
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Let's assume there are three servers acting as TG, sample VNF DUT and jump host.
+Ubuntu 18 is installed on all servers.
+
+Perform following steps to install NSB:
+
+1. Clone Yardstick repo to jump host.
+2. Add TG server to ``yardstick-baremetal`` group in
+ ``install-inventory.ini`` file to install NSB and dependencies.
+ Add server where VM with sample VNF will be deployed to
+ ``yardstick-standalone`` group in ``install-inventory.ini`` file.
+ Target VM image named ``yardstick-nsb-image.img`` will be placed to
+ ``/var/lib/libvirt/images/``.
+ Install python on servers.
+3. Modify ``nsb_setup.sh`` on jump host:
+
+.. code-block:: console
+
+ ansible-playbook \
+ -e IMAGE_PROPERTY='nsb' \
+ -e OS_RELEASE='bionic' \
+ -e INSTALLATION_MODE='container_pull' \
+ -e YARD_IMAGE_ARCH='amd64' ${extra_args} \
+ -i install-inventory.ini install.yaml
+
+4. Start deployment with Yardstick docker images based on Ubuntu 18:
+
+.. code-block:: console
+
+ ./nsb_setup.sh -i opnfv/yardstick-ubuntu-18.04:latest -o <openrc_file>
+
+5. Reboot servers.
+6. Enter to yardstick container and modify pod yaml file and run tests.
+
+
System Topology
---------------
@@ -881,6 +959,144 @@ Update contexts section
cidr: '152.16.40.10/24'
gateway_ip: '152.16.100.20'
+OVS-DPDK configuration options
+++++++++++++++++++++++++++++++
+
+There are number of configuration options available for OVS-DPDK context in
+test case. Mostly they are used for performance tuning.
+
+OVS-DPDK properties:
+''''''''''''''''''''
+
+OVS-DPDK properties example under *ovs_properties* section:
+
+ .. code-block:: console
+
+ ovs_properties:
+ version:
+ ovs: 2.8.1
+ dpdk: 17.05.2
+ pmd_threads: 4
+ pmd_cpu_mask: "0x3c"
+ ram:
+ socket_0: 2048
+ socket_1: 2048
+ queues: 2
+ vpath: "/usr/local"
+ max_idle: 30000
+ lcore_mask: 0x02
+ dpdk_pmd-rxq-affinity:
+ 0: "0:2,1:2"
+ 1: "0:2,1:2"
+ 2: "0:3,1:3"
+ 3: "0:3,1:3"
+ vhost_pmd-rxq-affinity:
+ 0: "0:3,1:3"
+ 1: "0:3,1:3"
+ 2: "0:4,1:4"
+ 3: "0:4,1:4"
+
+OVS-DPDK properties description:
+
+ +-------------------------+-------------------------------------------------+
+ | Parameters | Detail |
+ +=========================+=================================================+
+ | version || Version of OVS and DPDK to be installed |
+ | || There is a relation between OVS and DPDK |
+ | | version which can be found at |
+ | | `OVS-DPDK-versions`_ |
+ | || By default OVS: 2.6.0, DPDK: 16.07.2 |
+ +-------------------------+-------------------------------------------------+
+ | lcore_mask || Core bitmask used during DPDK initialization |
+ | | where the non-datapath OVS-DPDK threads such |
+ | | as handler and revalidator threads run |
+ +-------------------------+-------------------------------------------------+
+ | pmd_cpu_mask || Core bitmask that sets which cores are used by |
+ | || OVS-DPDK for datapath packet processing |
+ +-------------------------+-------------------------------------------------+
+ | pmd_threads || Number of PMD threads used by OVS-DPDK for |
+ | | datapath |
+ | || This core mask is evaluated in Yardstick |
+ | || It will be used if pmd_cpu_mask is not given |
+ | || Default is 2 |
+ +-------------------------+-------------------------------------------------+
+ | ram || Amount of RAM to be used for each socket, MB |
+ | || Default is 2048 MB |
+ +-------------------------+-------------------------------------------------+
+ | queues || Number of RX queues used for DPDK physical |
+ | | interface |
+ +-------------------------+-------------------------------------------------+
+ | dpdk_pmd-rxq-affinity || RX queue assignment to PMD threads for DPDK |
+ | || e.g.: <port number> : <queue-id>:<core-id> |
+ +-------------------------+-------------------------------------------------+
+ | vhost_pmd-rxq-affinity || RX queue assignment to PMD threads for vhost |
+ | || e.g.: <port number> : <queue-id>:<core-id> |
+ +-------------------------+-------------------------------------------------+
+ | vpath || User path for openvswitch files |
+ | || Default is ``/usr/local`` |
+ +-------------------------+-------------------------------------------------+
+ | max_idle || The maximum time that idle flows will remain |
+ | | cached in the datapath, ms |
+ +-------------------------+-------------------------------------------------+
+
+
+VM image properties
+'''''''''''''''''''
+
+VM image properties example under *flavor* section:
+
+ .. code-block:: console
+
+ flavor:
+ images: <path>
+ ram: 8192
+ extra_specs:
+ machine_type: 'pc-i440fx-xenial'
+ hw:cpu_sockets: 1
+ hw:cpu_cores: 6
+ hw:cpu_threads: 2
+ hw_socket: 0
+ cputune: |
+ <cputune>
+ <vcpupin vcpu="0" cpuset="7"/>
+ <vcpupin vcpu="1" cpuset="8"/>
+ ...
+ <vcpupin vcpu="11" cpuset="18"/>
+ <emulatorpin cpuset="11"/>
+ </cputune>
+
+VM image properties description:
+
+ +-------------------------+-------------------------------------------------+
+ | Parameters | Detail |
+ +=========================+=================================================+
+ | images || Path to the VM image generated by |
+ | | ``nsb_setup.sh`` |
+ | || Default path is ``/var/lib/libvirt/images/`` |
+ | || Default file name ``yardstick-nsb-image.img`` |
+ | | or ``yardstick-image.img`` |
+ +-------------------------+-------------------------------------------------+
+ | ram || Amount of RAM to be used for VM |
+ | || Default is 4096 MB |
+ +-------------------------+-------------------------------------------------+
+ | hw:cpu_sockets || Number of sockets provided to the guest VM |
+ | || Default is 1 |
+ +-------------------------+-------------------------------------------------+
+ | hw:cpu_cores || Number of cores provided to the guest VM |
+ | || Default is 2 |
+ +-------------------------+-------------------------------------------------+
+ | hw:cpu_threads || Number of threads provided to the guest VM |
+ | || Default is 2 |
+ +-------------------------+-------------------------------------------------+
+ | hw_socket || Generate vcpu cpuset from given HW socket |
+ | || Default is 0 |
+ +-------------------------+-------------------------------------------------+
+ | cputune || Maps virtual cpu with logical cpu |
+ +-------------------------+-------------------------------------------------+
+ | machine_type || Machine type to be emulated in VM |
+ | || Default is 'pc-i440fx-xenial' |
+ +-------------------------+-------------------------------------------------+
+
OpenStack with SR-IOV support
-----------------------------
diff --git a/docs/testing/user/userguide/14-nsb-operation.rst b/docs/testing/user/userguide/14-nsb-operation.rst
index 941a0bb65..69ffb8a3b 100644
--- a/docs/testing/user/userguide/14-nsb-operation.rst
+++ b/docs/testing/user/userguide/14-nsb-operation.rst
@@ -640,3 +640,37 @@ A testcase can be started with the following command as an example:
.. code-block:: bash
yardstick task start /yardstick/samples/vnf_samples/nsut/vpe/tc_baremetal_rfc2544_ipv4_1flow_64B_ixia.yaml
+
+Preparing test run of vIPSEC test case
+------------------------------------
+
+Location of vIPSEC test cases: ``samples/vnf_samples/nsut/ipsec/``.
+
+Before running a specific vIPSEC test case using NSB, some dependencies have to be
+preinstalled and properly configured.
+- VPP
+
+.. code-block:: console
+
+ export UBUNTU="xenial"
+ export RELEASE=".stable.1810"
+ sudo rm /etc/apt/sources.list.d/99fd.io.list
+ echo "deb [trusted=yes] https://nexus.fd.io/content/repositories/fd.io$RELEASE.ubuntu.$UBUNTU.main/ ./" | sudo tee -a /etc/apt/sources.list.d/99fd.io.list
+ sudo apt-get update
+ sudo apt-get install vpp vpp-lib vpp-plugin vpp-dbg vpp-dev vpp-api-java vpp-api-python vpp-api-lua
+
+- VAT templates
+
+ VAT templates is required for the VPP API.
+
+.. code-block:: console
+
+ mkdir -p /opt/nsb_bin/vpp/templates/
+ echo 'exec trace add dpdk-input 50' > /opt/nsb_bin/vpp/templates/enable_dpdk_traces.vat
+ echo 'exec trace add vhost-user-input 50' > /opt/nsb_bin/vpp/templates/enable_vhost_user_traces.vat
+ echo 'exec trace add memif-input 50' > /opt/nsb_bin/vpp/templates/enable_memif_traces.vat
+ cat > /opt/nsb_bin/vpp/templates/dump_interfaces.vat << EOL
+ sw_interface_dump
+ dump_interface_table
+ quit
+ EOL
diff --git a/docs/testing/user/userguide/nsb/nsb-list-of-tcs.rst b/docs/testing/user/userguide/nsb/nsb-list-of-tcs.rst
index 6c18c7d89..a578216da 100644
--- a/docs/testing/user/userguide/nsb/nsb-list-of-tcs.rst
+++ b/docs/testing/user/userguide/nsb/nsb-list-of-tcs.rst
@@ -36,3 +36,4 @@ NSB PROX Test Case Descriptions
tc_vfw_rfc2544
tc_vfw_rfc2544_correlated
tc_vfw_rfc3511
+ tc_vpp_baremetal_crypto_ipsec
diff --git a/docs/testing/user/userguide/nsb/tc_vpp_baremetal_crypto_ipsec.rst b/docs/testing/user/userguide/nsb/tc_vpp_baremetal_crypto_ipsec.rst
new file mode 100644
index 000000000..6a4a37697
--- /dev/null
+++ b/docs/testing/user/userguide/nsb/tc_vpp_baremetal_crypto_ipsec.rst
@@ -0,0 +1,113 @@
+.. This work is licensed under a Creative Commons Attribution 4.0 International
+.. License.
+.. http://creativecommons.org/licenses/by/4.0
+.. (c) OPNFV, 2019 Viosoft Corporation.
+
+***********************************************
+Yardstick Test Case Description: NSB VPP IPSEC
+***********************************************
+
++------------------------------------------------------------------------------+
+|NSB VPP test for vIPSEC characterization |
+| |
++--------------+---------------------------------------------------------------+
+|test case id | tc_baremetal_rfc2544_ipv4_{crypto_dev}_{crypto_alg} |
+| | |
+| | * crypto_dev = HW_cryptodev or SW_cryptodev; |
+| | * crypto_alg = aes-gcm or cbc-sha1; |
+| | |
++--------------+---------------------------------------------------------------+
+|metric | * Network Throughput NDR or PDR; |
+| | * Connections Per Second (CPS); |
+| | * Latency; |
+| | * Number of tunnels; |
+| | * TG Packets Out; |
+| | * TG Packets In; |
+| | * VNF Packets Out; |
+| | * VNF Packets In; |
+| | * Dropped packets; |
+| | |
++--------------+---------------------------------------------------------------+
+|test purpose | IPv4 IPsec tunnel mode performance test: |
+| | |
+| | * Finds and reports throughput NDR (Non Drop Rate) with zero |
+| | packet loss tolerance or throughput PDR (Partial Drop Rate) |
+| | with non-zero packet loss tolerance (LT) expressed in |
+| | number of packets transmitted. |
+| | |
+| | * The IPSEC test cases are implemented to run in baremetal |
+| | |
++--------------+---------------------------------------------------------------+
+|configuration | The IPSEC test cases are listed below: |
+| | |
+| | * tc_baremetal_rfc2544_ipv4_hw_aesgcm_IMIX_trex.yaml |
+| | * tc_baremetal_rfc2544_ipv4_hw_aesgcm_trex.yaml |
+| | * tc_baremetal_rfc2544_ipv4_hw_cbcsha1_IMIX_trex.yaml |
+| | * tc_baremetal_rfc2544_ipv4_hw_cbcsha1_trex.yaml |
+| | * tc_baremetal_rfc2544_ipv4_sw_aesgcm_IMIX_trex.yaml |
+| | * tc_baremetal_rfc2544_ipv4_sw_aesgcm_trex.yaml |
+| | * tc_baremetal_rfc2544_ipv4_sw_cbcsha1_IMIX_trex.yaml |
+| | * tc_baremetal_rfc2544_ipv4_sw_cbcsha1_trex.yaml |
+| | |
+| | Test duration is set as 500sec for each test. |
+| | Packet size set as 64 bytes or higher. |
+| | Number of tunnels set as 1 or higher. |
+| | Number of connections set as 1 or higher |
+| | These can be configured |
+| | |
++--------------+---------------------------------------------------------------+
+|test tool | Vector Packet Processing (VPP) |
+| | The VPP platform is an extensible framework that provides |
+| | out-of-the-box production quality switch/router functionality.|
+| | Its high performance, proven technology, its modularity and, |
+| | flexibility and rich feature set |
+| | |
++--------------+---------------------------------------------------------------+
+|applicability | This VPP IPSEC test cases can be configured with different: |
+| | |
+| | * packet sizes; |
+| | * test durations; |
+| | * tolerated loss; |
+| | * crypto device type; |
+| | * number of physical cores; |
+| | * number of tunnels; |
+| | * number of connections; |
+| | * encryption algorithms - integrity algorithm; |
+| | |
+| | Default values exist. |
+| | |
++--------------+---------------------------------------------------------------+
+|pre-test | For Baremetal tests cases VPP and DPDK must be installed in |
+|conditions | the hosts where the test is executed. The pod.yaml file must |
+| | have the necessary system and NIC information |
+| | |
++--------------+---------------------------------------------------------------+
+|test sequence | description and expected result |
+| | |
++--------------+---------------------------------------------------------------+
+|step 1 | For Baremetal test: The TG and VNF are started on the hosts |
+| | based on the pod file. |
+| | |
++--------------+---------------------------------------------------------------+
+|step 2 | Yardstick is connected with the TG and VNF by using ssh. |
+| | The test will resolve the topology and instantiate the VNF |
+| | and TG and collect the KPI's/metrics. |
+| | |
++--------------+---------------------------------------------------------------+
+|step 3 | Test packets are generated by TG on links to DUTs. If the |
+| | number of dropped packets is more than the tolerated loss |
+| | the line rate or throughput is halved. This is done until |
+| | the dropped packets are within an acceptable tolerated loss. |
+| | |
+| | The KPI is the number of packets per second for a packet size |
+| | specified in the test case with an accepted minimal packet |
+| | loss for the default configuration. |
+| | |
++--------------+---------------------------------------------------------------+
+|step 4 | In Baremetal test: The test quits the application and unbind |
+| | the DPDK ports. |
+| | |
++--------------+---------------------------------------------------------------+
+|test verdict | The test case will achieve a Throughput with an accepted |
+| | minimal tolerated packet loss. |
++--------------+---------------------------------------------------------------+ \ No newline at end of file
diff --git a/samples/vnf_samples/nsut/cmts/k8s_vcmts_topology.yaml b/samples/vnf_samples/nsut/cmts/k8s_vcmts_topology.yaml
new file mode 100755
index 000000000..95ac76964
--- /dev/null
+++ b/samples/vnf_samples/nsut/cmts/k8s_vcmts_topology.yaml
@@ -0,0 +1,36 @@
+# Copyright (c) 2019 Viosoft 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.
+
+{% set num_tg = get(extra_args, 'num_tg', 2) %}
+{% set num_sg = get(extra_args, 'num_sg', 2) %}
+
+nsd:nsd-catalog:
+ nsd:
+ - id: vcmts-topology
+ name: vcmts-topology
+ short-name: vcmts-topology
+ description: vcmts-topology
+ constituent-vnfd:
+ {% for tg_num in range(0, num_tg) %}
+ - member-vnf-index: '{{ tg_num + 1 }}'
+ vnfd-id-ref: tg__{{ tg_num }}
+ VNF model: ../../vnf_descriptors/tg_vcmts_tpl.yaml #VNF type
+ {% endfor %}
+ {% for vnf_num in range(0, num_sg * 2) %}
+ - member-vnf-index: '{{ vnf_num + num_tg + 1 }}'
+ vnfd-id-ref: vnf__{{ vnf_num }}
+ VNF model: ../../vnf_descriptors/vnf_vcmts_tpl.yaml #VNF type
+ {% endfor %}
+
+ vld: []
diff --git a/samples/vnf_samples/nsut/cmts/tc_vcmts_k8s_pktgen.yaml b/samples/vnf_samples/nsut/cmts/tc_vcmts_k8s_pktgen.yaml
new file mode 100755
index 000000000..6c85a0892
--- /dev/null
+++ b/samples/vnf_samples/nsut/cmts/tc_vcmts_k8s_pktgen.yaml
@@ -0,0 +1,360 @@
+# Copyright (c) 2019 Viosoft 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.
+
+
+{% set num_tg = 2 %}
+{% set num_sg = 4 %}
+
+{% set vcmtsd_image = "vcmts-d:perf" %}
+{% set qat_on = false %}
+
+schema: "yardstick:task:0.1"
+
+scenarios:
+- type: NSPerf
+ traffic_profile: ../../traffic_profiles/fixed.yaml
+ extra_args:
+ num_sg: {{ num_sg }}
+ num_tg: {{ num_tg }}
+ topology: k8s_vcmts_topology.yaml
+ nodes:
+{% for tg_num in range(0, num_tg) %}
+ tg__{{ tg_num }}: pktgen{{ tg_num }}-k8syardstick
+{% endfor %}
+{% for vnf_index in range(0, num_sg) %}
+ vnf__{{ vnf_index * 2 }}: vnf{{ vnf_index }}us-k8syardstick
+ vnf__{{ (vnf_index * 2) + 1}}: vnf{{ vnf_index }}ds-k8syardstick
+{% endfor %}
+
+ runner:
+ type: Duration
+ duration: 120
+
+ options:
+ vcmts_influxdb_ip: "10.80.5.150"
+ vcmts_influxdb_port: 8086
+ vcmtsd_values: /etc/yardstick/vcmtsd_values.yaml
+ pktgen_values: /etc/yardstick/pktgen_values.yaml
+ pktgen_rate: 6.5
+{% for vnf_index in range(0, num_sg) %}
+ vnf__{{ vnf_index * 2 }}:
+ sg_id: {{ vnf_index }}
+ stream_dir: "us"
+ vnf__{{ (vnf_index * 2) + 1}}:
+ sg_id: {{ vnf_index }}
+ stream_dir: "ds"
+{% endfor %}
+{% for tg_num in range(0, num_tg) %}
+ tg__{{ tg_num }}:
+ pktgen_id: {{ tg_num }}
+{% endfor %}
+
+context:
+ name: k8syardstick
+ type: Kubernetes
+
+ servers:
+{% for vnf_index in range(0, num_sg) %}
+ vnf{{ vnf_index }}us:
+ nodeSelector:
+ vcmts: "true"
+ containers:
+ - image: {{ vcmtsd_image }}
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: CMK_PROC_FS
+ value: "/host/proc"
+ command: /bin/bash
+ args: ['-c', 'mkdir /root/.ssh; cp /tmp/.ssh/authorized_keys ~/.ssh/.;
+ chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;
+ while true ; do sleep 10000; done']
+ resources:
+ requests:
+ memory: 10Ki
+{% if qat_on %}
+ hugepages-1Gi: 2Gi
+ qat.intel.com/generic: '1'
+{% else %}
+ hugepages-1Gi: 1Gi
+{% endif %}
+ limits:
+ memory: 1Gi
+{% if qat_on %}
+ hugepages-1Gi: 2Gi
+ qat.intel.com/generic: '1'
+{% else %}
+ hugepages-1Gi: 1Gi
+{% endif %}
+ lifecycle:
+ postStart:
+ exec:
+ command: [ "/bin/bash", "-c", "env > /tmp/qat" ]
+ volumeMounts:
+ - name: vcmts-configmap-vcmtspod
+ mountPath: /vcmts-config
+ - name: hugepages
+ mountPath: /hugepages
+ readOnly: false
+ - name: collectd
+ mountPath: /opt/collectd/var
+ readOnly: false
+ - name: sysfs
+ mountPath: /sys
+ readOnly: false
+ - name: sriov
+ mountPath: /sriov-cni
+ readOnly: false
+ - name: host-proc
+ mountPath: /host/proc
+ readOnly: true
+ - name: cmk-install-dir
+ mountPath: /opt/bin
+ - name: cmk-conf-dir
+ mountPath: /etc/cmk
+ - name: power-mgmt
+ mountPath: /opt/power_mgmt
+ ports:
+ - containerPort: 22022
+ securityContext:
+ allowPrivilegeEscalation: true
+ privileged: true
+ node_ports:
+ - name: lua # Lower case alphanumeric characters or '-'
+ port: 22022
+ networks:
+ - flannel
+ - xe0
+ - xe1
+ volumes:
+ - name: vcmts-configmap-vcmtspod
+ configMap:
+ name: vcmts-configmap-vcmtspod
+ defaultMode: 0744
+ - name: hugepages
+ emptyDir:
+ medium: HugePages
+ - name: collectd
+ hostPath:
+ path: /opt/collectd/var
+ - name: sysfs
+ hostPath:
+ path: /sys
+ - name: sriov
+ hostPath:
+ path: /var/lib/cni/sriov
+ - name: cmk-install-dir
+ hostPath:
+ path: /opt/bin
+ - name: host-proc
+ hostPath:
+ path: /proc
+ - name: cmk-conf-dir
+ hostPath:
+ path: /etc/cmk
+ - name: power-mgmt
+ hostPath:
+ path: /opt/power_mgmt
+
+ vnf{{ vnf_index }}ds:
+ nodeSelector:
+ vcmts: "true"
+ containers:
+ - image: {{ vcmtsd_image }}
+ imagePullPolicy: IfNotPresent
+ env:
+ - name: CMK_PROC_FS
+ value: "/host/proc"
+ command: /bin/bash
+ args: ['-c', 'mkdir /root/.ssh; cp /tmp/.ssh/authorized_keys ~/.ssh/.;
+ chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;
+ while true ; do sleep 10000; done']
+ resources:
+ requests:
+ memory: 10Ki
+{% if qat_on %}
+ hugepages-1Gi: 2Gi
+ qat.intel.com/generic: '1'
+{% else %}
+ hugepages-1Gi: 1Gi
+{% endif %}
+ limits:
+ memory: 1Gi
+{% if qat_on %}
+ hugepages-1Gi: 2Gi
+ qat.intel.com/generic: '1'
+{% else %}
+ hugepages-1Gi: 1Gi
+{% endif %}
+ lifecycle:
+ postStart:
+ exec:
+ command: [ "/bin/bash", "-c", "env > /tmp/qat" ]
+ volumeMounts:
+ - name: vcmts-configmap-vcmtspod
+ mountPath: /vcmts-config
+ - name: hugepages
+ mountPath: /hugepages
+ readOnly: false
+ - name: collectd
+ mountPath: /opt/collectd/var
+ readOnly: false
+ - name: sysfs
+ mountPath: /sys
+ readOnly: false
+ - name: sriov
+ mountPath: /sriov-cni
+ readOnly: false
+ - name: host-proc
+ mountPath: /host/proc
+ readOnly: true
+ - name: cmk-install-dir
+ mountPath: /opt/bin
+ - name: cmk-conf-dir
+ mountPath: /etc/cmk
+ - name: power-mgmt
+ mountPath: /opt/power_mgmt
+ ports:
+ - containerPort: 22022
+ securityContext:
+ allowPrivilegeEscalation: true
+ privileged: true
+ node_ports:
+ - name: lua # Lower case alphanumeric characters or '-'
+ port: 22022
+ networks:
+ - flannel
+ - xe0
+ - xe1
+ volumes:
+ - name: vcmts-configmap-vcmtspod
+ configMap:
+ name: vcmts-configmap-vcmtspod
+ defaultMode: 0744
+ - name: hugepages
+ emptyDir:
+ medium: HugePages
+ - name: collectd
+ hostPath:
+ path: /opt/collectd/var
+ - name: sysfs
+ hostPath:
+ path: /sys
+ - name: sriov
+ hostPath:
+ path: /var/lib/cni/sriov
+ - name: cmk-install-dir
+ hostPath:
+ path: /opt/bin
+ - name: host-proc
+ hostPath:
+ path: /proc
+ - name: cmk-conf-dir
+ hostPath:
+ path: /etc/cmk
+ - name: power-mgmt
+ hostPath:
+ path: /opt/power_mgmt
+{% endfor %}
+
+{% for index in range(0, num_tg) %}
+ pktgen{{index}}:
+ nodeSelector:
+ vcmtspktgen: "true"
+ containers:
+ - image: vcmts-pktgen:v18.10
+ imagePullPolicy: IfNotPresent
+ tty: true
+ stdin: true
+ env:
+ - name: LUA_PATH
+ value: "/vcmts/Pktgen.lua"
+ - name: CMK_PROC_FS
+ value: "/host/proc"
+ command: /bin/bash
+ args: ['-c', 'mkdir /root/.ssh; cp /tmp/.ssh/authorized_keys ~/.ssh/.;
+ chmod 700 ~/.ssh; chmod 600 ~/.ssh/*; service ssh restart;
+ while true ; do sleep 10000; done']
+ resources:
+ requests:
+ hugepages-1Gi: 9Gi
+ memory: 200Mi
+ limits:
+ hugepages-1Gi: 9Gi
+ memory: 200Mi
+ volumeMounts:
+ - name: sysfs
+ mountPath: /sys
+ readOnly: false
+ - name: hugepages
+ mountPath: /hugepages
+ readOnly: false
+ - name: sriov
+ mountPath: /sriov-cni
+ readOnly: false
+ - name: host-proc
+ mountPath: /host/proc
+ readOnly: true
+ - name: cmk-install-dir
+ mountPath: /opt/bin
+ - name: cmk-conf-dir
+ mountPath: /etc/cmk
+ - name: pktgen-config
+ mountPath: /pktgen-config
+ ports:
+ - containerPort: 22022
+ securityContext:
+ allowPrivilegeEscalation: true
+ privileged: true
+ volumes:
+ - name: sysfs
+ hostPath:
+ path: /sys
+ - name: hugepages
+ emptyDir:
+ medium: HugePages
+ - name: sriov
+ hostPath:
+ path: /var/lib/cni/sriov
+ - name: cmk-install-dir
+ hostPath:
+ path: /opt/bin
+ - name: host-proc
+ hostPath:
+ path: /proc
+ - name: cmk-conf-dir
+ hostPath:
+ path: /etc/cmk
+ - name: pktgen-config
+ configMap:
+ name: vcmts-configmap-pktgen
+ defaultMode: 0744
+ node_ports:
+ - name: lua # Lower case alphanumeric characters or '-'
+ port: 22022
+ networks:
+ - flannel
+ - xe0
+ - xe1
+{% endfor %}
+
+ networks:
+ flannel:
+ args: '[{ "delegate": { "isDefaultGateway": true }}]'
+ plugin: flannel
+ xe0:
+ args: '[{ "delegate": { "isDefaultGateway": true }}]'
+ plugin: flannel
+ xe1:
+ args: '[{ "delegate": { "isDefaultGateway": true }}]'
+ plugin: flannel
diff --git a/samples/vnf_samples/traffic_profiles/ipv4_throughput_latency_vpp.yaml b/samples/vnf_samples/traffic_profiles/ipv4_throughput_latency_vpp.yaml
index 1add9bfb4..abbad6728 100644
--- a/samples/vnf_samples/traffic_profiles/ipv4_throughput_latency_vpp.yaml
+++ b/samples/vnf_samples/traffic_profiles/ipv4_throughput_latency_vpp.yaml
@@ -20,6 +20,7 @@ description: Traffic profile to run RFC2544 latency
traffic_profile:
traffic_type: VppRFC2544Profile # defines traffic behavior - constant or look for highest possible throughput
enable_latency: true
+ intermediate_phases: 2
test_precision: 0.1
duration: 30
lower_bound: 1.0
diff --git a/samples/vnf_samples/vnf_descriptors/tg_vcmts_tpl.yaml b/samples/vnf_samples/vnf_descriptors/tg_vcmts_tpl.yaml
new file mode 100755
index 000000000..bb56fcb6a
--- /dev/null
+++ b/samples/vnf_samples/vnf_descriptors/tg_vcmts_tpl.yaml
@@ -0,0 +1,77 @@
+# Copyright (c) 2019 Viosoft 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: VcmtsPktgen
+ name: vcmtspktgen
+ short-name: vcmtspktgen
+ description: vCMTS Pktgen Kubernetes
+ vm-flavor:
+ vcpu-count: '4'
+ memory-mb: '4096'
+ mgmt-interface:
+ vdu-id: vcmtspktgen-kubernetes
+ {% if user is defined %}
+ user: '{{user}}' # Value filled by vnfdgen
+ {% endif %}
+ {% if password is defined %}
+ password: '{{password}}' # Value filled by vnfdgen
+ {% endif %}
+ {% if ip is defined %}
+ ip: '{{ip}}' # Value filled by vnfdgen
+ {% endif %}
+ {% if key_filename is defined %}
+ key_filename: '{{key_filename}}' # Value filled by vnfdgen
+ {% endif %}
+ connection-point:
+ - name: xe0
+ type: VPORT
+ - name: xe1
+ type: VPORT
+ vdu:
+ - id: vcmtspktgen-kubernetes
+ name: vcmtspktgen-kubernetes
+ description: vCMTS Pktgen Kubernetes
+ external-interface:
+ - name: xe0
+ virtual-interface:
+ type: virtio
+ # Substitution variables MUST be quoted. Otherwise Python can misinterpet them.
+ vpci: '{{ interfaces.xe0.vpci }}' # Value filled by vnfdgen
+ local_iface_name: eth0 # '{{ interfaces.xe0.local_iface_name }}'
+ driver: '{{ interfaces.xe0.driver}}' # 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
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe0
+ - name: xe1
+ virtual-interface:
+ type: virtio
+ # Substitution variables MUST be quoted. Otherwise Python can misinterpet them.
+ vpci: '{{ interfaces.xe1.vpci }}' # Value filled by vnfdgen
+ local_iface_name: eth0 # '{{ interfaces.xe1.local_iface_name }}'
+ 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: xe0
+ benchmark:
+ kpi:
+ - upstream/bits_per_second
+
diff --git a/samples/vnf_samples/vnf_descriptors/vnf_vcmts_tpl.yaml b/samples/vnf_samples/vnf_descriptors/vnf_vcmts_tpl.yaml
new file mode 100755
index 000000000..d1eb6a869
--- /dev/null
+++ b/samples/vnf_samples/vnf_descriptors/vnf_vcmts_tpl.yaml
@@ -0,0 +1,77 @@
+# Copyright (c) 2019 Viosoft 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: VcmtsVNF
+ name: vcmtsvnf
+ short-name: vcmtsvnf
+ description: vCMTS Upstream-Downstream Kubernetes
+ vm-flavor:
+ vcpu-count: '4'
+ memory-mb: '4096'
+ mgmt-interface:
+ vdu-id: vcmtsvnf-kubernetes
+ {% if user is defined %}
+ user: '{{user}}' # Value filled by vnfdgen
+ {% endif %}
+ {% if password is defined %}
+ password: '{{password}}' # Value filled by vnfdgen
+ {% endif %}
+ {% if ip is defined %}
+ ip: '{{ip}}' # Value filled by vnfdgen
+ {% endif %}
+ {% if key_filename is defined %}
+ key_filename: '{{key_filename}}' # Value filled by vnfdgen
+ {% endif %}
+ connection-point:
+ - name: xe0
+ type: VPORT
+ - name: xe1
+ type: VPORT
+ vdu:
+ - id: vcmtsvnf-kubernetes
+ name: vcmtsvnf-kubernetes
+ description: vCMTS Upstream-Downstream Kubernetes
+ external-interface:
+ - name: xe0
+ virtual-interface:
+ type: virtio
+ # Substitution variables MUST be quoted. Otherwise Python can misinterpet them.
+ vpci: '{{ interfaces.xe0.vpci }}' # Value filled by vnfdgen
+ local_iface_name: eth0 # NOT TESTED YET '{{ interfaces.xe0.local_iface_name }}' # Value filled by vnfdgen
+ driver: '{{ interfaces.xe0.driver}}' # 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
+ bandwidth: 10 Gbps
+ vnfd-connection-point-ref: xe0
+ - name: xe1
+ virtual-interface:
+ type: virtio
+ # Substitution variables MUST be quoted. Otherwise Python can misinterpet them.
+ vpci: '{{ interfaces.xe1.vpci }}' # Value filled by vnfdgen
+ local_iface_name: eth0 # NOT TESTED YET '{{ 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: xe0
+ benchmark:
+ kpi:
+ - upstream/bits_per_second
+
diff --git a/setup.py b/setup.py
index 881ef9272..cbf8b15c6 100755
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,8 @@ setup(
'network_services/nfvi/collectd.sh',
'resources/files/*',
'resources/scripts/install/*.bash',
- 'resources/scripts/remove/*.bash'
+ 'resources/scripts/remove/*.bash',
+ 'resources/templates/*.vat'
],
'etc': [
'yardstick/nodes/*/*.yaml',
diff --git a/yardstick/network_services/helpers/cpu.py b/yardstick/network_services/helpers/cpu.py
index 8cdd829a0..279af204a 100644
--- a/yardstick/network_services/helpers/cpu.py
+++ b/yardstick/network_services/helpers/cpu.py
@@ -15,11 +15,15 @@
import io
+# Number of threads per core.
+NR_OF_THREADS = 2
+
class CpuSysCores(object):
def __init__(self, connection=""):
self.core_map = {}
+ self.cpuinfo = {}
self.connection = connection
def _open_cpuinfo(self):
@@ -62,13 +66,14 @@ class CpuSysCores(object):
def get_cpu_layout(self):
_, stdout, _ = self.connection.execute("lscpu -p")
- cpuinfo = {}
- cpuinfo['cpuinfo'] = list()
+ self.cpuinfo = {}
+ self.cpuinfo['cpuinfo'] = list()
for line in stdout.split("\n"):
if line and line[0] != "#":
- cpuinfo['cpuinfo'].append([CpuSysCores._str2int(x) for x in
- line.split(",")])
- return cpuinfo
+ self.cpuinfo['cpuinfo'].append(
+ [CpuSysCores._str2int(x) for x in
+ line.split(",")])
+ return self.cpuinfo
def validate_cpu_cfg(self, vnf_cfg=None):
if vnf_cfg is None:
@@ -89,9 +94,80 @@ class CpuSysCores(object):
return 0
+ def is_smt_enabled(self):
+ return CpuSysCores.smt_enabled(self.cpuinfo)
+
+ def cpu_list_per_node(self, cpu_node, smt_used=False):
+ cpu_node = int(cpu_node)
+ cpu_info = self.cpuinfo.get("cpuinfo")
+ if cpu_info is None:
+ raise RuntimeError("Node cpuinfo not available.")
+
+ smt_enabled = self.is_smt_enabled()
+ if not smt_enabled and smt_used:
+ raise RuntimeError("SMT is not enabled.")
+
+ cpu_list = []
+ for cpu in cpu_info:
+ if cpu[3] == cpu_node:
+ cpu_list.append(cpu[0])
+
+ if not smt_enabled or smt_enabled and smt_used:
+ pass
+
+ if smt_enabled and not smt_used:
+ cpu_list_len = len(cpu_list)
+ cpu_list = cpu_list[:int(cpu_list_len / NR_OF_THREADS)]
+
+ return cpu_list
+
+ def cpu_slice_of_list_per_node(self, cpu_node, skip_cnt=0, cpu_cnt=0,
+ smt_used=False):
+ cpu_list = self.cpu_list_per_node(cpu_node, smt_used)
+
+ cpu_list_len = len(cpu_list)
+ if cpu_cnt + skip_cnt > cpu_list_len:
+ raise RuntimeError("cpu_cnt + skip_cnt > length(cpu list).")
+
+ if cpu_cnt == 0:
+ cpu_cnt = cpu_list_len - skip_cnt
+
+ if smt_used:
+ cpu_list_0 = cpu_list[:int(cpu_list_len / NR_OF_THREADS)]
+ cpu_list_1 = cpu_list[int(cpu_list_len / NR_OF_THREADS):]
+ cpu_list = [cpu for cpu in cpu_list_0[skip_cnt:skip_cnt + cpu_cnt]]
+ cpu_list_ex = [cpu for cpu in
+ cpu_list_1[skip_cnt:skip_cnt + cpu_cnt]]
+ cpu_list.extend(cpu_list_ex)
+ else:
+ cpu_list = [cpu for cpu in cpu_list[skip_cnt:skip_cnt + cpu_cnt]]
+
+ return cpu_list
+
+ def cpu_list_per_node_str(self, cpu_node, skip_cnt=0, cpu_cnt=0, sep=",",
+ smt_used=False):
+ cpu_list = self.cpu_slice_of_list_per_node(cpu_node,
+ skip_cnt=skip_cnt,
+ cpu_cnt=cpu_cnt,
+ smt_used=smt_used)
+ return sep.join(str(cpu) for cpu in cpu_list)
+
@staticmethod
def _str2int(string):
try:
return int(string)
except ValueError:
return 0
+
+ @staticmethod
+ def smt_enabled(cpuinfo):
+ cpu_info = cpuinfo.get("cpuinfo")
+ if cpu_info is None:
+ raise RuntimeError("Node cpuinfo not available.")
+ cpu_mems = [item[-4:] for item in cpu_info]
+ cpu_mems_len = int(len(cpu_mems) / NR_OF_THREADS)
+ count = 0
+ for cpu_mem in cpu_mems[:cpu_mems_len]:
+ if cpu_mem in cpu_mems[cpu_mems_len:]:
+ count += 1
+ return count == cpu_mems_len
diff --git a/yardstick/network_services/helpers/vpp_helpers/__init__.py b/yardstick/network_services/helpers/vpp_helpers/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/__init__.py
diff --git a/yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py b/yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py
new file mode 100644
index 000000000..fced05833
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/abstract_search_algorithm.py
@@ -0,0 +1,53 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/AbstractSearchAlgorithm.py;hb=HEAD
+
+
+from abc import ABCMeta, abstractmethod
+
+
+class AbstractSearchAlgorithm(object):
+ """Abstract class defining common API for search algorithms."""
+
+ __metaclass__ = ABCMeta
+
+ def __init__(self, measurer):
+ """Store the rate provider.
+
+ :param measurer: Object able to perform trial or composite measurements.
+ :type measurer: AbstractMeasurer.AbstractMeasurer
+ """
+ # TODO: Type check for AbstractMeasurer?
+ self.measurer = measurer
+
+ @abstractmethod
+ def narrow_down_ndr_and_pdr(
+ self, fail_rate, line_rate, packet_loss_ratio):
+ """Perform measurements to narrow down intervals, return them.
+
+ This will be renamed when custom loss ratio lists are supported.
+
+ :param fail_rate: Minimal target transmit rate [pps].
+ :param line_rate: Maximal target transmit rate [pps].
+ :param packet_loss_ratio: Fraction of packets lost, for PDR [1].
+ :type fail_rate: float
+ :type line_rate: float
+ :type packet_loss_ratio: float
+ :returns: Structure containing narrowed down intervals
+ and their measurements.
+ :rtype: NdrPdrResult.NdrPdrResult
+ """
+ # TODO: Do we agree on arguments related to precision or trial duration?
diff --git a/yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py b/yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py
new file mode 100644
index 000000000..582e3dc27
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/multiple_loss_ratio_search.py
@@ -0,0 +1,688 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/MultipleLossRatioSearch.py;hb=HEAD
+
+import datetime
+import logging
+import math
+import time
+
+from yardstick.network_services.helpers.vpp_helpers.abstract_search_algorithm import \
+ AbstractSearchAlgorithm
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+LOGGING = logging.getLogger(__name__)
+
+
+class MultipleLossRatioSearch(AbstractSearchAlgorithm):
+ """Optimized binary search algorithm for finding NDR and PDR bounds.
+
+ Traditional binary search algorithm needs initial interval
+ (lower and upper bound), and returns final interval after bisecting
+ (until some exit condition is met).
+ The exit condition is usually related to the interval width,
+ (upper bound value minus lower bound value).
+
+ The optimized algorithm contains several improvements
+ aimed to reduce overall search time.
+
+ One improvement is searching for two intervals at once.
+ The intervals are for NDR (No Drop Rate) and PDR (Partial Drop Rate).
+
+ Next improvement is that the initial interval does not need to be valid.
+ Imagine initial interval (10, 11) where 11 is smaller
+ than the searched value.
+ The algorithm will try (11, 13) interval next, and if 13 is still smaller,
+ (13, 17) and so on, doubling width until the upper bound is valid.
+ The part when interval expands is called external search,
+ the part when interval is bisected is called internal search.
+
+ Next improvement is that trial measurements at small trial duration
+ can be used to find a reasonable interval for full trial duration search.
+ This results in more trials performed, but smaller overall duration
+ in general.
+
+ Next improvement is bisecting in logarithmic quantities,
+ so that exit criteria can be independent of measurement units.
+
+ Next improvement is basing the initial interval on receive rates.
+
+ Final improvement is exiting early if the minimal value
+ is not a valid lower bound.
+
+ The complete search consist of several phases,
+ each phase performing several trial measurements.
+ Initial phase creates initial interval based on receive rates
+ at maximum rate and at maximum receive rate (MRR).
+ Final phase and preceding intermediate phases are performing
+ external and internal search steps,
+ each resulting interval is the starting point for the next phase.
+ The resulting interval of final phase is the result of the whole algorithm.
+
+ Each non-initial phase uses its own trial duration and width goal.
+ Any non-initial phase stops searching (for NDR or PDR independently)
+ when minimum is not a valid lower bound (at current duration),
+ or all of the following is true:
+ Both bounds are valid, bound bounds are measured at the current phase
+ trial duration, interval width is less than the width goal
+ for current phase.
+
+ TODO: Review and update this docstring according to rst docs.
+ TODO: Support configurable number of Packet Loss Ratios.
+ """
+
+ class ProgressState(object):
+ """Structure containing data to be passed around in recursion."""
+
+ def __init__(
+ self, result, phases, duration, width_goal, packet_loss_ratio,
+ minimum_transmit_rate, maximum_transmit_rate):
+ """Convert and store the argument values.
+
+ :param result: Current measured NDR and PDR intervals.
+ :param phases: How many intermediate phases to perform
+ before the current one.
+ :param duration: Trial duration to use in the current phase [s].
+ :param width_goal: The goal relative width for the curreent phase.
+ :param packet_loss_ratio: PDR fraction for the current search.
+ :param minimum_transmit_rate: Minimum target transmit rate
+ for the current search [pps].
+ :param maximum_transmit_rate: Maximum target transmit rate
+ for the current search [pps].
+ :type result: NdrPdrResult.NdrPdrResult
+ :type phases: int
+ :type duration: float
+ :type width_goal: float
+ :type packet_loss_ratio: float
+ :type minimum_transmit_rate: float
+ :type maximum_transmit_rate: float
+ """
+ self.result = result
+ self.phases = int(phases)
+ self.duration = float(duration)
+ self.width_goal = float(width_goal)
+ self.packet_loss_ratio = float(packet_loss_ratio)
+ self.minimum_transmit_rate = float(minimum_transmit_rate)
+ self.maximum_transmit_rate = float(maximum_transmit_rate)
+
+ def __init__(self, measurer, latency=False, pkt_size=64,
+ final_relative_width=0.005,
+ final_trial_duration=30.0, initial_trial_duration=1.0,
+ number_of_intermediate_phases=2, timeout=600.0, doublings=1):
+ """Store the measurer object and additional arguments.
+
+ :param measurer: Rate provider to use by this search object.
+ :param final_relative_width: Final lower bound transmit rate
+ cannot be more distant that this multiple of upper bound [1].
+ :param final_trial_duration: Trial duration for the final phase [s].
+ :param initial_trial_duration: Trial duration for the initial phase
+ and also for the first intermediate phase [s].
+ :param number_of_intermediate_phases: Number of intermediate phases
+ to perform before the final phase [1].
+ :param timeout: The search will fail itself when not finished
+ before this overall time [s].
+ :param doublings: How many doublings to do in external search step.
+ Default 1 is suitable for fairly stable tests,
+ less stable tests might get better overal duration with 2 or more.
+ :type measurer: AbstractMeasurer.AbstractMeasurer
+ :type final_relative_width: float
+ :type final_trial_duration: float
+ :type initial_trial_duration: int
+ :type number_of_intermediate_phases: int
+ :type timeout: float
+ :type doublings: int
+ """
+ super(MultipleLossRatioSearch, self).__init__(measurer)
+ self.latency = latency
+ self.pkt_size = int(pkt_size)
+ self.final_trial_duration = float(final_trial_duration)
+ self.final_relative_width = float(final_relative_width)
+ self.number_of_intermediate_phases = int(number_of_intermediate_phases)
+ self.initial_trial_duration = float(initial_trial_duration)
+ self.timeout = float(timeout)
+ self.doublings = int(doublings)
+
+ self.queue = None
+ self.port_pg_id = None
+ self.ports = []
+ self.test_data = {}
+ self.profiles = {}
+
+ @staticmethod
+ def double_relative_width(relative_width):
+ """Return relative width corresponding to double logarithmic width.
+
+ :param relative_width: The base relative width to double.
+ :type relative_width: float
+ :returns: The relative width of double logarithmic size.
+ :rtype: float
+ """
+ return 1.999 * relative_width - relative_width * relative_width
+ # The number should be 2.0, but we want to avoid rounding errors,
+ # and ensure half of double is not larger than the original value.
+
+ @staticmethod
+ def double_step_down(relative_width, current_bound):
+ """Return rate of double logarithmic width below.
+
+ :param relative_width: The base relative width to double.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type current_bound: float
+ :returns: Transmit rate smaller by logarithmically double width [pps].
+ :rtype: float
+ """
+ return current_bound * (
+ 1.0 - MultipleLossRatioSearch.double_relative_width(
+ relative_width))
+
+ @staticmethod
+ def expand_down(relative_width, doublings, current_bound):
+ """Return rate of expanded logarithmic width below.
+
+ :param relative_width: The base relative width to double.
+ :param doublings: How many doublings to do for expansion.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type doublings: int
+ :type current_bound: float
+ :returns: Transmit rate smaller by logarithmically double width [pps].
+ :rtype: float
+ """
+ for _ in range(doublings):
+ relative_width = MultipleLossRatioSearch.double_relative_width(
+ relative_width)
+ return current_bound * (1.0 - relative_width)
+
+ @staticmethod
+ def double_step_up(relative_width, current_bound):
+ """Return rate of double logarithmic width above.
+
+ :param relative_width: The base relative width to double.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type current_bound: float
+ :returns: Transmit rate larger by logarithmically double width [pps].
+ :rtype: float
+ """
+ return current_bound / (
+ 1.0 - MultipleLossRatioSearch.double_relative_width(
+ relative_width))
+
+ @staticmethod
+ def expand_up(relative_width, doublings, current_bound):
+ """Return rate of expanded logarithmic width above.
+
+ :param relative_width: The base relative width to double.
+ :param doublings: How many doublings to do for expansion.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type doublings: int
+ :type current_bound: float
+ :returns: Transmit rate smaller by logarithmically double width [pps].
+ :rtype: float
+ """
+ for _ in range(doublings):
+ relative_width = MultipleLossRatioSearch.double_relative_width(
+ relative_width)
+ return current_bound / (1.0 - relative_width)
+
+ @staticmethod
+ def half_relative_width(relative_width):
+ """Return relative width corresponding to half logarithmic width.
+
+ :param relative_width: The base relative width to halve.
+ :type relative_width: float
+ :returns: The relative width of half logarithmic size.
+ :rtype: float
+ """
+ return 1.0 - math.sqrt(1.0 - relative_width)
+
+ @staticmethod
+ def half_step_up(relative_width, current_bound):
+ """Return rate of half logarithmic width above.
+
+ :param relative_width: The base relative width to halve.
+ :param current_bound: The current target transmit rate to move [pps].
+ :type relative_width: float
+ :type current_bound: float
+ :returns: Transmit rate larger by logarithmically half width [pps].
+ :rtype: float
+ """
+ return current_bound / (
+ 1.0 - MultipleLossRatioSearch.half_relative_width(
+ relative_width))
+
+ def init_generator(self, ports, port_pg_id, profiles, test_data, queue):
+ self.ports = ports
+ self.port_pg_id = port_pg_id
+ self.profiles = profiles
+ self.test_data = test_data
+ self.queue = queue
+ self.queue.cancel_join_thread()
+
+ def collect_kpi(self, stats, test_value):
+ samples = self.measurer.generate_samples(stats, self.ports,
+ self.port_pg_id, self.latency)
+ samples.update(self.test_data)
+ LOGGING.info("Collect TG KPIs %s %s %s", datetime.datetime.now(),
+ test_value, samples)
+ self.queue.put(samples)
+
+ def narrow_down_ndr_and_pdr(
+ self, minimum_transmit_rate, maximum_transmit_rate,
+ packet_loss_ratio):
+ """Perform initial phase, create state object, proceed with next phases.
+
+ :param minimum_transmit_rate: Minimal target transmit rate [pps].
+ :param maximum_transmit_rate: Maximal target transmit rate [pps].
+ :param packet_loss_ratio: Fraction of packets lost, for PDR [1].
+ :type minimum_transmit_rate: float
+ :type maximum_transmit_rate: float
+ :type packet_loss_ratio: float
+ :returns: Structure containing narrowed down intervals
+ and their measurements.
+ :rtype: NdrPdrResult.NdrPdrResult
+ :raises RuntimeError: If total duration is larger than timeout.
+ """
+ minimum_transmit_rate = float(minimum_transmit_rate)
+ maximum_transmit_rate = float(maximum_transmit_rate)
+ packet_loss_ratio = float(packet_loss_ratio)
+ line_measurement = self.measure(
+ self.initial_trial_duration, maximum_transmit_rate, self.latency)
+ initial_width_goal = self.final_relative_width
+ for _ in range(self.number_of_intermediate_phases):
+ initial_width_goal = self.double_relative_width(initial_width_goal)
+ max_lo = maximum_transmit_rate * (1.0 - initial_width_goal)
+ mrr = max(
+ minimum_transmit_rate,
+ min(max_lo, line_measurement.receive_rate))
+ mrr_measurement = self.measure(
+ self.initial_trial_duration, mrr, self.latency)
+ # Attempt to get narrower width.
+ if mrr_measurement.loss_fraction > 0.0:
+ max2_lo = mrr * (1.0 - initial_width_goal)
+ mrr2 = min(max2_lo, mrr_measurement.receive_rate)
+ else:
+ mrr2 = mrr / (1.0 - initial_width_goal)
+ if mrr2 > minimum_transmit_rate and mrr2 < maximum_transmit_rate:
+ line_measurement = mrr_measurement
+ mrr_measurement = self.measure(
+ self.initial_trial_duration, mrr2, self.latency)
+ if mrr2 > mrr:
+ buf = line_measurement
+ line_measurement = mrr_measurement
+ mrr_measurement = buf
+ starting_interval = ReceiveRateInterval(
+ mrr_measurement, line_measurement)
+ starting_result = NdrPdrResult(starting_interval, starting_interval)
+ state = self.ProgressState(
+ starting_result, self.number_of_intermediate_phases,
+ self.final_trial_duration, self.final_relative_width,
+ packet_loss_ratio, minimum_transmit_rate, maximum_transmit_rate)
+ state = self.ndrpdr(state)
+ result = state.result
+ # theor_max_thruput = 0
+ result_samples = {}
+
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'NDR_LOWER', result.ndr_interval.measured_low.transmit_rate,
+ self.pkt_size, result.ndr_interval.measured_low.latency)
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'NDR_UPPER', result.ndr_interval.measured_high.transmit_rate,
+ self.pkt_size)
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'PDR_LOWER', result.pdr_interval.measured_low.transmit_rate,
+ self.pkt_size, result.pdr_interval.measured_low.latency)
+ MultipleLossRatioSearch.display_single_bound(result_samples,
+ 'PDR_UPPER', result.pdr_interval.measured_high.transmit_rate,
+ self.pkt_size)
+ pdr_msg = self.check_ndrpdr_interval_validity(result_samples, "PDR",
+ result.pdr_interval,
+ packet_loss_ratio)
+ ndr_msg = self.check_ndrpdr_interval_validity(result_samples, "NDR",
+ result.ndr_interval)
+ self.queue.put(result_samples)
+
+ LOGGING.debug("result_samples: %s", result_samples)
+ LOGGING.info(pdr_msg)
+ LOGGING.info(ndr_msg)
+
+ self.perform_additional_measurements_based_on_ndrpdr_result(result)
+
+ return result_samples
+
+ def _measure_and_update_state(self, state, transmit_rate):
+ """Perform trial measurement, update bounds, return new state.
+
+ :param state: State before this measurement.
+ :param transmit_rate: Target transmit rate for this measurement [pps].
+ :type state: ProgressState
+ :type transmit_rate: float
+ :returns: State after the measurement.
+ :rtype: ProgressState
+ """
+ # TODO: Implement https://stackoverflow.com/a/24683360
+ # to avoid the string manipulation if log verbosity is too low.
+ LOGGING.info("result before update: %s", state.result)
+ LOGGING.debug(
+ "relative widths in goals: %s", state.result.width_in_goals(
+ self.final_relative_width))
+ measurement = self.measure(state.duration, transmit_rate, self.latency)
+ ndr_interval = self._new_interval(
+ state.result.ndr_interval, measurement, 0.0)
+ pdr_interval = self._new_interval(
+ state.result.pdr_interval, measurement, state.packet_loss_ratio)
+ state.result = NdrPdrResult(ndr_interval, pdr_interval)
+ return state
+
+ @staticmethod
+ def _new_interval(old_interval, measurement, packet_loss_ratio):
+ """Return new interval with bounds updated according to the measurement.
+
+ :param old_interval: The current interval before the measurement.
+ :param measurement: The new meaqsurement to take into account.
+ :param packet_loss_ratio: Fraction for PDR (or zero for NDR).
+ :type old_interval: ReceiveRateInterval.ReceiveRateInterval
+ :type measurement: ReceiveRateMeasurement.ReceiveRateMeasurement
+ :type packet_loss_ratio: float
+ :returns: The updated interval.
+ :rtype: ReceiveRateInterval.ReceiveRateInterval
+ """
+ old_lo, old_hi = old_interval.measured_low, old_interval.measured_high
+ # Priority zero: direct replace if the target Tr is the same.
+ if measurement.target_tr in (old_lo.target_tr, old_hi.target_tr):
+ if measurement.target_tr == old_lo.target_tr:
+ return ReceiveRateInterval(measurement, old_hi)
+ else:
+ return ReceiveRateInterval(old_lo, measurement)
+ # Priority one: invalid lower bound allows only one type of update.
+ if old_lo.loss_fraction > packet_loss_ratio:
+ # We can only expand down, old bound becomes valid upper one.
+ if measurement.target_tr < old_lo.target_tr:
+ return ReceiveRateInterval(measurement, old_lo)
+ else:
+ return old_interval
+ # Lower bound is now valid.
+ # Next priorities depend on target Tr.
+ if measurement.target_tr < old_lo.target_tr:
+ # Lower external measurement, relevant only
+ # if the new measurement has high loss rate.
+ if measurement.loss_fraction > packet_loss_ratio:
+ # Returning the broader interval as old_lo
+ # would be invalid upper bound.
+ return ReceiveRateInterval(measurement, old_hi)
+ elif measurement.target_tr > old_hi.target_tr:
+ # Upper external measurement, only relevant for invalid upper bound.
+ if old_hi.loss_fraction <= packet_loss_ratio:
+ # Old upper bound becomes valid new lower bound.
+ return ReceiveRateInterval(old_hi, measurement)
+ else:
+ # Internal measurement, replaced boundary
+ # depends on measured loss fraction.
+ if measurement.loss_fraction > packet_loss_ratio:
+ # We have found a narrow valid interval,
+ # regardless of whether old upper bound was valid.
+ return ReceiveRateInterval(old_lo, measurement)
+ else:
+ # In ideal world, we would not want to shrink interval
+ # if upper bound is not valid.
+ # In the real world, we want to shrink it for
+ # "invalid upper bound at maximal rate" case.
+ return ReceiveRateInterval(measurement, old_hi)
+ # Fallback, the interval is unchanged by the measurement.
+ return old_interval
+
+ def ndrpdr(self, state):
+ """Pefrom trials for this phase. Return the new state when done.
+
+ :param state: State before this phase.
+ :type state: ProgressState
+ :returns: The updated state.
+ :rtype: ProgressState
+ :raises RuntimeError: If total duration is larger than timeout.
+ """
+ start_time = time.time()
+ if state.phases > 0:
+ # We need to finish preceding intermediate phases first.
+ saved_phases = state.phases
+ state.phases -= 1
+ # Preceding phases have shorter duration.
+ saved_duration = state.duration
+ duration_multiplier = state.duration / self.initial_trial_duration
+ phase_exponent = float(state.phases) / saved_phases
+ state.duration = self.initial_trial_duration * math.pow(
+ duration_multiplier, phase_exponent)
+ # Shorter durations do not need that narrow widths.
+ saved_width = state.width_goal
+ state.width_goal = self.double_relative_width(state.width_goal)
+ # Recurse.
+ state = self.ndrpdr(state)
+ # Restore the state for current phase.
+ state.duration = saved_duration
+ state.width_goal = saved_width
+ state.phases = saved_phases # Not needed, but just in case.
+ LOGGING.info(
+ "starting iterations with duration %s and relative width goal %s",
+ state.duration, state.width_goal)
+ while 1:
+ if time.time() > start_time + self.timeout:
+ raise RuntimeError("Optimized search takes too long.")
+ # Order of priorities: invalid bounds (nl, pl, nh, ph),
+ # then narrowing relative Tr widths.
+ # Durations are not priorities yet,
+ # they will settle on their own hopefully.
+ ndr_lo = state.result.ndr_interval.measured_low
+ ndr_hi = state.result.ndr_interval.measured_high
+ pdr_lo = state.result.pdr_interval.measured_low
+ pdr_hi = state.result.pdr_interval.measured_high
+ ndr_rel_width = max(
+ state.width_goal, state.result.ndr_interval.rel_tr_width)
+ pdr_rel_width = max(
+ state.width_goal, state.result.pdr_interval.rel_tr_width)
+ # If we are hitting maximal or minimal rate, we cannot shift,
+ # but we can re-measure.
+ if ndr_lo.loss_fraction > 0.0:
+ if ndr_lo.target_tr > state.minimum_transmit_rate:
+ new_tr = max(
+ state.minimum_transmit_rate,
+ self.expand_down(
+ ndr_rel_width, self.doublings, ndr_lo.target_tr))
+ LOGGING.info("ndr lo external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif ndr_lo.duration < state.duration:
+ LOGGING.info("ndr lo minimal re-measure")
+ state = self._measure_and_update_state(
+ state, state.minimum_transmit_rate)
+ continue
+ if pdr_lo.loss_fraction > state.packet_loss_ratio:
+ if pdr_lo.target_tr > state.minimum_transmit_rate:
+ new_tr = max(
+ state.minimum_transmit_rate,
+ self.expand_down(
+ pdr_rel_width, self.doublings, pdr_lo.target_tr))
+ LOGGING.info("pdr lo external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif pdr_lo.duration < state.duration:
+ LOGGING.info("pdr lo minimal re-measure")
+ state = self._measure_and_update_state(
+ state, state.minimum_transmit_rate)
+ continue
+ if ndr_hi.loss_fraction <= 0.0:
+ if ndr_hi.target_tr < state.maximum_transmit_rate:
+ new_tr = min(
+ state.maximum_transmit_rate,
+ self.expand_up(
+ ndr_rel_width, self.doublings, ndr_hi.target_tr))
+ LOGGING.info("ndr hi external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif ndr_hi.duration < state.duration:
+ LOGGING.info("ndr hi maximal re-measure")
+ state = self._measure_and_update_state(
+ state, state.maximum_transmit_rate)
+ continue
+ if pdr_hi.loss_fraction <= state.packet_loss_ratio:
+ if pdr_hi.target_tr < state.maximum_transmit_rate:
+ new_tr = min(
+ state.maximum_transmit_rate,
+ self.expand_up(
+ pdr_rel_width, self.doublings, pdr_hi.target_tr))
+ LOGGING.info("pdr hi external %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ elif pdr_hi.duration < state.duration:
+ LOGGING.info("ndr hi maximal re-measure")
+ state = self._measure_and_update_state(
+ state, state.maximum_transmit_rate)
+ continue
+ # If we are hitting maximum_transmit_rate,
+ # it is still worth narrowing width,
+ # hoping large enough loss fraction will happen.
+ # But if we are hitting the minimal rate (at current duration),
+ # no additional measurement will help with that,
+ # so we can stop narrowing in this phase.
+ if (ndr_lo.target_tr <= state.minimum_transmit_rate
+ and ndr_lo.loss_fraction > 0.0):
+ ndr_rel_width = 0.0
+ if (pdr_lo.target_tr <= state.minimum_transmit_rate
+ and pdr_lo.loss_fraction > state.packet_loss_ratio):
+ pdr_rel_width = 0.0
+ if ndr_rel_width > state.width_goal:
+ # We have to narrow NDR width first, as NDR internal search
+ # can invalidate PDR (but not vice versa).
+ new_tr = self.half_step_up(ndr_rel_width, ndr_lo.target_tr)
+ LOGGING.info("Bisecting for NDR at %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ if pdr_rel_width > state.width_goal:
+ # PDR iternal search.
+ new_tr = self.half_step_up(pdr_rel_width, pdr_lo.target_tr)
+ LOGGING.info("Bisecting for PDR at %s", new_tr)
+ state = self._measure_and_update_state(state, new_tr)
+ continue
+ # We do not need to improve width, but there still might be
+ # some measurements with smaller duration.
+ # We need to re-measure with full duration, possibly
+ # creating invalid bounds to resolve (thus broadening width).
+ if ndr_lo.duration < state.duration:
+ LOGGING.info("re-measuring NDR lower bound")
+ state = self._measure_and_update_state(state, ndr_lo.target_tr)
+ continue
+ if pdr_lo.duration < state.duration:
+ LOGGING.info("re-measuring PDR lower bound")
+ state = self._measure_and_update_state(state, pdr_lo.target_tr)
+ continue
+ # Except when lower bounds have high loss fraction, in that case
+ # we do not need to re-measure _upper_ bounds.
+ if ndr_hi.duration < state.duration and ndr_rel_width > 0.0:
+ LOGGING.info("re-measuring NDR upper bound")
+ state = self._measure_and_update_state(state, ndr_hi.target_tr)
+ continue
+ if pdr_hi.duration < state.duration and pdr_rel_width > 0.0:
+ LOGGING.info("re-measuring PDR upper bound")
+ state = self._measure_and_update_state(state, pdr_hi.target_tr)
+ continue
+ # Widths are narrow (or lower bound minimal), bound measurements
+ # are long enough, we can return.
+ LOGGING.info("phase done")
+ break
+ return state
+
+ def measure(self, duration, transmit_rate, latency):
+ duration = float(duration)
+ transmit_rate = float(transmit_rate)
+ # Trex needs target Tr per stream, but reports aggregate Tx and Dx.
+ unit_rate = str(transmit_rate / 2.0) + "pps"
+ stats = self.measurer.send_traffic_on_tg(self.ports, self.port_pg_id,
+ duration, unit_rate,
+ latency=latency)
+ self.measurer.client.reset(ports=self.ports)
+ self.measurer.client.clear_stats(ports=self.ports)
+ self.measurer.client.remove_all_streams(ports=self.ports)
+ for port, profile in self.profiles.items():
+ self.measurer.client.add_streams(profile, ports=[port])
+ self.collect_kpi(stats, unit_rate)
+ transmit_count = int(self.measurer.sent)
+ loss_count = int(self.measurer.loss)
+ measurement = ReceiveRateMeasurement(
+ duration, transmit_rate, transmit_count, loss_count)
+ measurement.latency = self.measurer.latency
+ return measurement
+
+ def perform_additional_measurements_based_on_ndrpdr_result(self, result):
+ duration = 5.0
+ rate = "{}{}".format(result.ndr_interval.measured_low.target_tr / 2.0,
+ 'pps')
+ for _ in range(0, 1):
+ stats = self.measurer.send_traffic_on_tg(self.ports,
+ self.port_pg_id, duration,
+ rate)
+ self.collect_kpi(stats, rate)
+ LOGGING.info('Traffic loss occurred: %s', self.measurer.loss)
+
+ @staticmethod
+ def display_single_bound(result_samples, result_type, rate_total, pkt_size,
+ latency=None):
+ bandwidth_total = float(rate_total) * (pkt_size + 20) * 8 / (10 ** 9)
+
+ result_samples["Result_{}".format(result_type)] = {
+ "rate_total_pps": float(rate_total),
+ "bandwidth_total_Gbps": float(bandwidth_total),
+ }
+
+ if latency:
+ for item in latency:
+ if latency.index(item) == 0:
+ name = "Result_{}_{}".format("stream0", result_type)
+ else:
+ name = "Result_{}_{}".format("stream1", result_type)
+ lat_min, lat_avg, lat_max = item.split('/')
+ result_samples[name] = {
+ "min_latency": float(lat_min),
+ "avg_latency": float(lat_avg),
+ "max_latency": float(lat_max),
+ }
+
+ @staticmethod
+ def check_ndrpdr_interval_validity(result_samples, result_type, interval,
+ packet_loss_ratio=0.0):
+ lower_bound = interval.measured_low
+ lower_bound_lf = lower_bound.loss_fraction
+
+ result_samples["Result_{}_packets_lost".format(result_type)] = {
+ "packet_loss_ratio": float(lower_bound_lf),
+ "packets_lost": float(lower_bound.loss_count),
+ }
+
+ if lower_bound_lf <= packet_loss_ratio:
+ return "Minimal rate loss fraction {} reach target {}".format(
+ lower_bound_lf, packet_loss_ratio)
+ else:
+ message = "Minimal rate loss fraction {} does not reach target {}".format(
+ lower_bound_lf, packet_loss_ratio)
+ if lower_bound_lf >= 1.0:
+ return '{}\nZero packets forwarded!'.format(message)
+ else:
+ return '{}\n{} packets lost.'.format(message,
+ lower_bound.loss_count)
diff --git a/yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py b/yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py
new file mode 100644
index 000000000..34a97f9fb
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/ndr_pdr_result.py
@@ -0,0 +1,68 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/NdrPdrResult.py;hb=HEAD
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+
+
+class NdrPdrResult(object):
+ """Two measurement intervals, return value of search algorithms.
+
+ Partial fraction is NOT part of the result. Pdr interval should be valid
+ for all partial fractions implied by the interval."""
+
+ def __init__(self, ndr_interval, pdr_interval):
+ """Store the measured intervals after checking argument types.
+
+ :param ndr_interval: Object containing data for NDR part of the result.
+ :param pdr_interval: Object containing data for PDR part of the result.
+ :type ndr_interval: ReceiveRateInterval.ReceiveRateInterval
+ :type pdr_interval: ReceiveRateInterval.ReceiveRateInterval
+ """
+ # TODO: Type checking is not very pythonic,
+ # perhaps users can fix wrong usage without it?
+ if not isinstance(ndr_interval, ReceiveRateInterval):
+ raise TypeError("ndr_interval, is not a ReceiveRateInterval: "
+ "{ndr!r}".format(ndr=ndr_interval))
+ if not isinstance(pdr_interval, ReceiveRateInterval):
+ raise TypeError("pdr_interval, is not a ReceiveRateInterval: "
+ "{pdr!r}".format(pdr=pdr_interval))
+ self.ndr_interval = ndr_interval
+ self.pdr_interval = pdr_interval
+
+ def width_in_goals(self, relative_width_goal):
+ """Return a debug string related to current widths in logarithmic scale.
+
+ :param relative_width_goal: Upper bound times this is the goal
+ difference between upper bound and lower bound.
+ :type relative_width_goal: float
+ :returns: Message containing NDR and PDR widths in goals.
+ :rtype: str
+ """
+ return "ndr {ndr_in_goals}; pdr {pdr_in_goals}".format(
+ ndr_in_goals=self.ndr_interval.width_in_goals(relative_width_goal),
+ pdr_in_goals=self.pdr_interval.width_in_goals(relative_width_goal))
+
+ def __str__(self):
+ """Return string as tuple of named values."""
+ return "NDR={ndr!s};PDR={pdr!s}".format(
+ ndr=self.ndr_interval, pdr=self.pdr_interval)
+
+ def __repr__(self):
+ """Return string evaluable as a constructor call."""
+ return "NdrPdrResult(ndr_interval={ndr!r},pdr_interval={pdr!r})".format(
+ ndr=self.ndr_interval, pdr=self.pdr_interval)
diff --git a/yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py b/yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py
new file mode 100644
index 000000000..517a99c1f
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/receive_rate_interval.py
@@ -0,0 +1,88 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/ReceiveRateInterval.py;hb=HEAD
+
+import math
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class ReceiveRateInterval(object):
+ """Structure defining two Rr measurements, and their relation."""
+
+ def __init__(self, measured_low, measured_high):
+ """Store the bound measurements after checking argument types.
+
+ :param measured_low: Measurement for the lower bound.
+ :param measured_high: Measurement for the upper bound.
+ :type measured_low: ReceiveRateMeasurement.ReceiveRateMeasurement
+ :type measured_high: ReceiveRateMeasurement.ReceiveRateMeasurement
+ """
+ # TODO: Type checking is not very pythonic,
+ # perhaps users can fix wrong usage without it?
+ if not isinstance(measured_low, ReceiveRateMeasurement):
+ raise TypeError("measured_low is not a ReceiveRateMeasurement: "
+ "{low!r}".format(low=measured_low))
+ if not isinstance(measured_high, ReceiveRateMeasurement):
+ raise TypeError("measured_high is not a ReceiveRateMeasurement: "
+ "{high!r}".format(high=measured_high))
+ self.measured_low = measured_low
+ self.measured_high = measured_high
+ # Declare secondary quantities to appease pylint.
+ self.abs_tr_width = None
+ """Absolute width of target transmit rate. Upper minus lower."""
+ self.rel_tr_width = None
+ """Relative width of target transmit rate. Absolute divided by upper."""
+ self.sort()
+
+ def sort(self):
+ """Sort bounds by target Tr, compute secondary quantities."""
+ if self.measured_low.target_tr > self.measured_high.target_tr:
+ self.measured_low, self.measured_high = (
+ self.measured_high, self.measured_low)
+ self.abs_tr_width = (
+ self.measured_high.target_tr - self.measured_low.target_tr)
+ self.rel_tr_width = round(
+ self.abs_tr_width / self.measured_high.target_tr, 5)
+
+ def width_in_goals(self, relative_width_goal):
+ """Return float value.
+
+ Relative width goal is some (negative) value on logarithmic scale.
+ Current relative width is another logarithmic value.
+ Return the latter divided by the former.
+ This is useful when investigating how did surprising widths come to be.
+
+ :param relative_width_goal: Upper bound times this is the goal
+ difference between upper bound and lower bound.
+ :type relative_width_goal: float
+ :returns: Current width as logarithmic multiple of goal width [1].
+ :rtype: float
+ """
+ return round(math.log(1.0 - self.rel_tr_width) / math.log(
+ 1.0 - relative_width_goal), 5)
+
+ def __str__(self):
+ """Return string as half-open interval."""
+ return "[{low!s};{high!s})".format(
+ low=self.measured_low, high=self.measured_high)
+
+ def __repr__(self):
+ """Return string evaluable as a constructor call."""
+ return ("ReceiveRateInterval(measured_low={low!r}"
+ ",measured_high={high!r})".format(low=self.measured_low,
+ high=self.measured_high))
diff --git a/yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py b/yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py
new file mode 100644
index 000000000..2c59ea104
--- /dev/null
+++ b/yardstick/network_services/helpers/vpp_helpers/receive_rate_measurement.py
@@ -0,0 +1,58 @@
+# Copyright (c) 2019 Viosoft 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.
+#
+# This is a modified copy of
+# https://gerrit.fd.io/r/gitweb?p=csit.git;a=blob_plain;f=resources/libraries/python/MLRsearch/ReceiveRateMeasurement.py;hb=HEAD
+
+
+class ReceiveRateMeasurement(object):
+ """Structure defining the result of single Rr measurement."""
+
+ def __init__(self, duration, target_tr, transmit_count, loss_count):
+ """Constructor, normalize primary and compute secondary quantities.
+
+ :param duration: Measurement duration [s].
+ :param target_tr: Target transmit rate [pps].
+ If bidirectional traffic is measured, this is bidirectional rate.
+ :param transmit_count: Number of packets transmitted [1].
+ :param loss_count: Number of packets transmitted but not received [1].
+ :type duration: float
+ :type target_tr: float
+ :type transmit_count: int
+ :type loss_count: int
+ """
+ self.duration = float(duration)
+ self.target_tr = float(target_tr)
+ self.transmit_count = int(transmit_count)
+ self.loss_count = int(loss_count)
+ self.receive_count = round(transmit_count - loss_count, 5)
+ self.transmit_rate = round(transmit_count / self.duration, 5)
+ self.loss_rate = round(loss_count / self.duration, 5)
+ self.receive_rate = round(self.receive_count / self.duration, 5)
+ self.loss_fraction = round(
+ float(self.loss_count) / self.transmit_count, 5)
+ # TODO: Do we want to store also the real time (duration + overhead)?
+
+ def __str__(self):
+ """Return string reporting input and loss fraction."""
+ return "d={dur!s},Tr={rate!s},Df={frac!s}".format(
+ dur=self.duration, rate=self.target_tr, frac=self.loss_fraction)
+
+ def __repr__(self):
+ """Return string evaluable as a constructor call."""
+ return ("ReceiveRateMeasurement(duration={dur!r},target_tr={rate!r}"
+ ",transmit_count={trans!r},loss_count={loss!r})".format(
+ dur=self.duration, rate=self.target_tr,
+ trans=self.transmit_count,
+ loss=self.loss_count))
diff --git a/yardstick/network_services/traffic_profile/vpp_rfc2544.py b/yardstick/network_services/traffic_profile/vpp_rfc2544.py
index 0f8185f90..412e4e69a 100644
--- a/yardstick/network_services/traffic_profile/vpp_rfc2544.py
+++ b/yardstick/network_services/traffic_profile/vpp_rfc2544.py
@@ -13,17 +13,19 @@
# limitations under the License.
import datetime
+import ipaddress
import logging
-from random import choice
-from string import ascii_letters
+import random
+import string
-from ipaddress import ip_address
from trex_stl_lib import api as Pkt
from trex_stl_lib import trex_stl_client
from trex_stl_lib import trex_stl_packet_builder_scapy
from trex_stl_lib import trex_stl_streams
from yardstick.common import constants
+from yardstick.network_services.helpers.vpp_helpers.multiple_loss_ratio_search import \
+ MultipleLossRatioSearch
from yardstick.network_services.traffic_profile.rfc2544 import RFC2544Profile, \
PortPgIDMap
from yardstick.network_services.traffic_profile.trex_traffic_profile import IP, \
@@ -37,6 +39,10 @@ class VppRFC2544Profile(RFC2544Profile):
def __init__(self, traffic_generator):
super(VppRFC2544Profile, self).__init__(traffic_generator)
+ tp_cfg = traffic_generator["traffic_profile"]
+ self.number_of_intermediate_phases = tp_cfg.get("intermediate_phases",
+ 2)
+
self.duration = self.config.duration
self.precision = self.config.test_precision
self.lower_bound = self.config.lower_bound
@@ -85,7 +91,7 @@ class VppRFC2544Profile(RFC2544Profile):
def _gen_payload(length):
payload = ""
for _ in range(length):
- payload += choice(ascii_letters)
+ payload += random.choice(string.ascii_letters)
return payload
@@ -153,8 +159,9 @@ class VppRFC2544Profile(RFC2544Profile):
dst=dst_start_ip,
proto=outer_l3v4['proto'])
if self.flow > 1:
- dst_start_int = int(ip_address(str(dst_start_ip)))
- dst_end_ip_new = ip_address(dst_start_int + self.flow - 1)
+ dst_start_int = int(ipaddress.ip_address(str(dst_start_ip)))
+ dst_end_ip_new = ipaddress.ip_address(
+ dst_start_int + self.flow - 1)
# self._set_proto_addr(IP, SRC, outer_l3v4['srcip4'], outer_l3v4['count'])
self._set_proto_addr(IP, DST,
"{start_ip}-{end_ip}".format(
@@ -248,8 +255,19 @@ class VppRFC2544Profile(RFC2544Profile):
def binary_search_with_optimized(self, traffic_generator, duration,
timeout, test_data):
- # TODO Support FD.io Multiple Loss Ratio search (MLRsearch)
- pass
+ self.queue.cancel_join_thread()
+ algorithm = MultipleLossRatioSearch(
+ measurer=traffic_generator, latency=self.enable_latency,
+ pkt_size=self.pkt_size,
+ final_trial_duration=duration,
+ final_relative_width=self.step_interval / 100,
+ number_of_intermediate_phases=self.number_of_intermediate_phases,
+ initial_trial_duration=1,
+ timeout=timeout)
+ algorithm.init_generator(self.ports, self.port_pg_id, self.profiles,
+ test_data, self.queue)
+ return algorithm.narrow_down_ndr_and_pdr(10000, self.max_rate,
+ self.tolerance_high)
def binary_search(self, traffic_generator, duration, tolerance_value,
test_data):
diff --git a/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py b/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py
index 75a8cce06..9aedefec1 100644
--- a/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py
+++ b/yardstick/network_services/vnf_generic/vnf/ipsec_vnf.py
@@ -15,18 +15,46 @@
import logging
import re
import time
+from collections import Counter
+from enum import Enum
from yardstick.benchmark.contexts.base import Context
from yardstick.common.process import check_if_process_failed
from yardstick.network_services import constants
-from yardstick.network_services.helpers.cpu import CpuSysCores
from yardstick.network_services.vnf_generic.vnf.sample_vnf import SampleVNF
from yardstick.network_services.vnf_generic.vnf.vpp_helpers import \
- VppSetupEnvHelper
+ VppSetupEnvHelper, VppConfigGenerator
LOG = logging.getLogger(__name__)
+class CryptoAlg(Enum):
+ """Encryption algorithms."""
+ AES_CBC_128 = ('aes-cbc-128', 'AES-CBC', 16)
+ AES_CBC_192 = ('aes-cbc-192', 'AES-CBC', 24)
+ AES_CBC_256 = ('aes-cbc-256', 'AES-CBC', 32)
+ AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
+
+ def __init__(self, alg_name, scapy_name, key_len):
+ self.alg_name = alg_name
+ self.scapy_name = scapy_name
+ self.key_len = key_len
+
+
+class IntegAlg(Enum):
+ """Integrity algorithms."""
+ SHA1_96 = ('sha1-96', 'HMAC-SHA1-96', 20)
+ SHA_256_128 = ('sha-256-128', 'SHA2-256-128', 32)
+ SHA_384_192 = ('sha-384-192', 'SHA2-384-192', 48)
+ SHA_512_256 = ('sha-512-256', 'SHA2-512-256', 64)
+ AES_GCM_128 = ('aes-gcm-128', 'AES-GCM', 20)
+
+ def __init__(self, alg_name, scapy_name, key_len):
+ self.alg_name = alg_name
+ self.scapy_name = scapy_name
+ self.key_len = key_len
+
+
class VipsecApproxSetupEnvHelper(VppSetupEnvHelper):
DEFAULT_IPSEC_VNF_CFG = {
'crypto_type': 'SW_cryptodev',
@@ -99,17 +127,43 @@ class VipsecApproxSetupEnvHelper(VppSetupEnvHelper):
return flow_src_start_ip
def build_config(self):
- # TODO Implement later
- pass
+ vnf_cfg = self.scenario_helper.options.get('vnf_config',
+ self.DEFAULT_IPSEC_VNF_CFG)
+ rxq = vnf_cfg.get('rxq', 1)
+ phy_cores = vnf_cfg.get('worker_threads', 1)
+ # worker_config = vnf_cfg.get('worker_config', '1C/1T').split('/')[1].lower()
+
+ vpp_cfg = self.create_startup_configuration_of_vpp()
+ self.add_worker_threads_and_rxqueues(vpp_cfg, phy_cores, rxq)
+ self.add_pci_devices(vpp_cfg)
+
+ frame_size_cfg = self.scenario_helper.all_options.get('framesize', {})
+ uplink_cfg = frame_size_cfg.get('uplink', {})
+ downlink_cfg = frame_size_cfg.get('downlink', {})
+ framesize = min(self.calculate_frame_size(uplink_cfg),
+ self.calculate_frame_size(downlink_cfg))
+ if framesize < 1522:
+ vpp_cfg.add_dpdk_no_multi_seg()
+
+ crypto_algorithms = self._get_crypto_algorithms()
+ if crypto_algorithms == 'aes-gcm':
+ self.add_dpdk_cryptodev(vpp_cfg, 'aesni_gcm', phy_cores)
+ elif crypto_algorithms == 'cbc-sha1':
+ self.add_dpdk_cryptodev(vpp_cfg, 'aesni_mb', phy_cores)
+
+ vpp_cfg.add_dpdk_dev_default_rxd(2048)
+ vpp_cfg.add_dpdk_dev_default_txd(2048)
+ self.apply_config(vpp_cfg, True)
+ self.update_vpp_interface_data()
def setup_vnf_environment(self):
resource = super(VipsecApproxSetupEnvHelper,
self).setup_vnf_environment()
self.start_vpp_service()
-
- sys_cores = CpuSysCores(self.ssh_helper)
- self._update_vnfd_helper(sys_cores.get_cpu_layout())
+ self._update_vnfd_helper(self.sys_cores.get_cpu_layout())
+ self.update_vpp_interface_data()
+ self.iface_update_numa()
return resource
@@ -144,12 +198,90 @@ class VipsecApproxSetupEnvHelper(VppSetupEnvHelper):
return ipsec_created
def get_vpp_statistics(self):
- # TODO Implement later
- return None
+ cmd = "vppctl show int {intf}"
+ result = {}
+ for interface in self.vnfd_helper.interfaces:
+ iface_name = self.get_value_by_interface_key(
+ interface["virtual-interface"]["ifname"], "vpp_name")
+ command = cmd.format(intf=iface_name)
+ _, stdout, _ = self.ssh_helper.execute(command)
+ result.update(
+ self.parser_vpp_stats(interface["virtual-interface"]["ifname"],
+ iface_name, stdout))
+ self.ssh_helper.execute("vppctl clear interfaces")
+ return result
+
+ @staticmethod
+ def parser_vpp_stats(interface, iface_name, stats):
+ packets_in = 0
+ packets_fwd = 0
+ packets_dropped = 0
+ result = {}
+
+ entries = re.split(r"\n+", stats)
+ tmp = [re.split(r"\s\s+", entry, 5) for entry in entries]
+
+ for item in tmp:
+ if isinstance(item, list):
+ if item[0] == iface_name and len(item) >= 5:
+ if item[3] == 'rx packets':
+ packets_in = int(item[4])
+ elif item[4] == 'rx packets':
+ packets_in = int(item[5])
+ elif len(item) == 3:
+ if item[1] == 'tx packets':
+ packets_fwd = int(item[2])
+ elif item[1] == 'drops' or item[1] == 'rx-miss':
+ packets_dropped = int(item[2])
+ if packets_dropped == 0 and packets_in > 0 and packets_fwd > 0:
+ packets_dropped = abs(packets_fwd - packets_in)
+
+ result[interface] = {
+ 'packets_in': packets_in,
+ 'packets_fwd': packets_fwd,
+ 'packets_dropped': packets_dropped,
+ }
+
+ return result
def create_ipsec_tunnels(self):
- # TODO Implement later
- pass
+ self.initialize_ipsec()
+
+ # TODO generate the same key
+ crypto_algorithms = self._get_crypto_algorithms()
+ if crypto_algorithms == 'aes-gcm':
+ encr_alg = CryptoAlg.AES_GCM_128
+ auth_alg = IntegAlg.AES_GCM_128
+ encr_key = 'LNYZXMBQDKESNLREHJMS'
+ auth_key = 'SWGLDTYZSQKVBZZMPIEV'
+ elif crypto_algorithms == 'cbc-sha1':
+ encr_alg = CryptoAlg.AES_CBC_128
+ auth_alg = IntegAlg.SHA1_96
+ encr_key = 'IFEMSHYLCZIYFUTT'
+ auth_key = 'PEALEIPSCPTRHYJSDXLY'
+
+ self.execute_script("enable_dpdk_traces.vat", json_out=False)
+ self.execute_script("enable_vhost_user_traces.vat", json_out=False)
+ self.execute_script("enable_memif_traces.vat", json_out=False)
+
+ node_name = self.find_encrypted_data_interface()["node_name"]
+ n_tunnels = self._get_n_tunnels()
+ n_connections = self._get_n_connections()
+ flow_dst_start_ip = self._get_flow_dst_start_ip()
+ if node_name == "vnf__0":
+ self.vpp_create_ipsec_tunnels(
+ self.find_encrypted_data_interface()["local_ip"],
+ self.find_encrypted_data_interface()["peer_intf"]["local_ip"],
+ self.find_encrypted_data_interface()["ifname"],
+ n_tunnels, n_connections, encr_alg, encr_key, auth_alg,
+ auth_key, flow_dst_start_ip)
+ elif node_name == "vnf__1":
+ self.vpp_create_ipsec_tunnels(
+ self.find_encrypted_data_interface()["local_ip"],
+ self.find_encrypted_data_interface()["peer_intf"]["local_ip"],
+ self.find_encrypted_data_interface()["ifname"],
+ n_tunnels, n_connections, encr_alg, encr_key, auth_alg,
+ auth_key, flow_dst_start_ip, 20000, 10000)
def find_raw_data_interface(self):
try:
@@ -160,6 +292,145 @@ class VipsecApproxSetupEnvHelper(VppSetupEnvHelper):
def find_encrypted_data_interface(self):
return self.vnfd_helper.find_virtual_interface(vld_id="ciphertext")
+ def create_startup_configuration_of_vpp(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_log()
+ vpp_config_generator.add_unix_cli_listen()
+ vpp_config_generator.add_unix_nodaemon()
+ vpp_config_generator.add_unix_coredump()
+ vpp_config_generator.add_dpdk_socketmem('1024,1024')
+ vpp_config_generator.add_dpdk_no_tx_checksum_offload()
+ vpp_config_generator.add_dpdk_log_level('debug')
+ for interface in self.vnfd_helper.interfaces:
+ vpp_config_generator.add_dpdk_uio_driver(
+ interface["virtual-interface"]["driver"])
+ vpp_config_generator.add_heapsize('4G')
+ # TODO Enable configuration depend on VPP version
+ vpp_config_generator.add_statseg_size('4G')
+ vpp_config_generator.add_plugin('disable', ['default'])
+ vpp_config_generator.add_plugin('enable', ['dpdk_plugin.so'])
+ vpp_config_generator.add_ip6_hash_buckets('2000000')
+ vpp_config_generator.add_ip6_heap_size('4G')
+ vpp_config_generator.add_ip_heap_size('4G')
+ return vpp_config_generator
+
+ def add_worker_threads_and_rxqueues(self, vpp_cfg, phy_cores,
+ rx_queues=None):
+ thr_count_int = phy_cores
+ cpu_count_int = phy_cores
+ num_mbufs_int = 32768
+
+ numa_list = []
+
+ if_list = [self.find_encrypted_data_interface()["ifname"],
+ self.find_raw_data_interface()["ifname"]]
+ for if_key in if_list:
+ try:
+ numa_list.append(
+ self.get_value_by_interface_key(if_key, 'numa_node'))
+ except KeyError:
+ pass
+ numa_cnt_mc = Counter(numa_list).most_common()
+
+ if numa_cnt_mc and numa_cnt_mc[0][0] is not None and \
+ numa_cnt_mc[0][0] != -1:
+ numa = numa_cnt_mc[0][0]
+ elif len(numa_cnt_mc) > 1 and numa_cnt_mc[0][0] == -1:
+ numa = numa_cnt_mc[1][0]
+ else:
+ numa = 0
+
+ try:
+ smt_used = self.sys_cores.is_smt_enabled()
+ except KeyError:
+ smt_used = False
+
+ cpu_main = self.sys_cores.cpu_list_per_node_str(numa, skip_cnt=1,
+ cpu_cnt=1)
+ cpu_wt = self.sys_cores.cpu_list_per_node_str(numa, skip_cnt=2,
+ cpu_cnt=cpu_count_int,
+ smt_used=smt_used)
+
+ if smt_used:
+ thr_count_int = 2 * cpu_count_int
+
+ if rx_queues is None:
+ rxq_count_int = int(thr_count_int / 2)
+ else:
+ rxq_count_int = rx_queues
+
+ if rxq_count_int == 0:
+ rxq_count_int = 1
+
+ num_mbufs_int = num_mbufs_int * rxq_count_int
+
+ vpp_cfg.add_cpu_main_core(cpu_main)
+ vpp_cfg.add_cpu_corelist_workers(cpu_wt)
+ vpp_cfg.add_dpdk_dev_default_rxq(rxq_count_int)
+ vpp_cfg.add_dpdk_num_mbufs(num_mbufs_int)
+
+ def add_pci_devices(self, vpp_cfg):
+ pci_devs = [self.find_encrypted_data_interface()["vpci"],
+ self.find_raw_data_interface()["vpci"]]
+ vpp_cfg.add_dpdk_dev(*pci_devs)
+
+ def add_dpdk_cryptodev(self, vpp_cfg, sw_pmd_type, count):
+ crypto_type = self._get_crypto_type()
+ smt_used = self.sys_cores.is_smt_enabled()
+ cryptodev = self.find_encrypted_data_interface()["vpci"]
+ socket_id = self.get_value_by_interface_key(
+ self.find_encrypted_data_interface()["ifname"], "numa_node")
+
+ if smt_used:
+ thr_count_int = count * 2
+ if crypto_type == 'HW_cryptodev':
+ vpp_cfg.add_dpdk_cryptodev(thr_count_int, cryptodev)
+ else:
+ vpp_cfg.add_dpdk_sw_cryptodev(sw_pmd_type, socket_id,
+ thr_count_int)
+ else:
+ thr_count_int = count
+ if crypto_type == 'HW_cryptodev':
+ vpp_cfg.add_dpdk_cryptodev(thr_count_int, cryptodev)
+ else:
+ vpp_cfg.add_dpdk_sw_cryptodev(sw_pmd_type, socket_id,
+ thr_count_int)
+
+ def initialize_ipsec(self):
+ flow_src_start_ip = self._get_flow_src_start_ip()
+
+ self.set_interface_state(
+ self.find_encrypted_data_interface()["ifname"], 'up')
+ self.set_interface_state(self.find_raw_data_interface()["ifname"],
+ 'up')
+ self.vpp_interfaces_ready_wait()
+ self.vpp_set_interface_mtu(
+ self.find_encrypted_data_interface()["ifname"])
+ self.vpp_set_interface_mtu(self.find_raw_data_interface()["ifname"])
+ self.vpp_interfaces_ready_wait()
+
+ self.set_ip(self.find_encrypted_data_interface()["ifname"],
+ self.find_encrypted_data_interface()["local_ip"], 24)
+ self.set_ip(self.find_raw_data_interface()["ifname"],
+ self.find_raw_data_interface()["local_ip"],
+ 24)
+
+ self.add_arp_on_dut(self.find_encrypted_data_interface()["ifname"],
+ self.find_encrypted_data_interface()["peer_intf"][
+ "local_ip"],
+ self.find_encrypted_data_interface()["peer_intf"][
+ "local_mac"])
+ self.add_arp_on_dut(self.find_raw_data_interface()["ifname"],
+ self.find_raw_data_interface()["peer_intf"][
+ "local_ip"],
+ self.find_raw_data_interface()["peer_intf"][
+ "local_mac"])
+
+ self.vpp_route_add(flow_src_start_ip, 8,
+ self.find_raw_data_interface()["peer_intf"][
+ "local_ip"],
+ self.find_raw_data_interface()["ifname"])
+
class VipsecApproxVnf(SampleVNF):
""" This class handles vIPSEC VNF model-driver definitions """
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py b/yardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py
new file mode 100755
index 000000000..c6df9d04c
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/tg_vcmts_pktgen.py
@@ -0,0 +1,215 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+import time
+import socket
+import yaml
+import os
+
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+from yardstick.common import exceptions
+
+
+LOG = logging.getLogger(__name__)
+
+
+class PktgenHelper(object):
+
+ RETRY_SECONDS = 0.5
+ RETRY_COUNT = 20
+ CONNECT_TIMEOUT = 5
+
+ def __init__(self, host, port=23000):
+ self.host = host
+ self.port = port
+ self.connected = False
+
+ def _connect(self):
+ self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ ret = True
+ try:
+ self._sock.settimeout(self.CONNECT_TIMEOUT)
+ self._sock.connect((self.host, self.port))
+ except (socket.gaierror, socket.error, socket.timeout):
+ self._sock.close()
+ ret = False
+
+ return ret
+
+ def connect(self):
+ if self.connected:
+ return True
+ LOG.info("Connecting to pktgen instance at %s...", self.host)
+ for idx in range(self.RETRY_COUNT):
+ self.connected = self._connect()
+ if self.connected:
+ return True
+ LOG.debug("Connection attempt %d: Unable to connect to %s, " \
+ "retrying in %d seconds",
+ idx, self.host, self.RETRY_SECONDS)
+ time.sleep(self.RETRY_SECONDS)
+
+ LOG.error("Unable to connect to pktgen instance on %s !",
+ self.host)
+ return False
+
+
+ def send_command(self, command):
+ if not self.connected:
+ LOG.error("Pktgen socket is not connected")
+ return False
+
+ try:
+ self._sock.sendall((command + "\n").encode())
+ time.sleep(1)
+ except (socket.timeout, socket.error):
+ LOG.error("Error sending command '%s'", command)
+ return False
+
+ return True
+
+
+class VcmtsPktgenSetupEnvHelper(sample_vnf.SetupEnvHelper):
+
+ BASE_PARAMETERS = "export LUA_PATH=/vcmts/Pktgen.lua;"\
+ + "export CMK_PROC_FS=/host/proc;"
+
+ PORTS_COUNT = 8
+
+ def generate_pcap_filename(self, port_cfg):
+ return port_cfg['traffic_type'] + "_" + port_cfg['num_subs'] \
+ + "cms_" + port_cfg['num_ofdm'] + "ofdm.pcap"
+
+ def find_port_cfg(self, ports_cfg, port_name):
+ for port_cfg in ports_cfg:
+ if port_name in port_cfg:
+ return port_cfg
+ return None
+
+ def build_pktgen_parameters(self, pod_cfg):
+ ports_cfg = pod_cfg['ports']
+ port_cfg = list()
+
+ for i in range(self.PORTS_COUNT):
+ port_cfg.append(self.find_port_cfg(ports_cfg, 'port_' + str(i)))
+
+ pktgen_parameters = self.BASE_PARAMETERS + " " \
+ + " /pktgen-config/setup.sh " + pod_cfg['pktgen_id'] \
+ + " " + pod_cfg['num_ports']
+
+ for i in range(self.PORTS_COUNT):
+ pktgen_parameters += " " + port_cfg[i]['net_pktgen']
+
+ for i in range(self.PORTS_COUNT):
+ pktgen_parameters += " " + self.generate_pcap_filename(port_cfg[i])
+
+ return pktgen_parameters
+
+ def start_pktgen(self, pod_cfg):
+ self.ssh_helper.drop_connection()
+ cmd = self.build_pktgen_parameters(pod_cfg)
+ LOG.debug("Executing: '%s'", cmd)
+ self.ssh_helper.send_command(cmd)
+ LOG.info("Pktgen executed")
+
+ def setup_vnf_environment(self):
+ pass
+
+
+class VcmtsPktgen(sample_vnf.SampleVNFTrafficGen):
+
+ TG_NAME = 'VcmtsPktgen'
+ APP_NAME = 'VcmtsPktgen'
+ RUN_WAIT = 4
+ DEFAULT_RATE = 8.0
+
+ PKTGEN_BASE_PORT = 23000
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if setup_env_helper_type is None:
+ setup_env_helper_type = VcmtsPktgenSetupEnvHelper
+ super(VcmtsPktgen, self).__init__(
+ name, vnfd, setup_env_helper_type, resource_helper_type)
+
+ self.pktgen_address = vnfd['mgmt-interface']['ip']
+ LOG.info("Pktgen container '%s', IP: %s", name, self.pktgen_address)
+
+ def extract_pod_cfg(self, pktgen_pods_cfg, pktgen_id):
+ for pod_cfg in pktgen_pods_cfg:
+ if pod_cfg['pktgen_id'] == pktgen_id:
+ return pod_cfg
+ return None
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ super(VcmtsPktgen, self).instantiate(scenario_cfg, context_cfg)
+ self._start_server()
+ options = scenario_cfg.get('options', {})
+ self.pktgen_rate = options.get('pktgen_rate', self.DEFAULT_RATE)
+
+ try:
+ pktgen_values_filepath = options['pktgen_values']
+ except KeyError:
+ raise KeyError("Missing pktgen_values key in scenario options" \
+ "section of the task definition file")
+
+ if not os.path.isfile(pktgen_values_filepath):
+ raise RuntimeError("The pktgen_values file path provided " \
+ "does not exists")
+
+ # The yaml_loader.py (SafeLoader) underlying regex has an issue
+ # with reading PCI addresses (processed as double). so the
+ # BaseLoader is used here.
+ with open(pktgen_values_filepath) as stream:
+ pktgen_values = yaml.load(stream, Loader=yaml.BaseLoader)
+
+ if pktgen_values == None:
+ raise RuntimeError("Error reading pktgen_values file provided (" +
+ pktgen_values_filepath + ")")
+
+ self.pktgen_id = int(options[self.name]['pktgen_id'])
+ self.resource_helper.pktgen_id = self.pktgen_id
+
+ self.pktgen_helper = PktgenHelper(self.pktgen_address,
+ self.PKTGEN_BASE_PORT + self.pktgen_id)
+
+ pktgen_pods_cfg = pktgen_values['topology']['pktgen_pods']
+
+ self.pod_cfg = self.extract_pod_cfg(pktgen_pods_cfg,
+ str(self.pktgen_id))
+
+ if self.pod_cfg == None:
+ raise KeyError("Pktgen with id " + str(self.pktgen_id) + \
+ " was not found")
+
+ self.setup_helper.start_pktgen(self.pod_cfg)
+
+ def run_traffic(self, traffic_profile):
+ if not self.pktgen_helper.connect():
+ raise exceptions.PktgenActionError(command="connect")
+ LOG.info("Connected to pktgen instance at %s", self.pktgen_address)
+
+ commands = []
+ for i in range(self.setup_helper.PORTS_COUNT):
+ commands.append('pktgen.set("' + str(i) + '", "rate", ' +
+ "%0.1f" % self.pktgen_rate + ');')
+
+ commands.append('pktgen.start("all");')
+
+ for command in commands:
+ if self.pktgen_helper.send_command(command):
+ LOG.debug("Command '%s' sent to pktgen", command)
+ LOG.info("Traffic started on %s...", self.name)
+ return True
diff --git a/yardstick/network_services/vnf_generic/vnf/vcmts_vnf.py b/yardstick/network_services/vnf_generic/vnf/vcmts_vnf.py
new file mode 100755
index 000000000..0b48ef4e9
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/vcmts_vnf.py
@@ -0,0 +1,273 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+import os
+import yaml
+
+from influxdb import InfluxDBClient
+
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import SetupEnvHelper
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.network_services.vnf_generic.vnf.base import GenericVNF
+from yardstick.network_services.vnf_generic.vnf.sample_vnf import ScenarioHelper
+from yardstick.network_services.vnf_generic.vnf.vnf_ssh_helper import VnfSshHelper
+from yardstick.network_services.utils import get_nsb_option
+
+
+LOG = logging.getLogger(__name__)
+
+
+class InfluxDBHelper(object):
+
+ INITIAL_VALUE = 'now() - 1m'
+
+ def __init__(self, vcmts_influxdb_ip, vcmts_influxdb_port):
+ self._vcmts_influxdb_ip = vcmts_influxdb_ip
+ self._vcmts_influxdb_port = vcmts_influxdb_port
+ self._last_upstream_rx = self.INITIAL_VALUE
+ self._last_values_time = dict()
+
+ def start(self):
+ self._read_client = InfluxDBClient(host=self._vcmts_influxdb_ip,
+ port=self._vcmts_influxdb_port,
+ database='collectd')
+ self._write_client = InfluxDBClient(host=constants.INFLUXDB_IP,
+ port=constants.INFLUXDB_PORT,
+ database='collectd')
+
+ def _get_last_value_time(self, measurement):
+ if measurement in self._last_values_time:
+ return self._last_values_time[measurement]
+ return self.INITIAL_VALUE
+
+ def _set_last_value_time(self, measurement, time):
+ self._last_values_time[measurement] = "'" + time + "'"
+
+ def _query_measurement(self, measurement):
+ # There is a delay before influxdb flushes the data
+ query = "SELECT * FROM " + measurement + " WHERE time > " \
+ + self._get_last_value_time(measurement) \
+ + " ORDER BY time ASC;"
+ query_result = self._read_client.query(query)
+ if len(query_result.keys()) == 0:
+ return None
+ return query_result.get_points(measurement)
+
+ def _rw_measurment(self, measurement, columns):
+ query_result = self._query_measurement(measurement)
+ if query_result == None:
+ return
+
+ points_to_write = list()
+ for entry in query_result:
+ point = {
+ "measurement": measurement,
+ "tags": {
+ "type": entry['type'],
+ "host": entry['host']
+ },
+ "time": entry['time'],
+ "fields": {}
+ }
+
+ for column in columns:
+ if column == 'value':
+ point["fields"][column] = float(entry[column])
+ else:
+ point["fields"][column] = entry[column]
+
+ points_to_write.append(point)
+ self._set_last_value_time(measurement, entry['time'])
+
+ # Write the points to yardstick database
+ if self._write_client.write_points(points_to_write):
+ LOG.debug("%d new points written to '%s' measurement",
+ len(points_to_write), measurement)
+
+ def copy_kpi(self):
+ self._rw_measurment("cpu_value", ["instance", "type_instance", "value"])
+ self._rw_measurment("cpufreq_value", ["type_instance", "value"])
+ self._rw_measurment("downstream_rx", ["value"])
+ self._rw_measurment("downstream_tx", ["value"])
+ self._rw_measurment("downstream_value", ["value"])
+ self._rw_measurment("ds_per_cm_value", ["instance", "value"])
+ self._rw_measurment("intel_rdt_value", ["instance", "type_instance", "value"])
+ self._rw_measurment("turbostat_value", ["instance", "type_instance", "value"])
+ self._rw_measurment("upstream_rx", ["value"])
+ self._rw_measurment("upstream_tx", ["value"])
+ self._rw_measurment("upstream_value", ["value"])
+
+
+class VcmtsdSetupEnvHelper(SetupEnvHelper):
+
+ BASE_PARAMETERS = "export LD_LIBRARY_PATH=/opt/collectd/lib:;"\
+ + "export CMK_PROC_FS=/host/proc;"
+
+ def build_us_parameters(self, pod_cfg):
+ return self.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + pod_cfg['cpu_socket_id'] \
+ + " --pool=shared" \
+ + " /vcmts-config/run_upstream.sh " + pod_cfg['sg_id'] \
+ + " " + pod_cfg['ds_core_type'] \
+ + " " + pod_cfg['num_ofdm'] + "ofdm" \
+ + " " + pod_cfg['num_subs'] + "cm" \
+ + " " + pod_cfg['cm_crypto'] \
+ + " " + pod_cfg['qat'] \
+ + " " + pod_cfg['net_us'] \
+ + " " + pod_cfg['power_mgmt']
+
+ def build_ds_parameters(self, pod_cfg):
+ return self.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + pod_cfg['cpu_socket_id'] \
+ + " --pool=" + pod_cfg['ds_core_type'] \
+ + " /vcmts-config/run_downstream.sh " + pod_cfg['sg_id'] \
+ + " " + pod_cfg['ds_core_type'] \
+ + " " + pod_cfg['ds_core_pool_index'] \
+ + " " + pod_cfg['num_ofdm'] + "ofdm" \
+ + " " + pod_cfg['num_subs'] + "cm" \
+ + " " + pod_cfg['cm_crypto'] \
+ + " " + pod_cfg['qat'] \
+ + " " + pod_cfg['net_ds'] \
+ + " " + pod_cfg['power_mgmt']
+
+ def build_cmd(self, stream_dir, pod_cfg):
+ if stream_dir == 'ds':
+ return self.build_ds_parameters(pod_cfg)
+ else:
+ return self.build_us_parameters(pod_cfg)
+
+ def run_vcmtsd(self, stream_dir, pod_cfg):
+ cmd = self.build_cmd(stream_dir, pod_cfg)
+ LOG.debug("Executing %s", cmd)
+ self.ssh_helper.send_command(cmd)
+
+ def setup_vnf_environment(self):
+ pass
+
+
+class VcmtsVNF(GenericVNF):
+
+ RUN_WAIT = 4
+
+ def __init__(self, name, vnfd):
+ super(VcmtsVNF, self).__init__(name, vnfd)
+ self.name = name
+ self.bin_path = get_nsb_option('bin_path', '')
+ self.scenario_helper = ScenarioHelper(self.name)
+ self.ssh_helper = VnfSshHelper(self.vnfd_helper.mgmt_interface, self.bin_path)
+
+ self.setup_helper = VcmtsdSetupEnvHelper(self.vnfd_helper,
+ self.ssh_helper,
+ self.scenario_helper)
+
+ def extract_pod_cfg(self, vcmts_pods_cfg, sg_id):
+ for pod_cfg in vcmts_pods_cfg:
+ if pod_cfg['sg_id'] == sg_id:
+ return pod_cfg
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ self._update_collectd_options(scenario_cfg, context_cfg)
+ self.scenario_helper.scenario_cfg = scenario_cfg
+ self.context_cfg = context_cfg
+
+ options = scenario_cfg.get('options', {})
+
+ try:
+ self.vcmts_influxdb_ip = options['vcmts_influxdb_ip']
+ self.vcmts_influxdb_port = options['vcmts_influxdb_port']
+ except KeyError:
+ raise KeyError("Missing destination InfluxDB details in scenario" \
+ " section of the task definition file")
+
+ try:
+ vcmtsd_values_filepath = options['vcmtsd_values']
+ except KeyError:
+ raise KeyError("Missing vcmtsd_values key in scenario options" \
+ "section of the task definition file")
+
+ if not os.path.isfile(vcmtsd_values_filepath):
+ raise RuntimeError("The vcmtsd_values file path provided " \
+ "does not exists")
+
+ # The yaml_loader.py (SafeLoader) underlying regex has an issue
+ # with reading PCI addresses (processed as double). so the
+ # BaseLoader is used here.
+ with open(vcmtsd_values_filepath) as stream:
+ vcmtsd_values = yaml.load(stream, Loader=yaml.BaseLoader)
+
+ if vcmtsd_values == None:
+ raise RuntimeError("Error reading vcmtsd_values file provided (" +
+ vcmtsd_values_filepath + ")")
+
+ vnf_options = options.get(self.name, {})
+ sg_id = str(vnf_options['sg_id'])
+ stream_dir = vnf_options['stream_dir']
+
+ try:
+ vcmts_pods_cfg = vcmtsd_values['topology']['vcmts_pods']
+ except KeyError:
+ raise KeyError("Missing vcmts_pods key in the " \
+ "vcmtsd_values file provided")
+
+ pod_cfg = self.extract_pod_cfg(vcmts_pods_cfg, sg_id)
+ if pod_cfg == None:
+ raise exceptions.IncorrectConfig(error_msg="Service group " + sg_id + " not found")
+
+ self.setup_helper.run_vcmtsd(stream_dir, pod_cfg)
+
+ def _update_collectd_options(self, scenario_cfg, context_cfg):
+ scenario_options = scenario_cfg.get('options', {})
+ generic_options = scenario_options.get('collectd', {})
+ scenario_node_options = scenario_options.get(self.name, {})\
+ .get('collectd', {})
+ context_node_options = context_cfg.get('nodes', {})\
+ .get(self.name, {}).get('collectd', {})
+
+ options = generic_options
+ self._update_options(options, scenario_node_options)
+ self._update_options(options, context_node_options)
+
+ self.setup_helper.collectd_options = options
+
+ def _update_options(self, options, additional_options):
+ for k, v in additional_options.items():
+ if isinstance(v, dict) and k in options:
+ options[k].update(v)
+ else:
+ options[k] = v
+
+ def wait_for_instantiate(self):
+ pass
+
+ def terminate(self):
+ pass
+
+ def scale(self, flavor=""):
+ pass
+
+ def collect_kpi(self):
+ self.influxdb_helper.copy_kpi()
+ return {"n/a": "n/a"}
+
+ def start_collect(self):
+ self.influxdb_helper = InfluxDBHelper(self.vcmts_influxdb_ip,
+ self.vcmts_influxdb_port)
+ self.influxdb_helper.start()
+
+ def stop_collect(self):
+ pass
diff --git a/yardstick/network_services/vnf_generic/vnf/vims_vnf.py b/yardstick/network_services/vnf_generic/vnf/vims_vnf.py
new file mode 100644
index 000000000..0e339b171
--- /dev/null
+++ b/yardstick/network_services/vnf_generic/vnf/vims_vnf.py
@@ -0,0 +1,105 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import logging
+import time
+
+from yardstick.network_services.vnf_generic.vnf import sample_vnf
+
+LOG = logging.getLogger(__name__)
+
+
+class VimsSetupEnvHelper(sample_vnf.SetupEnvHelper):
+
+ def setup_vnf_environment(self):
+ LOG.debug('VimsSetupEnvHelper:\n')
+
+
+class VimsResourceHelper(sample_vnf.ClientResourceHelper):
+ pass
+
+
+class VimsPcscfVnf(sample_vnf.SampleVNF):
+
+ APP_NAME = "VimsPcscf"
+ APP_WORD = "VimsPcscf"
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = VimsResourceHelper
+ if setup_env_helper_type is None:
+ setup_env_helper_type = VimsSetupEnvHelper
+ super(VimsPcscfVnf, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+
+ def wait_for_instantiate(self):
+ pass
+
+ def _run(self):
+ pass
+
+ def start_collect(self):
+ # TODO
+ pass
+
+ def collect_kpi(self):
+ # TODO
+ pass
+
+
+class VimsHssVnf(sample_vnf.SampleVNF):
+
+ APP_NAME = "VimsHss"
+ APP_WORD = "VimsHss"
+ CMD = "sudo /media/generate_user.sh {} {} >> /dev/null 2>&1"
+
+ def __init__(self, name, vnfd, setup_env_helper_type=None,
+ resource_helper_type=None):
+ if resource_helper_type is None:
+ resource_helper_type = VimsResourceHelper
+ if setup_env_helper_type is None:
+ setup_env_helper_type = VimsSetupEnvHelper
+ super(VimsHssVnf, self).__init__(name, vnfd, setup_env_helper_type,
+ resource_helper_type)
+ self.start_user = 1
+ self.end_user = 10000
+ self.WAIT_TIME = 600
+
+ def instantiate(self, scenario_cfg, context_cfg):
+ LOG.debug("scenario_cfg=%s\n", scenario_cfg)
+ self.start_user = scenario_cfg.get("options", {}).get("start_user", self.start_user)
+ self.end_user = scenario_cfg.get("options", {}).get("end_user", self.end_user)
+ # TODO
+ # Need to check HSS services are ready before generating user accounts
+ # Now, adding time sleep that manually configured by user
+ # to wait for HSS services.
+ # Note: for heat, waiting time is too long (~ 600s)
+ self.WAIT_TIME = scenario_cfg.get("options", {}).get("wait_time", self.WAIT_TIME)
+ time.sleep(self.WAIT_TIME)
+ LOG.debug("Generate user accounts from %d to %d\n",
+ self.start_user, self.end_user)
+ cmd = self.CMD.format(self.start_user, self.end_user)
+ self.ssh_helper.execute(cmd, None, 3600, False)
+
+ def wait_for_instantiate(self):
+ pass
+
+ def start_collect(self):
+ # TODO
+ pass
+
+ def collect_kpi(self):
+ # TODO
+ pass
diff --git a/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py b/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py
index 86c42ecfd..4e67b3c65 100644
--- a/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py
+++ b/yardstick/network_services/vnf_generic/vnf/vpp_helpers.py
@@ -12,14 +12,184 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import binascii
+import ipaddress
+import json
import logging
+import os
+import re
+import tempfile
+import time
+from collections import OrderedDict
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.network_services.helpers.cpu import CpuSysCores
from yardstick.network_services.vnf_generic.vnf.sample_vnf import \
DpdkVnfSetupEnvHelper
LOG = logging.getLogger(__name__)
+class VppConfigGenerator(object):
+ VPP_LOG_FILE = '/tmp/vpe.log'
+
+ def __init__(self):
+ self._nodeconfig = {}
+ self._vpp_config = ''
+
+ def add_config_item(self, config, value, path):
+ if len(path) == 1:
+ config[path[0]] = value
+ return
+ if path[0] not in config:
+ config[path[0]] = {}
+ elif isinstance(config[path[0]], str):
+ config[path[0]] = {} if config[path[0]] == '' \
+ else {config[path[0]]: ''}
+ self.add_config_item(config[path[0]], value, path[1:])
+
+ def add_unix_log(self, value=None):
+ path = ['unix', 'log']
+ if value is None:
+ value = self.VPP_LOG_FILE
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_unix_cli_listen(self, value='/run/vpp/cli.sock'):
+ path = ['unix', 'cli-listen']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_unix_nodaemon(self):
+ path = ['unix', 'nodaemon']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_unix_coredump(self):
+ path = ['unix', 'full-coredump']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_dev(self, *devices):
+ for device in devices:
+ if VppConfigGenerator.pci_dev_check(device):
+ path = ['dpdk', 'dev {0}'.format(device)]
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_cryptodev(self, count, cryptodev):
+ for i in range(count):
+ cryptodev_config = 'dev {0}'.format(
+ re.sub(r'\d.\d$', '1.' + str(i), cryptodev))
+ path = ['dpdk', cryptodev_config]
+ self.add_config_item(self._nodeconfig, '', path)
+ self.add_dpdk_uio_driver('igb_uio')
+
+ def add_dpdk_sw_cryptodev(self, sw_pmd_type, socket_id, count):
+ for _ in range(count):
+ cryptodev_config = 'vdev cryptodev_{0}_pmd,socket_id={1}'. \
+ format(sw_pmd_type, str(socket_id))
+ path = ['dpdk', cryptodev_config]
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_dev_default_rxq(self, value):
+ path = ['dpdk', 'dev default', 'num-rx-queues']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_dev_default_rxd(self, value):
+ path = ['dpdk', 'dev default', 'num-rx-desc']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_dev_default_txd(self, value):
+ path = ['dpdk', 'dev default', 'num-tx-desc']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_log_level(self, value):
+ path = ['dpdk', 'log-level']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_socketmem(self, value):
+ path = ['dpdk', 'socket-mem']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_num_mbufs(self, value):
+ path = ['dpdk', 'num-mbufs']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_dpdk_uio_driver(self, value=None):
+ path = ['dpdk', 'uio-driver']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_cpu_main_core(self, value):
+ path = ['cpu', 'main-core']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_cpu_corelist_workers(self, value):
+ path = ['cpu', 'corelist-workers']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_heapsize(self, value):
+ path = ['heapsize']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_ip6_hash_buckets(self, value):
+ path = ['ip6', 'hash-buckets']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_ip6_heap_size(self, value):
+ path = ['ip6', 'heap-size']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_ip_heap_size(self, value):
+ path = ['ip', 'heap-size']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_statseg_size(self, value):
+ path = ['statseg', 'size']
+ self.add_config_item(self._nodeconfig, value, path)
+
+ def add_plugin(self, state, *plugins):
+ for plugin in plugins:
+ path = ['plugins', 'plugin {0}'.format(plugin), state]
+ self.add_config_item(self._nodeconfig, ' ', path)
+
+ def add_dpdk_no_multi_seg(self):
+ path = ['dpdk', 'no-multi-seg']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def add_dpdk_no_tx_checksum_offload(self):
+ path = ['dpdk', 'no-tx-checksum-offload']
+ self.add_config_item(self._nodeconfig, '', path)
+
+ def dump_config(self, obj=None, level=-1):
+ if obj is None:
+ obj = self._nodeconfig
+ obj = OrderedDict(sorted(obj.items()))
+
+ indent = ' '
+ if level >= 0:
+ self._vpp_config += '{}{{\n'.format(level * indent)
+ if isinstance(obj, dict):
+ for key, val in obj.items():
+ if hasattr(val, '__iter__') and not isinstance(val, str):
+ self._vpp_config += '{}{}\n'.format((level + 1) * indent,
+ key)
+ self.dump_config(val, level + 1)
+ else:
+ self._vpp_config += '{}{} {}\n'.format(
+ (level + 1) * indent,
+ key, val)
+ if level >= 0:
+ self._vpp_config += '{}}}\n'.format(level * indent)
+
+ return self._vpp_config
+
+ @staticmethod
+ def pci_dev_check(pci_dev):
+ pattern = re.compile("^[0-9A-Fa-f]{4}:[0-9A-Fa-f]{2}:"
+ "[0-9A-Fa-f]{2}\\.[0-9A-Fa-f]$")
+ if not pattern.match(pci_dev):
+ raise ValueError('PCI address {addr} is not in valid format '
+ 'xxxx:xx:xx.x'.format(addr=pci_dev))
+ return True
+
+
class VppSetupEnvHelper(DpdkVnfSetupEnvHelper):
APP_NAME = "vpp"
CFG_CONFIG = "/etc/vpp/startup.conf"
@@ -31,6 +201,7 @@ class VppSetupEnvHelper(DpdkVnfSetupEnvHelper):
def __init__(self, vnfd_helper, ssh_helper, scenario_helper):
super(VppSetupEnvHelper, self).__init__(vnfd_helper, ssh_helper,
scenario_helper)
+ self.sys_cores = CpuSysCores(self.ssh_helper)
def kill_vnf(self):
ret_code, _, _ = \
@@ -74,3 +245,449 @@ class VppSetupEnvHelper(DpdkVnfSetupEnvHelper):
ifname=interface).get(key)
except (KeyError, ValueError):
return None
+
+ def vpp_create_ipsec_tunnels(self, if1_ip_addr, if2_ip_addr, if_name,
+ n_tunnels, n_connections, crypto_alg,
+ crypto_key, integ_alg, integ_key, addrs_ip,
+ spi_1=10000, spi_2=20000):
+ mask_length = 32
+ if n_connections <= n_tunnels:
+ count = 1
+ else:
+ count = int(n_connections / n_tunnels)
+ addr_ip_i = int(ipaddress.ip_address(str(addrs_ip)))
+ dst_start_ip = addr_ip_i
+
+ tmp_fd, tmp_path = tempfile.mkstemp()
+
+ vpp_ifname = self.get_value_by_interface_key(if_name, 'vpp_name')
+ ckey = binascii.hexlify(crypto_key.encode())
+ ikey = binascii.hexlify(integ_key.encode())
+
+ integ = ''
+ if crypto_alg.alg_name != 'aes-gcm-128':
+ integ = 'integ_alg {integ_alg} ' \
+ 'local_integ_key {local_integ_key} ' \
+ 'remote_integ_key {remote_integ_key} ' \
+ .format(integ_alg=integ_alg.alg_name,
+ local_integ_key=ikey,
+ remote_integ_key=ikey)
+ create_tunnels_cmds = 'ipsec_tunnel_if_add_del ' \
+ 'local_spi {local_spi} ' \
+ 'remote_spi {remote_spi} ' \
+ 'crypto_alg {crypto_alg} ' \
+ 'local_crypto_key {local_crypto_key} ' \
+ 'remote_crypto_key {remote_crypto_key} ' \
+ '{integ} ' \
+ 'local_ip {local_ip} ' \
+ 'remote_ip {remote_ip}\n'
+ start_tunnels_cmds = 'ip_add_del_route {raddr}/{mask} via {addr} ipsec{i}\n' \
+ 'exec set interface unnumbered ipsec{i} use {uifc}\n' \
+ 'sw_interface_set_flags ipsec{i} admin-up\n'
+
+ with os.fdopen(tmp_fd, 'w') as tmp_file:
+ for i in range(0, n_tunnels):
+ create_tunnel = create_tunnels_cmds.format(local_spi=spi_1 + i,
+ remote_spi=spi_2 + i,
+ crypto_alg=crypto_alg.alg_name,
+ local_crypto_key=ckey,
+ remote_crypto_key=ckey,
+ integ=integ,
+ local_ip=if1_ip_addr,
+ remote_ip=if2_ip_addr)
+ tmp_file.write(create_tunnel)
+ self.execute_script(tmp_path, json_out=False, copy_on_execute=True)
+ os.remove(tmp_path)
+
+ tmp_fd, tmp_path = tempfile.mkstemp()
+
+ with os.fdopen(tmp_fd, 'w') as tmp_file:
+ for i in range(0, n_tunnels):
+ if count > 1:
+ dst_start_ip = addr_ip_i + i * count
+ dst_end_ip = ipaddress.ip_address(dst_start_ip + count - 1)
+ ips = [ipaddress.ip_address(ip) for ip in
+ [str(ipaddress.ip_address(dst_start_ip)),
+ str(dst_end_ip)]]
+ lowest_ip, highest_ip = min(ips), max(ips)
+ mask_length = self.get_prefix_length(int(lowest_ip),
+ int(highest_ip),
+ lowest_ip.max_prefixlen)
+ # TODO check duplicate route for some IPs
+ elif count == 1:
+ dst_start_ip = addr_ip_i + i
+ start_tunnel = start_tunnels_cmds.format(
+ raddr=str(ipaddress.ip_address(dst_start_ip)),
+ mask=mask_length,
+ addr=if2_ip_addr,
+ i=i, count=count,
+ uifc=vpp_ifname)
+ tmp_file.write(start_tunnel)
+ # TODO add route for remain IPs
+
+ self.execute_script(tmp_path, json_out=False, copy_on_execute=True)
+ os.remove(tmp_path)
+
+ def apply_config(self, vpp_cfg, restart_vpp=True):
+ vpp_config = vpp_cfg.dump_config()
+ ret, _, _ = \
+ self.ssh_helper.execute('echo "{config}" | sudo tee {filename}'.
+ format(config=vpp_config,
+ filename=self.CFG_CONFIG))
+ if ret != 0:
+ raise RuntimeError('Writing config file failed')
+ if restart_vpp:
+ self.start_vpp_service()
+
+ def vpp_route_add(self, network, prefix_len, gateway=None, interface=None,
+ use_sw_index=True, resolve_attempts=10,
+ count=1, vrf=None, lookup_vrf=None, multipath=False,
+ weight=None, local=False):
+ if interface:
+ if use_sw_index:
+ int_cmd = ('sw_if_index {}'.format(
+ self.get_value_by_interface_key(interface,
+ 'vpp_sw_index')))
+ else:
+ int_cmd = interface
+ else:
+ int_cmd = ''
+
+ rap = 'resolve-attempts {}'.format(resolve_attempts) \
+ if resolve_attempts else ''
+
+ via = 'via {}'.format(gateway) if gateway else ''
+
+ cnt = 'count {}'.format(count) \
+ if count else ''
+
+ vrf = 'vrf {}'.format(vrf) if vrf else ''
+
+ lookup_vrf = 'lookup-in-vrf {}'.format(
+ lookup_vrf) if lookup_vrf else ''
+
+ multipath = 'multipath' if multipath else ''
+
+ weight = 'weight {}'.format(weight) if weight else ''
+
+ local = 'local' if local else ''
+
+ with VatTerminal(self.ssh_helper, json_param=False) as vat:
+ vat.vat_terminal_exec_cmd_from_template('add_route.vat',
+ network=network,
+ prefix_length=prefix_len,
+ via=via,
+ vrf=vrf,
+ interface=int_cmd,
+ resolve_attempts=rap,
+ count=cnt,
+ lookup_vrf=lookup_vrf,
+ multipath=multipath,
+ weight=weight,
+ local=local)
+
+ def add_arp_on_dut(self, iface_key, ip_address, mac_address):
+ with VatTerminal(self.ssh_helper) as vat:
+ return vat.vat_terminal_exec_cmd_from_template(
+ 'add_ip_neighbor.vat',
+ sw_if_index=self.get_value_by_interface_key(iface_key,
+ 'vpp_sw_index'),
+ ip_address=ip_address, mac_address=mac_address)
+
+ def set_ip(self, interface, address, prefix_length):
+ with VatTerminal(self.ssh_helper) as vat:
+ return vat.vat_terminal_exec_cmd_from_template(
+ 'add_ip_address.vat',
+ sw_if_index=self.get_value_by_interface_key(interface,
+ 'vpp_sw_index'),
+ address=address, prefix_length=prefix_length)
+
+ def set_interface_state(self, interface, state):
+ sw_if_index = self.get_value_by_interface_key(interface,
+ 'vpp_sw_index')
+
+ if state == 'up':
+ state = 'admin-up link-up'
+ elif state == 'down':
+ state = 'admin-down link-down'
+ else:
+ raise ValueError('Unexpected interface state: {}'.format(state))
+ with VatTerminal(self.ssh_helper) as vat:
+ return vat.vat_terminal_exec_cmd_from_template(
+ 'set_if_state.vat', sw_if_index=sw_if_index, state=state)
+
+ def vpp_set_interface_mtu(self, interface, mtu=9200):
+ sw_if_index = self.get_value_by_interface_key(interface,
+ 'vpp_sw_index')
+ if sw_if_index:
+ with VatTerminal(self.ssh_helper, json_param=False) as vat:
+ vat.vat_terminal_exec_cmd_from_template(
+ "hw_interface_set_mtu.vat", sw_if_index=sw_if_index,
+ mtu=mtu)
+
+ def vpp_interfaces_ready_wait(self, timeout=30):
+ if_ready = False
+ not_ready = []
+ start = time.time()
+ while not if_ready:
+ out = self.vpp_get_interface_data()
+ if time.time() - start > timeout:
+ for interface in out:
+ if interface.get('admin_up_down') == 1:
+ if interface.get('link_up_down') != 1:
+ LOG.debug('%s link-down',
+ interface.get('interface_name'))
+ raise RuntimeError('timeout, not up {0}'.format(not_ready))
+ not_ready = []
+ for interface in out:
+ if interface.get('admin_up_down') == 1:
+ if interface.get('link_up_down') != 1:
+ not_ready.append(interface.get('interface_name'))
+ if not not_ready:
+ if_ready = True
+ else:
+ LOG.debug('Interfaces still in link-down state: %s, '
+ 'waiting...', not_ready)
+ time.sleep(1)
+
+ def vpp_get_interface_data(self, interface=None):
+ with VatTerminal(self.ssh_helper) as vat:
+ response = vat.vat_terminal_exec_cmd_from_template(
+ "interface_dump.vat")
+ data = response[0]
+ if interface is not None:
+ if isinstance(interface, str):
+ param = "interface_name"
+ elif isinstance(interface, int):
+ param = "sw_if_index"
+ else:
+ raise TypeError
+ for data_if in data:
+ if data_if[param] == interface:
+ return data_if
+ return dict()
+ return data
+
+ def update_vpp_interface_data(self):
+ data = {}
+ interface_dump_json = self.execute_script_json_out(
+ "dump_interfaces.vat")
+ interface_list = json.loads(interface_dump_json)
+ for interface in self.vnfd_helper.interfaces:
+ if_mac = interface['virtual-interface']['local_mac']
+ interface_dict = VppSetupEnvHelper.get_vpp_interface_by_mac(
+ interface_list, if_mac)
+ if not interface_dict:
+ LOG.debug('Interface %s not found by MAC %s', interface,
+ if_mac)
+ continue
+ data[interface['virtual-interface']['ifname']] = {
+ 'vpp_name': interface_dict["interface_name"],
+ 'vpp_sw_index': interface_dict["sw_if_index"]
+ }
+ for iface_key, updated_vnfd in data.items():
+ self._update_vnfd_helper(updated_vnfd, iface_key)
+
+ def iface_update_numa(self):
+ iface_numa = {}
+ for interface in self.vnfd_helper.interfaces:
+ cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(
+ interface["virtual-interface"]["vpci"])
+ ret, out, _ = self.ssh_helper.execute(cmd)
+ if ret == 0:
+ try:
+ numa_node = int(out)
+ if numa_node < 0:
+ if self.vnfd_helper["cpuinfo"][-1][3] + 1 == 1:
+ iface_numa[
+ interface['virtual-interface']['ifname']] = {
+ 'numa_node': 0
+ }
+ else:
+ raise ValueError
+ else:
+ iface_numa[
+ interface['virtual-interface']['ifname']] = {
+ 'numa_node': numa_node
+ }
+ except ValueError:
+ LOG.debug(
+ 'Reading numa location failed for: %s',
+ interface["virtual-interface"]["vpci"])
+ for iface_key, updated_vnfd in iface_numa.items():
+ self._update_vnfd_helper(updated_vnfd, iface_key)
+
+ def execute_script(self, vat_name, json_out=True, copy_on_execute=False):
+ if copy_on_execute:
+ self.ssh_helper.put_file(vat_name, vat_name)
+ remote_file_path = vat_name
+ else:
+ vat_path = self.ssh_helper.join_bin_path("vpp", "templates")
+ remote_file_path = '{0}/{1}'.format(vat_path, vat_name)
+
+ cmd = "{vat_bin} {json} in {vat_path} script".format(
+ vat_bin=self.VAT_BIN_NAME,
+ json="json" if json_out is True else "",
+ vat_path=remote_file_path)
+
+ try:
+ return self.ssh_helper.execute(cmd=cmd)
+ except Exception:
+ raise RuntimeError("VAT script execution failed: {0}".format(cmd))
+
+ def execute_script_json_out(self, vat_name):
+ vat_path = self.ssh_helper.join_bin_path("vpp", "templates")
+ remote_file_path = '{0}/{1}'.format(vat_path, vat_name)
+
+ _, stdout, _ = self.execute_script(vat_name, json_out=True)
+ return self.cleanup_vat_json_output(stdout, vat_file=remote_file_path)
+
+ @staticmethod
+ def cleanup_vat_json_output(json_output, vat_file=None):
+ retval = json_output
+ clutter = ['vat#', 'dump_interface_table error: Misc',
+ 'dump_interface_table:6019: JSON output supported only ' \
+ 'for VPE API calls and dump_stats_table']
+ if vat_file:
+ clutter.append("{0}(2):".format(vat_file))
+ for garbage in clutter:
+ retval = retval.replace(garbage, '')
+ return retval.strip()
+
+ @staticmethod
+ def _convert_mac_to_number_list(mac_address):
+ list_mac = []
+ for num in mac_address.split(":"):
+ list_mac.append(int(num, 16))
+ return list_mac
+
+ @staticmethod
+ def get_vpp_interface_by_mac(interfaces_list, mac_address):
+ interface_dict = {}
+ list_mac_address = VppSetupEnvHelper._convert_mac_to_number_list(
+ mac_address)
+ LOG.debug("MAC address %s converted to list %s.", mac_address,
+ list_mac_address)
+ for interface in interfaces_list:
+ # TODO: create vat json integrity checking and move there
+ if "l2_address" not in interface:
+ raise KeyError(
+ "key l2_address not found in interface dict."
+ "Probably input list is not parsed from correct VAT "
+ "json output.")
+ if "l2_address_length" not in interface:
+ raise KeyError(
+ "key l2_address_length not found in interface "
+ "dict. Probably input list is not parsed from correct "
+ "VAT json output.")
+ mac_from_json = interface["l2_address"][:6]
+ if mac_from_json == list_mac_address:
+ if interface["l2_address_length"] != 6:
+ raise ValueError("l2_address_length value is not 6.")
+ interface_dict = interface
+ break
+ return interface_dict
+
+ @staticmethod
+ def get_prefix_length(number1, number2, bits):
+ for i in range(bits):
+ if number1 >> i == number2 >> i:
+ return bits - i
+ return 0
+
+
+class VatTerminal(object):
+
+ __VAT_PROMPT = ("vat# ",)
+ __LINUX_PROMPT = (":~# ", ":~$ ", "~]$ ", "~]# ")
+
+
+ def __init__(self, ssh_helper, json_param=True):
+ json_text = ' json' if json_param else ''
+ self.json = json_param
+ self.ssh_helper = ssh_helper
+ EXEC_RETRY = 3
+
+ try:
+ self._tty = self.ssh_helper.interactive_terminal_open()
+ except Exception:
+ raise RuntimeError("Cannot open interactive terminal")
+
+ for _ in range(EXEC_RETRY):
+ try:
+ self.ssh_helper.interactive_terminal_exec_command(
+ self._tty,
+ 'sudo -S {0}{1}'.format(VppSetupEnvHelper.VAT_BIN_NAME,
+ json_text),
+ self.__VAT_PROMPT)
+ except exceptions.SSHTimeout:
+ continue
+ else:
+ break
+
+ self._exec_failure = False
+ self.vat_stdout = None
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.vat_terminal_close()
+
+ def vat_terminal_exec_cmd(self, cmd):
+ try:
+ out = self.ssh_helper.interactive_terminal_exec_command(self._tty,
+ cmd,
+ self.__VAT_PROMPT)
+ self.vat_stdout = out
+ except exceptions.SSHTimeout:
+ self._exec_failure = True
+ raise RuntimeError(
+ "VPP is not running on node. VAT command {0} execution failed".
+ format(cmd))
+ if self.json:
+ obj_start = out.find('{')
+ obj_end = out.rfind('}')
+ array_start = out.find('[')
+ array_end = out.rfind(']')
+
+ if obj_start == -1 and array_start == -1:
+ raise RuntimeError(
+ "VAT command {0}: no JSON data.".format(cmd))
+
+ if obj_start < array_start or array_start == -1:
+ start = obj_start
+ end = obj_end + 1
+ else:
+ start = array_start
+ end = array_end + 1
+ out = out[start:end]
+ json_out = json.loads(out)
+ return json_out
+ else:
+ return None
+
+ def vat_terminal_close(self):
+ if not self._exec_failure:
+ try:
+ self.ssh_helper.interactive_terminal_exec_command(self._tty,
+ 'quit',
+ self.__LINUX_PROMPT)
+ except exceptions.SSHTimeout:
+ raise RuntimeError("Failed to close VAT console")
+ try:
+ self.ssh_helper.interactive_terminal_close(self._tty)
+ except Exception:
+ raise RuntimeError("Cannot close interactive terminal")
+
+ def vat_terminal_exec_cmd_from_template(self, vat_template_file, **args):
+ file_path = os.path.join(constants.YARDSTICK_ROOT_PATH,
+ 'yardstick/resources/templates/',
+ vat_template_file)
+ with open(file_path, 'r') as template_file:
+ cmd_template = template_file.readlines()
+ ret = []
+ for line_tmpl in cmd_template:
+ vat_cmd = line_tmpl.format(**args)
+ ret.append(self.vat_terminal_exec_cmd(vat_cmd.replace('\n', '')))
+ return ret
diff --git a/yardstick/resources/templates/add_ip_address.vat b/yardstick/resources/templates/add_ip_address.vat
new file mode 100644
index 000000000..d59480c33
--- /dev/null
+++ b/yardstick/resources/templates/add_ip_address.vat
@@ -0,0 +1 @@
+sw_interface_add_del_address sw_if_index {sw_if_index} {address}/{prefix_length}
diff --git a/yardstick/resources/templates/add_ip_neighbor.vat b/yardstick/resources/templates/add_ip_neighbor.vat
new file mode 100644
index 000000000..730e7112a
--- /dev/null
+++ b/yardstick/resources/templates/add_ip_neighbor.vat
@@ -0,0 +1 @@
+ip_neighbor_add_del sw_if_index {sw_if_index} dst {ip_address} mac {mac_address}
diff --git a/yardstick/resources/templates/add_route.vat b/yardstick/resources/templates/add_route.vat
new file mode 100644
index 000000000..64c6a6c3b
--- /dev/null
+++ b/yardstick/resources/templates/add_route.vat
@@ -0,0 +1 @@
+ip_add_del_route {network}/{prefix_length} {via} {vrf} {interface} {resolve_attempts} {count} {lookup_vrf} {multipath} {weight} {local} \ No newline at end of file
diff --git a/yardstick/resources/templates/del_route.vat b/yardstick/resources/templates/del_route.vat
new file mode 100644
index 000000000..e7fe4bc1e
--- /dev/null
+++ b/yardstick/resources/templates/del_route.vat
@@ -0,0 +1 @@
+ip_add_del_route {network}/{prefix_length} via {gateway} sw_if_index {sw_if_index} del \ No newline at end of file
diff --git a/yardstick/resources/templates/flush_ip_addresses.vat b/yardstick/resources/templates/flush_ip_addresses.vat
new file mode 100644
index 000000000..f38fcf12c
--- /dev/null
+++ b/yardstick/resources/templates/flush_ip_addresses.vat
@@ -0,0 +1 @@
+sw_interface_add_del_address sw_if_index {sw_if_index} del-all \ No newline at end of file
diff --git a/yardstick/resources/templates/hw_interface_set_mtu.vat b/yardstick/resources/templates/hw_interface_set_mtu.vat
new file mode 100644
index 000000000..645d1a80c
--- /dev/null
+++ b/yardstick/resources/templates/hw_interface_set_mtu.vat
@@ -0,0 +1 @@
+hw_interface_set_mtu sw_if_index {sw_if_index} mtu {mtu}
diff --git a/yardstick/resources/templates/interface_dump.vat b/yardstick/resources/templates/interface_dump.vat
new file mode 100644
index 000000000..850c348f6
--- /dev/null
+++ b/yardstick/resources/templates/interface_dump.vat
@@ -0,0 +1 @@
+sw_interface_dump
diff --git a/yardstick/resources/templates/set_if_state.vat b/yardstick/resources/templates/set_if_state.vat
new file mode 100644
index 000000000..e2c2d4b29
--- /dev/null
+++ b/yardstick/resources/templates/set_if_state.vat
@@ -0,0 +1 @@
+sw_interface_set_flags sw_if_index {sw_if_index} {state}
diff --git a/yardstick/tests/unit/network_services/helpers/test_cpu.py b/yardstick/tests/unit/network_services/helpers/test_cpu.py
index c28178d4b..a1c0826fb 100644
--- a/yardstick/tests/unit/network_services/helpers/test_cpu.py
+++ b/yardstick/tests/unit/network_services/helpers/test_cpu.py
@@ -141,3 +141,75 @@ class TestCpuSysCores(unittest.TestCase):
def test__str2int_error(self):
self.assertEqual(0, CpuSysCores._str2int("err"))
+
+ def test_smt_enabled(self):
+ self.assertEqual(False, CpuSysCores.smt_enabled(
+ {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}))
+
+ def test_is_smt_enabled(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual(False, cpu_topo.is_smt_enabled())
+
+ def test_cpu_list_per_node(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual([0, 1], cpu_topo.cpu_list_per_node(0, False))
+
+ def test_cpu_list_per_node_error(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'err': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ with self.assertRaises(RuntimeError) as raised:
+ cpu_topo.cpu_list_per_node(0, False)
+ self.assertIn('Node cpuinfo not available.', str(raised.exception))
+
+ def test_cpu_list_per_node_smt_error(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ with self.assertRaises(RuntimeError) as raised:
+ cpu_topo.cpu_list_per_node(0, True)
+ self.assertIn('SMT is not enabled.', str(raised.exception))
+
+ def test_cpu_slice_of_list_per_node(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual([1],
+ cpu_topo.cpu_slice_of_list_per_node(0, 1, 0,
+ False))
+
+ def test_cpu_slice_of_list_per_node_error(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ with self.assertRaises(RuntimeError) as raised:
+ cpu_topo.cpu_slice_of_list_per_node(1, 1, 1, False)
+ self.assertIn('cpu_cnt + skip_cnt > length(cpu list).',
+ str(raised.exception))
+
+ def test_cpu_list_per_node_str(self):
+ with mock.patch("yardstick.ssh.SSH") as ssh:
+ ssh_mock = mock.Mock(autospec=ssh.SSH)
+ cpu_topo = CpuSysCores(ssh_mock)
+ cpu_topo.cpuinfo = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 1, 0, 0, 0, 1, 1, 1, 0]]}
+ self.assertEqual("1",
+ cpu_topo.cpu_list_per_node_str(0, 1, 1, ',',
+ False))
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/__init__.py
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py
new file mode 100644
index 000000000..d3145546a
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_multiple_loss_ratio_search.py
@@ -0,0 +1,2164 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+import mock
+
+from yardstick.network_services.helpers.vpp_helpers.multiple_loss_ratio_search import \
+ MultipleLossRatioSearch
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+from yardstick.network_services.traffic_profile.rfc2544 import PortPgIDMap
+
+
+class TestMultipleLossRatioSearch(unittest.TestCase):
+
+ def test___init__(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(True, algorithm.latency)
+ self.assertEqual(64, algorithm.pkt_size)
+ self.assertEqual(30, algorithm.final_trial_duration)
+ self.assertEqual(0.005, algorithm.final_relative_width)
+ self.assertEqual(2, algorithm.number_of_intermediate_phases)
+ self.assertEqual(1, algorithm.initial_trial_duration)
+ self.assertEqual(720, algorithm.timeout)
+ self.assertEqual(1, algorithm.doublings)
+
+ def test_double_relative_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(0.00997, algorithm.double_relative_width(0.005))
+
+ def test_double_step_down(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(99003.0, algorithm.double_step_down(0.005, 100000))
+
+ def test_expand_down(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(99003.0, algorithm.expand_down(0.005, 1, 100000))
+
+ def test_double_step_up(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(101007.0401907013,
+ algorithm.double_step_up(0.005, 100000))
+
+ def test_expand_up(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(101007.0401907013,
+ algorithm.expand_up(0.005, 1, 100000))
+
+ def test_half_relative_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(0.0025031328369998773,
+ algorithm.half_relative_width(0.005))
+
+ def test_half_step_up(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ self.assertEqual(100250.94142341711,
+ algorithm.half_step_up(0.005, 100000))
+
+ def test_init_generator(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(),
+ mock.Mock(), mock.Mock()))
+ self.assertEqual(ports, algorithm.ports)
+ self.assertEqual(port_pg_id, algorithm.port_pg_id)
+
+ def test_collect_kpi(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ algorithm.init_generator(ports, port_pg_id, mock.Mock, mock.Mock,
+ mock.Mock())
+ self.assertIsNone(algorithm.collect_kpi({}, 100000))
+
+ def test_narrow_down_ndr_and_pdr(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, 'ndrpdr') as \
+ mock_ndrpdr:
+ ndr_measured_low = ReceiveRateMeasurement(10, 13880000, 13879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(10, 14880000, 14879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(10, 11880000, 11879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(10, 12880000, 12879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock_ndrpdr.return_value = MultipleLossRatioSearch.ProgressState(
+ starting_result, 2, 30, 0.005, 0.0,
+ 4857361, 4977343)
+ self.assertEqual(
+ {'Result_NDR_LOWER': {'bandwidth_total_Gbps': 0.9327310944,
+ 'rate_total_pps': 1387992.7},
+ 'Result_NDR_UPPER': {
+ 'bandwidth_total_Gbps': 0.9999310943999999,
+ 'rate_total_pps': 1487992.7},
+ 'Result_NDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_PDR_LOWER': {
+ 'bandwidth_total_Gbps': 0.7983310943999999,
+ 'rate_total_pps': 1187992.7},
+ 'Result_PDR_UPPER': {'bandwidth_total_Gbps': 0.8655310944,
+ 'rate_total_pps': 1287992.7},
+ 'Result_PDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_stream0_NDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream0_PDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream1_NDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0},
+ 'Result_stream1_PDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0}},
+ algorithm.narrow_down_ndr_and_pdr(12880000, 15880000, 0.0))
+
+ def test__measure_and_update_state(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ starting_result = NdrPdrResult(starting_interval, starting_interval)
+ previous_state = MultipleLossRatioSearch.ProgressState(starting_result,
+ 2, 30, 0.005,
+ 0.0, 4857361,
+ 4977343)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure:
+ mock_measure.return_value = ReceiveRateMeasurement(1,
+ 4626121.09635,
+ 4626100, 13074)
+ state = algorithm._measure_and_update_state(previous_state,
+ 4626121.09635)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(1, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(4626121.09635,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(4626100,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(13074,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(4613026,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(4626100,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(13074.0,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(4613026.0,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00283,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(1, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(4857361,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(4857339,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(84965,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(4772374,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(4857339,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(84965.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(4772374.0,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.01749,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(1, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(4626121.09635,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(4626100,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(13074,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(4613026,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(4626100,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(13074.0,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(4613026.0,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00283,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(1, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(4857361,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(4857339,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(84965,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(4772374,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(4857339,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(84965.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(4772374.0,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.01749,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(2, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(4857361, state.minimum_transmit_rate)
+ self.assertEqual(4977343, state.maximum_transmit_rate)
+
+ def test_new_interval(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 3972540.4108, 21758482, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.0)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(3972540.4108, result.measured_low.target_tr)
+ self.assertEqual(21758482, result.measured_low.transmit_count)
+ self.assertEqual(0, result.measured_low.loss_count)
+ self.assertEqual(21758482, result.measured_low.receive_count)
+ self.assertEqual(21758482, result.measured_low.transmit_rate)
+ self.assertEqual(0.0, result.measured_low.loss_rate)
+ self.assertEqual(21758482.0, result.measured_low.receive_rate)
+ self.assertEqual(0.0, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4857361, result.measured_high.target_tr)
+ self.assertEqual(4857339, result.measured_high.transmit_count)
+ self.assertEqual(84965, result.measured_high.loss_count)
+ self.assertEqual(4772374, result.measured_high.receive_count)
+ self.assertEqual(4857339, result.measured_high.transmit_rate)
+ self.assertEqual(84965.0, result.measured_high.loss_rate)
+ self.assertEqual(4772374.0, result.measured_high.receive_rate)
+ self.assertEqual(0.01749, result.measured_high.loss_fraction)
+
+ def test_new_interval_zero(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4977343, 21758482, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.0)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(21758482, result.measured_high.transmit_count)
+ self.assertEqual(0, result.measured_high.loss_count)
+ self.assertEqual(21758482, result.measured_high.receive_count)
+ self.assertEqual(21758482.0, result.measured_high.transmit_rate)
+ self.assertEqual(0.0, result.measured_high.loss_rate)
+ self.assertEqual(21758482.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0, result.measured_high.loss_fraction)
+
+ def test_new_interval_one(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 5000000, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.0)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_1st(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4000000, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.5)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_1st_loss(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4000000, 2175848, 1000000)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.02)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4000000.0, result.measured_low.target_tr)
+ self.assertEqual(2175848, result.measured_low.transmit_count)
+ self.assertEqual(1000000, result.measured_low.loss_count)
+ self.assertEqual(1175848, result.measured_low.receive_count)
+ self.assertEqual(2175848.0, result.measured_low.transmit_rate)
+ self.assertEqual(1000000.0, result.measured_low.loss_rate)
+ self.assertEqual(1175848.0, result.measured_low.receive_rate)
+ self.assertEqual(0.45959, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_2nd(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 5000000, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.5)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4977343.0, result.measured_low.target_tr)
+ self.assertEqual(4977320, result.measured_low.transmit_count)
+ self.assertEqual(119959, result.measured_low.loss_count)
+ self.assertEqual(4857361, result.measured_low.receive_count)
+ self.assertEqual(4977320.0, result.measured_low.transmit_rate)
+ self.assertEqual(119959.0, result.measured_low.loss_rate)
+ self.assertEqual(4857361.0, result.measured_low.receive_rate)
+ self.assertEqual(0.0241, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(5000000.0, result.measured_high.target_tr)
+ self.assertEqual(2175848, result.measured_high.transmit_count)
+ self.assertEqual(0, result.measured_high.loss_count)
+ self.assertEqual(2175848, result.measured_high.receive_count)
+ self.assertEqual(2175848.0, result.measured_high.transmit_rate)
+ self.assertEqual(0.0, result.measured_high.loss_rate)
+ self.assertEqual(2175848.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_3rd(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4867361, 2175848, 0)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.5)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4867361.0, result.measured_low.target_tr)
+ self.assertEqual(2175848, result.measured_low.transmit_count)
+ self.assertEqual(0, result.measured_low.loss_count)
+ self.assertEqual(2175848, result.measured_low.receive_count)
+ self.assertEqual(2175848.0, result.measured_low.transmit_rate)
+ self.assertEqual(0.0, result.measured_low.loss_rate)
+ self.assertEqual(2175848.0, result.measured_low.receive_rate)
+ self.assertEqual(0.0, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4977343.0, result.measured_high.target_tr)
+ self.assertEqual(4977320, result.measured_high.transmit_count)
+ self.assertEqual(119959, result.measured_high.loss_count)
+ self.assertEqual(4857361, result.measured_high.receive_count)
+ self.assertEqual(4977320.0, result.measured_high.transmit_rate)
+ self.assertEqual(119959.0, result.measured_high.loss_rate)
+ self.assertEqual(4857361.0, result.measured_high.receive_rate)
+ self.assertEqual(0.0241, result.measured_high.loss_fraction)
+
+ def test_new_interval_valid_3rd_loss(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ measured = ReceiveRateMeasurement(1, 4867361, 2175848, 1000000)
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ result = algorithm._new_interval(receive_rate_interval, measured, 0.2)
+ self.assertIsInstance(result, ReceiveRateInterval)
+ self.assertEqual(1, result.measured_low.duration)
+ self.assertEqual(4857361.0, result.measured_low.target_tr)
+ self.assertEqual(4857339, result.measured_low.transmit_count)
+ self.assertEqual(84965, result.measured_low.loss_count)
+ self.assertEqual(4772374, result.measured_low.receive_count)
+ self.assertEqual(4857339.0, result.measured_low.transmit_rate)
+ self.assertEqual(84965.0, result.measured_low.loss_rate)
+ self.assertEqual(4772374.0, result.measured_low.receive_rate)
+ self.assertEqual(0.01749, result.measured_low.loss_fraction)
+ self.assertEqual(1, result.measured_high.duration)
+ self.assertEqual(4867361.0, result.measured_high.target_tr)
+ self.assertEqual(2175848, result.measured_high.transmit_count)
+ self.assertEqual(1000000, result.measured_high.loss_count)
+ self.assertEqual(1175848, result.measured_high.receive_count)
+ self.assertEqual(2175848.0, result.measured_high.transmit_rate)
+ self.assertEqual(1000000.0, result.measured_high.loss_rate)
+ self.assertEqual(1175848.0, result.measured_high.receive_rate)
+ self.assertEqual(0.45959, result.measured_high.loss_fraction)
+
+ def test_ndrpdr(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure:
+ measured_low = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_ndr_rel_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ measured_low = ReceiveRateMeasurement(30, 880000, 879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ ending_interval = ReceiveRateInterval(measured_high, measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ ending_result = NdrPdrResult(ending_interval, ending_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_pdr_rel_width(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 880000, 879927, 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(ndr_interval, ndr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_ndr_lo_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ measured_low = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 100)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(starting_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_ndr_hi_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ measured_low = ReceiveRateMeasurement(60, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 100)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(starting_result, -1, 30,
+ 0.005, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(60.0, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(247998.78333,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(247998.78333,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(60.0, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(247998.78333,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(247998.78333,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879827,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495994.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(1e-05,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.005, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_error(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=0)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure:
+ measured_low = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(30, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ with self.assertRaises(RuntimeError) as raised:
+ algorithm.ndrpdr(previous_state)
+
+ self.assertIn('Optimized search takes too long.',
+ str(raised.exception))
+
+ def test_ndrpdr_update_state_ndr_hi(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_ndr_hi_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 4880000,
+ 10880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0, state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(0, state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_ndr_lo(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 100000)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 100000)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 100000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_lo(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 100000)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 100000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_lo_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ pdr_measured_high = ReceiveRateMeasurement(30, 14880000, 14879927,
+ 100000)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(pdr_interval, pdr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 14880000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(14880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(12880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(14880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(14879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(14779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(495997.56667,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(492664.23333,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00672,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_hi(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 13880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(ndr_interval, ndr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 30, 0.005, 0.0, 100000,
+ 14880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(12880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_ndrpdr_update_state_pdr_hi_duration(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock(), mock.Mock,
+ mock.Mock()))
+ with mock.patch.object(algorithm, 'measure') as \
+ mock_measure, \
+ mock.patch.object(algorithm, '_measure_and_update_state') as \
+ mock__measure_and_update_state:
+ ndr_measured_low = ReceiveRateMeasurement(30, 10880000, 10879927,
+ 0)
+ ndr_measured_high = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 100000)
+ ndr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_low = ReceiveRateMeasurement(30, 12880000, 12879927,
+ 0)
+ pdr_measured_high = ReceiveRateMeasurement(30, 13880000, 14879927,
+ 0)
+ pdr_measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ pdr_measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ ndr_interval = ReceiveRateInterval(ndr_measured_low,
+ ndr_measured_high)
+ pdr_interval = ReceiveRateInterval(pdr_measured_low,
+ pdr_measured_high)
+ starting_result = NdrPdrResult(ndr_interval, pdr_interval)
+ ending_result = NdrPdrResult(ndr_interval, ndr_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock__measure_and_update_state.return_value = \
+ MultipleLossRatioSearch.ProgressState(ending_result, -1, 30,
+ 0.2, 0.0, 14880000,
+ 14880000)
+ previous_state = MultipleLossRatioSearch.ProgressState(
+ starting_result, -1, 50, 0.005, 0.0, 100000,
+ 10880000)
+ state = algorithm.ndrpdr(previous_state)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertIsInstance(state, MultipleLossRatioSearch.ProgressState)
+ self.assertEqual(30, state.result.ndr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.ndr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.ndr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.ndr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.ndr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.ndr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.ndr_interval.measured_high.duration)
+ self.assertEqual(12880000.0,
+ state.result.ndr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.ndr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.ndr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.ndr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.ndr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.ndr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.ndr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.ndr_interval.measured_high.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_low.duration)
+ self.assertEqual(10880000.0,
+ state.result.pdr_interval.measured_low.target_tr)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.transmit_count)
+ self.assertEqual(0,
+ state.result.pdr_interval.measured_low.loss_count)
+ self.assertEqual(10879927,
+ state.result.pdr_interval.measured_low.receive_count)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.transmit_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_rate)
+ self.assertEqual(362664.23333,
+ state.result.pdr_interval.measured_low.receive_rate)
+ self.assertEqual(0.0,
+ state.result.pdr_interval.measured_low.loss_fraction)
+ self.assertEqual(30, state.result.pdr_interval.measured_high.duration)
+ self.assertEqual(12880000,
+ state.result.pdr_interval.measured_high.target_tr)
+ self.assertEqual(12879927,
+ state.result.pdr_interval.measured_high.transmit_count)
+ self.assertEqual(100000,
+ state.result.pdr_interval.measured_high.loss_count)
+ self.assertEqual(12779927,
+ state.result.pdr_interval.measured_high.receive_count)
+ self.assertEqual(429330.9,
+ state.result.pdr_interval.measured_high.transmit_rate)
+ self.assertEqual(3333.33333,
+ state.result.pdr_interval.measured_high.loss_rate)
+ self.assertEqual(425997.56667,
+ state.result.pdr_interval.measured_high.receive_rate)
+ self.assertEqual(0.00776,
+ state.result.pdr_interval.measured_high.loss_fraction)
+ self.assertEqual(-1, state.phases)
+ self.assertEqual(30, state.duration)
+ self.assertEqual(0.2, state.width_goal)
+ self.assertEqual(0.0, state.packet_loss_ratio)
+ self.assertEqual(14880000, state.minimum_transmit_rate)
+ self.assertEqual(14880000, state.maximum_transmit_rate)
+
+ def test_measure(self):
+ measurer = mock.MagicMock()
+ measurer.sent = 102563094
+ measurer.loss = 30502
+ algorithm = MultipleLossRatioSearch(measurer=measurer, latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.MagicMock(),
+ mock.Mock, mock.Mock()))
+ measurement = algorithm.measure(30, 3418770.3425, True)
+ self.assertIsInstance(measurement, ReceiveRateMeasurement)
+ self.assertEqual(30, measurement.duration)
+ self.assertEqual(3418770.3425, measurement.target_tr)
+ self.assertEqual(102563094, measurement.transmit_count)
+ self.assertEqual(30502, measurement.loss_count)
+ self.assertEqual(102532592, measurement.receive_count)
+ self.assertEqual(3418769.8, measurement.transmit_rate)
+ self.assertEqual(1016.73333, measurement.loss_rate)
+ self.assertEqual(3417753.06667, measurement.receive_rate)
+ self.assertEqual(0.0003, measurement.loss_fraction)
+
+ def test_perform_additional_measurements_based_on_ndrpdr_result(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ ports = [0, 1]
+ port_pg_id = PortPgIDMap()
+ port_pg_id.add_port(0)
+ port_pg_id.add_port(1)
+ self.assertIsNone(
+ algorithm.init_generator(ports, port_pg_id, mock.Mock, mock.Mock,
+ mock.Mock()))
+ result = mock.MagicMock()
+ result.ndr_interval.measured_low.target_tr.return_result = 100000
+ self.assertIsNone(
+ algorithm.perform_additional_measurements_based_on_ndrpdr_result(
+ result))
+
+ def test_display_single_bound(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ result_samples = {}
+ self.assertIsNone(
+ algorithm.display_single_bound(result_samples, 'NDR_LOWER',
+ 4857361, 64,
+ ['20/849/1069', '40/69/183']))
+ self.assertEqual(
+ {'Result_NDR_LOWER': {'bandwidth_total_Gbps': 3.264146592,
+ 'rate_total_pps': 4857361.0},
+ 'Result_stream0_NDR_LOWER': {'avg_latency': 849.0,
+ 'max_latency': 1069.0,
+ 'min_latency': 20.0},
+ 'Result_stream1_NDR_LOWER': {'avg_latency': 69.0,
+ 'max_latency': 183.0,
+ 'min_latency': 40.0}},
+ result_samples)
+
+ def test_check_ndrpdr_interval_validity(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ result_samples = {}
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 0)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 0)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual('Minimal rate loss fraction 0.0 reach target 0.0',
+ algorithm.check_ndrpdr_interval_validity(
+ result_samples, 'NDR_LOWER',
+ receive_rate_interval))
+ self.assertEqual(
+ {'Result_NDR_LOWER_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0}},
+ result_samples)
+
+ def test_check_ndrpdr_interval_validity_fail(self):
+ algorithm = MultipleLossRatioSearch(measurer=mock.Mock(), latency=True,
+ pkt_size=64,
+ final_trial_duration=30,
+ final_relative_width=0.005,
+ number_of_intermediate_phases=2,
+ initial_trial_duration=1,
+ timeout=720)
+ result_samples = {}
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual(
+ 'Minimal rate loss fraction 0.01749 does not reach target 0.005\n84965 packets lost.',
+ algorithm.check_ndrpdr_interval_validity(result_samples,
+ 'NDR_LOWER',
+ receive_rate_interval,
+ 0.005))
+ self.assertEqual({'Result_NDR_LOWER_packets_lost': {
+ 'packet_loss_ratio': 0.01749,
+ 'packets_lost': 84965.0}}, result_samples)
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py
new file mode 100644
index 000000000..ea9c39a03
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_ndr_pdr_result.py
@@ -0,0 +1,91 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+import mock
+
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class TestNdrPdrResult(unittest.TestCase):
+
+ def test___init__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertIsInstance(ndrpdr_result.ndr_interval, ReceiveRateInterval)
+ self.assertIsInstance(ndrpdr_result.pdr_interval, ReceiveRateInterval)
+
+ def test___init__ndr_error(self):
+ starting_interval = mock.MagicMock()
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ end_interval = ReceiveRateInterval(measured_low, measured_high)
+ with self.assertRaises(TypeError) as raised:
+ NdrPdrResult(starting_interval, end_interval)
+ self.assertIn('ndr_interval, is not a ReceiveRateInterval: ',
+ str(raised.exception))
+
+ def test___init__pdr_error(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ end_interval = mock.MagicMock()
+ with self.assertRaises(TypeError) as raised:
+ NdrPdrResult(starting_interval, end_interval)
+ self.assertIn('pdr_interval, is not a ReceiveRateInterval: ',
+ str(raised.exception))
+
+ def test_width_in_goals(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertEqual('ndr 4.86887; pdr 4.86887',
+ ndrpdr_result.width_in_goals(0.005))
+
+ def test___str__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertEqual(
+ 'NDR=[d=1.0,Tr=4857361.0,Df=0.01749;d=1.0,Tr=4977343.0,Df=0.0241);'
+ 'PDR=[d=1.0,Tr=4857361.0,Df=0.01749;d=1.0,Tr=4977343.0,Df=0.0241)',
+ ndrpdr_result.__str__())
+
+ def test___repr__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ starting_interval = ReceiveRateInterval(measured_low, measured_high)
+ ndrpdr_result = NdrPdrResult(starting_interval, starting_interval)
+ self.assertEqual(
+ 'NdrPdrResult(ndr_interval=ReceiveRateInterval(measured_low=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4857361.0,' \
+ 'transmit_count=4857339,loss_count=84965),measured_high=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4977343.0,' \
+ 'transmit_count=4977320,loss_count=119959)),pdr_interval=' \
+ 'ReceiveRateInterval(measured_low=ReceiveRateMeasurement' \
+ '(duration=1.0,target_tr=4857361.0,transmit_count=4857339,' \
+ 'loss_count=84965),measured_high=ReceiveRateMeasurement' \
+ '(duration=1.0,target_tr=4977343.0,transmit_count=4977320,' \
+ 'loss_count=119959)))',
+ ndrpdr_result.__repr__())
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py
new file mode 100644
index 000000000..bbf241613
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_interval.py
@@ -0,0 +1,100 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+import mock
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class TestReceiveRateInterval(unittest.TestCase):
+
+ def test__init__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertIsInstance(receive_rate_interval.measured_low,
+ ReceiveRateMeasurement)
+ self.assertIsInstance(receive_rate_interval.measured_high,
+ ReceiveRateMeasurement)
+
+ def test__init__measured_low_error(self):
+ measured_low = mock.MagicMock()
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ with self.assertRaises(TypeError) as raised:
+ ReceiveRateInterval(measured_low, measured_high)
+ self.assertIn('measured_low is not a ReceiveRateMeasurement: ',
+ str(raised.exception))
+
+ def test__init__measured_high_error(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = mock.MagicMock()
+ with self.assertRaises(TypeError) as raised:
+ ReceiveRateInterval(measured_low, measured_high)
+ self.assertIn('measured_high is not a ReceiveRateMeasurement: ',
+ str(raised.exception))
+
+ def test_sort(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertIsNone(receive_rate_interval.sort())
+ self.assertEqual(119982.0, receive_rate_interval.abs_tr_width)
+ self.assertEqual(0.02411,
+ receive_rate_interval.rel_tr_width)
+
+ def test_sort_swap(self):
+ measured_low = ReceiveRateMeasurement(1, 14857361, 14857339, 184965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertIsNone(receive_rate_interval.sort())
+ self.assertEqual(9880018.0, receive_rate_interval.abs_tr_width)
+ self.assertEqual(0.66499,
+ receive_rate_interval.rel_tr_width)
+
+ def test_width_in_goals(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual(4.86887,
+ receive_rate_interval.width_in_goals(0.005))
+
+ def test___str__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual(
+ '[d=1.0,Tr=4857361.0,Df=0.01749;d=1.0,Tr=4977343.0,Df=0.0241)',
+ receive_rate_interval.__str__())
+
+ def test___repr__(self):
+ measured_low = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ measured_high = ReceiveRateMeasurement(1, 4977343, 4977320, 119959)
+ receive_rate_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ self.assertEqual('ReceiveRateInterval(measured_low=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4857361.0,' \
+ 'transmit_count=4857339,loss_count=84965),measured_high=' \
+ 'ReceiveRateMeasurement(duration=1.0,target_tr=4977343.0,' \
+ 'transmit_count=4977320,loss_count=119959))',
+ receive_rate_interval.__repr__())
diff --git a/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py
new file mode 100644
index 000000000..d4e2d7920
--- /dev/null
+++ b/yardstick/tests/unit/network_services/helpers/vpp_helpers/test_receive_rate_measurement.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
+
+
+class TestReceiveRateMeasurement(unittest.TestCase):
+
+ def test__init__(self):
+ measured = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ self.assertEqual(1, measured.duration)
+ self.assertEqual(4857361, measured.target_tr)
+ self.assertEqual(4857339, measured.transmit_count)
+ self.assertEqual(84965, measured.loss_count)
+ self.assertEqual(4772374, measured.receive_count)
+ self.assertEqual(4857339, measured.transmit_rate)
+ self.assertEqual(84965.0, measured.loss_rate)
+ self.assertEqual(4772374.0, measured.receive_rate)
+ self.assertEqual(0.01749, measured.loss_fraction)
+
+ def test___str__(self):
+ measured = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ self.assertEqual('d=1.0,Tr=4857361.0,Df=0.01749',
+ measured.__str__())
+
+ def test___repr__(self):
+ measured = ReceiveRateMeasurement(1, 4857361, 4857339, 84965)
+ self.assertEqual('ReceiveRateMeasurement(duration=1.0,' \
+ 'target_tr=4857361.0,transmit_count=4857339,loss_count=84965)',
+ measured.__repr__())
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py b/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py
index 4e5a0f708..8ad17b547 100644
--- a/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py
+++ b/yardstick/tests/unit/network_services/traffic_profile/test_vpp_rfc2544.py
@@ -18,8 +18,17 @@ from trex_stl_lib import trex_stl_packet_builder_scapy
from trex_stl_lib import trex_stl_streams
from yardstick.common import constants
+from yardstick.network_services.helpers.vpp_helpers.multiple_loss_ratio_search import \
+ MultipleLossRatioSearch
+from yardstick.network_services.helpers.vpp_helpers.ndr_pdr_result import \
+ NdrPdrResult
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_interval import \
+ ReceiveRateInterval
+from yardstick.network_services.helpers.vpp_helpers.receive_rate_measurement import \
+ ReceiveRateMeasurement
from yardstick.network_services.traffic_profile import base as tp_base
from yardstick.network_services.traffic_profile import rfc2544, vpp_rfc2544
+from yardstick.network_services.traffic_profile.rfc2544 import PortPgIDMap
from yardstick.tests.unit import base
@@ -129,6 +138,7 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
self.assertEqual(vpp_rfc2544_profile.max_rate,
vpp_rfc2544_profile.rate)
self.assertEqual(0, vpp_rfc2544_profile.min_rate)
+ self.assertEqual(2, vpp_rfc2544_profile.number_of_intermediate_phases)
self.assertEqual(30, vpp_rfc2544_profile.duration)
self.assertEqual(0.1, vpp_rfc2544_profile.precision)
self.assertEqual(1.0, vpp_rfc2544_profile.lower_bound)
@@ -287,6 +297,7 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
self.TRAFFIC_PROFILE_MAX_RATE)
vpp_rfc2544_profile.init_queue(mock.MagicMock())
+ vpp_rfc2544_profile.pkt_size = 64
vpp_rfc2544_profile.params = {
'downlink_0': 'profile1',
'uplink_0': 'profile2'}
@@ -480,6 +491,7 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
mock_latency.side_effect = ['latency1', 'latency2']
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
self.TRAFFIC_PROFILE_MAX_RATE)
+ vpp_rfc2544_profile.pkt_size = 64
vpp_rfc2544_profile.port_pg_id = rfc2544.PortPgIDMap()
vpp_rfc2544_profile.port_pg_id.add_port(1)
with mock.patch.object(vpp_rfc2544_profile, '_create_single_packet') as \
@@ -523,10 +535,69 @@ class TestVppRFC2544Profile(base.BaseUnitTestCase):
def test_binary_search_with_optimized(self):
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
self.TRAFFIC_PROFILE)
+ vpp_rfc2544_profile.pkt_size = 64
+ vpp_rfc2544_profile.init_queue(mock.MagicMock())
mock_generator = mock.MagicMock()
- self.assertIsNone(
- vpp_rfc2544_profile.binary_search_with_optimized(mock_generator,
- 30, 720, ''))
+ mock_generator.vnfd_helper.interfaces = [
+ {"name": "xe0"}, {"name": "xe0"}
+ ]
+
+ vpp_rfc2544_profile.ports = [0, 1]
+ vpp_rfc2544_profile.port_pg_id = PortPgIDMap()
+ vpp_rfc2544_profile.port_pg_id.add_port(0)
+ vpp_rfc2544_profile.port_pg_id.add_port(1)
+ vpp_rfc2544_profile.profiles = mock.MagicMock()
+ vpp_rfc2544_profile.test_data = mock.MagicMock()
+ vpp_rfc2544_profile.queue = mock.MagicMock()
+
+ with mock.patch.object(MultipleLossRatioSearch, 'measure') as \
+ mock_measure, \
+ mock.patch.object(MultipleLossRatioSearch, 'ndrpdr') as \
+ mock_ndrpdr:
+ measured_low = ReceiveRateMeasurement(1, 14880000, 14879927, 0)
+ measured_high = ReceiveRateMeasurement(1, 14880000, 14879927, 0)
+ measured_low.latency = ['1000/3081/3962', '500/3149/3730']
+ measured_high.latency = ['1000/3081/3962', '500/3149/3730']
+ starting_interval = ReceiveRateInterval(measured_low,
+ measured_high)
+ starting_result = NdrPdrResult(starting_interval,
+ starting_interval)
+ mock_measure.return_value = ReceiveRateMeasurement(1, 14880000,
+ 14879927, 0)
+ mock_ndrpdr.return_value = MultipleLossRatioSearch.ProgressState(
+ starting_result, 2, 30, 0.005, 0.0,
+ 4857361, 4977343)
+
+ result_samples = vpp_rfc2544_profile.binary_search_with_optimized(
+ traffic_generator=mock_generator, duration=30,
+ timeout=720,
+ test_data={})
+
+ expected = {'Result_NDR_LOWER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_NDR_UPPER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_NDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_PDR_LOWER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_PDR_UPPER': {'bandwidth_total_Gbps': 9.999310944,
+ 'rate_total_pps': 14879927.0},
+ 'Result_PDR_packets_lost': {'packet_loss_ratio': 0.0,
+ 'packets_lost': 0.0},
+ 'Result_stream0_NDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream0_PDR_LOWER': {'avg_latency': 3081.0,
+ 'max_latency': 3962.0,
+ 'min_latency': 1000.0},
+ 'Result_stream1_NDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0},
+ 'Result_stream1_PDR_LOWER': {'avg_latency': 3149.0,
+ 'max_latency': 3730.0,
+ 'min_latency': 500.0}}
+ self.assertEqual(expected, result_samples)
def test_binary_search(self):
vpp_rfc2544_profile = vpp_rfc2544.VppRFC2544Profile(
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py
index f8126307c..8b245b3bf 100644
--- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_ipsec_vnf.py
@@ -19,11 +19,12 @@ import mock
from yardstick.benchmark.contexts import base as ctx_base
from yardstick.common import utils
+from yardstick.network_services.helpers import cpu
from yardstick.network_services.nfvi.resource import ResourceProfile
-from yardstick.network_services.vnf_generic.vnf import ipsec_vnf
+from yardstick.network_services.vnf_generic.vnf import ipsec_vnf, vpp_helpers
from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
-from yardstick.network_services.vnf_generic.vnf.ipsec_vnf import \
- VipsecApproxSetupEnvHelper
+from yardstick.network_services.vnf_generic.vnf.ipsec_vnf import CryptoAlg, \
+ IntegAlg, VipsecApproxSetupEnvHelper
from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import \
mock_ssh
@@ -32,6 +33,24 @@ SSH_HELPER = 'yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper
NAME = 'vnf__1'
+class TestCryptoAlg(unittest.TestCase):
+
+ def test__init__(self):
+ encr_alg = CryptoAlg.AES_GCM_128
+ self.assertEqual('aes-gcm-128', encr_alg.alg_name)
+ self.assertEqual('AES-GCM', encr_alg.scapy_name)
+ self.assertEqual(20, encr_alg.key_len)
+
+
+class TestIntegAlg(unittest.TestCase):
+
+ def test__init__(self):
+ auth_alg = IntegAlg.AES_GCM_128
+ self.assertEqual('aes-gcm-128', auth_alg.alg_name)
+ self.assertEqual('AES-GCM', auth_alg.scapy_name)
+ self.assertEqual(20, auth_alg.key_len)
+
+
@mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.Process")
class TestVipsecApproxVnf(unittest.TestCase):
VNFD = {'vnfd:vnfd-catalog':
@@ -791,6 +810,62 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
}
}
+ ALL_OPTIONS_CBC_ALGORITHMS = {
+ "flow": {
+ "count": 1,
+ "dst_ip": [
+ "20.0.0.0-20.0.0.100"
+ ],
+ "src_ip": [
+ "10.0.0.0-10.0.0.100"
+ ]
+ },
+ "framesize": {
+ "downlink": {
+ "64B": 100
+ },
+ "uplink": {
+ "64B": 100
+ }
+ },
+ "rfc2544": {
+ "allowed_drop_rate": "0.0 - 0.005"
+ },
+ "tg__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "queues_per_port": 7
+ },
+ "traffic_type": 4,
+ "vnf__0": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vnf__1": {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "SW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ },
+ "vpp_config": {
+ "crypto_algorithms": "cbc-sha1",
+ "tunnel": 1
+ }
+ }
+
ALL_OPTIONS_ERROR = {
"flow_error": {
"count": 1,
@@ -859,6 +934,18 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
}
}
+ OPTIONS_HW = {
+ "collectd": {
+ "interval": 1
+ },
+ "vnf_config": {
+ "crypto_type": "HW_cryptodev",
+ "rxq": 1,
+ "worker_config": "1C/1T",
+ "worker_threads": 4
+ }
+ }
+
CPU_LAYOUT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 1, 1, 0],
[2, 1, 0, 0, 0, 2, 2, 1],
@@ -877,6 +964,24 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
[15, 8, 0, 1, 0, 15, 15, 7],
[16, 9, 0, 1, 0, 16, 16, 8],
[17, 9, 0, 1, 0, 17, 17, 8]]}
+ CPU_SMT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0, 1, 1, 0],
+ [2, 1, 0, 0, 0, 2, 2, 1],
+ [3, 1, 0, 0, 0, 3, 3, 1],
+ [4, 2, 0, 0, 0, 4, 4, 2],
+ [5, 2, 0, 0, 0, 5, 5, 2],
+ [6, 3, 0, 0, 0, 6, 6, 3],
+ [7, 3, 0, 0, 0, 7, 7, 3],
+ [8, 4, 0, 0, 0, 8, 8, 4],
+ [9, 5, 0, 1, 0, 0, 0, 0],
+ [10, 6, 0, 1, 0, 1, 1, 0],
+ [11, 6, 0, 1, 0, 2, 2, 1],
+ [12, 7, 0, 1, 0, 3, 3, 1],
+ [13, 7, 0, 1, 0, 4, 4, 2],
+ [14, 8, 0, 1, 0, 5, 5, 2],
+ [15, 8, 0, 1, 0, 6, 6, 3],
+ [16, 9, 0, 1, 0, 7, 7, 3],
+ [17, 9, 0, 1, 0, 8, 8, 4]]}
VPP_INTERFACES_DUMP = [
{
@@ -1126,12 +1231,97 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
vnfd_helper = VnfdHelper(
TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.build_config())
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 4)
+
+ def test_build_config_cbc_algorithms(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS_CBC_ALGORITHMS
ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
ssh_helper,
scenario_helper)
- ipsec_approx_setup_helper.build_config()
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.build_config())
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 4)
@mock.patch.object(utils, 'setup_hugepages')
def test_setup_vnf_environment(self, *args):
@@ -1147,9 +1337,36 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
ssh_helper,
scenario_helper)
- self.assertIsInstance(
- ipsec_approx_setup_helper.setup_vnf_environment(),
- ResourceProfile)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ self.assertIsInstance(
+ ipsec_approx_setup_helper.setup_vnf_environment(),
+ ResourceProfile)
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual(0,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2,
+ ipsec_approx_setup_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 4)
def test_calculate_frame_size(self):
vnfd_helper = VnfdHelper(
@@ -1214,6 +1431,90 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
self.assertFalse(ipsec_approx_setup_helper.check_status())
def test_get_vpp_statistics(self):
+ def execute(cmd):
+ if 'TenGigabitEthernetff/6/0' in cmd:
+ return 0, output_xe0, ''
+ elif 'VirtualFunctionEthernetff/7/0' in cmd:
+ return 0, output_xe1, ''
+ return 0, '0', ''
+
+ output_xe0 = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ ' Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 up 9200/0/0/0 ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568\n' \
+ ' ' \
+ 'rx-miss 27789925'
+ output_xe1 = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ ' Counter Count \n' \
+ 'VirtualFunctionEthernetff/7/0 2 up 9200/0/0/0 ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568\n' \
+ ' ' \
+ 'rx-miss 27789925'
+
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute = execute
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertEqual({'xe0': {'packets_dropped': 27789925,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568},
+ 'xe1': {'packets_dropped': 27789925,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568}},
+ ipsec_approx_setup_helper.get_vpp_statistics())
+
+ def test_parser_vpp_stats(self):
+ output = \
+ ' Name Idx State MTU (L3/IP4/IP6/MPLS)' \
+ 'Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 up 9200/0/0/0 ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568\n' \
+ ' ' \
+ 'rx-miss 27789925'
vnfd_helper = VnfdHelper(
TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
ssh_helper = mock.Mock()
@@ -1222,18 +1523,152 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
ssh_helper,
scenario_helper)
- ipsec_approx_setup_helper.get_vpp_statistics()
+ self.assertEqual({'xe0': {'packets_dropped': 27789925,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568}},
+ ipsec_approx_setup_helper.parser_vpp_stats('xe0',
+ 'TenGigabitEthernetff/6/0',
+ output))
+
+ def test_parser_vpp_stats_no_miss(self):
+ output = \
+ ' Name Idx State ' \
+ 'Counter Count \n' \
+ 'TenGigabitEthernetff/6/0 1 up ' \
+ 'rx packets 23373568\n' \
+ ' ' \
+ 'rx bytes 1402414080\n' \
+ ' ' \
+ 'tx packets 20476416\n' \
+ ' ' \
+ 'tx bytes 1228584960\n' \
+ ' ' \
+ 'ip4 23373568'
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+ self.assertEqual({'xe0': {'packets_dropped': 2897152,
+ 'packets_fwd': 20476416,
+ 'packets_in': 23373568}},
+ ipsec_approx_setup_helper.parser_vpp_stats('xe0',
+ 'TenGigabitEthernetff/6/0',
+ output))
def test_create_ipsec_tunnels(self):
vnfd_helper = VnfdHelper(
TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out, \
+ mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'vpp_get_interface_data') as \
+ mock_ipsec_approx_setup_helper:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ mock_vat_terminal_exec_cmd_from_template.return_value = self.VPP_INTERFACES_DUMP
+ mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.create_ipsec_tunnels())
+ self.assertGreaterEqual(
+ mock_vat_terminal_exec_cmd_from_template.call_count, 9)
+
+ def test_create_ipsec_tunnels_cbc_algorithms(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS_CBC_ALGORITHMS
ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
ssh_helper,
scenario_helper)
- ipsec_approx_setup_helper.create_ipsec_tunnels()
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'find_encrypted_data_interface') as \
+ mock_find_encrypted_data_interface, \
+ mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'vpp_get_interface_data') as \
+ mock_ipsec_approx_setup_helper:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ mock_find_encrypted_data_interface.return_value = {
+ 'dpdk_port_num': 0,
+ 'driver': 'igb_uio',
+ 'dst_ip': '192.168.100.1',
+ 'dst_mac': '90:e2:ba:7c:30:e8',
+ 'ifname': 'xe0',
+ 'local_ip': '192.168.100.2',
+ 'local_mac': '90:e2:ba:7c:41:a8',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'vnf__1',
+ 'numa_node': 0,
+ 'peer_ifname': 'xe0',
+ 'peer_intf': {'dpdk_port_num': 0,
+ 'driver': 'igb_uio',
+ 'dst_ip': '192.168.100.2',
+ 'dst_mac': '90:e2:ba:7c:41:a8',
+ 'ifname': 'xe0',
+ 'local_ip': '192.168.100.1',
+ 'local_mac': '90:e2:ba:7c:30:e8',
+ 'netmask': '255.255.255.0',
+ 'network': {},
+ 'node_name': 'tg__0',
+ 'peer_ifname': 'xe0',
+ 'peer_name': 'vnf__0',
+ 'vld_id': 'uplink_0',
+ 'vpci': '0000:81:00.0'},
+ 'peer_name': 'tg__0',
+ 'vld_id': 'uplink_0',
+ 'vpci': '0000:ff:06.0',
+ 'vpp_name': u'TenGigabitEthernetff/6/0',
+ 'vpp_sw_index': 1}
+ mock_vat_terminal_exec_cmd_from_template.return_value = self.VPP_INTERFACES_DUMP
+ mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.create_ipsec_tunnels())
+ self.assertGreaterEqual(
+ mock_vat_terminal_exec_cmd_from_template.call_count, 9)
def test_find_raw_data_interface(self):
expected = {'dpdk_port_num': 0,
@@ -1246,6 +1681,7 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
'netmask': '255.255.255.0',
'network': {},
'node_name': 'vnf__0',
+ 'numa_node': 0,
'peer_ifname': 'xe0',
'peer_intf': {'dpdk_port_num': 0,
'driver': 'igb_uio',
@@ -1263,7 +1699,9 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
'vpci': '0000:81:00.0'},
'peer_name': 'tg__0',
'vld_id': 'uplink_0',
- 'vpci': '0000:ff:06.0'}
+ 'vpci': '0000:ff:06.0',
+ 'vpp_name': u'TenGigabitEthernetff/6/0',
+ 'vpp_sw_index': 1}
vnfd_helper = VnfdHelper(
TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
ssh_helper = mock.Mock()
@@ -1298,6 +1736,7 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
'netmask': '255.255.255.0',
'network': {},
'node_name': 'vnf__0',
+ 'numa_node': 0,
'peer_ifname': 'xe1',
'peer_intf': {'driver': 'igb_uio',
'dst_ip': '1.1.1.1',
@@ -1314,7 +1753,9 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
'vpci': '0000:00:07.0'},
'peer_name': 'vnf__1',
'vld_id': 'ciphertext',
- 'vpci': '0000:ff:07.0'}
+ 'vpci': '0000:ff:07.0',
+ 'vpp_name': u'VirtualFunctionEthernetff/7/0',
+ 'vpp_sw_index': 2}
vnfd_helper = VnfdHelper(
TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
ssh_helper = mock.Mock()
@@ -1325,3 +1766,341 @@ class TestVipsecApproxSetupEnvHelper(unittest.TestCase):
scenario_helper)
self.assertEqual(expected,
ipsec_approx_setup_helper.find_encrypted_data_interface())
+
+ def test_create_startup_configuration_of_vpp(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsInstance(
+ ipsec_approx_setup_helper.create_startup_configuration_of_vpp(),
+ vpp_helpers.VppConfigGenerator)
+
+ def test_add_worker_threads_and_rxqueues(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(
+ ipsec_approx_setup_helper.add_worker_threads_and_rxqueues(
+ vpp_config_generator, 1, 1))
+ self.assertEqual(
+ 'cpu\n{\n corelist-workers 2\n main-core 1\n}\ndpdk\n{\n ' \
+ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_worker_threads_and_rxqueues_smt(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_SMT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(
+ ipsec_approx_setup_helper.add_worker_threads_and_rxqueues(
+ vpp_config_generator, 1))
+ self.assertEqual(
+ 'cpu\n{\n corelist-workers 2,6\n main-core 1\n}\ndpdk\n{\n ' \
+ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_worker_threads_and_rxqueues_with_numa(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(
+ ipsec_approx_setup_helper.add_worker_threads_and_rxqueues(
+ vpp_config_generator, 1, 1))
+ self.assertEqual(
+ 'cpu\n{\n corelist-workers 2\n main-core 1\n}\ndpdk\n{\n ' \
+ 'dev default\n {\n num-rx-queues 1\n }\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_pci_devices(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_pci_devices(
+ vpp_config_generator))
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:ff:06.0 \n dev 0000:ff:07.0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev_hw(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS_HW
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:ff:01.0 \n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev_smt_used(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_LAYOUT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev_smt_used_hw(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS_HW
+ scenario_helper.all_options = self.ALL_OPTIONS
+ vpp_config_generator = vpp_helpers.VppConfigGenerator()
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ ipsec_approx_setup_helper.sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper.sys_cores.cpuinfo = self.CPU_SMT
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ ipsec_approx_setup_helper.sys_cores.get_cpu_layout())
+ self.assertIsNone(ipsec_approx_setup_helper.add_dpdk_cryptodev(
+ vpp_config_generator, 'aesni_gcm', 1))
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:ff:01.0 \n dev 0000:ff:01.1 \n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_initialize_ipsec(self):
+ vnfd_helper = VnfdHelper(
+ TestVipsecApproxVnf.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+ scenario_helper.all_options = self.ALL_OPTIONS
+
+ ipsec_approx_setup_helper = VipsecApproxSetupEnvHelper(vnfd_helper,
+ ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'execute_script_json_out') as \
+ mock_execute_script_json_out, \
+ mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template, \
+ mock.patch.object(ipsec_approx_setup_helper,
+ 'vpp_get_interface_data') as \
+ mock_ipsec_approx_setup_helper:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ mock_execute_script_json_out.return_value = str(
+ self.VPP_INTERFACES_DUMP).replace("\'", "\"")
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ mock_ipsec_approx_setup_helper.return_value = self.VPP_INTERFACES_DUMP
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ ipsec_approx_setup_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ ipsec_approx_setup_helper.update_vpp_interface_data()
+ ipsec_approx_setup_helper.iface_update_numa()
+ self.assertIsNone(ipsec_approx_setup_helper.initialize_ipsec())
+ self.assertGreaterEqual(
+ mock_vat_terminal_exec_cmd_from_template.call_count, 9)
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py
new file mode 100755
index 000000000..3b226d3f1
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_vcmts_pktgen.py
@@ -0,0 +1,652 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+import mock
+import socket
+import threading
+import time
+import os
+import copy
+
+from yardstick.benchmark.contexts import base as ctx_base
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.vnf_generic.vnf import tg_vcmts_pktgen
+from yardstick.common import exceptions
+
+
+NAME = "tg__0"
+
+
+class TestPktgenHelper(unittest.TestCase):
+
+ def test___init__(self):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ self.assertEqual(pktgen_helper.host, "localhost")
+ self.assertEqual(pktgen_helper.port, 23000)
+ self.assertFalse(pktgen_helper.connected)
+
+ def _run_fake_server(self):
+ server_sock = socket.socket()
+ server_sock.bind(('localhost', 23000))
+ server_sock.listen(0)
+ client_socket, _ = server_sock.accept()
+ client_socket.close()
+ server_sock.close()
+
+ def test__connect(self):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ self.assertFalse(pktgen_helper._connect())
+ server_thread = threading.Thread(target=self._run_fake_server)
+ server_thread.start()
+ time.sleep(0.5)
+ self.assertTrue(pktgen_helper._connect())
+ pktgen_helper._sock.close()
+ server_thread.join()
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.tg_vcmts_pktgen.time')
+ def test_connect(self, *args):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ pktgen_helper.connected = True
+ self.assertTrue(pktgen_helper.connect())
+ pktgen_helper.connected = False
+
+ pktgen_helper._connect = mock.MagicMock(return_value=True)
+ self.assertTrue(pktgen_helper.connect())
+ self.assertTrue(pktgen_helper.connected)
+
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ pktgen_helper._connect = mock.MagicMock(return_value=False)
+ self.assertFalse(pktgen_helper.connect())
+ self.assertFalse(pktgen_helper.connected)
+
+ def test_send_command(self):
+ pktgen_helper = tg_vcmts_pktgen.PktgenHelper("localhost", 23000)
+ self.assertFalse(pktgen_helper.send_command(""))
+
+ pktgen_helper.connected = True
+ pktgen_helper._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.assertFalse(pktgen_helper.send_command(""))
+
+ pktgen_helper._sock = mock.MagicMock()
+ self.assertTrue(pktgen_helper.send_command(""))
+
+
+class TestVcmtsPktgenSetupEnvHelper(unittest.TestCase):
+
+ PKTGEN_PARAMETERS = "export LUA_PATH=/vcmts/Pktgen.lua;"\
+ "export CMK_PROC_FS=/host/proc;"\
+ " /pktgen-config/setup.sh 0 4 18:02.0 "\
+ "18:02.1 18:02.2 18:02.3 00:00.0 00:00.0 "\
+ "00:00.0 00:00.0 imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap imix1_100cms_1ofdm.pcap "\
+ "imix1_100cms_1ofdm.pcap"
+
+ OPTIONS = {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ }
+
+ def setUp(self):
+ vnfd_helper = VnfdHelper(
+ TestVcmtsPktgen.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+
+ self.setup_helper = tg_vcmts_pktgen.VcmtsPktgenSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ def test_generate_pcap_filename(self):
+ pcap_file_name = self.setup_helper.generate_pcap_filename(\
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0]['ports'][0])
+ self.assertEquals(pcap_file_name, "imix1_100cms_1ofdm.pcap")
+
+ def test_find_port_cfg(self):
+ port_cfg = self.setup_helper.find_port_cfg(\
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0]['ports'], "port_0")
+ self.assertIsNotNone(port_cfg)
+
+ port_cfg = self.setup_helper.find_port_cfg(\
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0]['ports'], "port_8")
+ self.assertIsNone(port_cfg)
+
+ def test_build_pktgen_parameters(self):
+ parameters = self.setup_helper.build_pktgen_parameters(
+ TestVcmtsPktgen.PKTGEN_POD_VALUES[0])
+ self.assertEquals(parameters, self.PKTGEN_PARAMETERS)
+
+ def test_start_pktgen(self):
+ self.setup_helper.ssh_helper = mock.MagicMock()
+ self.setup_helper.start_pktgen(TestVcmtsPktgen.PKTGEN_POD_VALUES[0])
+ self.setup_helper.ssh_helper.send_command.assert_called_with(
+ self.PKTGEN_PARAMETERS)
+
+ def test_setup_vnf_environment(self):
+ self.assertIsNone(self.setup_helper.setup_vnf_environment())
+
+class TestVcmtsPktgen(unittest.TestCase):
+
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{
+ "benchmark": {
+ "kpi": [
+ "upstream/bits_per_second"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "vCMTS Pktgen Kubernetes",
+ "id": "VcmtsPktgen",
+ "mgmt-interface": {
+ "ip": "192.168.24.150",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "user": "root",
+ "vdu-id": "vcmtspktgen-kubernetes"
+ },
+ "name": "vcmtspktgen",
+ "short-name": "vcmtspktgen",
+ "vdu": [
+ {
+ "description": "vCMTS Pktgen Kubernetes",
+ "external-interface": [],
+ "id": "vcmtspktgen-kubernetes",
+ "name": "vcmtspktgen-kubernetes"
+ }
+ ],
+ "vm-flavor": {
+ "memory-mb": "4096",
+ "vcpu-count": "4"
+ }
+ }]
+ }}
+
+ PKTGEN_POD_VALUES = [
+ {
+ "num_ports": "4",
+ "pktgen_id": "0",
+ "ports": [
+ {
+ "net_pktgen": "18:02.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_0": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:02.1",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_1": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:02.2",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_2": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:02.3",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_3": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_4": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_5": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_6": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_7": "",
+ "traffic_type": "imix1"
+ }
+ ]
+ },
+ {
+ "num_ports": 4,
+ "pktgen_id": 1,
+ "ports": [
+ {
+ "net_pktgen": "18:0a.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_0": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:0a.1",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_1": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:0a.2",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_2": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "18:0a.3",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_3": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_4": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_5": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_6": "",
+ "traffic_type": "imix1"
+ },
+ {
+ "net_pktgen": "00:00.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "port_7": "",
+ "traffic_type": "imix1"
+ }
+ ]
+ }
+ ]
+
+ SCENARIO_CFG = {
+ "nodes": {
+ "tg__0": "pktgen0-k8syardstick-a3b663c2",
+ "vnf__0": "vnf0us-k8syardstick-a3b663c2",
+ "vnf__1": "vnf0ds-k8syardstick-a3b663c2"
+ },
+ "options": {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ },
+ "task_id": "a3b663c2-e616-4777-b6d0-ec2ea7a06f42",
+ "task_path": "samples/vnf_samples/nsut/cmts",
+ "tc": "tc_vcmts_k8s_pktgen",
+ "topology": "k8s_vcmts_topology.yaml",
+ "traffic_profile": "../../traffic_profiles/fixed.yaml",
+ "type": "NSPerf"
+ }
+
+ CONTEXT_CFG = {
+ "networks": {
+ "flannel": {
+ "name": "flannel"
+ },
+ "xe0": {
+ "name": "xe0"
+ },
+ "xe1": {
+ "name": "xe1"
+ }
+ },
+ "nodes": {
+ "tg__0": {
+ "VNF model": "../../vnf_descriptors/tg_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.24.150",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.24.150",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.24.150",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.24.150",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "member-vnf-index": "1",
+ "name": "pktgen0-k8syardstick-a3b663c2",
+ "private_ip": "192.168.24.150",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 60270,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 43619,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 60270,
+ "user": "root",
+ "vnfd-id-ref": "tg__0"
+ },
+ "vnf__0": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.132",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.132",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.132",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.132",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "member-vnf-index": "3",
+ "name": "vnf0us-k8syardstick-a3b663c2",
+ "private_ip": "192.168.100.132",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 57057,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 29700,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 57057,
+ "user": "root",
+ "vnfd-id-ref": "vnf__0"
+ },
+ "vnf__1": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.134",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.134",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.134",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.134",
+ "key_filename": "/tmp/yardstick_key-a3b663c2",
+ "member-vnf-index": "4",
+ "name": "vnf0ds-k8syardstick-a3b663c2",
+ "private_ip": "192.168.100.134",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 18581,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 18469,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 18581,
+ "user": "root",
+ "vnfd-id-ref": "vnf__1"
+ }
+ }
+ }
+
+ PKTGEN_VALUES_PATH = "/tmp/pktgen_values.yaml"
+
+ PKTGEN_VALUES = \
+ "serviceAccount: cmk-serviceaccount\n" \
+ "images:\n" \
+ " vcmts_pktgen: vcmts-pktgen:v18.10\n" \
+ "topology:\n" \
+ " pktgen_replicas: 8\n" \
+ " pktgen_pods:\n" \
+ " - pktgen_id: 0\n" \
+ " num_ports: 4\n" \
+ " ports:\n" \
+ " - port_0:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.0\n" \
+ " - port_1:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.1\n" \
+ " - port_2:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.2\n" \
+ " - port_3:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.3\n" \
+ " - port_4:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.4\n" \
+ " - port_5:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.5\n" \
+ " - port_6:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.6\n" \
+ " - port_7:\n" \
+ " traffic_type: 'imix2'\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " net_pktgen: 8a:02.7\n"
+
+ def setUp(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ self.vcmts_pktgen = tg_vcmts_pktgen.VcmtsPktgen(NAME, vnfd)
+ self.vcmts_pktgen._start_server = mock.Mock(return_value=0)
+ self.vcmts_pktgen.resource_helper = mock.MagicMock()
+ self.vcmts_pktgen.setup_helper = mock.MagicMock()
+
+ def test___init__(self):
+ self.assertFalse(self.vcmts_pktgen.traffic_finished)
+ self.assertIsNotNone(self.vcmts_pktgen.setup_helper)
+ self.assertIsNotNone(self.vcmts_pktgen.resource_helper)
+
+ def test_extract_pod_cfg(self):
+ pod_cfg = self.vcmts_pktgen.extract_pod_cfg(self.PKTGEN_POD_VALUES, "0")
+ self.assertIsNotNone(pod_cfg)
+ self.assertEqual(pod_cfg["pktgen_id"], "0")
+ pod_cfg = self.vcmts_pktgen.extract_pod_cfg(self.PKTGEN_POD_VALUES, "4")
+ self.assertIsNone(pod_cfg)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_missing_pktgen_values_key(self, *args):
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'].pop('pktgen_values', None)
+ with self.assertRaises(KeyError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_missing_pktgen_values_file(self, *args):
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['pktgen_values'] = self.PKTGEN_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_empty_pktgen_values_file(self, *args):
+ yaml_sample = open(self.PKTGEN_VALUES_PATH, 'w')
+ yaml_sample.write("")
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['pktgen_values'] = self.PKTGEN_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_invalid_pktgen_id(self, *args):
+ yaml_sample = open(self.PKTGEN_VALUES_PATH, 'w')
+ yaml_sample.write(self.PKTGEN_VALUES)
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'][NAME]['pktgen_id'] = 12
+ with self.assertRaises(KeyError):
+ self.vcmts_pktgen.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+
+ @mock.patch.object(ctx_base.Context, 'get_context_from_server',
+ return_value='fake_context')
+ def test_instantiate_all_valid(self, *args):
+ yaml_sample = open(self.PKTGEN_VALUES_PATH, 'w')
+ yaml_sample.write(self.PKTGEN_VALUES)
+ yaml_sample.close()
+
+ self.vcmts_pktgen.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)
+ self.assertIsNotNone(self.vcmts_pktgen.pod_cfg)
+ self.assertEqual(self.vcmts_pktgen.pod_cfg["pktgen_id"], "0")
+
+ if os.path.isfile(self.PKTGEN_VALUES_PATH):
+ os.remove(self.PKTGEN_VALUES_PATH)
+
+ def test_run_traffic_failed_connect(self):
+ self.vcmts_pktgen.pktgen_helper = mock.MagicMock()
+ self.vcmts_pktgen.pktgen_helper.connect.return_value = False
+ with self.assertRaises(exceptions.PktgenActionError):
+ self.vcmts_pktgen.run_traffic({})
+
+ def test_run_traffic_successful_connect(self):
+ self.vcmts_pktgen.pktgen_helper = mock.MagicMock()
+ self.vcmts_pktgen.pktgen_helper.connect.return_value = True
+ self.vcmts_pktgen.pktgen_rate = 8.0
+ self.assertTrue(self.vcmts_pktgen.run_traffic({}))
+ self.vcmts_pktgen.pktgen_helper.connect.assert_called_once()
+ self.vcmts_pktgen.pktgen_helper.send_command.assert_called_with(
+ 'pktgen.start("all");')
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py
new file mode 100755
index 000000000..11e3d6e17
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vcmts_vnf.py
@@ -0,0 +1,651 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+import mock
+import copy
+import os
+
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
+from yardstick.network_services.vnf_generic.vnf import vcmts_vnf
+from yardstick.common import exceptions
+
+from influxdb.resultset import ResultSet
+
+NAME = "vnf__0"
+
+
+class TestInfluxDBHelper(unittest.TestCase):
+
+ def test___init__(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ self.assertEqual(influxdb_helper._vcmts_influxdb_ip, "localhost")
+ self.assertEqual(influxdb_helper._vcmts_influxdb_port, 8086)
+ self.assertIsNotNone(influxdb_helper._last_upstream_rx)
+ self.assertIsNotNone(influxdb_helper._last_values_time)
+
+ def test_start(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper.start()
+ self.assertIsNotNone(influxdb_helper._read_client)
+ self.assertIsNotNone(influxdb_helper._write_client)
+
+ def test__get_last_value_time(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ self.assertEqual(influxdb_helper._get_last_value_time('cpu_value'),
+ vcmts_vnf.InfluxDBHelper.INITIAL_VALUE)
+
+ influxdb_helper._last_values_time['cpu_value'] = "RANDOM"
+ self.assertEqual(influxdb_helper._get_last_value_time('cpu_value'),
+ "RANDOM")
+
+ def test__set_last_value_time(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._set_last_value_time('cpu_value', '00:00')
+ self.assertEqual(influxdb_helper._last_values_time['cpu_value'],
+ "'00:00'")
+
+ def test__query_measurement(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._read_client = mock.MagicMock()
+
+ resulted_generator = mock.MagicMock()
+ resulted_generator.keys.return_value = []
+ influxdb_helper._read_client.query.return_value = resulted_generator
+ query_result = influxdb_helper._query_measurement('cpu_value')
+ self.assertIsNone(query_result)
+
+ resulted_generator = mock.MagicMock()
+ resulted_generator.keys.return_value = ["", ""]
+ resulted_generator.get_points.return_value = ResultSet({"":""})
+ influxdb_helper._read_client.query.return_value = resulted_generator
+ query_result = influxdb_helper._query_measurement('cpu_value')
+ self.assertIsNotNone(query_result)
+
+ def test__rw_measurment(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._query_measurement = mock.MagicMock()
+ influxdb_helper._query_measurement.return_value = None
+ influxdb_helper._rw_measurment('cpu_value', [])
+ self.assertEqual(len(influxdb_helper._last_values_time), 0)
+
+ entry = {
+ "type":"type",
+ "host":"host",
+ "time":"time",
+ "id": "1",
+ "value": "1.0"
+ }
+ influxdb_helper._query_measurement.return_value = [entry]
+ influxdb_helper._write_client = mock.MagicMock()
+ influxdb_helper._rw_measurment('cpu_value', ["id", "value"])
+ self.assertEqual(len(influxdb_helper._last_values_time), 1)
+ influxdb_helper._write_client.write_points.assert_called_once()
+
+ def test_copy_kpi(self):
+ influxdb_helper = vcmts_vnf.InfluxDBHelper("localhost", 8086)
+ influxdb_helper._rw_measurment = mock.MagicMock()
+ influxdb_helper.copy_kpi()
+ influxdb_helper._rw_measurment.assert_called()
+
+
+class TestVcmtsdSetupEnvHelper(unittest.TestCase):
+ POD_CFG = {
+ "cm_crypto": "aes",
+ "cpu_socket_id": "0",
+ "ds_core_pool_index": "2",
+ "ds_core_type": "exclusive",
+ "net_ds": "1a:02.1",
+ "net_us": "1a:02.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "power_mgmt": "pm_on",
+ "qat": "qat_off",
+ "service_group_config": "",
+ "sg_id": "0",
+ "vcmtsd_image": "vcmts-d:perf"
+ }
+
+ OPTIONS = {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ }
+
+ def setUp(self):
+ vnfd_helper = VnfdHelper(
+ TestVcmtsVNF.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+
+ self.setup_helper = vcmts_vnf.VcmtsdSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ def _build_us_parameters(self):
+ return vcmts_vnf.VcmtsdSetupEnvHelper.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + str(self.POD_CFG['cpu_socket_id']) \
+ + " --pool=shared" \
+ + " /vcmts-config/run_upstream.sh " + self.POD_CFG['sg_id'] \
+ + " " + self.POD_CFG['ds_core_type'] \
+ + " " + str(self.POD_CFG['num_ofdm']) + "ofdm" \
+ + " " + str(self.POD_CFG['num_subs']) + "cm" \
+ + " " + self.POD_CFG['cm_crypto'] \
+ + " " + self.POD_CFG['qat'] \
+ + " " + self.POD_CFG['net_us'] \
+ + " " + self.POD_CFG['power_mgmt']
+
+ def test_build_us_parameters(self):
+ constructed = self._build_us_parameters()
+ result = self.setup_helper.build_us_parameters(self.POD_CFG)
+ self.assertEqual(constructed, result)
+
+ def _build_ds_parameters(self):
+ return vcmts_vnf.VcmtsdSetupEnvHelper.BASE_PARAMETERS + " " \
+ + " /opt/bin/cmk isolate --conf-dir=/etc/cmk" \
+ + " --socket-id=" + str(self.POD_CFG['cpu_socket_id']) \
+ + " --pool=" + self.POD_CFG['ds_core_type'] \
+ + " /vcmts-config/run_downstream.sh " + self.POD_CFG['sg_id'] \
+ + " " + self.POD_CFG['ds_core_type'] \
+ + " " + str(self.POD_CFG['ds_core_pool_index']) \
+ + " " + str(self.POD_CFG['num_ofdm']) + "ofdm" \
+ + " " + str(self.POD_CFG['num_subs']) + "cm" \
+ + " " + self.POD_CFG['cm_crypto'] \
+ + " " + self.POD_CFG['qat'] \
+ + " " + self.POD_CFG['net_ds'] \
+ + " " + self.POD_CFG['power_mgmt']
+
+ def test_build_ds_parameters(self):
+ constructed = self._build_ds_parameters()
+ result = self.setup_helper.build_ds_parameters(self.POD_CFG)
+ self.assertEqual(constructed, result)
+
+ def test_build_cmd(self):
+ us_constructed = self._build_us_parameters()
+ us_result = self.setup_helper.build_cmd('us', self.POD_CFG)
+ self.assertEqual(us_constructed, us_result)
+ ds_constructed = self._build_ds_parameters()
+ ds_result = self.setup_helper.build_cmd('ds', self.POD_CFG)
+ self.assertEqual(ds_constructed, ds_result)
+
+ def test_run_vcmtsd(self):
+ us_constructed = self._build_us_parameters()
+
+ vnfd_helper = VnfdHelper(
+ TestVcmtsVNF.VNFD['vnfd:vnfd-catalog']['vnfd'][0])
+ ssh_helper = mock.MagicMock()
+ scenario_helper = mock.Mock()
+ scenario_helper.options = self.OPTIONS
+
+ setup_helper = vcmts_vnf.VcmtsdSetupEnvHelper(
+ vnfd_helper, ssh_helper, scenario_helper)
+
+ setup_helper.run_vcmtsd('us', self.POD_CFG)
+ ssh_helper.send_command.assert_called_with(us_constructed)
+
+ def test_setup_vnf_environment(self):
+ self.assertIsNone(self.setup_helper.setup_vnf_environment())
+
+class TestVcmtsVNF(unittest.TestCase):
+
+ VNFD = {'vnfd:vnfd-catalog':
+ {'vnfd':
+ [{
+ "benchmark": {
+ "kpi": [
+ "upstream/bits_per_second"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "vCMTS Upstream-Downstream Kubernetes",
+ "id": "VcmtsVNF",
+ "mgmt-interface": {
+ "ip": "192.168.100.35",
+ "key_filename": "/tmp/yardstick_key-81dcca91",
+ "user": "root",
+ "vdu-id": "vcmtsvnf-kubernetes"
+ },
+ "name": "vcmtsvnf",
+ "short-name": "vcmtsvnf",
+ "vdu": [
+ {
+ "description": "vCMTS Upstream-Downstream Kubernetes",
+ "external-interface": [],
+ "id": "vcmtsvnf-kubernetes",
+ "name": "vcmtsvnf-kubernetes"
+ }
+ ],
+ "vm-flavor": {
+ "memory-mb": "4096",
+ "vcpu-count": "4"
+ }
+ }]
+ }
+ }
+
+ POD_CFG = [
+ {
+ "cm_crypto": "aes",
+ "cpu_socket_id": "0",
+ "ds_core_pool_index": "2",
+ "ds_core_type": "exclusive",
+ "net_ds": "1a:02.1",
+ "net_us": "1a:02.0",
+ "num_ofdm": "1",
+ "num_subs": "100",
+ "power_mgmt": "pm_on",
+ "qat": "qat_off",
+ "service_group_config": "",
+ "sg_id": "0",
+ "vcmtsd_image": "vcmts-d:perf"
+ },
+ ]
+
+ SCENARIO_CFG = {
+ "nodes": {
+ "tg__0": "pktgen0-k8syardstick-afae18b2",
+ "vnf__0": "vnf0us-k8syardstick-afae18b2",
+ "vnf__1": "vnf0ds-k8syardstick-afae18b2"
+ },
+ "options": {
+ "pktgen_values": "/tmp/pktgen_values.yaml",
+ "tg__0": {
+ "pktgen_id": 0
+ },
+ "vcmts_influxdb_ip": "10.80.5.150",
+ "vcmts_influxdb_port": 8086,
+ "vcmtsd_values": "/tmp/vcmtsd_values.yaml",
+ "vnf__0": {
+ "sg_id": 0,
+ "stream_dir": "us"
+ },
+ "vnf__1": {
+ "sg_id": 0,
+ "stream_dir": "ds"
+ }
+ },
+ "task_id": "afae18b2-9902-477f-8128-49afde7c3040",
+ "task_path": "samples/vnf_samples/nsut/cmts",
+ "tc": "tc_vcmts_k8s_pktgen",
+ "topology": "k8s_vcmts_topology.yaml",
+ "traffic_profile": "../../traffic_profiles/fixed.yaml",
+ "type": "NSPerf"
+ }
+
+ CONTEXT_CFG = {
+ "networks": {
+ "flannel": {
+ "name": "flannel"
+ },
+ "xe0": {
+ "name": "xe0"
+ },
+ "xe1": {
+ "name": "xe1"
+ }
+ },
+ "nodes": {
+ "tg__0": {
+ "VNF model": "../../vnf_descriptors/tg_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.24.110",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.24.110",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.24.110",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.24.110",
+ "key_filename": "/tmp/yardstick_key-afae18b2",
+ "member-vnf-index": "1",
+ "name": "pktgen0-k8syardstick-afae18b2",
+ "private_ip": "192.168.24.110",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 17153,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 51250,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 17153,
+ "user": "root",
+ "vnfd-id-ref": "tg__0"
+ },
+ "vnf__0": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.53",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.53",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.53",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.53",
+ "key_filename": "/tmp/yardstick_key-afae18b2",
+ "member-vnf-index": "3",
+ "name": "vnf0us-k8syardstick-afae18b2",
+ "private_ip": "192.168.100.53",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 34027,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 32580,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 34027,
+ "user": "root",
+ "vnfd-id-ref": "vnf__0"
+ },
+ "vnf__1": {
+ "VNF model": "../../vnf_descriptors/vnf_vcmts_tpl.yaml",
+ "interfaces": {
+ "flannel": {
+ "local_ip": "192.168.100.52",
+ "local_mac": None,
+ "network_name": "flannel"
+ },
+ "xe0": {
+ "local_ip": "192.168.100.52",
+ "local_mac": None,
+ "network_name": "xe0"
+ },
+ "xe1": {
+ "local_ip": "192.168.100.52",
+ "local_mac": None,
+ "network_name": "xe1"
+ }
+ },
+ "ip": "192.168.100.52",
+ "key_filename": "/tmp/yardstick_key-afae18b2",
+ "member-vnf-index": "4",
+ "name": "vnf0ds-k8syardstick-afae18b2",
+ "private_ip": "192.168.100.52",
+ "service_ports": [
+ {
+ "name": "ssh",
+ "node_port": 58661,
+ "port": 22,
+ "protocol": "TCP",
+ "target_port": 22
+ },
+ {
+ "name": "lua",
+ "node_port": 58233,
+ "port": 22022,
+ "protocol": "TCP",
+ "target_port": 22022
+ }
+ ],
+ "ssh_port": 58661,
+ "user": "root",
+ "vnfd-id-ref": "vnf__1"
+ },
+ }
+ }
+
+ VCMTSD_VALUES_PATH = "/tmp/vcmtsd_values.yaml"
+
+ VCMTSD_VALUES = \
+ "serviceAccount: cmk-serviceaccount\n" \
+ "topology:\n" \
+ " vcmts_replicas: 16\n" \
+ " vcmts_pods:\n" \
+ " - service_group_config:\n" \
+ " sg_id: 0\n" \
+ " net_us: 18:02.0\n" \
+ " net_ds: 18:02.1\n" \
+ " num_ofdm: 4\n" \
+ " num_subs: 300\n" \
+ " cm_crypto: aes\n" \
+ " qat: qat_off\n" \
+ " power_mgmt: pm_on\n" \
+ " cpu_socket_id: 0\n" \
+ " ds_core_type: exclusive\n" \
+ " ds_core_pool_index: 0\n" \
+ " vcmtsd_image: vcmts-d:feat"
+
+ VCMTSD_VALUES_INCOMPLETE = \
+ "serviceAccount: cmk-serviceaccount\n" \
+ "topology:\n" \
+ " vcmts_replicas: 16"
+
+ def setUp(self):
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ self.vnf = vcmts_vnf.VcmtsVNF(NAME, vnfd)
+
+ def test___init__(self, *args):
+ self.assertIsNotNone(self.vnf.setup_helper)
+
+ def test_extract_pod_cfg(self):
+ pod_cfg = self.vnf.extract_pod_cfg(self.POD_CFG, "0")
+ self.assertIsNotNone(pod_cfg)
+ self.assertEqual(pod_cfg['sg_id'], '0')
+ pod_cfg = self.vnf.extract_pod_cfg(self.POD_CFG, "1")
+ self.assertIsNone(pod_cfg)
+
+ def test_instantiate_missing_influxdb_info(self):
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'].pop('vcmts_influxdb_ip', None)
+ with self.assertRaises(KeyError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ def test_instantiate_missing_vcmtsd_values_file(self):
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['vcmtsd_values'] = self.VCMTSD_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ def test_instantiate_empty_vcmtsd_values_file(self):
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write("")
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options']['vcmtsd_values'] = self.VCMTSD_VALUES_PATH
+ with self.assertRaises(RuntimeError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ def test_instantiate_missing_vcmtsd_values_key(self):
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'].pop('vcmtsd_values', None)
+ with self.assertRaises(KeyError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ def test_instantiate_invalid_vcmtsd_values(self):
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write(self.VCMTSD_VALUES_INCOMPLETE)
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ with self.assertRaises(KeyError):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ def test_instantiate_invalid_sg_id(self):
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write(self.VCMTSD_VALUES)
+ yaml_sample.close()
+
+ err_scenario_cfg = copy.deepcopy(self.SCENARIO_CFG)
+ err_scenario_cfg['options'][NAME]['sg_id'] = 8
+ with self.assertRaises(exceptions.IncorrectConfig):
+ self.vnf.instantiate(err_scenario_cfg, self.CONTEXT_CFG)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ @mock.patch('yardstick.network_services.vnf_generic.vnf.vcmts_vnf.VnfSshHelper')
+ def test_instantiate_all_valid(self, ssh, *args):
+ mock_ssh(ssh)
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnf = vcmts_vnf.VcmtsVNF(NAME, vnfd)
+
+ yaml_sample = open(self.VCMTSD_VALUES_PATH, 'w')
+ yaml_sample.write(self.VCMTSD_VALUES)
+ yaml_sample.close()
+
+ vnf.instantiate(self.SCENARIO_CFG, self.CONTEXT_CFG)
+ self.assertEqual(vnf.vcmts_influxdb_ip, "10.80.5.150")
+ self.assertEqual(vnf.vcmts_influxdb_port, 8086)
+
+ if os.path.isfile(self.VCMTSD_VALUES_PATH):
+ os.remove(self.VCMTSD_VALUES_PATH)
+
+ def test__update_collectd_options(self):
+ scenario_cfg = {'options':
+ {'collectd':
+ {'interval': 3,
+ 'plugins':
+ {'plugin3': {'param': 3}}},
+ 'vnf__0':
+ {'collectd':
+ {'interval': 2,
+ 'plugins':
+ {'plugin3': {'param': 2},
+ 'plugin2': {'param': 2}}}}}}
+ context_cfg = {'nodes':
+ {'vnf__0':
+ {'collectd':
+ {'interval': 1,
+ 'plugins':
+ {'plugin3': {'param': 1},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}}}}
+ expected = {'interval': 1,
+ 'plugins':
+ {'plugin3': {'param': 1},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+
+ self.vnf._update_collectd_options(scenario_cfg, context_cfg)
+ self.assertEqual(self.vnf.setup_helper.collectd_options, expected)
+
+ def test__update_options(self):
+ options1 = {'interval': 1,
+ 'param1': 'value1',
+ 'plugins':
+ {'plugin3': {'param': 3},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+ options2 = {'interval': 2,
+ 'param2': 'value2',
+ 'plugins':
+ {'plugin4': {'param': 4},
+ 'plugin2': {'param': 2},
+ 'plugin1': {'param': 2}}}
+ expected = {'interval': 1,
+ 'param1': 'value1',
+ 'param2': 'value2',
+ 'plugins':
+ {'plugin4': {'param': 4},
+ 'plugin3': {'param': 3},
+ 'plugin2': {'param': 1},
+ 'plugin1': {'param': 1}}}
+
+ vnfd = self.VNFD['vnfd:vnfd-catalog']['vnfd'][0]
+ vnf = vcmts_vnf.VcmtsVNF('vnf1', vnfd)
+ vnf._update_options(options2, options1)
+ self.assertEqual(options2, expected)
+
+ def test_wait_for_instantiate(self):
+ self.assertIsNone(self.vnf.wait_for_instantiate())
+
+ def test_terminate(self):
+ self.assertIsNone(self.vnf.terminate())
+
+ def test_scale(self):
+ self.assertIsNone(self.vnf.scale())
+
+ def test_collect_kpi(self):
+ self.vnf.influxdb_helper = mock.MagicMock()
+ self.vnf.collect_kpi()
+ self.vnf.influxdb_helper.copy_kpi.assert_called_once()
+
+ def test_start_collect(self):
+ self.vnf.vcmts_influxdb_ip = "localhost"
+ self.vnf.vcmts_influxdb_port = 8800
+
+ self.assertIsNone(self.vnf.start_collect())
+ self.assertIsNotNone(self.vnf.influxdb_helper)
+
+ def test_stop_collect(self):
+ self.assertIsNone(self.vnf.stop_collect())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py
new file mode 100644
index 000000000..d86dab8ad
--- /dev/null
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vims_vnf.py
@@ -0,0 +1,713 @@
+# Copyright (c) 2019 Viosoft 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.
+
+import unittest
+import mock
+
+from yardstick.network_services.vnf_generic.vnf import vims_vnf
+from yardstick.tests.unit.network_services.vnf_generic.vnf.test_base import mock_ssh
+
+
+class TestVimsPcscfVnf(unittest.TestCase):
+
+ VNFD_0 = {
+ "short-name": "SippVnf",
+ "vdu": [
+ {
+ "id": "sippvnf-baremetal",
+ "routing_table": "",
+ "external-interface": [
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe0",
+ "name": "xe0"
+ },
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe1",
+ "name": "xe1"
+ }
+ ],
+ "name": "sippvnf-baremetal",
+ "description": "Sipp"
+ }
+ ],
+ "description": "ImsbenchSipp",
+ "mgmt-interface": {
+ "vdu-id": "sipp-baremetal",
+ "password": "r00t",
+ "user": "root",
+ "ip": "10.80.3.11"
+ },
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "id": "SippVnf",
+ "name": "SippVnf"
+ }
+
+ def setUp(self):
+ self.pcscf_vnf = vims_vnf.VimsPcscfVnf('vnf__0', self.VNFD_0)
+
+ def test___init__(self):
+ self.assertEqual(self.pcscf_vnf.name, 'vnf__0')
+ self.assertIsInstance(self.pcscf_vnf.resource_helper,
+ vims_vnf.VimsResourceHelper)
+ self.assertIsNone(self.pcscf_vnf._vnf_process)
+
+ def test_wait_for_instantiate(self):
+ self.assertIsNone(self.pcscf_vnf.wait_for_instantiate())
+
+ def test__run(self):
+ self.assertIsNone(self.pcscf_vnf._run())
+
+ def test_start_collect(self):
+ self.assertIsNone(self.pcscf_vnf.start_collect())
+
+ def test_collect_kpi(self):
+ self.assertIsNone(self.pcscf_vnf.collect_kpi())
+
+
+class TestVimsHssVnf(unittest.TestCase):
+
+ VNFD_1 = {
+ "short-name": "SippVnf",
+ "vdu": [
+ {
+ "id": "sippvnf-baremetal",
+ "routing_table": "",
+ "external-interface": [
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe0",
+ "name": "xe0"
+ },
+ {
+ "virtual-interface": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "vnfd-connection-point-ref": "xe1",
+ "name": "xe1"
+ }
+ ],
+ "name": "sippvnf-baremetal",
+ "description": "Sipp"
+ }
+ ],
+ "description": "ImsbenchSipp",
+ "mgmt-interface": {
+ "vdu-id": "sipp-baremetal",
+ "password": "r00t",
+ "user": "root",
+ "ip": "10.80.3.11"
+ },
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "id": "SippVnf",
+ "name": "SippVnf"
+ }
+
+ SCENARIO_CFG = {
+ "task_id": "86414e11-5ef5-4426-b175-71baaa00fbd7",
+ "tc": "tc_vims_baremetal_sipp",
+ "runner": {
+ "interval": 1,
+ "output_config": {
+ "DEFAULT": {
+ "debug": "False",
+ "dispatcher": [
+ "influxdb"
+ ]
+ },
+ "nsb": {
+ "debug": "False",
+ "trex_client_lib": "/opt/nsb_bin/trex_client/stl",
+ "bin_path": "/opt/nsb_bin",
+ "trex_path": "/opt/nsb_bin/trex/scripts",
+ "dispatcher": "influxdb"
+ },
+ "dispatcher_influxdb": {
+ "username": "root",
+ "target": "http://10.80.3.11:8086",
+ "db_name": "yardstick",
+ "timeout": "5",
+ "debug": "False",
+ "password": "root",
+ "dispatcher": "influxdb"
+ },
+ "dispatcher_http": {
+ "debug": "False",
+ "dispatcher": "influxdb",
+ "timeout": "5",
+ "target": "http://127.0.0.1:8000/results"
+ },
+ "dispatcher_file": {
+ "debug": "False",
+ "backup_count": "0",
+ "max_bytes": "0",
+ "dispatcher": "influxdb",
+ "file_path": "/tmp/yardstick.out"
+ }
+ },
+ "runner_id": 22610,
+ "duration": 60,
+ "type": "Vims"
+ },
+ "nodes": {
+ "vnf__0": "pcscf.yardstick-86414e11",
+ "vnf__1": "hss.yardstick-86414e11",
+ "tg__0": "sipp.yardstick-86414e11"
+ },
+ "topology": "vims-topology.yaml",
+ "type": "NSPerf",
+ "traffic_profile": "../../traffic_profiles/ipv4_throughput.yaml",
+ "task_path": "samples/vnf_samples/nsut/vims",
+ "options": {
+ "init_reg_max": 5000,
+ "end_user": 10000,
+ "reg_cps": 20,
+ "rereg_cps": 20,
+ "rereg_step": 10,
+ "wait_time": 5,
+ "start_user": 1,
+ "msgc_cps": 10,
+ "dereg_step": 10,
+ "call_cps": 10,
+ "reg_step": 10,
+ "init_reg_cps": 50,
+ "dereg_cps": 20,
+ "msgc_step": 5,
+ "call_step": 5,
+ "hold_time": 15,
+ "port": 5060,
+ "run_mode": "nortp"
+ }
+ }
+
+ CONTEXT_CFG = {
+ "nodes": {
+ "tg__0": {
+ "ip": "10.80.3.11",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "xe1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vnf__0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "vnf__1": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/tg_sipp_vnfd.yaml",
+ "name": "sipp.yardstick-86414e11",
+ "vnfd-id-ref": "tg__0",
+ "member-vnf-index": "1",
+ "role": "TrafficGen",
+ "ctx_type": "Node"
+ },
+ "vnf__0": {
+ "ip": "10.80.3.7",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "tg__0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/vims_pcscf_vnfd.yaml",
+ "name": "pcscf.yardstick-86414e11",
+ "vnfd-id-ref": "vnf__0",
+ "member-vnf-index": "2",
+ "role": "VirtualNetworkFunction",
+ "ctx_type": "Node"
+ },
+ "vnf__1": {
+ "ip": "10.80.3.7",
+ "interfaces": {
+ "xe0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "tg__0": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "peer_intf": {
+ "vld_id": "data_network",
+ "peer_ifname": "xe1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "network": {},
+ "local_ip": "10.80.3.7",
+ "peer_intf": {
+ "vld_id": "ims_network",
+ "peer_ifname": "xe0",
+ "dst_mac": "90:e2:ba:7c:41:e8",
+ "network": {},
+ "local_ip": "10.80.3.11",
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ },
+ "node_name": "vnf__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:a8"
+ },
+ "node_name": "tg__0",
+ "netmask": "255.255.255.0",
+ "peer_name": "vnf__1",
+ "dst_ip": "10.80.3.7",
+ "ifname": "xe1",
+ "local_mac": "90:e2:ba:7c:30:e8"
+ }
+ },
+ "node_name": "vnf__1",
+ "netmask": "255.255.255.0",
+ "peer_name": "tg__0",
+ "dst_ip": "10.80.3.11",
+ "ifname": "xe0",
+ "local_mac": "90:e2:ba:7c:41:e8"
+ }
+ },
+ "user": "root",
+ "password": "r00t",
+ "VNF model": "../../vnf_descriptors/vims_hss_vnfd.yaml",
+ "name": "hss.yardstick-86414e11",
+ "vnfd-id-ref": "vnf__1",
+ "member-vnf-index": "3",
+ "role": "VirtualNetworkFunction",
+ "ctx_type": "Node"
+ }
+ },
+ "networks": {}
+ }
+
+ def setUp(self):
+ self.hss_vnf = vims_vnf.VimsHssVnf('vnf__1', self.VNFD_1)
+
+ def test___init__(self):
+ self.assertIsInstance(self.hss_vnf.resource_helper,
+ vims_vnf.VimsResourceHelper)
+ self.assertIsNone(self.hss_vnf._vnf_process)
+
+ @mock.patch("yardstick.network_services.vnf_generic.vnf.sample_vnf.VnfSshHelper")
+ def test_instantiate(self, ssh):
+ mock_ssh(ssh)
+ hss_vnf = vims_vnf.VimsHssVnf('vnf__1', self.VNFD_1)
+ self.assertIsNone(hss_vnf.instantiate(self.SCENARIO_CFG,
+ self.CONTEXT_CFG))
+
+ def test_wait_for_instantiate(self):
+ self.assertIsNone(self.hss_vnf.wait_for_instantiate())
+
+ def test_start_collect(self):
+ self.assertIsNone(self.hss_vnf.start_collect())
+
+ def test_collect_kpi(self):
+ self.assertIsNone(self.hss_vnf.collect_kpi())
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py
index 597844c72..c3066d7fe 100644
--- a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py
+++ b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_vpp_helpers.py
@@ -11,13 +11,199 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+import ipaddress
import unittest
import mock
+from yardstick.common import exceptions
+from yardstick.network_services.helpers import cpu
+from yardstick.network_services.vnf_generic.vnf import vpp_helpers
from yardstick.network_services.vnf_generic.vnf.base import VnfdHelper
from yardstick.network_services.vnf_generic.vnf.vpp_helpers import \
- VppSetupEnvHelper
+ VppSetupEnvHelper, VppConfigGenerator, VatTerminal
+
+
+class TestVppConfigGenerator(unittest.TestCase):
+
+ def test_add_config_item(self):
+ test_item = {}
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_config_item(test_item, '/tmp/vpe.log',
+ ['unix', 'log'])
+ self.assertEqual({'unix': {'log': '/tmp/vpe.log'}}, test_item)
+
+ def test_add_config_item_str(self):
+ test_item = {'unix': ''}
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_config_item(test_item, '/tmp/vpe.log',
+ ['unix', 'log'])
+ self.assertEqual({'unix': {'log': '/tmp/vpe.log'}}, test_item)
+
+ def test_add_unix_log(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_log()
+ self.assertEqual('unix\n{\n log /tmp/vpe.log\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_unix_cli_listen(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_cli_listen()
+ self.assertEqual('unix\n{\n cli-listen /run/vpp/cli.sock\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_unix_nodaemon(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_nodaemon()
+ self.assertEqual('unix\n{\n nodaemon \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_unix_coredump(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_coredump()
+ self.assertEqual('unix\n{\n full-coredump \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev('0000:00:00.0')
+ self.assertEqual('dpdk\n{\n dev 0000:00:00.0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_cryptodev(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_cryptodev(2, '0000:00:00.0')
+ self.assertEqual(
+ 'dpdk\n{\n dev 0000:00:01.0 \n dev 0000:00:01.1 \n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_sw_cryptodev(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_sw_cryptodev('aesni_gcm', 0, 2)
+ self.assertEqual(
+ 'dpdk\n{\n vdev cryptodev_aesni_gcm_pmd,socket_id=0 \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev_default_rxq(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev_default_rxq(1)
+ self.assertEqual(
+ 'dpdk\n{\n dev default\n {\n num-rx-queues 1\n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev_default_rxd(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev_default_rxd(2048)
+ self.assertEqual(
+ 'dpdk\n{\n dev default\n {\n num-rx-desc 2048\n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_dev_default_txd(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_dev_default_txd(2048)
+ self.assertEqual(
+ 'dpdk\n{\n dev default\n {\n num-tx-desc 2048\n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_log_level(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_log_level('debug')
+ self.assertEqual('dpdk\n{\n log-level debug\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_socketmem(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_socketmem('1024,1024')
+ self.assertEqual('dpdk\n{\n socket-mem 1024,1024\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_num_mbufs(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_num_mbufs(32768)
+ self.assertEqual('dpdk\n{\n num-mbufs 32768\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_uio_driver(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_uio_driver('igb_uio')
+ self.assertEqual('dpdk\n{\n uio-driver igb_uio\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_cpu_main_core(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_cpu_main_core('1,2')
+ self.assertEqual('cpu\n{\n main-core 1,2\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_cpu_corelist_workers(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_cpu_corelist_workers('1,2')
+ self.assertEqual('cpu\n{\n corelist-workers 1,2\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_heapsize(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_heapsize('4G')
+ self.assertEqual('heapsize 4G\n', vpp_config_generator.dump_config())
+
+ def test_add_ip6_hash_buckets(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_ip6_hash_buckets(2000000)
+ self.assertEqual('ip6\n{\n hash-buckets 2000000\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_ip6_heap_size(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_ip6_heap_size('4G')
+ self.assertEqual('ip6\n{\n heap-size 4G\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_ip_heap_size(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_ip_heap_size('4G')
+ self.assertEqual('ip\n{\n heap-size 4G\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_statseg_size(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_statseg_size('4G')
+ self.assertEqual('statseg\n{\n size 4G\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_plugin(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_plugin('enable', ['dpdk_plugin.so'])
+ self.assertEqual(
+ 'plugins\n{\n plugin [\'dpdk_plugin.so\']\n {\n enable \n }\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_no_multi_seg(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_no_multi_seg()
+ self.assertEqual('dpdk\n{\n no-multi-seg \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_add_dpdk_no_tx_checksum_offload(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_dpdk_no_tx_checksum_offload()
+ self.assertEqual('dpdk\n{\n no-tx-checksum-offload \n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_dump_config(self):
+ vpp_config_generator = VppConfigGenerator()
+ vpp_config_generator.add_unix_log()
+ self.assertEqual('unix\n{\n log /tmp/vpe.log\n}\n',
+ vpp_config_generator.dump_config())
+
+ def test_pci_dev_check(self):
+ self.assertTrue(VppConfigGenerator.pci_dev_check('0000:00:00.0'))
+
+ def test_pci_dev_check_error(self):
+ with self.assertRaises(ValueError) as raised:
+ VppConfigGenerator.pci_dev_check('0000:00:0.0')
+ self.assertIn(
+ 'PCI address 0000:00:0.0 is not in valid format xxxx:xx:xx.x',
+ str(raised.exception))
class TestVppSetupEnvHelper(unittest.TestCase):
@@ -130,6 +316,224 @@ class TestVppSetupEnvHelper(unittest.TestCase):
]
}
+ VNFD_1 = {
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "VPP IPsec",
+ "id": "VipsecApproxVnf",
+ "mgmt-interface": {
+ "ip": "10.10.10.101",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "ipsecvnf-baremetal"
+ },
+ "name": "IpsecVnf",
+ "short-name": "IpsecVnf",
+ "vdu": [
+ {
+ "description": "VPP Ipsec",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:ff:07.0"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "ipsecvnf-baremetal",
+ "name": "ipsecvnf-baremetal",
+ "routing_table": []
+ }
+ ]
+ }
+
+ VNFD_2 = {
+ "benchmark": {
+ "kpi": [
+ "packets_in",
+ "packets_fwd",
+ "packets_dropped"
+ ]
+ },
+ "connection-point": [
+ {
+ "name": "xe0",
+ "type": "VPORT"
+ },
+ {
+ "name": "xe1",
+ "type": "VPORT"
+ }
+ ],
+ "description": "VPP IPsec",
+ "id": "VipsecApproxVnf",
+ "mgmt-interface": {
+ "ip": "10.10.10.101",
+ "password": "r00t",
+ "user": "root",
+ "vdu-id": "ipsecvnf-baremetal"
+ },
+ "name": "IpsecVnf",
+ "short-name": "IpsecVnf",
+ "vdu": [
+ {
+ "description": "VPP Ipsec",
+ "external-interface": [
+ {
+ "name": "xe0",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.1",
+ "dst_mac": "90:e2:ba:7c:30:e8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.2",
+ "local_mac": "90:e2:ba:7c:41:a8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe0",
+ "peer_intf": {
+ "dpdk_port_num": 0,
+ "driver": "igb_uio",
+ "dst_ip": "192.168.100.2",
+ "dst_mac": "90:e2:ba:7c:41:a8",
+ "ifname": "xe0",
+ "local_ip": "192.168.100.1",
+ "local_mac": "90:e2:ba:7c:30:e8",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "tg__0",
+ "peer_ifname": "xe0",
+ "peer_name": "vnf__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:81:00.0"
+ },
+ "peer_name": "tg__0",
+ "vld_id": "uplink_0",
+ "vpci": "0000:ff:06.0"
+ },
+ "vnfd-connection-point-ref": "xe0"
+ },
+ {
+ "name": "xe1",
+ "virtual-interface": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.2",
+ "dst_mac": "0a:b1:ec:fd:a2:66",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.1",
+ "local_mac": "4e:90:85:d3:c5:13",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__0",
+ "peer_ifname": "xe1",
+ "peer_intf": {
+ "driver": "igb_uio",
+ "dst_ip": "1.1.1.1",
+ "dst_mac": "4e:90:85:d3:c5:13",
+ "ifname": "xe1",
+ "local_ip": "1.1.1.2",
+ "local_mac": "0a:b1:ec:fd:a2:66",
+ "netmask": "255.255.255.0",
+ "network": {},
+ "node_name": "vnf__1",
+ "peer_ifname": "xe1",
+ "peer_name": "vnf__0",
+ "vld_id": "ciphertext",
+ "vpci": "0000:00:07.0"
+ },
+ "peer_name": "vnf__1",
+ "vld_id": "ciphertext",
+ "vpci": "0000:ff:07.0"
+ },
+ "vnfd-connection-point-ref": "xe1"
+ }
+ ],
+ "id": "ipsecvnf-baremetal",
+ "name": "ipsecvnf-baremetal",
+ "routing_table": []
+ }
+ ]
+ }
+
VNFD = {
'vnfd:vnfd-catalog': {
'vnfd': [
@@ -216,6 +620,105 @@ class TestVppSetupEnvHelper(unittest.TestCase):
}
]
+ VPP_INTERFACES_DUMP_MAC_ERR = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0,
+ "l2_address_length": 0,
+ "l2_address": [0, 0, 0, 0, 0, 0, 0, 0],
+ "interface_name": "local0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 0,
+ "link_speed": 0,
+ "mtu": 0,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 169, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ },
+ {
+ "sw_if_index": 2,
+ "sup_sw_if_index": 2,
+ "l2_address_length": 6,
+ "l2_address": [78, 144, 133, 211, 197, 20, 0, 0],
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9206,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }
+ ]
+
+ CPU_LAYOUT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0, 1, 1, 0]]}
+ CPU_SMT = {'cpuinfo': [[0, 0, 0, 0, 0, 0, 0, 0],
+ [1, 0, 0, 0, 0, 1, 1, 0],
+ [2, 1, 0, 0, 0, 2, 2, 1],
+ [3, 1, 0, 0, 0, 3, 3, 1],
+ [4, 2, 0, 0, 0, 4, 4, 2],
+ [5, 2, 0, 0, 0, 5, 5, 2],
+ [6, 3, 0, 0, 0, 6, 6, 3],
+ [7, 3, 0, 0, 0, 7, 7, 3],
+ [8, 4, 0, 0, 0, 8, 8, 4],
+ [9, 5, 0, 1, 0, 0, 0, 0],
+ [10, 6, 0, 1, 0, 1, 1, 0],
+ [11, 6, 0, 1, 0, 2, 2, 1],
+ [12, 7, 0, 1, 0, 3, 3, 1],
+ [13, 7, 0, 1, 0, 4, 4, 2],
+ [14, 8, 0, 1, 0, 5, 5, 2],
+ [15, 8, 0, 1, 0, 6, 6, 3],
+ [16, 9, 0, 1, 0, 7, 7, 3],
+ [17, 9, 0, 1, 0, 8, 8, 4]]}
+
def test_kill_vnf(self):
vnfd_helper = VnfdHelper(self.VNFD_0)
ssh_helper = mock.Mock()
@@ -333,3 +836,772 @@ class TestVppSetupEnvHelper(unittest.TestCase):
self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key(
'xe2', 'vpp-err'))
+
+ def test_vpp_create_ipsec_tunnels(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_create_ipsec_tunnels('10.10.10.2',
+ '10.10.10.1', 'xe0',
+ 1, 1, mock.Mock(),
+ 'crypto_key',
+ mock.Mock(),
+ 'integ_key',
+ '20.20.20.0'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+
+ def test_vpp_create_ipsec_1000_tunnels(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_create_ipsec_tunnels('10.10.10.2',
+ '10.10.10.1', 'xe0',
+ 1000, 128000,
+ mock.Mock(),
+ 'crypto_key',
+ mock.Mock(),
+ 'integ_key',
+ '20.20.20.0'))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+
+ def test_apply_config(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.apply_config(mock.Mock()))
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+
+ def test_apply_config_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 1, '', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with self.assertRaises(RuntimeError) as raised:
+ vpp_setup_env_helper.apply_config(mock.Mock())
+
+ self.assertIn('Writing config file failed', str(raised.exception))
+
+ def test_vpp_route_add(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_route_add('xe0', '10.10.10.1', 24))
+
+ def test_vpp_route_add_without_index(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_route_add('xe0', '10.10.10.1', 24,
+ interface='xe0',
+ use_sw_index=False))
+
+ def test_add_arp_on_dut(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('', vpp_setup_env_helper.add_arp_on_dut('xe0',
+ '10.10.10.1',
+ '00:00:00:00:00:00'))
+
+ def test_set_ip(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('',
+ vpp_setup_env_helper.set_ip('xe0', '10.10.10.1',
+ 24))
+
+ def test_set_interface_state(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('',
+ vpp_setup_env_helper.set_interface_state('xe0',
+ 'up'))
+
+ def test_set_interface_state_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ with self.assertRaises(ValueError) as raised:
+ vpp_setup_env_helper.set_interface_state('xe0', 'error')
+ self.assertIn('Unexpected interface state: error',
+ str(raised.exception))
+
+ def test_set_interface_down_state(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertEqual('',
+ vpp_setup_env_helper.set_interface_state('xe0',
+ 'down'))
+
+ def test_vpp_set_interface_mtu(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = ''
+ self.assertIsNone(
+ vpp_setup_env_helper.vpp_set_interface_mtu('xe0', 9200))
+
+ def test_vpp_interfaces_ready_wait(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertIsNone(vpp_setup_env_helper.vpp_interfaces_ready_wait())
+
+ def test_vpp_interfaces_ready_wait_timeout(self):
+ json_output = [[
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0,
+ "l2_address_length": 0,
+ "l2_address": [0, 0, 0, 0, 0, 0, 0, 0],
+ "interface_name": "xe0",
+ "admin_up_down": 1,
+ "link_up_down": 0,
+ "link_duplex": 0,
+ "link_speed": 0,
+ "mtu": 0,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }]]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ with self.assertRaises(RuntimeError) as raised:
+ vpp_setup_env_helper.vpp_interfaces_ready_wait(5)
+ self.assertIn('timeout, not up [\'xe0\']', str(raised.exception))
+
+ def test_vpp_get_interface_data(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual(json_output[0],
+ vpp_setup_env_helper.vpp_get_interface_data())
+
+ def test_vpp_get_interface_data_ifname(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual(json_output[0][2],
+ vpp_setup_env_helper.vpp_get_interface_data(
+ 'VirtualFunctionEthernetff/7/0'))
+
+ def test_vpp_get_interface_data_ifname_error(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual({}, vpp_setup_env_helper.vpp_get_interface_data(
+ 'error'))
+
+ def test_vpp_get_interface_data_ifindex(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ self.assertEqual(json_output[0][1],
+ vpp_setup_env_helper.vpp_get_interface_data(1))
+
+ def test_vpp_get_interface_data_error(self):
+ json_output = [self.VPP_INTERFACES_DUMP]
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+
+ with mock.patch.object(vpp_helpers.VatTerminal,
+ 'vat_terminal_exec_cmd_from_template') as \
+ mock_vat_terminal_exec_cmd_from_template:
+ mock_vat_terminal_exec_cmd_from_template.return_value = json_output
+ with self.assertRaises(TypeError) as raised:
+ vpp_setup_env_helper.vpp_get_interface_data(1.0)
+ self.assertEqual('', str(raised.exception))
+
+ def test_update_vpp_interface_data(self):
+ output = '{}\n{}'.format(self.VPP_INTERFACES_DUMP,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, output.replace("\'", "\""), ''
+ ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates'
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.update_vpp_interface_data())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 1)
+ self.assertEqual('TenGigabitEthernetff/6/0',
+ vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_name'))
+ self.assertEqual(1, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'vpp_sw_index'))
+ self.assertEqual('VirtualFunctionEthernetff/7/0',
+ vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_name'))
+ self.assertEqual(2, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'vpp_sw_index'))
+
+ def test_update_vpp_interface_data_error(self):
+ output = '{}\n{}'.format(self.VPP_INTERFACES_DUMP_MAC_ERR,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, output.replace("\'", "\""), ''
+ ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates'
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.update_vpp_interface_data())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 1)
+
+ def test_iface_update_numa(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '0', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertIsNone(vpp_setup_env_helper.iface_update_numa())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+
+ def test_iface_update_numa_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_1)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '-1', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout:
+ mock_get_cpu_layout.return_value = self.CPU_LAYOUT
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ self.assertIsNone(vpp_setup_env_helper.iface_update_numa())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertEqual(0, vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+
+ def test_iface_update_without_numa(self):
+ vnfd_helper = VnfdHelper(self.VNFD_2)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, '-1', ''
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with mock.patch.object(cpu.CpuSysCores, 'get_cpu_layout') as \
+ mock_get_cpu_layout:
+ mock_get_cpu_layout.return_value = self.CPU_SMT
+ sys_cores = cpu.CpuSysCores(ssh_helper)
+ vpp_setup_env_helper._update_vnfd_helper(
+ sys_cores.get_cpu_layout())
+ self.assertIsNone(vpp_setup_env_helper.iface_update_numa())
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 2)
+ self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe0', 'numa_node'))
+ self.assertIsNone(vpp_setup_env_helper.get_value_by_interface_key(
+ 'xe1', 'numa_node'))
+
+ def test_execute_script(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ vpp_setup_env_helper.execute_script('dump_interfaces.vat', True, True)
+ self.assertGreaterEqual(ssh_helper.put_file.call_count, 1)
+ self.assertGreaterEqual(ssh_helper.execute.call_count, 1)
+
+ def test_execute_script_error(self):
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.side_effect = Exception
+
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ with self.assertRaises(Exception) as raised:
+ vpp_setup_env_helper.execute_script('dump_interfaces.vat', True,
+ True)
+ self.assertIn(
+ 'VAT script execution failed: vpp_api_test json in dump_interfaces.vat script',
+ str(raised.exception))
+ self.assertGreaterEqual(ssh_helper.put_file.call_count, 1)
+
+ def test_execute_script_json_out(self):
+ json_output = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0
+ },
+ {
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 168, 0, 0]
+ },
+ {
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0
+ }
+ ]
+ output = '{}\n{}'.format(json_output,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ vnfd_helper = VnfdHelper(self.VNFD_0)
+ ssh_helper = mock.Mock()
+ ssh_helper.execute.return_value = 0, output, ''
+ ssh_helper.join_bin_path.return_value = '/opt/nsb_bin/vpp/templates'
+ scenario_helper = mock.Mock()
+ vpp_setup_env_helper = VppSetupEnvHelper(vnfd_helper, ssh_helper,
+ scenario_helper)
+ self.assertEqual(str(json_output),
+ vpp_setup_env_helper.execute_script_json_out(
+ 'dump_interfaces.vat'))
+
+ def test_self_cleanup_vat_json_output(self):
+ json_output = [
+ {
+ "sw_if_index": 0,
+ "sup_sw_if_index": 0
+ },
+ {
+ "l2_address_length": 6,
+ "l2_address": [144, 226, 186, 124, 65, 168, 0, 0]
+ },
+ {
+ "interface_name": "VirtualFunctionEthernetff/7/0",
+ "admin_up_down": 0
+ }
+ ]
+
+ output = '{}\n{}'.format(json_output,
+ 'dump_interface_table:6019: JSON output ' \
+ 'supported only for VPE API calls and dump_stats_table\n' \
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat(2): \n' \
+ 'dump_interface_table error: Misc')
+ self.assertEqual(str(json_output),
+ VppSetupEnvHelper.cleanup_vat_json_output(output,
+ '/opt/nsb_bin/vpp/templates/dump_interfaces.vat'))
+
+ def test__convert_mac_to_number_list(self):
+ self.assertEqual([144, 226, 186, 124, 65, 168],
+ VppSetupEnvHelper._convert_mac_to_number_list(
+ '90:e2:ba:7c:41:a8'))
+
+ def test_get_vpp_interface_by_mac(self):
+ mac_address = '90:e2:ba:7c:41:a8'
+ self.assertEqual({'admin_up_down': 0,
+ 'interface_name': 'TenGigabitEthernetff/6/0',
+ 'l2_address': [144, 226, 186, 124, 65, 168, 0, 0],
+ 'l2_address_length': 6,
+ 'link_duplex': 2,
+ 'link_speed': 32,
+ 'link_up_down': 0,
+ 'mtu': 9202,
+ 'sub_default': 0,
+ 'sub_dot1ad': 0,
+ 'sub_exact_match': 0,
+ 'sub_id': 0,
+ 'sub_inner_vlan_id': 0,
+ 'sub_inner_vlan_id_any': 0,
+ 'sub_number_of_tags': 0,
+ 'sub_outer_vlan_id': 0,
+ 'sub_outer_vlan_id_any': 0,
+ 'sup_sw_if_index': 1,
+ 'sw_if_index': 1,
+ 'vtr_op': 0,
+ 'vtr_push_dot1q': 0,
+ 'vtr_tag1': 0,
+ 'vtr_tag2': 0},
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ self.VPP_INTERFACES_DUMP, mac_address))
+
+ def test_get_vpp_interface_by_mac_error(self):
+ mac_address = '90:e2:ba:7c:41:a9'
+ with self.assertRaises(ValueError) as raised:
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ [{
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 7,
+ "l2_address": [144, 226, 186, 124, 65, 169, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }], mac_address)
+
+ self.assertIn('l2_address_length value is not 6.',
+ str(raised.exception))
+
+ def test_get_vpp_interface_by_mac_l2_error(self):
+ mac_address = '90:e2:ba:7c:41:a7'
+ with self.assertRaises(KeyError) as raised:
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ [{
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length": 6,
+ "l2_address_err": [144, 226, 186, 124, 65, 167, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }], mac_address)
+
+ self.assertIn(
+ 'key l2_address not found in interface dict.Probably input list ' \
+ 'is not parsed from correct VAT json output.',
+ str(raised.exception))
+
+ def test_get_vpp_interface_by_mac_l2_length_error(self):
+ mac_address = '90:e2:ba:7c:41:a6'
+ with self.assertRaises(KeyError) as raised:
+ VppSetupEnvHelper.get_vpp_interface_by_mac(
+ [{
+ "sw_if_index": 1,
+ "sup_sw_if_index": 1,
+ "l2_address_length_err": 6,
+ "l2_address": [144, 226, 186, 124, 65, 166, 0, 0],
+ "interface_name": "TenGigabitEthernetff/6/0",
+ "admin_up_down": 0,
+ "link_up_down": 0,
+ "link_duplex": 2,
+ "link_speed": 32,
+ "mtu": 9202,
+ "sub_id": 0,
+ "sub_dot1ad": 0,
+ "sub_number_of_tags": 0,
+ "sub_outer_vlan_id": 0,
+ "sub_inner_vlan_id": 0,
+ "sub_exact_match": 0,
+ "sub_default": 0,
+ "sub_outer_vlan_id_any": 0,
+ "sub_inner_vlan_id_any": 0,
+ "vtr_op": 0,
+ "vtr_push_dot1q": 0,
+ "vtr_tag1": 0,
+ "vtr_tag2": 0
+ }], mac_address)
+
+ self.assertIn(
+ 'key l2_address_length not found in interface dict. Probably ' \
+ 'input list is not parsed from correct VAT json output.',
+ str(raised.exception))
+
+ def test_get_prefix_length(self):
+ start_ip = '10.10.10.0'
+ end_ip = '10.10.10.127'
+ ips = [ipaddress.ip_address(ip) for ip in
+ [str(ipaddress.ip_address(start_ip)), str(end_ip)]]
+ lowest_ip, highest_ip = min(ips), max(ips)
+
+ self.assertEqual(25,
+ VppSetupEnvHelper.get_prefix_length(int(lowest_ip),
+ int(highest_ip),
+ lowest_ip.max_prefixlen))
+
+ def test_get_prefix_length_zero_prefix(self):
+ start_ip = '10.0.0.0'
+ end_ip = '10.0.0.0'
+ ips = [ipaddress.ip_address(ip) for ip in
+ [str(ipaddress.ip_address(start_ip)), str(end_ip)]]
+ lowest_ip, highest_ip = min(ips), max(ips)
+
+ self.assertEqual(0,
+ VppSetupEnvHelper.get_prefix_length(int(lowest_ip),
+ int(highest_ip),
+ 0))
+
+
+class TestVatTerminal(unittest.TestCase):
+
+ def test___init___error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_open.side_effect = exceptions.SSHTimeout
+
+ with self.assertRaises(RuntimeError) as raised:
+ VatTerminal(ssh_helper, json_param=True)
+ self.assertIn('Cannot open interactive terminal',
+ str(raised.exception))
+
+ def test___init___exec_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout
+ VatTerminal(ssh_helper, json_param=True)
+
+ def test_vat_terminal_exec_cmd(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ {'empty': 'value'}).replace("\'", "\"")
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ self.assertEqual({'empty': 'value'},
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200"))
+
+ def test_vat_terminal_exec_cmd_array(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ [{'empty': 'value'}]).replace("\'", "\"")
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ self.assertEqual([{'empty': 'value'}],
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200"))
+
+ def test_vat_terminal_exec_cmd_without_output(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ {'empty': 'value'}).replace("\'", "\"")
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+
+ self.assertIsNone(vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200"))
+
+ def test_vat_terminal_exec_cmd_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ {'empty': 'value'}).replace("\'", "\"")
+ ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout
+
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200")
+ self.assertIn(
+ 'VPP is not running on node. VAT command hw_interface_set_mtu ' \
+ 'sw_if_index 1 mtu 9200 execution failed',
+ str(raised.exception))
+
+ def test_vat_terminal_exec_cmd_output_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.return_value = str(
+ 'empty: value').replace("\'", "\"")
+
+ vat_terminal = VatTerminal(ssh_helper, json_param=True)
+
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_exec_cmd(
+ "hw_interface_set_mtu sw_if_index 1 mtu 9200")
+ self.assertIn(
+ 'VAT command hw_interface_set_mtu sw_if_index 1 mtu 9200: no JSON data.',
+ str(raised.exception))
+
+ def test_vat_terminal_close(self):
+ ssh_helper = mock.Mock()
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+ self.assertIsNone(vat_terminal.vat_terminal_close())
+
+ def test_vat_terminal_close_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_exec_command.side_effect = exceptions.SSHTimeout
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_close()
+ self.assertIn('Failed to close VAT console', str(raised.exception))
+
+ def test_vat_terminal_close_vat_error(self):
+ ssh_helper = mock.Mock()
+ ssh_helper.interactive_terminal_close.side_effect = exceptions.SSHTimeout
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+ with self.assertRaises(RuntimeError) as raised:
+ vat_terminal.vat_terminal_close()
+ self.assertIn('Cannot close interactive terminal',
+ str(raised.exception))
+
+ def test_vat_terminal_exec_cmd_from_template(self):
+ ssh_helper = mock.Mock()
+ vat_terminal = VatTerminal(ssh_helper, json_param=False)
+
+ with mock.patch.object(vat_terminal, 'vat_terminal_exec_cmd') as \
+ mock_vat_terminal_exec_cmd:
+ mock_vat_terminal_exec_cmd.return_value = 'empty'
+ self.assertEqual(['empty'],
+ vat_terminal.vat_terminal_exec_cmd_from_template(
+ "hw_interface_set_mtu.vat", sw_if_index=1,
+ mtu=9200))