summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Liu <yong.liu@intel.com>2015-08-13 14:16:37 +0800
committerMarvin Liu <yong.liu@intel.com>2015-08-13 14:16:37 +0800
commit1851d5c4c6e29a2f1838a1de475f68945df6c1c5 (patch)
tree771f814f4d2a892b2108d96a9cdd27bf975c673a
parent96e1bf463f6e7a2d25de6a058d6d62d312bb7c0f (diff)
parent836e580abe87becc244265120e1f64d11ce1036c (diff)
downloaddts-1851d5c4c6e29a2f1838a1de475f68945df6c1c5.zip
dts-1851d5c4c6e29a2f1838a1de475f68945df6c1c5.tar.gz
dts-1851d5c4c6e29a2f1838a1de475f68945df6c1c5.tar.xz
Merge branch '1.1'
-rw-r--r--conf/dpdk_test_case_checklist.xlsbin0 -> 19968 bytes
-rw-r--r--conf/ports.cfg7
-rw-r--r--conf/scene/dpdk_vf_passthrough.cfg32
-rw-r--r--conf/scene/pf_passthrough.cfg25
-rw-r--r--conf/scene/vf_passthrough.cfg28
-rw-r--r--conf/scene/vf_passthrough_1.cfg27
-rw-r--r--conf/sriov_kvm.cfg164
-rw-r--r--conf/vhost_cuse_sample.cfg14
-rw-r--r--conf/vhost_sample.cfg14
-rw-r--r--conf/virt_global.cfg22
-rw-r--r--conf/vm_power_manager.cfg40
-rw-r--r--conf/vxlan_sample.cfg28
-rw-r--r--dep/QMP/qemu-ga-client299
-rw-r--r--dep/QMP/qmp.py193
-rw-r--r--dep/macfwd_log.patch10
-rw-r--r--dep/nvgre.py33
-rw-r--r--dep/vxlan.py33
-rw-r--r--executions/execution.cfg (renamed from execution.cfg)13
-rw-r--r--executions/execution_FVL.cfg43
-rw-r--r--executions/execution_rxmode.cfg62
-rw-r--r--executions/execution_smoke.cfg31
-rw-r--r--framework/checkCase.py100
-rw-r--r--[-rwxr-xr-x]framework/config.py186
-rw-r--r--framework/crb.py184
-rw-r--r--framework/debugger.py48
-rw-r--r--framework/dts.py220
-rw-r--r--framework/dut.py341
-rw-r--r--framework/etgen.py52
-rw-r--r--framework/excel_reporter.py9
-rw-r--r--framework/exception.py94
-rw-r--r--framework/logger.py76
-rwxr-xr-xframework/main.py16
-rw-r--r--framework/net_device.py752
-rw-r--r--framework/pmd_output.py101
-rw-r--r--framework/project_dpdk.py44
-rw-r--r--framework/qemu_kvm.py1107
-rw-r--r--framework/qemu_libvirt.py515
-rw-r--r--framework/settings.py78
-rw-r--r--framework/ssh_connection.py12
-rw-r--r--framework/ssh_pexpect.py67
-rw-r--r--framework/test_case.py8
-rw-r--r--framework/test_result.py6
-rw-r--r--framework/tester.py86
-rw-r--r--framework/utils.py100
-rw-r--r--framework/virt_base.py368
-rw-r--r--framework/virt_dut.py344
-rw-r--r--framework/virt_resource.py494
-rw-r--r--framework/virt_scene.py535
-rw-r--r--test_plans/dual_vlan_test_plan.rst394
-rw-r--r--test_plans/dynamic_config_test_plan.rst199
-rw-r--r--test_plans/generic_filter_test_plan.rst483
-rw-r--r--test_plans/ipv4_reassembly_test_plan.rst233
-rw-r--r--test_plans/nvgre_test_plan.rst389
-rw-r--r--test_plans/pmdrss_hash_test_plan.rst152
-rw-r--r--test_plans/pmdrssreta_test_plan.rst178
-rw-r--r--test_plans/queue_start_stop_test_plan.rst75
-rw-r--r--test_plans/scatter_test_plan.rst119
-rw-r--r--test_plans/shutdown_api_test_plan.rst167
-rw-r--r--test_plans/sriov_kvm_test_plan.rst756
-rw-r--r--test_plans/tso_test_plan.rst184
-rw-r--r--test_plans/uni_pkt_test_plan.rst832
-rw-r--r--test_plans/unit_tests_cmdline_test_plan.rst54
-rw-r--r--test_plans/unit_tests_dump_test_plan.rst169
-rw-r--r--test_plans/unit_tests_eal_test_plan.rst315
-rw-r--r--test_plans/unit_tests_ivshmem_test_plan.rst54
-rw-r--r--test_plans/unit_tests_kni_test_plan.rst60
-rw-r--r--test_plans/unit_tests_lpm_test_plan.rst80
-rw-r--r--test_plans/unit_tests_mbuf_test_plan.rst70
-rw-r--r--test_plans/unit_tests_mempool_test_plan.rst75
-rw-r--r--test_plans/unit_tests_pmd_perf_test_plan.rst79
-rw-r--r--test_plans/unit_tests_power_test_plan.rst80
-rw-r--r--test_plans/unit_tests_qos_test_plan.rst100
-rw-r--r--test_plans/unit_tests_ring_test_plan.rst123
-rw-r--r--test_plans/unit_tests_ringpmd_test_plan.rst60
-rw-r--r--test_plans/unit_tests_timer_test_plan.rst98
-rw-r--r--test_plans/vm_power_manager_test_plan.rst304
-rw-r--r--test_plans/vxlan_sample_test_plan.rst255
-rw-r--r--test_plans/vxlan_test_plan.rst394
-rw-r--r--tests/TestSuite_blacklist.py2
-rw-r--r--tests/TestSuite_checksum_offload.py103
-rw-r--r--tests/TestSuite_cmdline.py2
-rw-r--r--tests/TestSuite_dual_vlan.py408
-rw-r--r--tests/TestSuite_dynamic_config.py262
-rw-r--r--tests/TestSuite_fdir.py1086
-rw-r--r--tests/TestSuite_generic_filter.py828
-rw-r--r--tests/TestSuite_hello_world.py7
-rw-r--r--tests/TestSuite_ieee1588.py33
-rw-r--r--tests/TestSuite_ipv4_reassembly.py581
-rw-r--r--tests/TestSuite_jumboframes.py50
-rw-r--r--tests/TestSuite_multiprocess.py39
-rw-r--r--tests/TestSuite_nvgre.py997
-rw-r--r--tests/TestSuite_pmd.py33
-rw-r--r--tests/TestSuite_pmdrss_hash.py671
-rw-r--r--tests/TestSuite_pmdrssreta.py264
-rw-r--r--tests/TestSuite_queue_start_stop.py209
-rw-r--r--tests/TestSuite_scatter.py134
-rw-r--r--tests/TestSuite_shutdown_api.py519
-rw-r--r--tests/TestSuite_sriov_kvm.py1269
-rw-r--r--tests/TestSuite_tso.py387
-rw-r--r--tests/TestSuite_unit_tests_cmdline.py89
-rw-r--r--tests/TestSuite_unit_tests_dump.py211
-rw-r--r--tests/TestSuite_unit_tests_eal.py409
-rw-r--r--tests/TestSuite_unit_tests_ivshmem.py93
-rw-r--r--tests/TestSuite_unit_tests_kni.py106
-rw-r--r--tests/TestSuite_unit_tests_lpm.py108
-rw-r--r--tests/TestSuite_unit_tests_mbuf.py88
-rw-r--r--tests/TestSuite_unit_tests_mempool.py97
-rw-r--r--tests/TestSuite_unit_tests_pmd_perf.py146
-rw-r--r--tests/TestSuite_unit_tests_power.py99
-rw-r--r--tests/TestSuite_unit_tests_qos.py113
-rw-r--r--tests/TestSuite_unit_tests_ring.py101
-rw-r--r--tests/TestSuite_unit_tests_ringpmd.py103
-rw-r--r--tests/TestSuite_unit_tests_timer.py96
-rw-r--r--tests/TestSuite_vhost_cuse_sample.py454
-rw-r--r--tests/TestSuite_vhost_sample.py425
-rw-r--r--tests/TestSuite_vlan.py151
-rw-r--r--tests/TestSuite_vm_power_manager.py448
-rw-r--r--tests/TestSuite_vxlan.py1138
-rw-r--r--tests/TestSuite_vxlan_sample.py635
-rw-r--r--tests/TestSuite_whitelist.py38
-rwxr-xr-xtools/dump_case.py97
-rwxr-xr-xtools/parse_opt.py193
-rwxr-xr-xtools/setup.py589
123 files changed, 26727 insertions, 776 deletions
diff --git a/conf/dpdk_test_case_checklist.xls b/conf/dpdk_test_case_checklist.xls
new file mode 100644
index 0000000..de3f5a2
--- /dev/null
+++ b/conf/dpdk_test_case_checklist.xls
Binary files differ
diff --git a/conf/ports.cfg b/conf/ports.cfg
index 43cab27..27ebfe0 100644
--- a/conf/ports.cfg
+++ b/conf/ports.cfg
@@ -4,8 +4,15 @@
# pci=Pci BDF,intf=Kernel interface;
# pci=Pci BDF,mac=Mac address,peer=Tester Pci BDF,numa=Port Numa
# pci=Pci BDF,peer=IXIA:card.port
+# [VM NAME] virtual machine name; This section is for virutal scenario
+# ports =
+# dev_idx=device index of ports info, peer=Tester Pci BDF
[DUT IP]
ports =
pci=XX:XX.X,intf=eth0;
pci=YY:YY.Y,mac=XX:XX:XX:XX:XX:XX,peer=ZZ:ZZ.Z,numa=0;
pci=ZZ:ZZ.Y,peer=IXIA:X.Y
+[VM NAME]
+ports =
+ dev_idx=0,peer=XX:XX.X;
+ dev_idx=1,peer=YY:YY.Y;
diff --git a/conf/scene/dpdk_vf_passthrough.cfg b/conf/scene/dpdk_vf_passthrough.cfg
new file mode 100644
index 0000000..2f3c008
--- /dev/null
+++ b/conf/scene/dpdk_vf_passthrough.cfg
@@ -0,0 +1,32 @@
+# vm configuration for host dpdk and vf passthrough cases
+# host application is testpmd and allocated lcore 0-3 for it
+# default target will be x86_64-native-linuxapp-gcc
+# numa 0,1,yes yes mean cpu numa match the first port
+# skipcores list mean those core will not used by vm
+# dut=vm_dut; mean vm_dut act as dut
+# dut=dut; mean host dut act as dut
+# portmap=cfg; mean vm_dut port map will be load from cfg
+# portmap=auto; mean vm_dut will create portmap automatically
+# devices = dev_gen/host/dev_gen+host not useful now
+[scene]
+suite =
+ dut=vm_dut,portmap=cfg;
+ tester=tester;
+ type=kvm;
+host =
+ dpdk=testpmd,cores=0 1 2 3,target=x86_64-native-linuxapp-gcc;
+[vm0]
+cpu =
+ model=host,number=4,numa=auto,skipcores=0 1 2 3;
+mem =
+ size=2048,hugepage=no;
+disk =
+ file=/storage/vm-image/vm0.img;
+dev_gen =
+ pf_idx=0,vf_num=1,driver=igb_uio;
+ pf_idx=1,vf_num=1,driver=igb_uio;
+device =
+ vf_idx=0,pf_dev=0,guestpci=auto;
+ vf_idx=0,pf_dev=1,guestpci=auto;
+vnc =
+ displayNum=1;
diff --git a/conf/scene/pf_passthrough.cfg b/conf/scene/pf_passthrough.cfg
new file mode 100644
index 0000000..91b5eaf
--- /dev/null
+++ b/conf/scene/pf_passthrough.cfg
@@ -0,0 +1,25 @@
+# vm configuration for pf passthrough cases
+# numa 0,1,yes yes mean cpu numa match the first port
+# skipcores list mean those core will not used by vm
+# dut=vm_dut; mean vm_dut act as dut
+# dut=dut; mean host dut act as dut
+# portmap=cfg; mean vm_dut port map will be load from cfg
+# portmap=auto; mean vm_dut will create portmap automatically
+# devices = dev_gen/host/dev_gen+host not useful now
+[scene]
+suite =
+ dut=vm_dut,portmap=auto;
+ tester=tester;
+ type=kvm;
+[vm]
+cpu =
+ model=host,number=4,numa_aware=yes;
+mem =
+ size=2048,hugepage=no;
+disk =
+ file=/storage/vm-image/vm0.img;
+device =
+ pf_idx=0,guestpci=auto;
+ pf_idx=1,guestpci=auto;
+vnc =
+ displayNum=1;
diff --git a/conf/scene/vf_passthrough.cfg b/conf/scene/vf_passthrough.cfg
new file mode 100644
index 0000000..aa5493d
--- /dev/null
+++ b/conf/scene/vf_passthrough.cfg
@@ -0,0 +1,28 @@
+# vm configuration for vf passthrough cases
+# numa 0,1,yes yes mean cpu numa match the first port
+# skipcores list mean those core will not used by vm
+# dut=vm_dut; mean vm_dut act as dut
+# dut=dut; mean host dut act as dut
+# portmap=cfg; mean vm_dut port map will be load from cfg
+# portmap=auto; mean vm_dut will create portmap automatically
+# devices = dev_gen/host/dev_gen+host not useful now
+[scene]
+suite =
+ dut=vm_dut,portmap=auto;
+ tester=tester;
+ type=kvm;
+[vm0]
+cpu =
+ model=host,number=4,numa=auto,skipcores=0 1 2 3;
+mem =
+ size=2048,hugepage=no;
+disk =
+ file=/storage/vm-image/vm0.img;
+dev_gen =
+ pf_idx=0,vf_num=2,driver=default;
+ pf_idx=1,vf_num=2,driver=default;
+device =
+ vf_idx=0,pf_dev=0,guestpci=auto;
+ vf_idx=0,pf_dev=1,guestpci=auto;
+vnc =
+ displayNum=1;
diff --git a/conf/scene/vf_passthrough_1.cfg b/conf/scene/vf_passthrough_1.cfg
new file mode 100644
index 0000000..afd760a
--- /dev/null
+++ b/conf/scene/vf_passthrough_1.cfg
@@ -0,0 +1,27 @@
+# vm configuration for vf passthrough cases
+# numa 0,1,yes yes mean cpu numa match the first port
+# skipcores list mean those core will not used by vm
+# dut=vm_dut; mean vm_dut act as dut
+# dut=dut; mean host dut act as dut
+# portmap=cfg; mean vm_dut port map will be load from cfg
+# portmap=auto; mean vm_dut will create portmap automatically
+# devices = dev_gen/host/dev_gen+host not useful now
+[scene]
+suite =
+ dut=vm_dut,portmap=auto;
+ tester=tester;
+ type=kvm;
+[vm0]
+cpu =
+ model=host,number=4,numa=auto,skipcores=0 1 2 3;
+mem =
+ size=2048,hugepage=no;
+disk =
+ file=/storage/vm-image/vm0.img;
+dev_gen =
+ pf_idx=0,vf_num=2,driver=default;
+device =
+ vf_idx=0,pf_dev=0,guestpci=auto;
+ vf_idx=1,pf_dev=0,guestpci=auto;
+vnc =
+ displayNum=1;
diff --git a/conf/sriov_kvm.cfg b/conf/sriov_kvm.cfg
new file mode 100644
index 0000000..8db36bb
--- /dev/null
+++ b/conf/sriov_kvm.cfg
@@ -0,0 +1,164 @@
+# QEMU options
+# name
+# name: vm0
+#
+# enable_kvm
+# enable: [yes | no]
+#
+# cpu
+# model: [host | core2duo | ...]
+# usage:
+# choose model value from the command
+# qemu-system-x86_64 -cpu help
+# number: '4' #number of vcpus
+# cpupin: '3 4 5 6' # host cpu list
+#
+# mem
+# size: 1024
+#
+# disk
+# file: /path/to/image/test.img
+#
+# net
+# type: [nic | user | tap | bridge | ...]
+# nic
+# opt_vlan: 0
+# note: Default is 0.
+# opt_macaddr: 00:00:00:00:01:01
+# note: if creating a nic, it`s better to specify a MAC,
+# else it will get a random number.
+# opt_model:["e1000" | "virtio" | "i82551" | ...]
+# note: Default is e1000.
+# opt_name: 'nic1'
+# opt_addr: ''
+# note: PCI cards only.
+# opt_vectors:
+# note: This option currently only affects virtio cards.
+# user
+# opt_vlan: 0
+# note: default is 0.
+# opt_hostfwd: [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport
+# note: If not specified, it will be setted automatically.
+# tap
+# opt_vlan: 0
+# note: default is 0.
+# opt_br: br0
+# note: if choosing tap, need to specify bridge name,
+# else it will be br0.
+# opt_script: QEMU_IFUP_PATH
+# note: if not specified, default is self.QEMU_IFUP_PATH.
+# opt_downscript: QEMU_IFDOWN_PATH
+# note: if not specified, default is self.QEMU_IFDOWN_PATH.
+#
+# device
+# driver: [pci-assign | virtio-net-pci | ...]
+# pci-assign
+# prop_host: 08:00.0
+# prop_addr: 00:00:00:00:01:02
+# virtio-net-pci
+# prop_netdev: mynet1
+# prop_id: net1
+# prop_mac: 00:00:00:00:01:03
+# prop_bus: pci.0
+# prop_addr: 0x3
+#
+# monitor
+# port: 6061
+# note: if adding monitor to vm, need to specicy
+# this port, else it will get a free port
+# on the host machine.
+#
+# qga
+# enable: [yes | no]
+#
+# serial_port
+# enable: [yes | no]
+#
+# vnc
+# displayNum: 1
+# note: you can choose a number not used on the host.
+#
+# daemon
+# enable: 'yes'
+# note:
+# By default VM will start with the daemonize status.
+# Not support starting it on the stdin now.
+
+
+# vm configuration for pmd sriov case
+[vm0]
+cpu =
+ model=host,number=4,cpupin=5 6 7 8;
+disk =
+ file=/home/image/vdisk01-sriov-fc20.img;
+login =
+ user=root,password=tester;
+net =
+ type=nic,opt_vlan=0;
+ type=user,opt_vlan=0;
+monitor =
+ port=;
+qga =
+ enable=yes;
+vnc =
+ displayNum=1;
+daemon =
+ enable=yes;
+
+[vm1]
+cpu =
+ model=host,number=4,cpupin=9 10 11 12;
+disk =
+ file=/home/image/vdisk02-sriov-fc20.img;
+login =
+ user=root,password=tester;
+net =
+ type=nic,opt_vlan=1;
+ type=user,opt_vlan=1;
+monitor =
+ port=;
+qga =
+ enable=yes;
+vnc =
+ displayNum=2;
+daemon =
+ enable=yes;
+
+[vm2]
+cpu =
+ model=host,number=4,cpupin=13 14 15 16;
+disk =
+ file=/home/image/vdisk03-ivshmem-fc20.img;
+login =
+ user=root,password=tester;
+net =
+ type=nic,opt_vlan=3;
+ type=tap,opt_vlan=3,opt_br=br0;
+monitor =
+ port=;
+qga =
+ enable=yes;
+vnc =
+ displayNum=3;
+daemon =
+ enable=yes;
+
+[vm3]
+cpu =
+ model=host,number=4,cpupin=17 18 19 20;
+disk =
+ file=/home/image/vdisk04-ivshmem-fc20.img;
+login =
+ user=root,password=tester;
+net =
+ type=nic,opt_vlan=4;
+ type=tap,opt_vlan=4,opt_br=br0;
+monitor =
+ port=;
+qga =
+ enable=yes;
+vnc =
+ displayNum=4;
+daemon =
+ enable=yes;
+
diff --git a/conf/vhost_cuse_sample.cfg b/conf/vhost_cuse_sample.cfg
new file mode 100644
index 0000000..ce34af8
--- /dev/null
+++ b/conf/vhost_cuse_sample.cfg
@@ -0,0 +1,14 @@
+# vm configuration for vhost sample case
+[vm0]
+cpu =
+ model=host,number=2,cpupin=24 25;
+mem =
+ size=4096,hugepage=yes;
+disk =
+ file=/home/img/vm0.img;
+login =
+ user=root,password=tester;
+vnc =
+ displayNum=4;
+daemon =
+ enable=yes;
diff --git a/conf/vhost_sample.cfg b/conf/vhost_sample.cfg
new file mode 100644
index 0000000..ce34af8
--- /dev/null
+++ b/conf/vhost_sample.cfg
@@ -0,0 +1,14 @@
+# vm configuration for vhost sample case
+[vm0]
+cpu =
+ model=host,number=2,cpupin=24 25;
+mem =
+ size=4096,hugepage=yes;
+disk =
+ file=/home/img/vm0.img;
+login =
+ user=root,password=tester;
+vnc =
+ displayNum=4;
+daemon =
+ enable=yes;
diff --git a/conf/virt_global.cfg b/conf/virt_global.cfg
new file mode 100644
index 0000000..176650a
--- /dev/null
+++ b/conf/virt_global.cfg
@@ -0,0 +1,22 @@
+# virtualization global configurations
+#[LIBVIRT]
+#[KVM]
+#[XEN]
+[LIBVIRT]
+cpu =
+ number=4,cpupin=3 4 5 6;
+mem =
+ size=2048;
+[KVM]
+cpu =
+ model=host,number=4,cpupin=3 4 5 6;
+mem =
+ size=2048;
+[XEN]
+cpu =
+ number=4,cpupin=3 4 5 6;
+mem =
+ size=2048;
+vif =
+ mac=random,bridge=br0
+
diff --git a/conf/vm_power_manager.cfg b/conf/vm_power_manager.cfg
new file mode 100644
index 0000000..c77819b
--- /dev/null
+++ b/conf/vm_power_manager.cfg
@@ -0,0 +1,40 @@
+# libvirtd options:
+# [VM name] section value is the name for VM
+# cpu # hard code type to host-passthrough
+# number: number of vcpus
+# cpupin: host cpu list
+# mem
+# size: 4096
+# disk
+# file: absolute path to disk image
+# type: disk image format
+# login
+# user: user name to login into VM
+# password: passwork to login into VM
+# device
+# pf_idx: pass-through device index of DUT ports
+# guestpci: hardcode value of guest pci address
+# virtio_serial_channel
+# path: virtio unix socket absolute path
+# name: virtio serial name in VM
+
+# vm configuration for vm power management case
+[vm0]
+cpu =
+ number=4,cpupin=5 6 7 8;
+mem =
+ size=4096;
+disk =
+ file=/storage/vm-image/vm0.img,type=raw;
+login =
+ user=root,password=tester;
+device =
+ pf_idx=0,guestpci=00:08.0;
+ pf_idx=1,guestpci=00:09.0;
+[vm1]
+mem =
+ size=4096;
+disk =
+ file=/storage/vm-image/vm1.img,type=raw;
+login =
+ user=root,password=tester;
diff --git a/conf/vxlan_sample.cfg b/conf/vxlan_sample.cfg
new file mode 100644
index 0000000..28d0f95
--- /dev/null
+++ b/conf/vxlan_sample.cfg
@@ -0,0 +1,28 @@
+# vm configuration for vxlan sample case
+[vm0]
+cpu =
+ model=host,number=4,cpupin=24 25 26 27;
+mem =
+ size=4096,hugepage=yes;
+disk =
+ file=/storage/vm-image/vm0.img;
+login =
+ user=root,password=tester;
+vnc =
+ displayNum=1;
+
+[vm1]
+cpu =
+ model=host,number=4,cpupin=28 29 30 31;
+mem =
+ size=4096,hugepage=yes;
+disk =
+ file=/storage/vm-image/vm1.img;
+login =
+ user=root,password=tester;
+qga =
+ enable=yes;
+vnc =
+ displayNum=2;
+daemon =
+ enable=yes;
diff --git a/dep/QMP/qemu-ga-client b/dep/QMP/qemu-ga-client
new file mode 100644
index 0000000..46676c3
--- /dev/null
+++ b/dep/QMP/qemu-ga-client
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+
+# QEMU Guest Agent Client
+#
+# Copyright (C) 2012 Ryota Ozaki <ozaki.ryota@gmail.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+#
+# Usage:
+#
+# Start QEMU with:
+#
+# # qemu [...] -chardev socket,path=/tmp/qga.sock,server,nowait,id=qga0 \
+# -device virtio-serial -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
+#
+# Run the script:
+#
+# $ qemu-ga-client --address=/tmp/qga.sock <command> [args...]
+#
+# or
+#
+# $ export QGA_CLIENT_ADDRESS=/tmp/qga.sock
+# $ qemu-ga-client <command> [args...]
+#
+# For example:
+#
+# $ qemu-ga-client cat /etc/resolv.conf
+# # Generated by NetworkManager
+# nameserver 10.0.2.3
+# $ qemu-ga-client fsfreeze status
+# thawed
+# $ qemu-ga-client fsfreeze freeze
+# 2 filesystems frozen
+#
+# See also: http://wiki.qemu.org/Features/QAPI/GuestAgent
+#
+
+import base64
+import random
+
+import qmp
+
+
+class QemuGuestAgent(qmp.QEMUMonitorProtocol):
+ def __getattr__(self, name):
+ def wrapper(**kwds):
+ return self.command('guest-' + name.replace('_', '-'), **kwds)
+ return wrapper
+
+
+class QemuGuestAgentClient:
+ error = QemuGuestAgent.error
+
+ def __init__(self, address):
+ self.qga = QemuGuestAgent(address)
+ self.qga.connect(negotiate=False)
+
+ def sync(self, timeout=3):
+ # Avoid being blocked forever
+ if not self.ping(timeout):
+ raise EnvironmentError('Agent seems not alive')
+ uid = random.randint(0, (1 << 32) - 1)
+ while True:
+ ret = self.qga.sync(id=uid)
+ if isinstance(ret, int) and int(ret) == uid:
+ break
+
+ def __file_read_all(self, handle):
+ eof = False
+ data = ''
+ while not eof:
+ ret = self.qga.file_read(handle=handle, count=1024)
+ _data = base64.b64decode(ret['buf-b64'])
+ data += _data
+ eof = ret['eof']
+ return data
+
+ def read(self, path):
+ handle = self.qga.file_open(path=path)
+ try:
+ data = self.__file_read_all(handle)
+ finally:
+ self.qga.file_close(handle=handle)
+ return data
+
+ def info(self):
+ info = self.qga.info()
+
+ msgs = []
+ msgs.append('version: ' + info['version'])
+ msgs.append('supported_commands:')
+ enabled = [c['name'] for c in info['supported_commands'] if c['enabled']]
+ msgs.append('\tenabled: ' + ', '.join(enabled))
+ disabled = [c['name'] for c in info['supported_commands'] if not c['enabled']]
+ msgs.append('\tdisabled: ' + ', '.join(disabled))
+
+ return '\n'.join(msgs)
+
+ def __gen_ipv4_netmask(self, prefixlen):
+ mask = int('1' * prefixlen + '0' * (32 - prefixlen), 2)
+ return '.'.join([str(mask >> 24),
+ str((mask >> 16) & 0xff),
+ str((mask >> 8) & 0xff),
+ str(mask & 0xff)])
+
+ def ifconfig(self):
+ nifs = self.qga.network_get_interfaces()
+
+ msgs = []
+ for nif in nifs:
+ msgs.append(nif['name'] + ':')
+ if 'ip-addresses' in nif:
+ for ipaddr in nif['ip-addresses']:
+ if ipaddr['ip-address-type'] == 'ipv4':
+ addr = ipaddr['ip-address']
+ mask = self.__gen_ipv4_netmask(int(ipaddr['prefix']))
+ msgs.append("\tinet %s netmask %s" % (addr, mask))
+ elif ipaddr['ip-address-type'] == 'ipv6':
+ addr = ipaddr['ip-address']
+ prefix = ipaddr['prefix']
+ msgs.append("\tinet6 %s prefixlen %s" % (addr, prefix))
+ if nif['hardware-address'] != '00:00:00:00:00:00':
+ msgs.append("\tether " + nif['hardware-address'])
+
+ return '\n'.join(msgs)
+
+ def ping(self, timeout):
+ self.qga.settimeout(timeout)
+ try:
+ self.qga.ping()
+ except self.qga.timeout:
+ return False
+ return True
+
+ def fsfreeze(self, cmd):
+ if cmd not in ['status', 'freeze', 'thaw']:
+ raise StandardError('Invalid command: ' + cmd)
+
+ return getattr(self.qga, 'fsfreeze' + '_' + cmd)()
+
+ def fstrim(self, minimum=0):
+ return getattr(self.qga, 'fstrim')(minimum=minimum)
+
+ def suspend(self, mode):
+ if mode not in ['disk', 'ram', 'hybrid']:
+ raise StandardError('Invalid mode: ' + mode)
+
+ try:
+ getattr(self.qga, 'suspend' + '_' + mode)()
+ # On error exception will raise
+ except self.qga.timeout:
+ # On success command will timed out
+ return
+
+ def shutdown(self, mode='powerdown'):
+ if mode not in ['powerdown', 'halt', 'reboot']:
+ raise StandardError('Invalid mode: ' + mode)
+
+ try:
+ self.qga.shutdown(mode=mode)
+ except self.qga.timeout:
+ return
+
+
+def _cmd_cat(client, args):
+ if len(args) != 1:
+ print('Invalid argument')
+ print('Usage: cat <file>')
+ sys.exit(1)
+ print(client.read(args[0]))
+
+
+def _cmd_fsfreeze(client, args):
+ usage = 'Usage: fsfreeze status|freeze|thaw'
+ if len(args) != 1:
+ print('Invalid argument')
+ print(usage)
+ sys.exit(1)
+ if args[0] not in ['status', 'freeze', 'thaw']:
+ print('Invalid command: ' + args[0])
+ print(usage)
+ sys.exit(1)
+ cmd = args[0]
+ ret = client.fsfreeze(cmd)
+ if cmd == 'status':
+ print(ret)
+ elif cmd == 'freeze':
+ print("%d filesystems frozen" % ret)
+ else:
+ print("%d filesystems thawed" % ret)
+
+
+def _cmd_fstrim(client, args):
+ if len(args) == 0:
+ minimum = 0
+ else:
+ minimum = int(args[0])
+ print(client.fstrim(minimum))
+
+
+def _cmd_ifconfig(client, args):
+ print(client.ifconfig())
+
+
+def _cmd_info(client, args):
+ print(client.info())
+
+
+def _cmd_ping(client, args):
+ if len(args) == 0:
+ timeout = 3
+ else:
+ timeout = float(args[0])
+ alive = client.ping(timeout)
+ if not alive:
+ print("Not responded in %s sec" % args[0])
+ sys.exit(1)
+
+
+def _cmd_suspend(client, args):
+ usage = 'Usage: suspend disk|ram|hybrid'
+ if len(args) != 1:
+ print('Less argument')
+ print(usage)
+ sys.exit(1)
+ if args[0] not in ['disk', 'ram', 'hybrid']:
+ print('Invalid command: ' + args[0])
+ print(usage)
+ sys.exit(1)
+ client.suspend(args[0])
+
+
+def _cmd_shutdown(client, args):
+ client.shutdown()
+_cmd_powerdown = _cmd_shutdown
+
+
+def _cmd_halt(client, args):
+ client.shutdown('halt')
+
+
+def _cmd_reboot(client, args):
+ client.shutdown('reboot')
+
+
+commands = [m.replace('_cmd_', '') for m in dir() if '_cmd_' in m]
+
+
+def main(address, cmd, args):
+ if not os.path.exists(address):
+ print('%s not found' % address)
+ sys.exit(1)
+
+ if cmd not in commands:
+ print('Invalid command: ' + cmd)
+ print('Available commands: ' + ', '.join(commands))
+ sys.exit(1)
+
+ try:
+ client = QemuGuestAgentClient(address)
+ except QemuGuestAgent.error, e:
+ import errno
+
+ print(e)
+ if e.errno == errno.ECONNREFUSED:
+ print('Hint: qemu is not running?')
+ sys.exit(1)
+
+ if cmd != 'ping':
+ client.sync()
+
+ globals()['_cmd_' + cmd](client, args)
+
+
+if __name__ == '__main__':
+ import sys
+ import os
+ import optparse
+
+ address = os.environ['QGA_CLIENT_ADDRESS'] if 'QGA_CLIENT_ADDRESS' in os.environ else None
+
+ usage = "%prog [--address=<unix_path>|<ipv4_address>] <command> [args...]\n"
+ usage += '<command>: ' + ', '.join(commands)
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option('--address', action='store', type='string',
+ default=address, help='Specify a ip:port pair or a unix socket path')
+ options, args = parser.parse_args()
+
+ address = options.address
+ if address is None:
+ parser.error('address is not specified')
+ sys.exit(1)
+
+ if len(args) == 0:
+ parser.error('Less argument')
+ sys.exit(1)
+
+ main(address, args[0], args[1:])
diff --git a/dep/QMP/qmp.py b/dep/QMP/qmp.py
new file mode 100644
index 0000000..4ade3ce
--- /dev/null
+++ b/dep/QMP/qmp.py
@@ -0,0 +1,193 @@
+# QEMU Monitor Protocol Python class
+#
+# Copyright (C) 2009, 2010 Red Hat Inc.
+#
+# Authors:
+# Luiz Capitulino <lcapitulino@redhat.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2. See
+# the COPYING file in the top-level directory.
+
+import json
+import errno
+import socket
+
+class QMPError(Exception):
+ pass
+
+class QMPConnectError(QMPError):
+ pass
+
+class QMPCapabilitiesError(QMPError):
+ pass
+
+class QEMUMonitorProtocol:
+ def __init__(self, address, server=False):
+ """
+ Create a QEMUMonitorProtocol class.
+
+ @param address: QEMU address, can be either a unix socket path (string)
+ or a tuple in the form ( address, port ) for a TCP
+ connection
+ @param server: server mode listens on the socket (bool)
+ @raise socket.error on socket connection errors
+ @note No connection is established, this is done by the connect() or
+ accept() methods
+ """
+ self.__events = []
+ self.__address = address
+ self.__sock = self.__get_sock()
+ if server:
+ self.__sock.bind(self.__address)
+ self.__sock.listen(1)
+
+ def __get_sock(self):
+ if isinstance(self.__address, tuple):
+ family = socket.AF_INET
+ else:
+ family = socket.AF_UNIX
+ return socket.socket(family, socket.SOCK_STREAM)
+
+ def __negotiate_capabilities(self):
+ greeting = self.__json_read()
+ if greeting is None or not greeting.has_key('QMP'):
+ raise QMPConnectError
+ # Greeting seems ok, negotiate capabilities
+ resp = self.cmd('qmp_capabilities')
+ if "return" in resp:
+ return greeting
+ raise QMPCapabilitiesError
+
+ def __json_read(self, only_event=False):
+ while True:
+ data = self.__sockfile.readline()
+ if not data:
+ return
+ resp = json.loads(data)
+ if 'event' in resp:
+ self.__events.append(resp)
+ if not only_event:
+ continue
+ return resp
+
+ error = socket.error
+
+ def connect(self, negotiate=True):
+ """
+ Connect to the QMP Monitor and perform capabilities negotiation.
+
+ @return QMP greeting dict
+ @raise socket.error on socket connection errors
+ @raise QMPConnectError if the greeting is not received
+ @raise QMPCapabilitiesError if fails to negotiate capabilities
+ """
+ self.__sock.connect(self.__address)
+ self.__sockfile = self.__sock.makefile()
+ if negotiate:
+ return self.__negotiate_capabilities()
+
+ def accept(self):
+ """
+ Await connection from QMP Monitor and perform capabilities negotiation.
+
+ @return QMP greeting dict
+ @raise socket.error on socket connection errors
+ @raise QMPConnectError if the greeting is not received
+ @raise QMPCapabilitiesError if fails to negotiate capabilities
+ """
+ self.__sock, _ = self.__sock.accept()
+ self.__sockfile = self.__sock.makefile()
+ return self.__negotiate_capabilities()
+
+ def cmd_obj(self, qmp_cmd):
+ """
+ Send a QMP command to the QMP Monitor.
+
+ @param qmp_cmd: QMP command to be sent as a Python dict
+ @return QMP response as a Python dict or None if the connection has
+ been closed
+ """
+ try:
+ self.__sock.sendall(json.dumps(qmp_cmd))
+ except socket.error, err:
+ if err[0] == errno.EPIPE:
+ return
+ raise socket.error(err)
+ return self.__json_read()
+
+ def cmd(self, name, args=None, id=None):
+ """
+ Build a QMP command and send it to the QMP Monitor.
+
+ @param name: command name (string)
+ @param args: command arguments (dict)
+ @param id: command id (dict, list, string or int)
+ """
+ qmp_cmd = { 'execute': name }
+ if args:
+ qmp_cmd['arguments'] = args
+ if id:
+ qmp_cmd['id'] = id
+ return self.cmd_obj(qmp_cmd)
+
+ def command(self, cmd, **kwds):
+ ret = self.cmd(cmd, kwds)
+ if not ret:
+ return
+ else:
+ if ret.has_key('error'):
+ raise Exception(ret['error']['desc'])
+ return ret['return']
+
+ def pull_event(self, wait=False):
+ """
+ Get and delete the first available QMP event.
+
+ @param wait: block until an event is available (bool)
+ """
+ self.__sock.setblocking(0)
+ try:
+ self.__json_read()
+ except socket.error, err:
+ if err[0] == errno.EAGAIN:
+ # No data available
+ pass
+ self.__sock.setblocking(1)
+ if not self.__events and wait:
+ self.__json_read(only_event=True)
+ event = self.__events[0]
+ del self.__events[0]
+ return event
+
+ def get_events(self, wait=False):
+ """
+ Get a list of available QMP events.
+
+ @param wait: block until an event is available (bool)
+ """
+ self.__sock.setblocking(0)
+ try:
+ self.__json_read()
+ except socket.error, err:
+ if err[0] == errno.EAGAIN:
+ # No data available
+ pass
+ self.__sock.setblocking(1)
+ if not self.__events and wait:
+ self.__json_read(only_event=True)
+ return self.__events
+
+ def clear_events(self):
+ """
+ Clear current list of pending events.
+ """
+ self.__events = []
+
+ def close(self):
+ self.__sock.close()
+ self.__sockfile.close()
+
+ timeout = socket.timeout
+
+ def settimeout(self, timeout):
+ self.__sock.settimeout(timeout)
diff --git a/dep/macfwd_log.patch b/dep/macfwd_log.patch
new file mode 100644
index 0000000..0f657f8
--- /dev/null
+++ b/dep/macfwd_log.patch
@@ -0,0 +1,10 @@
+--- app/test-pmd/macfwd.c.org 2015-07-02 10:51:12.821246109 +0800
++++ app/test-pmd/macfwd.c 2015-07-02 10:50:11.343243319 +0800
+@@ -102,6 +102,7 @@
+ nb_pkt_per_burst);
+ if (unlikely(nb_rx == 0))
+ return;
++ printf("ports %u queue %u receive %u packages\n", fs->rx_port, fs->rx_queue, nb_rx);
+
+ #ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+ fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
diff --git a/dep/nvgre.py b/dep/nvgre.py
new file mode 100644
index 0000000..d844bd1
--- /dev/null
+++ b/dep/nvgre.py
@@ -0,0 +1,33 @@
+## This file is part of Scapy
+##
+## Copyright (C) Min Cao <min.cao@intel.com>
+
+"""
+NVGRE (Network Virtual GRE).
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import UDP,IP
+from scapy.layers.l2 import Ether
+
+IPPROTO_NVGRE=47
+
+class NVGRE(Packet):
+ name = "Network Virtual GRE"
+ fields_desc = [BitField("c", 0, 1),
+ BitField("r", 0, 1),
+ BitField("k", 1, 1),
+ BitField("s", 0, 1),
+ BitField("reserved0", 0, 9),
+ BitField("ver", 0, 3),
+ XShortField("protocoltype", 0x6558),
+ X3BytesField("TNI", 1),
+ ByteField("reserved1", 0)]
+ def mysummary(self):
+ return self.sprintf("NVGRE (tni=%NVGRE.tni%)")
+
+
+bind_layers(IP, NVGRE, proto=IPPROTO_NVGRE)
+bind_layers(NVGRE, Ether)
+
diff --git a/dep/vxlan.py b/dep/vxlan.py
new file mode 100644
index 0000000..e50d4b4
--- /dev/null
+++ b/dep/vxlan.py
@@ -0,0 +1,33 @@
+'''
+Created on Jul 29, 2014
+
+@author: yliu86
+'''
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.inet import UDP, IP
+from scapy.layers.dns import DNS
+from scapy.layers.l2 import Ether
+
+vxlanmagic = "0x8"
+
+
+class Vxlan(Packet):
+ name = "Virtual eXtensible Local Area Network"
+ fields_desc = [ByteField("flag", 8),
+ X3BytesField("reserved1", 0),
+ X3BytesField("vni", 0),
+ ByteField("reserved2", 0)]
+
+ def guess_payload_class(self, payload):
+ if self.flag == vxlanmagic:
+ return Vxlan
+ else:
+ return Packet.guess_payload_class(self, payload)
+
+ def mysummary(self):
+ return self.sprintf("VXLAN (vni=%VXLAN.vni%)")
+
+split_layers(UDP, DNS, sport=53)
+bind_layers(UDP, Vxlan, dport=4789)
+bind_layers(Vxlan, Ether)
diff --git a/execution.cfg b/executions/execution.cfg
index a67d7b3..6e42b90 100644
--- a/execution.cfg
+++ b/executions/execution.cfg
@@ -13,10 +13,19 @@ test_suites=
jumboframes,
ipfrag,
link_flowctrl,
- fdir,
vlan,
ip_pipeline,
- pmd_bonded
+ pmd_bonded,
+ dynamic_config,
+ generic_filter,
+ dual_vlan,
+ shutdown_api,
+ fdir,
+ ipv4_reassembly,
+ scatter,
+ pmdrssreta,
+ pmd,
+ l2fwd
targets=
x86_64-native-linuxapp-gcc
parameters=nic_type=cfg:func=true
diff --git a/executions/execution_FVL.cfg b/executions/execution_FVL.cfg
new file mode 100644
index 0000000..9f25802
--- /dev/null
+++ b/executions/execution_FVL.cfg
@@ -0,0 +1,43 @@
+[Execution1]
+crbs=<CRB IP Address>
+drivername=<driver name igb_uio or vfio-pci>
+test_suites=
+ checksum_offload,
+ dynamic_config,
+ generic_filter,
+ dual_vlan,
+ vlan,
+ shutdown_api,
+ queue_start_stop,
+ tso,
+ fdir,
+ nvgre,
+ vxlan,
+ vxlan_sample,
+ pmd,
+ ipfrag,
+ timer,
+ jumboframes,
+ multiprocess,
+ l2fwd,
+ whitelist,
+ blacklist,
+ ipv4_reassembly,
+ scatter,
+ pmdrssreta,
+ pmdrss_hash,
+ ieee1588
+targets=
+ x86_64-native-linuxapp-gcc
+parameters=nic_type=cfg:func=true
+
+[Execution2]
+crbs=<Performance CRB IP Address>
+drivername=<driver name igb_uio or vfio-pci>
+test_suites=
+ l2fwd,
+ l3fwd,
+ pmd
+targets=
+ x86_64-native-linuxapp-gcc
+parameters=nic_type=niantic:perf=true
diff --git a/executions/execution_rxmode.cfg b/executions/execution_rxmode.cfg
new file mode 100644
index 0000000..cf46dbf
--- /dev/null
+++ b/executions/execution_rxmode.cfg
@@ -0,0 +1,62 @@
+[Execution1]
+crbs=<CRB IP Address>
+drivername=igb_uio
+rx_mode=scalar
+test_suites=
+ fdir,
+ jumboframes,
+ scatter,
+ ieee1588,
+ checksum_offload,
+ link_flowctrl,
+ pmd,
+ vlan,
+ shutdown_api,
+ dual_vlan,
+ pmdrssreta,
+ generic_filter
+targets=
+ x86_64-native-linuxapp-gcc
+parameters=nic_type=cfg:func=true
+
+[Execution2]
+crbs=<CRB IP Address>
+drivername=igb_uio
+rx_mode=full
+test_suites=
+ fdir,
+ jumboframes,
+ scatter,
+ ieee1588,
+ checksum_offload,
+ link_flowctrl,
+ pmd,
+ vlan,
+ shutdown_api,
+ dual_vlan,
+ pmdrssreta,
+ generic_filter
+targets=
+ x86_64-native-linuxapp-gcc
+parameters=nic_type=cfg:func=true
+
+[Execution3]
+crbs=<CRB IP Address>
+drivername=igb_uio
+rx_mode=vector
+test_suites=
+ fdir,
+ jumboframes,
+ scatter,
+ ieee1588,
+ checksum_offload,
+ link_flowctrl,
+ pmd,
+ vlan,
+ shutdown_api,
+ dual_vlan,
+ pmdrssreta,
+ generic_filter
+targets=
+ x86_64-native-linuxapp-gcc
+parameters=nic_type=cfg:func=true
diff --git a/executions/execution_smoke.cfg b/executions/execution_smoke.cfg
new file mode 100644
index 0000000..7631f5c
--- /dev/null
+++ b/executions/execution_smoke.cfg
@@ -0,0 +1,31 @@
+[Execution1]
+crbs=<CRB IP Address>
+drivername=<driver name igb_uio or vfio-pci>
+test_suites=
+ unit_tests_cmdline,
+ unit_tests_eal,
+ unit_tests_dump,
+ unit_tests_ivshmem,
+ unit_tests_kni,
+ unit_tests_lpm,
+ unit_tests_mbuf,
+ unit_tests_mempool,
+ unit_tests_power,
+ unit_tests_pmd_perf,
+ unit_tests_qos,
+ unit_tests_ring,
+ unit_tests_ringpmd,
+ unit_tests_timer,
+ dynamic_config,
+ jumboframes,
+ scatter,
+ ieee1588,
+ multiprocess,
+ l2fwd,
+ pmd,
+ checksum_offload,
+ whitelist,
+ blacklist
+targets=
+ x86_64-native-linuxapp-gcc
+parameters=nic_type=niantic:func=true
diff --git a/framework/checkCase.py b/framework/checkCase.py
new file mode 100644
index 0000000..b2e79a0
--- /dev/null
+++ b/framework/checkCase.py
@@ -0,0 +1,100 @@
+import xlrd
+
+from settings import nic_name_from_type
+
+filter_file = r'./conf/dpdk_test_case_checklist.xls'
+filter_case = []
+check_function_dict = {}
+
+class parse_file():
+
+ def __init__(self):
+ try:
+ self.book = xlrd.open_workbook(filter_file)
+ self.sheet = self.book.sheet_by_index(0)
+ self.init_check_function_dict()
+ except:
+ pass
+
+ def init_check_function_dict(self):
+ '''
+ init check case functio, and skip case message.
+ '''
+ row_data = self.sheet.row_values(0)
+ for i in range(1,len(row_data)):
+ if row_data[i].lower() in ['wq number', 'comments']:
+ if 'message' not in check_function_dict:
+ check_function_dict['message'] = [i]
+ else:
+ check_function_dict['message'].append(i)
+ else:
+ check_function_dict[row_data[i].lower()] = i
+
+ def set_filter_case(self):
+ for row in range(self.sheet.nrows):
+ row_data = self.sheet.row_values(row)
+ # add case name
+ tmp_filter = [row_data[0]]
+ for i in range(1,len(row_data) - 2):
+ tmp_filter.append(row_data[i].split(','))
+
+ tmp_filter.append(row_data[-2])
+ tmp_filter.append(row_data[-1])
+
+ filter_case.append(tmp_filter)
+
+class check_case_skip():
+ def __init__(self, Dut):
+ self.dut = Dut
+ self.comments = ''
+
+ def check_os(self,os_type):
+ if 'all' == os_type[0].lower():
+ return True
+ dut_os_type = self.dut.get_os_type()
+ if dut_os_type in os_type:
+ return True
+ else:
+ return False
+
+ def check_nic(self, nic_type):
+ if 'all' == nic_type[0].lower():
+ return True
+ dut_nic_type = nic_name_from_type(self.dut.ports_info[0]['type'])
+ if dut_nic_type in nic_type:
+ return True
+ else:
+ return False
+
+ def check_target(self,target):
+ if 'all' == target[0].lower():
+ return True
+ if self.dut.target in target:
+ return True
+ else:
+ return False
+
+ def case_skip(self, case_name):
+ skip_flage = False
+ for rule in filter_case[1:]:
+ # check case name
+ if case_name == rule[0]:
+ for key in check_function_dict.keys():
+ try:
+ if 'message' == key:
+ continue
+ check_function = getattr(self, 'check_%s' % key)
+ except:
+ print "can't check %s type" % key
+ if check_function(rule[check_function_dict[key]]):
+ skip_flage = True
+ else:
+ skip_flage = False
+ break
+ if skip_flage:
+ if 'message' in check_function_dict:
+ for i in check_function_dict['message']:
+ self.comments += '%s,' % rule[i]
+ return skip_flage
+
+ return skip_flage
diff --git a/framework/config.py b/framework/config.py
index d2548e8..65cecd4 100755..100644
--- a/framework/config.py
+++ b/framework/config.py
@@ -37,45 +37,143 @@ import re
import ConfigParser # config parse module
import argparse # prase arguments module
-portconf = "conf/ports.cfg"
-crbconf = "conf/crbs.cfg"
+from exception import ConfigParseException, VirtConfigParseException
+
+PORTCONF = "conf/ports.cfg"
+CRBCONF = "conf/crbs.cfg"
+VIRTCONF = "conf/virt_global.cfg"
class UserConf():
- def __init__(self, port_conf=portconf, crb_conf=crbconf):
- self.port_config = port_conf
- self.crb_config = crb_conf
+ def __init__(self, config):
+ self.conf = ConfigParser.SafeConfigParser()
+ load_files = self.conf.read(config)
+ if load_files == []:
+ print "FAILED LOADING %s!!!" % config
+ self.conf = None
+ raise ConfigParseException(config)
+
+ def get_sections(self):
+ if self.conf is None:
+ return None
+
+ return self.conf.sections()
+
+ def load_section(self, section):
+ if self.conf is None:
+ return None
+
+ items = None
+ for conf_sect in self.conf.sections():
+ if conf_sect == section:
+ items = self.conf.items(section)
+
+ return items
+
+ def load_config(self, item):
+ confs = [conf.strip() for conf in item.split(';')]
+ if '' in confs:
+ confs.remove('')
+ return confs
+
+ def load_param(self, conf):
+ paramDict = dict()
+
+ for param in conf.split(','):
+ (key, _, value) = param.partition('=')
+ paramDict[key] = value
+ return paramDict
+
+
+class VirtConf(UserConf):
+
+ def __init__(self, virt_conf=VIRTCONF):
+ self.config_file = virt_conf
+ self.virt_cfg = {}
+ try:
+ self.virt_conf = UserConf(self.config_file)
+ except ConfigParseException:
+ self.virt_conf = None
+ raise VirtConfigParseException
+
+ def load_virt_config(self, name):
+ self.virt_cfgs = []
+
+ try:
+ virt_confs = self.virt_conf.load_section(name)
+ except:
+ print "FAILED FIND SECTION %s!!!" % name
+ return
+
+ for virt_conf in virt_confs:
+ virt_cfg = {}
+ virt_params = []
+ key, config = virt_conf
+ confs = self.virt_conf.load_config(config)
+ for config in confs:
+ virt_params.append(self.load_virt_param(config))
+ virt_cfg[key] = virt_params
+ self.virt_cfgs.append(virt_cfg)
+
+ def get_virt_config(self):
+ return self.virt_cfgs
+
+ def load_virt_param(self, config):
+ cfg_params = self.virt_conf.load_param(config)
+ return cfg_params
+
+
+class PortConf(UserConf):
+
+ def __init__(self, port_conf=PORTCONF):
+ self.config_file = port_conf
self.ports_cfg = {}
self.pci_regex = "([\da-f]{2}:[\da-f]{2}.\d{1})$"
try:
- self.port_conf = ConfigParser.SafeConfigParser()
- self.port_conf.read(self.port_config)
- except Exception as e:
- print "FAILED LOADING PORT CONFIG!!!"
+ self.port_conf = UserConf(self.config_file)
+ except ConfigParseException:
+ self.port_conf = None
+ raise PortConfigParseException
def load_ports_config(self, crbIP):
- ports = []
- for crb in self.port_conf.sections():
- if crb != crbIP:
+ self.ports_cfg = {}
+ if self.port_conf is None:
+ return
+
+ ports = self.port_conf.load_section(crbIP)
+ if ports is None:
+ return
+ key, config = ports[0]
+ confs = self.port_conf.load_config(config)
+
+ for config in confs:
+ port_param = self.port_conf.load_param(config)
+
+ # port config for vm in virtualization scenario
+ if 'dev_idx' in port_param:
+ keys = port_param.keys()
+ keys.remove('dev_idx')
+ self.ports_cfg[port_param['dev_idx']] = {
+ key: port_param[key] for key in keys}
continue
- ports = [port.strip()
- for port in self.port_conf.get(crb, 'ports').split(';')]
- for port in ports:
- port_cfg = self.__parse_port_param(port)
# check pci BDF validity
- if 'pci' not in port_cfg:
+ if 'pci' not in port_param:
print "NOT FOUND CONFIG FOR NO PCI ADDRESS!!!"
continue
- m = re.match(self.pci_regex, port_cfg['pci'])
+ m = re.match(self.pci_regex, port_param['pci'])
if m is None:
print "INVALID CONFIG FOR NO PCI ADDRESS!!!"
continue
- keys = port_cfg.keys()
+ keys = port_param.keys()
keys.remove('pci')
- self.ports_cfg[port_cfg['pci']] = {key: port_cfg[key] for key in keys}
+ self.ports_cfg[port_param['pci']] = {
+ key: port_param[key] for key in keys}
+ if 'numa' in self.ports_cfg[port_param['pci']]:
+ numa_str = self.ports_cfg[port_param['pci']]['numa']
+ self.ports_cfg[port_param['pci']]['numa'] = int(numa_str)
def get_ports_config(self):
return self.ports_cfg
@@ -86,23 +184,37 @@ class UserConf():
else:
return False
- def __parse_port_param(self, port):
- portDict = dict()
-
- for param in port.split(','):
- (key, _, value) = param.partition('=')
- if key == 'numa':
- portDict[key] = int(value)
- else:
- portDict[key] = value
- return portDict
-
if __name__ == '__main__':
- parser = argparse.ArgumentParser(description="Load DTS configuration files")
- parser.add_argument("-p", "--portconf", default=portconf)
- parser.add_argument("-c", "--crbconf", default=crbconf)
+ parser = argparse.ArgumentParser(
+ description="Load DTS configuration files")
+ parser.add_argument("-p", "--portconf", default=PORTCONF)
+ parser.add_argument("-c", "--crbconf", default=CRBCONF)
+ parser.add_argument("-v", "--virtconf", default=VIRTCONF)
args = parser.parse_args()
- conf = UserConf()
- conf.load_ports_config('192.168.1.1')
- conf.check_port_available('0000:86:00.0')
+
+ # not existed configuration file
+ try:
+ VirtConf('/tmp/not-existed.cfg')
+ except VirtConfigParseException:
+ print "Capture config parse failure"
+
+ # example for basic use configuration file
+ conf = UserConf(PORTCONF)
+ for section in conf.get_sections():
+ items = conf.load_section(section)
+ key, value = items[0]
+ confs = conf.load_config(value)
+ for config in confs:
+ conf.load_param(config)
+
+ # example for port configuration file
+ portconf = PortConf(PORTCONF)
+ portconf.load_ports_config('DUT IP')
+ print portconf.get_ports_config()
+ portconf.check_port_available('86:00.0')
+
+ # example for global virtualization configuration file
+ virtconf = VirtConf(VIRTCONF)
+ virtconf.load_virt_config('LIBVIRT')
+ print virtconf.get_virt_config()
diff --git a/framework/crb.py b/framework/crb.py
index a699bfc..dd18207 100644
--- a/framework/crb.py
+++ b/framework/crb.py
@@ -69,6 +69,12 @@ class Crb(object):
return self.session.send_expect(cmds, expected, timeout, verify)
+ def get_session_output(self, timeout=TIMEOUT):
+ """
+ Get session output message before timeout
+ """
+ return self.session.get_session_before(timeout)
+
def set_test_types(self, func_tests, perf_tests):
"""
Enable or disable function/performance test.
@@ -80,7 +86,9 @@ class Crb(object):
"""
Get the huge page number of CRB.
"""
- huge_pages = self.send_expect("awk '/HugePages_Total/ { print $2 }' /proc/meminfo", "# ")
+ huge_pages = self.send_expect(
+ "awk '/HugePages_Total/ { print $2 }' /proc/meminfo",
+ "# ", alt_session=True)
if huge_pages != "":
return int(huge_pages)
return 0
@@ -90,8 +98,19 @@ class Crb(object):
Mount hugepage file system on CRB.
"""
self.send_expect("umount `awk '/hugetlbfs/ { print $2 }' /proc/mounts`", '# ')
- self.send_expect('mkdir -p /mnt/huge', '# ')
- self.send_expect('mount -t hugetlbfs nodev /mnt/huge', '# ')
+ out = self.send_expect("awk '/hugetlbfs/ { print $2 }' /proc/mounts", "# ")
+ # only mount hugepage when no hugetlbfs mounted
+ if not len(out):
+ self.send_expect('mkdir -p /mnt/huge', '# ')
+ self.send_expect('mount -t hugetlbfs nodev /mnt/huge', '# ')
+
+ def strip_hugepage_path(self):
+ mounts = self.send_expect("cat /proc/mounts |grep hugetlbfs", "# ")
+ infos = mounts.split()
+ if len(infos) >= 2:
+ return infos[1]
+ else:
+ return ''
def set_huge_pages(self, huge_pages, numa=-1):
"""
@@ -115,6 +134,9 @@ class Crb(object):
"""
self.base_dir = base_dir
+ def set_virttype(self, virttype):
+ self.virttype = virttype
+
def admin_ports(self, port, status):
"""
Force set port's interface status.
@@ -127,13 +149,15 @@ class Crb(object):
Force set remote interface link status in FreeBSD.
"""
eth = self.ports_info[port]['intf']
- self.send_expect("ifconfig %s %s" % (eth, status), "# ")
+ self.send_expect("ifconfig %s %s" %
+ (eth, status), "# ", alt_session=True)
def admin_ports_linux(self, eth, status):
"""
Force set remote interface link status in Linux.
"""
- self.send_expect("ip link set %s %s" % (eth, status), "# ")
+ self.send_expect("ip link set %s %s" %
+ (eth, status), "# ", alt_session=True)
def pci_devices_information(self):
"""
@@ -157,8 +181,9 @@ class Crb(object):
"""
Look for the NIC's information (PCI Id and card type).
"""
- out = self.send_expect("lspci -nn | grep -i eth", "# ")
- rexp = r"([\da-f]{2}:[\da-f]{2}.\d{1}) Ethernet .*?([\da-f]{4}:[\da-f]{4})"
+ out = self.send_expect(
+ "lspci -nn | grep -i eth", "# ", alt_session=True)
+ rexp = r"([\da-f]{2}:[\da-f]{2}.\d{1}) .*Eth.*?ernet .*?([\da-f]{4}:[\da-f]{4})"
pattern = re.compile(rexp)
match = pattern.findall(out)
self.pci_devices_info = []
@@ -169,7 +194,7 @@ class Crb(object):
"""
Look for the NIC's information (PCI Id and card type).
"""
- out = self.send_expect("pciconf -l", "# ")
+ out = self.send_expect("pciconf -l", "# ", alt_session=True)
rexp = r"pci0:([\da-f]{1,3}:[\da-f]{1,2}:\d{1}):\s*class=0x020000.*chip=0x([\da-f]{4})8086"
pattern = re.compile(rexp)
match = pattern.findall(out)
@@ -179,66 +204,69 @@ class Crb(object):
card_type = "8086:%s" % match[i][1]
self.pci_devices_info.append((match[i][0], card_type))
- def get_interface_name(self, bus_id, devfun_id=''):
+ def get_pci_dev_driver(self, bus_id, devfun_id):
"""
- Get interface name of specified pci device.
+ Get the driver of specified pci device.
"""
- get_interface_name = getattr(self, 'get_interface_name_%s' % self.get_os_type())
- return get_interface_name(bus_id, devfun_id)
+ get_pci_dev_driver = getattr(
+ self, 'get_pci_dev_driver_%s' % self.get_os_type())
+ return get_pci_dev_driver(bus_id, devfun_id)
- def get_interface_name_linux(self, bus_id, devfun_id):
+ def get_pci_dev_driver_linux(self, bus_id, devfun_id):
"""
- Get interface name of specified pci device on linux.
+ Get the driver of specified pci device on linux.
"""
- command = 'ls --color=never /sys/bus/pci/devices/0000:%s:%s/net' % (bus_id, devfun_id)
- out = self.send_expect(command, '# ', verify=True)
- if out == -1:
- name = ""
- else:
- name = out.split()[0]
- return name
-
- def get_interface_name_freebsd(self, bus_id, devfun_id):
- """
- Get interface name of specified pci device on Freebsd.
- """
- out = self.send_expect("pciconf -l", "# ")
- rexp = r"(\w*)@pci0:%s" % bus_id
+ out = self.send_expect("cat /sys/bus/pci/devices/0000\:%s\:%s/uevent" %
+ (bus_id, devfun_id), "# ", alt_session=True)
+ rexp = r"DRIVER=(.+?)\r"
pattern = re.compile(rexp)
- match = pattern.findall(out)
- return match[0]
+ match = pattern.search(out)
+ if not match:
+ return None
+ return match.group(1)
- def get_mac_addr(self, intf, bus_id='', devfun_id=''):
+ def get_pci_dev_driver_freebsd(self, bus_id, devfun_id):
"""
- Get mac address of specified pci device.
+ Get the driver of specified pci device.
"""
- get_mac_addr = getattr(self, 'get_mac_addr_%s' % self.get_os_type())
- return get_mac_addr(intf, bus_id, devfun_id)
+ return True
- def get_mac_addr_linux(self, intf, bus_id, devfun_id):
+ def get_pci_dev_id(self, bus_id, devfun_id):
"""
- Get mac address of specified pci device on linux.
+ Get the pci id of specified pci device.
"""
- command = ('cat /sys/bus/pci/devices/0000:%s:%s/net/%s/address' %
- (bus_id, devfun_id, intf))
- return self.send_expect(command, '# ')
+ get_pci_dev_id = getattr(
+ self, 'get_pci_dev_id_%s' % self.get_os_type())
+ return get_pci_dev_id(bus_id, devfun_id)
- def get_mac_addr_freebsd(self, intf, bus_id, devfun_id):
+ def get_pci_dev_id_linux(self, bus_id, devfun_id):
"""
- Get mac address of specified pci device on Freebsd.
+ Get the pci id of specified pci device on linux.
"""
- out = self.send_expect('ifconfig %s' % intf, '# ')
- rexp = r"ether ([\da-f:]*)"
+ out = self.send_expect("cat /sys/bus/pci/devices/0000\:%s\:%s/uevent" %
+ (bus_id, devfun_id), "# ", alt_session=True)
+ rexp = r"PCI_ID=(.+)"
pattern = re.compile(rexp)
- match = pattern.findall(out)
- return match[0]
+ match = re.search(out)
+ if not match:
+ return None
+ return match.group(1)
def get_device_numa(self, bus_id, devfun_id):
"""
- Get numa id of specified pci device
+ Get numa number of specified pci device.
"""
- numa = self.send_expect("cat /sys/bus/pci/devices/0000\:%s\:%s/numa_node" %
- (bus_id, devfun_id), "# ")
+ get_device_numa = getattr(
+ self, "get_device_numa_%s" % self.get_os_type())
+ return get_device_numa(bus_id, devfun_id)
+
+ def get_device_numa_linux(self, bus_id, devfun_id):
+ """
+ Get numa number of specified pci device on Linux.
+ """
+ numa = self.send_expect(
+ "cat /sys/bus/pci/devices/0000\:%s\:%s/numa_node" %
+ (bus_id, devfun_id), "# ", alt_session=True)
try:
numa = int(numa)
@@ -259,14 +287,14 @@ class Crb(object):
Get ipv6 address of specified pci device on linux.
"""
out = self.send_expect("ip -family inet6 address show dev %s | awk '/inet6/ { print $2 }'"
- % intf, "# ")
+ % intf, "# ", alt_session=True)
return out.split('/')[0]
def get_ipv6_addr_freebsd(self, intf):
"""
Get ipv6 address of specified pci device on Freebsd.
"""
- out = self.send_expect('ifconfig %s' % intf, '# ')
+ out = self.send_expect('ifconfig %s' % intf, '# ', alt_session=True)
rexp = r"inet6 ([\da-f:]*)%"
pattern = re.compile(rexp)
match = pattern.findall(out)
@@ -275,6 +303,22 @@ class Crb(object):
return match[0]
+ def disable_ipv6(self, intf):
+ """
+ Disable ipv6 of of specified interface
+ """
+ if intf != 'N/A':
+ self.send_expect("sysctl net.ipv6.conf.%s.disable_ipv6=1" %
+ intf, "# ", alt_session=True)
+
+ def enable_ipv6(self, intf):
+ """
+ Enable ipv6 of of specified interface
+ """
+ if intf != 'N/A':
+ self.send_expect("sysctl net.ipv6.conf.%s.disable_ipv6=0" %
+ intf, "# ", alt_session=True)
+
def create_file(self, contents, fileName):
"""
Create file with contents and copy it to CRB.
@@ -290,6 +334,21 @@ class Crb(object):
cmd = "for i in `lsof /var/run/.rte_config /var/run/dpdk_config \
| awk '/config/ {print $2}'` ; do kill -9 $i; done"
self.alt_session.session.send_expect(cmd, "# ", 10)
+ proce_cmd = "lsof /var/run/.rte_config /var/run/dpdk_config | awk '{print $2}'"
+ hugepage_cmd = "lsof /var/run/.rte_hugepage_info | awk {print $2}"
+ out = self.alt_session.session.send_expect(proce_cmd, "# ",10)
+ if "PID" in out:
+ self.logger.warning("There are some dpdk process not killed")
+ self.logger.warning("**************************************")
+ self.logger.warning(out)
+ self.logger.warning("**************************************")
+
+ out = self.alt_session.session.send_expect(hugepage_cmd, "# ",10)
+ if "PID" in out:
+ self.logger.warning("There are some dpdk process not free hugepage")
+ self.logger.warning("**************************************")
+ self.logger.warning(out)
+ self.logger.warning("**************************************")
time.sleep(.7)
def close(self):
@@ -318,7 +377,7 @@ class Crb(object):
if isinstance(self, Dut) and self.get_os_type() == 'freebsd':
expected = 'FreeBSD.*#'
- self.send_expect('uname', expected, 2)
+ self.send_expect('uname', expected, 2, alt_session=True)
def init_core_list(self):
"""
@@ -378,8 +437,14 @@ class Crb(object):
self.cores = []
cpuinfo = \
- self.send_expect("grep \"processor\\|physical id\\|core id\\|^$\" /proc/cpuinfo", "#")
+ self.send_expect(
+ "grep --color=never \"processor\\|physical id\\|core id\\|^$\" /proc/cpuinfo",
+ "#", alt_session=True)
cpuinfo = cpuinfo.split('\r\n\r\n')
+ # haswell cpu on cottonwood core id not correct
+ # need addtional coremap for haswell cpu
+ core_id = 0
+ coremap = {}
for line in cpuinfo:
m = re.search("processor\t: (\d+)\r\n" +
"physical id\t: (\d+)\r\n" +
@@ -389,11 +454,16 @@ class Crb(object):
thread = m.group(1)
socket = m.group(2)
core = m.group(3)
+
+ if core not in coremap.keys():
+ coremap[core] = core_id
+ core_id += 1
+
if self.crb['bypass core0'] and core == '0' and socket == '0':
self.logger.info("Core0 bypassed")
continue
self.cores.append(
- {'thread': thread, 'socket': socket, 'core': core})
+ {'thread': thread, 'socket': socket, 'core': coremap[core]})
self.number_of_cores = len(self.cores)
@@ -516,9 +586,9 @@ class Crb(object):
temp = []
for sock in sockList:
- core_list = set([int(n['core']) for n in partial_cores if int(
+ core_list = list([int(n['core']) for n in partial_cores if int(
n['socket']) == sock])
- core_list = list(core_list)[:nr_cores]
+ core_list = core_list[:nr_cores]
temp.extend(core_list)
core_list = temp
@@ -536,9 +606,9 @@ class Crb(object):
coreList_aux = [int(core_list[n])for n in range(
(nr_cores * i), (nr_cores * i + nr_cores))]
for core in coreList_aux:
- thread_list = set([int(n['thread']) for n in partial_cores if (
+ thread_list = list([int(n['thread']) for n in partial_cores if (
(int(n['core']) == core) and (int(n['socket']) == sock))])
- thread_list = list(thread_list)[:nr_threads]
+ thread_list = thread_list[:nr_threads]
temp.extend(thread_list)
thread_list = temp
i += 1
diff --git a/framework/debugger.py b/framework/debugger.py
index a5f3e84..e877336 100644
--- a/framework/debugger.py
+++ b/framework/debugger.py
@@ -28,23 +28,30 @@ import signal
import code
import time
import dts
+import imp
+import dts
+from test_case import TestCase
-console = None # global console object
-debug_cmd = '' # global debug state
+console = None # global console object
+debug_cmd = '' # global debug state
+AliveSuite = None # global suite for run command
+AliveModule = None # global module for reload
+AliveCase = None # global case name for run command
def help_command():
console.push('print \'Help on debug module\'')
console.push('print \'DESCRIPTION\'')
console.push('print \'DTS debug module support few debug commands\'')
- console.push('print \' - help: help messages\'')
- console.push('print \' - list: list all connections\'')
- console.push('print \' - connect: bind to specified connection\'')
+ console.push('print \' - help(): help messages\'')
+ console.push('print \' - list(): list all connections\'')
+ console.push('print \' - connect(): bind to specified connection\'')
console.push('print \' - : connect(\"dut\")\'')
- console.push('print \' - quit: quit debug module\'')
- console.push('print \' - exit: exit processing procedure\'')
- console.push('print \' - debug: call python debug module for further debug\'')
+ console.push('print \' - quit(): quit debug module\'')
+ console.push('print \' - exit(): exit processing procedure\'')
+ console.push('print \' - debug(): call python debug module for further debug\'')
+ console.push('print \' - rerun(): re-run the interrupted test case\'')
def list_command():
@@ -70,6 +77,30 @@ def connect_command(connect):
session.session.interact()
+def rerun_command():
+ """
+ Rerun test case specified in command line
+ """
+ global AliveSuite, AliveModule, AliveCase
+ new_module = imp.reload(AliveModule)
+
+ # save arguments required to initialize suite
+ dut = AliveSuite.__dict__['dut']
+ tester = AliveSuite.__dict__['tester']
+ target = AliveSuite.__dict__['target']
+ suite = AliveSuite.__dict__['suite']
+
+ for test_classname, test_class in dts.get_subclasses(new_module, TestCase):
+ suite_obj = test_class(dut, tester, target, suite)
+
+ # copy all element from previous suite to reloaded suite
+ dts.copy_instance_attr(AliveSuite, suite_obj)
+ # re-run specified test case
+ for case in dts.get_test_cases(suite_obj, r'%s' % AliveCase):
+ if callable(case):
+ case()
+
+
def exit_command():
"""
Exit dts framework.
@@ -108,6 +139,7 @@ def keyboard_handle(signum, frame):
command['debug'] = debug_command
command['help'] = help_command
command['connect'] = connect_command
+ command['rerun'] = rerun_command
console.push('print \"Use help command for detail information\"')
try:
code.interact(local=command)
diff --git a/framework/dts.py b/framework/dts.py
index c9ecccb..613926c 100644
--- a/framework/dts.py
+++ b/framework/dts.py
@@ -37,6 +37,8 @@ import traceback # exception traceback
import inspect # load attribute
import atexit # register callback when exit
import json # json format
+import signal # signal module for debug mode
+import time # time module for unique output folder
import rst # rst file support
from crbs import crbs
@@ -49,16 +51,21 @@ from test_case import TestCase
from test_result import Result
from stats_reporter import StatsReporter
from excel_reporter import ExcelReporter
+from utils import *
from exception import TimeoutException
from logger import getLogger
import logger
-
+import debugger
+from virt_scene import VirtScene
+from checkCase import *
import sys
reload(sys)
sys.setdefaultencoding('UTF8')
+PROJECT_MODULE_PREFIX = 'project_'
debug_mode = False
+debug_case = False
config = None
table = None
results_table_rows = []
@@ -66,51 +73,22 @@ results_table_header = []
performance_only = False
functional_only = False
nic = None
+rx_mode = None
requested_tests = None
dut = None
+duts = None
tester = None
result = None
excel_report = None
stats = None
log_handler = None
+module = None
+Package = ''
+Patches = []
drivername = ""
interrupttypr = ""
-def RED(text):
- return "\x1B[" + "31;1m" + text + "\x1B[" + "0m"
-
-
-def BLUE(text):
- return "\x1B[" + "36;1m" + text + "\x1B[" + "0m"
-
-
-def GREEN(text):
- return "\x1B[" + "32;1m" + text + "\x1B[" + "0m"
-
-
-def regexp(s, to_match, allString=False):
- """
- Ensure that the re `to_match' only has one group in it.
- """
-
- scanner = re.compile(to_match, re.DOTALL)
- if allString:
- return scanner.findall(s)
- m = scanner.search(s)
- if m is None:
- log_handler.warning("Failed to match " + to_match + " in the string " + s)
- return None
- return m.group(1)
-
-
-def pprint(some_dict):
- """
- Print JSON format dictionary object.
- """
- return json.dumps(some_dict, sort_keys=True, indent=4)
-
-
def report(text, frame=False, annex=False):
"""
Save report text into rst file.
@@ -132,36 +110,6 @@ def close_crb_sessions():
log_handler.info("DTS ended")
-def get_nic_driver(pci_id):
- """
- Return linux driver for specified pci device
- """
- driverlist = dict(zip(NICS.values(), DRIVERS.keys()))
- try:
- driver = DRIVERS[driverlist[pci_id]]
- except Exception as e:
- driver = None
- return driver
-
-
-def accepted_nic(pci_id):
- """
- Return True if the pci_id is a known NIC card in the settings file and if
- it is selected in the execution file, otherwise it returns False.
- """
- if pci_id not in NICS.values():
- return False
-
- if nic is 'any':
- return True
-
- else:
- if pci_id == NICS[nic]:
- return True
-
- return False
-
-
def get_crb_os(crb):
if 'OS' in crb:
return crb['OS']
@@ -200,12 +148,24 @@ def dts_parse_config(section):
"""
Parse execution file configuration.
"""
+ try:
+ scenario = config.get(section, 'scenario')
+ except:
+ scenario = ''
+
+ global nic
+ global rx_mode
+
duts = [dut_.strip() for dut_ in config.get(section,
'crbs').split(',')]
targets = [target.strip()
for target in config.get(section, 'targets').split(',')]
test_suites = [suite.strip()
for suite in config.get(section, 'test_suites').split(',')]
+ try:
+ rx_mode = config.get(section, 'rx_mode').strip()
+ except:
+ rx_mode = None
for suite in test_suites:
if suite == '':
@@ -213,16 +173,17 @@ def dts_parse_config(section):
nic = [_.strip() for _ in paramDict['nic_type'].split(',')][0]
- return duts[0], targets, test_suites, nic
+ return duts[0], targets, test_suites, nic, scenario
def get_project_obj(project_name, super_class, crbInst, serializer):
"""
Load project module and return crb instance.
"""
+ global PROJECT_MODULE_PREFIX
project_obj = None
try:
- project_module = __import__("project_" + project_name)
+ project_module = __import__(PROJECT_MODULE_PREFIX + project_name)
for project_subclassname, project_subclass in get_subclasses(project_module, super_class):
project_obj = project_subclass(crbInst, serializer)
@@ -239,11 +200,16 @@ def dts_log_testsuite(test_suite, log_handler, test_classname):
"""
Change to SUITE self logger handler.
"""
+ global duts
test_suite.logger = getLogger(test_classname)
test_suite.logger.config_suite(test_classname)
log_handler.config_suite(test_classname, 'dts')
dut.logger.config_suite(test_classname, 'dut')
+ dut.test_classname = test_classname
tester.logger.config_suite(test_classname, 'tester')
+ if duts and len(duts):
+ for crb in duts:
+ crb.logger.config_suite(test_classname, 'virtdut')
try:
if tester.it_uses_external_generator():
getattr(tester, 'ixia_packet_gen')
@@ -259,6 +225,9 @@ def dts_log_execution(log_handler):
log_handler.config_execution('dts')
dut.logger.config_execution('dut')
tester.logger.config_execution('tester')
+ if duts and len(duts):
+ for crb in duts:
+ crb.logger.config_execution('virtdut')
try:
if tester.it_uses_external_generator():
getattr(tester, 'ixia_packet_gen')
@@ -267,19 +236,22 @@ def dts_log_execution(log_handler):
pass
-def dts_crbs_init(crbInst, skip_setup, read_cache, project, base_dir, nic):
+def dts_crbs_init(crbInst, skip_setup, read_cache, project, base_dir, nic, virttype):
"""
Create dts dut/tester instance and initialize them.
"""
global dut
global tester
- serializer.set_serialized_filename('../.%s.cache' % crbInst['IP'])
+ serializer.set_serialized_filename(FOLDERS['Output'] +
+ '/.%s.cache' % crbInst['IP'])
serializer.load_from_file()
dut = get_project_obj(project, Dut, crbInst, serializer)
tester = get_project_obj(project, Tester, crbInst, serializer)
+ dts_log_execution(log_handler)
dut.tester = tester
tester.dut = dut
+ dut.set_virttype(virttype)
dut.set_speedup_options(read_cache, skip_setup)
dut.set_directory(base_dir)
dut.set_nic_type(nic)
@@ -292,10 +264,10 @@ def dts_crbs_init(crbInst, skip_setup, read_cache, project, base_dir, nic):
def dts_crbs_exit():
"""
- Remove logger handler when exit.
+ Call dut and tester exit function after execution finished
"""
- dut.logger.logger_exit()
- tester.logger.logger_exit()
+ dut.crb_exit()
+ tester.crb_exit()
def dts_run_prerequisties(pkgName, patch):
@@ -315,16 +287,33 @@ def dts_run_prerequisties(pkgName, patch):
return False
-def dts_run_target(crbInst, targets, test_suites, nic):
+def dts_run_target(crbInst, targets, test_suites, nic, scenario):
"""
Run each target in execution targets.
"""
+ global skip_case_mode
+ skip_case_mode = check_case_skip(dut)
+ if scenario != '':
+ scene = VirtScene(dut, tester, scenario)
+ else:
+ scene = None
+
+ if scene:
+ scene.load_config()
+ scene.create_scene()
+
for target in targets:
log_handler.info("\nTARGET " + target)
result.target = target
try:
- dut.set_target(target)
+ if scene:
+ scene.set_target(target)
+ # skip set_target when host has been setup by scenario
+ if not scene.host_bound:
+ dut.set_target(target, bind_dev=False)
+ else:
+ dut.set_target(target)
except AssertionError as ex:
log_handler.error(" TARGET ERROR: " + str(ex))
result.add_failed_target(result.dut, target, str(ex))
@@ -337,17 +326,18 @@ def dts_run_target(crbInst, targets, test_suites, nic):
if 'nic_type' not in paramDict:
paramDict['nic_type'] = 'any'
nic = 'any'
- result.nic = nic
- dts_run_suite(crbInst, test_suites, target, nic)
+ dts_run_suite(crbInst, test_suites, target, nic, scene)
+
+ if scene:
+ scene.destroy_scene()
+ scene = None
dut.restore_interfaces()
- dut.close()
tester.restore_interfaces()
- tester.close()
-def dts_run_suite(crbInst, test_suites, target, nic):
+def dts_run_suite(crbInst, test_suites, target, nic, scene):
"""
Run each suite in test suite list.
"""
@@ -357,9 +347,19 @@ def dts_run_suite(crbInst, test_suites, target, nic):
result.test_suite = test_suite
rst.generate_results_rst(crbInst['name'], target, nic, test_suite, performance_only)
test_module = __import__('TestSuite_' + test_suite)
+ global module
+ module = test_module
for test_classname, test_class in get_subclasses(test_module, TestCase):
- test_suite = test_class(dut, tester, target)
+ if scene and scene.vm_dut_enable:
+ global duts
+ duts = scene.get_vm_duts()
+ tester.dut = duts[0]
+ test_suite = test_class(duts[0], tester, target, test_suite)
+ else:
+ test_suite = test_class(dut, tester, target, test_suite)
+ result.nic = test_suite.nic
+
dts_log_testsuite(test_suite, log_handler, test_classname)
log_handler.info("\nTEST SUITE : " + test_classname)
@@ -386,7 +386,7 @@ def dts_run_suite(crbInst, test_suites, target, nic):
def run_all(config_file, pkgName, git, patch, skip_setup,
read_cache, project, suite_dir, test_cases,
- base_dir, output_dir, verbose, debug):
+ base_dir, output_dir, verbose, virttype, debug, debugcase):
"""
Main process of DTS, it will run all test suites in the config file.
"""
@@ -400,8 +400,20 @@ def run_all(config_file, pkgName, git, patch, skip_setup,
global stats
global log_handler
global debug_mode
-
+ global debug_case
+ global Package
+ global Patches
+ global scenario
+ global check_case_inst
+ # save global variable
+ Package = pkgName
+ Patches = patch
+ check_case = parse_file()
+ check_case.set_filter_case()
# prepare the output folder
+ if output_dir == '':
+ output_dir = FOLDERS['Output']
+
if not os.path.exists(output_dir):
os.mkdir(output_dir)
@@ -413,6 +425,8 @@ def run_all(config_file, pkgName, git, patch, skip_setup,
# enable debug mode
if debug is True:
debug_mode = True
+ if debugcase is True:
+ debug_case = True
# init log_handler handler
if verbose is True:
@@ -447,8 +461,7 @@ def run_all(config_file, pkgName, git, patch, skip_setup,
dts_parse_param(section)
# verify if the delimiter is good if the lists are vertical
- dutIP, targets, test_suites, nics = dts_parse_config(section)
-
+ dutIP, targets, test_suites, nics, scenario = dts_parse_config(section)
log_handler.info("\nDUT " + dutIP)
# look up in crbs - to find the matching IP
@@ -466,14 +479,15 @@ def run_all(config_file, pkgName, git, patch, skip_setup,
result.dut = dutIP
# init dut, tester crb
- dts_crbs_init(crbInst, skip_setup, read_cache, project, base_dir, nics)
+ dts_crbs_init(crbInst, skip_setup, read_cache, project, base_dir, nics, virttype)
+ check_case_inst = check_case_skip(dut)
# Run DUT prerequisites
if dts_run_prerequisties(pkgName, patch) is False:
dts_crbs_exit()
continue
- dts_run_target(crbInst, targets, test_suites, nics)
+ dts_run_target(crbInst, targets, test_suites, nics, scenario)
dts_crbs_exit()
@@ -503,6 +517,11 @@ def get_subclasses(module, clazz):
yield (subclazz_name, subclazz)
+def copy_instance_attr(from_inst, to_inst):
+ for key in from_inst.__dict__.keys():
+ to_inst.__dict__[key] = from_inst.__dict__[key]
+
+
def get_functional_test_cases(test_suite):
"""
Get all functional test cases.
@@ -544,6 +563,9 @@ def execute_test_setup_all(test_case):
Execute suite setup_all function before cases.
"""
try:
+ # clear all previous output
+ test_case.dut.get_session_output(timeout=0.1)
+ test_case.tester.get_session_output(timeout=0.1)
test_case.set_up_all()
return True
except Exception:
@@ -568,15 +590,37 @@ def execute_test_case(test_suite, test_case):
Execute specified test case in specified suite. If any exception occured in
validation process, save the result and tear down this case.
"""
+ global debug_mode
+ global debug_case
+ global module
result.test_case = test_case.__name__
-
rst.write_title("Test Case: " + test_case.__name__)
+ if check_case_inst.case_skip(test_case.__name__[len("test_"):]):
+ log_handler.info('Test Case %s Result SKIPED:' % test_case.__name__)
+ rst.write_result("N/A")
+ result.test_case_skip(skip_case_mode.comments)
+ save_all_results()
+ return
+
if performance_only:
rst.write_annex_title("Annex: " + test_case.__name__)
try:
log_handler.info('Test Case %s Begin' % test_case.__name__)
+ test_suite.running_case = test_case.__name__
+ # clear all previous output
+ test_suite.dut.get_session_output(timeout=0.1)
+ test_suite.tester.get_session_output(timeout=0.1)
+ # run set_up function for each case
test_suite.set_up()
- test_case()
+ # prepare debugger re-run case environment
+ if debug_mode or debug_case:
+ debugger.AliveSuite = test_suite
+ debugger.AliveModule = module
+ debugger.AliveCase = test_case.__name__
+ if debug_case:
+ debugger.keyboard_handle(signal.SIGINT, None)
+ else:
+ test_case()
result.test_case_passed()
diff --git a/framework/dut.py b/framework/dut.py
index 45a317e..a5c9db3 100644
--- a/framework/dut.py
+++ b/framework/dut.py
@@ -33,11 +33,15 @@ import os
import re
import time
import dts
-from config import UserConf
-from settings import NICS
+import settings
+from config import PortConf
+from settings import NICS, LOG_NAME_SEP
from ssh_connection import SSHConnection
from crb import Crb
+from net_device import NetDevice
from logger import getLogger
+from virt_resource import VirtResource
+from utils import RED
class Dut(Crb):
@@ -60,20 +64,36 @@ class Dut(Crb):
def __init__(self, crb, serializer):
super(Dut, self).__init__(crb, serializer)
self.NAME = 'dut'
+
+ self.host_init_flag = False
self.logger = getLogger(self.NAME)
self.session = SSHConnection(self.get_ip_address(), self.NAME,
self.get_password())
self.session.init_log(self.logger)
- self.alt_session = SSHConnection(self.get_ip_address(), self.NAME + '_alt',
- self.get_password())
+ self.alt_session = SSHConnection(
+ self.get_ip_address(),
+ self.NAME + '_alt',
+ self.get_password())
self.alt_session.init_log(self.logger)
self.number_of_cores = 0
self.tester = None
self.cores = []
self.architecture = None
self.ports_info = None
- self.conf = UserConf()
+ self.conf = PortConf()
self.ports_map = []
+ self.virt_pool = None
+
+ def init_host_session(self):
+ if self.host_init_flag:
+ pass
+ else:
+ self.host_session = SSHConnection(
+ self.get_ip_address(),
+ self.NAME + '_host',
+ self.get_password())
+ self.host_session.init_log(self.logger)
+ self.host_init_flag = True
def change_config_option(self, target, parameter, value):
"""
@@ -82,12 +102,12 @@ class Dut(Crb):
self.send_expect("sed -i 's/%s=.*$/%s=%s/' config/defconfig_%s" %
(parameter, parameter, value, target), "# ")
- def set_nic_type(self, nic):
+ def set_nic_type(self, nic_type):
"""
Set CRB NICS ready to validated.
"""
- self.nic = nic
- if 'cfg' in nic:
+ self.nic_type = nic_type
+ if 'cfg' in nic_type:
self.conf.load_ports_config(self.get_ip_address())
def set_toolchain(self, target):
@@ -156,6 +176,8 @@ class Dut(Crb):
self.init_core_list()
self.pci_devices_information()
+ # make sure ipv6 enable before scan
+ self.enable_tester_ipv6()
# scan ports before restore interface
self.scan_ports()
# restore dut ports to kernel
@@ -167,11 +189,17 @@ class Dut(Crb):
self.mount_procfs()
# auto detect network topology
self.map_available_ports()
+ # disable tester port ipv6
+ self.disable_tester_ipv6()
# print latest ports_info
- self.logger.info(dts.pprint(self.ports_info))
+ for port_info in self.ports_info:
+ self.logger.info(port_info)
if self.ports_map is None or len(self.ports_map) == 0:
raise ValueError("ports_map should not be empty, please check all links")
+ # initialize virtualization resource pool
+ self.virt_pool = VirtResource(self)
+
def restore_interfaces(self):
"""
Restore all ports's interfaces.
@@ -195,20 +223,22 @@ class Dut(Crb):
pci_bus = port['pci']
pci_id = port['type']
# get device driver
- driver = dts.get_nic_driver(pci_id)
+ driver = settings.get_nic_driver(pci_id)
if driver is not None:
# unbind device driver
addr_array = pci_bus.split(':')
bus_id = addr_array[0]
devfun_id = addr_array[1]
+ port = NetDevice(self, bus_id, devfun_id)
+
self.send_expect('echo 0000:%s > /sys/bus/pci/devices/0000\:%s\:%s/driver/unbind'
% (pci_bus, bus_id, devfun_id), '# ')
# bind to linux kernel driver
self.send_expect('modprobe %s' % driver, '# ')
self.send_expect('echo 0000:%s > /sys/bus/pci/drivers/%s/bind'
% (pci_bus, driver), '# ')
- itf = self.get_interface_name(addr_array[0], addr_array[1])
+ itf = port.get_interface_name()
self.send_expect("ifconfig %s up" % itf, "# ")
else:
self.logger.info("NOT FOUND DRIVER FOR PORT (%s|%s)!!!" % (pci_bus, pci_id))
@@ -228,7 +258,10 @@ class Dut(Crb):
"""
Setup Linux hugepages.
"""
+ if self.virttype == 'XEN':
+ return
hugepages_size = self.send_expect("awk '/Hugepagesize/ {print $2}' /proc/meminfo", "# ")
+ total_huge_pages = self.get_total_huge_pages()
if int(hugepages_size) < (1024 * 1024):
if self.architecture == "x86_64":
@@ -239,12 +272,12 @@ class Dut(Crb):
elif self.architecture == "x86_x32":
arch_huge_pages = hugepages if hugepages > 0 else 256
- total_huge_pages = self.get_total_huge_pages()
-
- self.mount_huge_pages()
if total_huge_pages != arch_huge_pages:
self.set_huge_pages(arch_huge_pages)
+ self.mount_huge_pages()
+ self.hugepage_path = self.strip_hugepage_path()
+
def setup_memory_freebsd(self, hugepages=-1):
"""
Setup Freebsd hugepages.
@@ -265,6 +298,20 @@ class Dut(Crb):
return 'taskset %s ' % core
+ def is_ssh_session_port(self, pci_bus):
+ """
+ Check if the pci device is the dut SSH session port.
+ """
+ port = None
+ for port_info in self.ports_info:
+ if pci_bus == port_info['pci']:
+ port = port_info['port']
+ break
+ if port and port.get_ipv4_addr() == crbs['IP'].strip():
+ return True
+ else:
+ return False
+
def bind_interfaces_linux(self, driver='igb_uio', nics_to_bind=None):
"""
Bind the interfaces to the selected driver. nics_to_bind can be None
@@ -275,12 +322,17 @@ class Dut(Crb):
current_nic = 0
for (pci_bus, pci_id) in self.pci_devices_info:
- if dts.accepted_nic(pci_id):
+ if settings.accepted_nic(pci_id):
+ if self.is_ssh_session_port(pci_bus):
+ continue
if nics_to_bind is None or current_nic in nics_to_bind:
binding_list += '%s ' % (pci_bus)
current_nic += 1
+ if current_nic == 0:
+ self.logger.info("Not nic need bind driver: %s" % driver)
+ return
self.send_expect('tools/dpdk_nic_bind.py %s' % binding_list, '# ')
@@ -293,13 +345,19 @@ class Dut(Crb):
current_nic = 0
for (pci_bus, pci_id) in self.pci_devices_info:
- if dts.accepted_nic(pci_id):
+ if settings.accepted_nic(pci_id):
+ if self.is_ssh_session_port(pci_bus):
+ continue
if nics_to_bind is None or current_nic in nics_to_bind:
binding_list += '%s ' % (pci_bus)
current_nic += 1
+ if current_nic == 0:
+ self.logger.info("Not nic need unbind driver")
+ return
+
self.send_expect('tools/dpdk_nic_bind.py %s' % binding_list, '# ', 30)
def get_ports(self, nic_type='any', perf=None, socket=None):
@@ -321,7 +379,10 @@ class Dut(Crb):
elif nic_type == 'cfg':
for portid in range(len(self.ports_info)):
if self.ports_info[portid]['source'] == 'cfg':
- ports.append(portid)
+ if (socket is None or
+ self.ports_info[portid]['numa'] == -1 or
+ socket == self.ports_info[portid]['numa']):
+ ports.append(portid)
return ports
else:
for portid in range(len(self.ports_info)):
@@ -439,36 +500,52 @@ class Dut(Crb):
Check that whether auto scanned ports ready to use
"""
pci_addr = "%s:%s" % (pci_bus, pci_id)
- if self.nic == 'any':
+ if self.nic_type == 'any':
return True
- elif self.nic == 'cfg':
+ elif self.nic_type == 'cfg':
if self.conf.check_port_available(pci_bus) is True:
return True
- elif self.nic not in NICS.keys():
- self.logger.warning("NOT SUPPORTED NIC TYPE: %s" % self.nic)
+ elif self.nic_type not in NICS.keys():
+ self.logger.warning("NOT SUPPORTED NIC TYPE: %s" % self.nic_type)
else:
- codename = NICS[self.nic]
+ codename = NICS[self.nic_type]
if pci_id == codename:
return True
return False
def rescan_ports(self):
- unknow_interface = dts.RED('Skipped: unknow_interface')
+ """
+ Rescan ports information
+ """
+ if self.read_cache and self.load_serializer_ports():
+ return
+
+ if self.ports_info:
+ self.rescan_ports_uncached()
+ self.save_serializer_ports()
+
+ def rescan_ports_uncached(self):
+ """
+ rescan ports and update port's mac adress, intf, ipv6 address.
+ """
+ rescan_ports_uncached = getattr(self, 'rescan_ports_uncached_%s' % self.get_os_type())
+ return rescan_ports_uncached()
+
+ def rescan_ports_uncached_linux(self):
+ unknow_interface = RED('Skipped: unknow_interface')
for port_info in self.ports_info:
- pci_bus = port_info['pci']
- addr_array = pci_bus.split(':')
- bus_id = addr_array[0]
- devfun_id = addr_array[1]
- intf = self.get_interface_name(bus_id, devfun_id)
+ port = port_info['port']
+ intf = port.get_interface_name()
if "No such file" in intf:
self.logger.info("DUT: [0000:%s] %s" % (pci_bus, unknow_interface))
+ continue
out = self.send_expect("ip link show %s" % intf, "# ")
if "DOWN" in out:
self.send_expect("ip link set %s up" % intf, "# ")
time.sleep(5)
- macaddr = self.get_mac_addr(intf, bus_id, devfun_id)
+ macaddr = port.get_mac_addr()
out = self.send_expect("ip -family inet6 address show dev %s | awk '/inet6/ { print $2 }'"
% intf, "# ")
ipv6 = out.split('/')[0]
@@ -480,16 +557,77 @@ class Dut(Crb):
port_info['intf'] = intf
port_info['ipv6'] = ipv6
+ def rescan_ports_uncached_freebsd(self):
+ unknow_interface = RED('Skipped: unknow_interface')
+
+ for port_info in self.ports_info:
+ port = port_info['port']
+ intf = port.get_interface_name()
+ if "No such file" in intf:
+ self.logger.info("DUT: [0000:%s] %s" % (pci_bus, unknow_interface))
+ continue
+ self.send_expect("ifconfig %s up" % intf, "# ")
+ time.sleep(5)
+ macaddr = port.get_mac_addr()
+ ipv6 = port.get_ipv6_addr()
+ # Unconnected ports don't have IPv6
+ if ipv6 is None:
+ ipv6 = "Not connected"
+
+ port_info['mac'] = macaddr
+ port_info['intf'] = intf
+ port_info['ipv6'] = ipv6
+
+ def load_serializer_ports(self):
+ cached_ports_info = self.serializer.load(self.PORT_INFO_CACHE_KEY)
+ if cached_ports_info is None:
+ return None
+
+ self.ports_info = cached_ports_info
+
+ def save_serializer_ports(self):
+ cached_ports_info = []
+ for port in self.ports_info:
+ port_info = {}
+ for key in port.keys():
+ if type(port[key]) is str:
+ port_info[key] = port[key]
+ cached_ports_info.append(port_info)
+ self.serializer.save(self.PORT_INFO_CACHE_KEY, cached_ports_info)
+
def scan_ports(self):
"""
Scan ports information or just read it from cache file.
"""
if self.read_cache:
- self.ports_info = self.serializer.load(self.PORT_INFO_CACHE_KEY)
+ self.load_serializer_ports()
+ self.scan_ports_cached()
if not self.read_cache or self.ports_info is None:
self.scan_ports_uncached()
- self.serializer.save(self.PORT_INFO_CACHE_KEY, self.ports_info)
+
+ def scan_ports_cached(self):
+ """
+ Scan cached ports, instantiate tester port
+ """
+ scan_ports_cached = getattr(self, 'scan_ports_cached_%s' % self.get_os_type())
+ return scan_ports_cached()
+
+ def scan_ports_cached_linux(self):
+ """
+ Scan Linux ports and instantiate tester port
+ """
+ if self.ports_info is None:
+ return
+
+ for port_info in self.ports_info:
+ port = NetDevice(self, port_info['pci'], port_info['type'])
+ intf = port.get_interface_name()
+
+ self.logger.info("DUT cached: [000:%s %s] %s" % (port_info['pci'],
+ port_info['type'], intf))
+
+ port_info['port'] = port
def scan_ports_uncached(self):
"""
@@ -504,8 +642,8 @@ class Dut(Crb):
"""
self.ports_info = []
- skipped = dts.RED('Skipped: Unknown/not selected')
- unknow_interface = dts.RED('Skipped: unknow_interface')
+ skipped = RED('Skipped: Unknown/not selected')
+ unknow_interface = RED('Skipped: unknow_interface')
for (pci_bus, pci_id) in self.pci_devices_info:
if self.check_ports_available(pci_bus, pci_id) is False:
@@ -517,9 +655,11 @@ class Dut(Crb):
bus_id = addr_array[0]
devfun_id = addr_array[1]
- numa = self.get_device_numa(bus_id, devfun_id)
+ port = NetDevice(self, bus_id, devfun_id)
+ numa = port.socket
# store the port info to port mapping
- self.ports_info.append({'pci': pci_bus, 'type': pci_id, 'numa': numa})
+ self.ports_info.append(
+ {'port': port, 'pci': pci_bus, 'type': pci_id, 'numa': numa})
def scan_ports_uncached_freebsd(self):
"""
@@ -527,19 +667,20 @@ class Dut(Crb):
"""
self.ports_info = []
- skipped = dts.RED('Skipped: Unknown/not selected')
+ skipped = RED('Skipped: Unknown/not selected')
for (pci_bus, pci_id) in self.pci_devices_info:
- if not dts.accepted_nic(pci_id):
+ if not settings.accepted_nic(pci_id):
self.logger.info("DUT: [%s %s] %s" % (pci_bus, pci_id,
skipped))
continue
- intf = self.get_interface_name(pci_bus)
+ port = NetDevice(self, pci_bus, '')
+ intf = port.get_interface_name()
- macaddr = self.get_mac_addr(intf)
- ipv6 = self.get_ipv6_addr(intf)
+ macaddr = port.get_mac_addr()
+ ipv6 = port.get_ipv6_addr()
if ipv6 is None:
ipv6 = "Not available"
@@ -559,9 +700,68 @@ class Dut(Crb):
pci_str = "%s:%s.%s" % (pci_bus_id, pci_dev_str, pci_split[2])
# store the port info to port mapping
- self.ports_info.append({'pci': pci_str, 'type': pci_id, 'intf':
+ self.ports_info.append({'port': port, 'pci': pci_str, 'type': pci_id, 'intf':
intf, 'mac': macaddr, 'ipv6': ipv6, 'numa': -1})
+ def generate_sriov_vfs_by_port(self, port_id, vf_num, driver='default'):
+ """
+ Generate SRIOV VFs with default driver it is bound now or specifid driver.
+ """
+ port = self.ports_info[port_id]['port']
+ port_driver = port.get_nic_driver()
+
+ if driver == 'default':
+ if not port_driver:
+ self.logger.info(
+ "No driver on specified port, can not generate SRIOV VF.")
+ return None
+ else:
+ if port_driver != driver:
+ port.bind_driver(driver)
+ port.generate_sriov_vfs(vf_num)
+
+ # append the VF PCIs into the ports_info
+ sriov_vfs_pci = port.get_sriov_vfs_pci()
+ self.ports_info[port_id]['sriov_vfs_pci'] = sriov_vfs_pci
+
+ # instantiate the VF with NetDevice
+ vfs_port = []
+ for vf_pci in sriov_vfs_pci:
+ addr_array = vf_pci.split(':')
+ bus_id = addr_array[0]
+ devfun_id = addr_array[1]
+ vf_port = NetDevice(self, bus_id, devfun_id)
+ vfs_port.append(vf_port)
+ self.ports_info[port_id]['vfs_port'] = vfs_port
+
+ pci = self.ports_info[port_id]['pci']
+ self.virt_pool.add_vf_on_pf(pf_pci=pci, vflist=sriov_vfs_pci)
+
+ def destroy_sriov_vfs_by_port(self, port_id):
+ port = self.ports_info[port_id]['port']
+ vflist = []
+ port_driver = port.get_nic_driver()
+ if 'sriov_vfs_pci' in self.ports_info[port_id] and \
+ self.ports_info[port_id]['sriov_vfs_pci']:
+ vflist = self.ports_info[port_id]['sriov_vfs_pci']
+ else:
+ if not port.get_sriov_vfs_pci():
+ return
+
+ if not port_driver:
+ self.logger.info(
+ "No driver on specified port, skip destroy SRIOV VF.")
+ else:
+ sriov_vfs_pci = port.destroy_sriov_vfs()
+ self.ports_info[port_id]['sriov_vfs_pci'] = []
+ self.ports_info[port_id]['vfs_port'] = []
+
+ pci = self.ports_info[port_id]['pci']
+ self.virt_pool.del_vf_on_pf(pf_pci=pci, vflist=vflist)
+
+ def get_vm_core_list(self):
+ return VMCORELIST[self.crb['VM CoreList']]
+
def load_portconf(self):
"""
Load port configurations for ports_info. If manually configured infor
@@ -636,7 +836,13 @@ class Dut(Crb):
if ipv6 == "Not connected":
continue
- out = self.tester.send_ping6(remotePort, ipv6, self.get_mac_address(dutPort))
+ if getattr(self, 'send_ping6', None):
+ out = self.send_ping6(
+ dutPort, self.tester.ports_info[remotePort]['ipv6'],
+ self.get_mac_address(dutPort))
+ else:
+ out = self.tester.send_ping6(
+ remotePort, ipv6, self.get_mac_address(dutPort))
if ('64 bytes from' in out):
self.logger.info("PORT MAP: [dut %d: tester %d]" % (dutPort, remotePort))
@@ -655,3 +861,54 @@ class Dut(Crb):
for port in remove:
self.ports_info.remove(port)
+
+ def disable_tester_ipv6(self):
+ for tester_port in self.ports_map:
+ if self.tester.ports_info[tester_port]['type'] != 'ixia':
+ port = self.tester.ports_info[tester_port]['port']
+ port.disable_ipv6()
+
+ def enable_tester_ipv6(self):
+ for tester_port in range(len(self.tester.ports_info)):
+ if self.tester.ports_info[tester_port]['type'] != 'ixia':
+ port = self.tester.ports_info[tester_port]['port']
+ port.enable_ipv6()
+
+ def check_port_occupied(self, port):
+ out = self.alt_session.send_expect('lsof -i:%d' % port, '# ')
+ if out == '':
+ return False
+ else:
+ return True
+
+ def get_maximal_vnc_num(self):
+ out = self.send_expect("ps aux | grep '\-vnc' | grep -v grep", '# ')
+ if out:
+ ports = re.findall(r'-vnc .*?:(\d+)', out)
+ for num in range(len(ports)):
+ ports[num] = int(ports[num])
+ ports.sort()
+ else:
+ ports = [0, ]
+ return ports[-1]
+
+ def close(self):
+ """
+ Close ssh session of DUT.
+ """
+ if self.session:
+ self.session.close()
+ self.session = None
+ if self.alt_session:
+ self.alt_session.close()
+ self.alt_session = None
+ if self.host_init_flag:
+ self.host_session.close()
+
+ def crb_exit(self):
+ """
+ Recover all resource before crb exit
+ """
+ self.logger.logger_exit()
+ self.enable_tester_ipv6()
+ self.close()
diff --git a/framework/etgen.py b/framework/etgen.py
index 8270f24..1803a1f 100644
--- a/framework/etgen.py
+++ b/framework/etgen.py
@@ -189,11 +189,34 @@ class IxiaPacketGenerator(SSHConnection):
self.send_expect("clearOwnershipAndLogout", "% ")
def parse_pcap(self, fpcap):
- """
- Parse packet in pcap file and convert it into tcl commands.
- """
- self.send_expect("echo {print [i.command() for i in rdpcap('%s', -1)]; exit()} > dumppcap.py" %
- fpcap, "% ")
+ dump_str1 = "cmds = []\n"
+ dump_str2 = "for i in rdpcap('%s', -1):\n" % fpcap
+ dump_str3 = " if 'Vxlan' in i.command():\n" + \
+ " vxlan_str = ''\n" + \
+ " l = len(i[Vxlan])\n" + \
+ " vxlan = str(i[Vxlan])\n" + \
+ " first = True\n" + \
+ " for j in range(l):\n" + \
+ " if first:\n" + \
+ " vxlan_str += \"Vxlan(hexval='%02X\" %ord(vxlan[j])\n" + \
+ " first = False\n" + \
+ " else:\n" + \
+ " vxlan_str += \" %02X\" %ord(vxlan[j])\n" + \
+ " vxlan_str += \"\')\"\n" + \
+ " command = re.sub(r\"Vxlan(.*)\", vxlan_str, i.command())\n" + \
+ " else:\n" + \
+ " command = i.command()\n" + \
+ " cmds.append(command)\n" + \
+ "print cmds\n" + \
+ "exit()"
+
+ f = open("dumppcap.py", "w")
+ f.write(dump_str1)
+ f.write(dump_str2)
+ f.write(dump_str3)
+ f.close()
+
+ self.session.copy_file_to("dumppcap.py")
out = self.send_expect("scapy -c dumppcap.py 2>/dev/null", "% ", 120)
flows = eval(out)
return flows
@@ -254,7 +277,15 @@ class IxiaPacketGenerator(SSHConnection):
self.add_tcl_cmd("udp config -sourcePort %d" % sport)
self.add_tcl_cmd("udp config -destPort %d" % dport)
self.add_tcl_cmd("udp config -length %d" % len)
- self.add_tcl_cmd("udp set %d %d %d" % (self.chasId, port['card'], port['port']))
+ self.add_tcl_cmd("udp set %d %d %d" %
+ (self.chasId, port['card'], port['port']))
+
+ def vxlan(self, port, hexval):
+ self.add_tcl_cmd("protocolPad setDefault")
+ self.add_tcl_cmd("protocol config -enableProtocolPad true")
+ self.add_tcl_cmd("protocolPad config -dataBytes \"%s\"" % hexval)
+ self.add_tcl_cmd("protocolPad set %d %d %d" %
+ (self.chasId, port['card'], port['port']))
def tcp(self, port, sport, dport, seq, ack, dataofs, reserved, flags, window, chksum, urgptr, options=None):
"""
@@ -297,6 +328,10 @@ class IxiaPacketGenerator(SSHConnection):
match = pat.match(header)
params = eval('dict(%s)' % match.group(2))
method_name = match.group(1)
+ if method_name == 'Vxlan':
+ method = getattr(self, method_name.lower())
+ method(txport, **params)
+ break
if method_name in SCAPY2IXIA:
method = getattr(self, method_name.lower())
method(txport, **params)
@@ -571,6 +606,9 @@ class IxiaPacketGenerator(SSHConnection):
for port in rxPortlist:
self.start_pktGroup(self.pci_to_port(self.tester.get_pci(port)))
+ def hook_transmissoin_func(self):
+ pass
+
def get_transmission_results(self, rx_port_list, tx_port_list, delay=5):
"""
Override this method if you want to change the way of getting results
@@ -593,6 +631,8 @@ class IxiaPacketGenerator(SSHConnection):
self.logger.info("Rate: %f Mpps" % (rate * 1.0 / 1000000))
self.logger.info("Mbps rate: %f Mbps" % (bpsRate * 1.0 / 1000000))
+ self.hook_transmissoin_func()
+
self.send_expect("ixStopTransmit portList", "%", 30)
if rate == 0 and oversize > 0:
diff --git a/framework/excel_reporter.py b/framework/excel_reporter.py
index 809dead..2030d87 100644
--- a/framework/excel_reporter.py
+++ b/framework/excel_reporter.py
@@ -85,13 +85,15 @@ class ExcelReporter(object):
self.sheet.write(0, 7, 'Pass', self.header_style)
self.sheet.write(0, 8, 'Fail', self.header_style)
self.sheet.write(0, 9, 'Blocked', self.header_style)
- self.sheet.write(0, 10, 'Not Run', self.header_style)
- self.sheet.write(0, 11, 'Total', self.header_style)
+ self.sheet.write(0, 10, 'N/A', self.header_style)
+ self.sheet.write(0, 11, 'Not Run', self.header_style)
+ self.sheet.write(0, 12, 'Total', self.header_style)
self.sheet.write(1, 7, Formula('COUNTIF(F2:F2000,"PASSED")'))
self.sheet.write(1, 8, Formula('COUNTIF(F2:F2000,"FAILED*") + COUNTIF(F2:F2000,"IXA*")'))
self.sheet.write(1, 9, Formula('COUNTIF(F2:F2000,"BLOCKED*")'))
- self.sheet.write(1, 11, Formula('H2+I2+J2+K2'))
+ self.sheet.write(1, 10, Formula('COUNTIF(F2:F2000,"N/A*")'))
+ self.sheet.write(1, 12, Formula('H2+I2+J2+K2+L2'))
self.sheet.col(0).width = 4000
self.sheet.col(1).width = 7500
@@ -105,6 +107,7 @@ class ExcelReporter(object):
self.sheet.col(9).width = 3000
self.sheet.col(10).width = 3000
self.sheet.col(11).width = 3000
+ self.sheet.col(12).width = 3000
def __styles(self):
header_pattern = xlwt.Pattern()
diff --git a/framework/exception.py b/framework/exception.py
index be38c16..0e7a344 100644
--- a/framework/exception.py
+++ b/framework/exception.py
@@ -46,3 +46,97 @@ class SSHConnectionException(Exception):
def __str__(self):
return 'Error trying to connect with %s' % self.host
+
+
+class SSHSessionDeadException(Exception):
+
+ """
+ SSH session is not alive.
+ It can no longer be used.
+ """
+
+ def __init__(self, host):
+ self.host = host
+
+ def __str__(self):
+ return 'SSH session with %s has been dead' % self.host
+
+
+class StartVMFailedException(Exception):
+
+ """
+ Start VM failed.
+ """
+
+ def __init__(self, error):
+ self.error = error
+
+ def __str__(self):
+ return repr(self.error)
+
+
+class ConfigParseException(Exception):
+
+ """
+ Configuration file parse failure exception.
+ """
+
+ def __init__(self, conf_file):
+ self.config = conf_file
+
+ def __str__(self):
+ return "Faile to parse config file [%s]" % (self.config)
+
+
+class VirtConfigParseException(Exception):
+ pass
+
+
+class PortConfigParseException(Exception):
+ pass
+
+
+class VirtConfigParamException(Exception):
+
+ """
+ Virtualizatoin param execution exception.
+ """
+ def __init__(self, param):
+ self.param = param
+
+ def __str__(self):
+ return "Faile to execute param [%s]" % (self.param)
+
+
+class VirtDutConnectException(Exception):
+ pass
+
+
+class VirtConfigParamException(Exception):
+
+ """
+ Virtualizatoin param execution exception.
+ """
+ def __init__(self, param):
+ self.param = param
+
+ def __str__(self):
+ return "Faile to execute param [%s]" % (self.param)
+
+
+class VirtDutConnectException(Exception):
+ pass
+
+
+class VirtDutInitException(Exception):
+ def __init__(self, vm_dut):
+ self.vm_dut = vm_dut
+
+class VirtDeviceCreateException(Exception):
+ pass
+
+class VirtVmOperationException(Exception):
+ pass
+
+class VirtHostPrepareException(Exception):
+ pass
diff --git a/framework/logger.py b/framework/logger.py
index 1829e18..ab55493 100644
--- a/framework/logger.py
+++ b/framework/logger.py
@@ -35,6 +35,9 @@ import sys
import inspect
import re
+from settings import LOG_NAME_SEP, FOLDERS
+from utils import RED
+
"""
DTS logger module with several log level. DTS framwork and TestSuite log
will saved into different log files.
@@ -58,6 +61,9 @@ logging.SUITE_TESTER_OUTPUT = logging.DEBUG + 4
logging.DTS_IXIA_CMD = logging.INFO + 5
logging.DTS_IXIA_OUTPUT = logging.DEBUG + 5
+logging.DTS_VIRTDUT_CMD = logging.INFO + 6
+logging.DTS_VIRTDUT_OUTPUT = logging.DEBUG + 6
+
logging.addLevelName(logging.DTS_DUT_CMD, 'DTS_DUT_CMD')
logging.addLevelName(logging.DTS_DUT_OUTPUT, 'DTS_DUT_OUTPUT')
logging.addLevelName(logging.DTS_DUT_RESULT, 'DTS_DUT_RESUTL')
@@ -66,6 +72,12 @@ logging.addLevelName(logging.DTS_TESTER_CMD, 'DTS_TESTER_CMD')
logging.addLevelName(logging.DTS_TESTER_OUTPUT, 'DTS_TESTER_OUTPUT')
logging.addLevelName(logging.DTS_TESTER_RESULT, 'DTS_TESTER_RESULT')
+logging.addLevelName(logging.DTS_IXIA_CMD, 'DTS_IXIA_CMD')
+logging.addLevelName(logging.DTS_IXIA_OUTPUT, 'DTS_IXIA_OUTPUT')
+
+logging.addLevelName(logging.DTS_VIRTDUT_CMD, 'VIRTDUT_CMD')
+logging.addLevelName(logging.DTS_VIRTDUT_OUTPUT, 'VIRTDUT_OUTPUT')
+
logging.addLevelName(logging.SUITE_DUT_CMD, 'SUITE_DUT_CMD')
logging.addLevelName(logging.SUITE_DUT_OUTPUT, 'SUITE_DUT_OUTPUT')
@@ -82,15 +94,18 @@ stream_fmt = '%(color)s%(levelname)20s: %(message)s' + RESET_COLOR
log_dir = None
-def RED(text):
- return "\x1B[" + "31;1m" + text + "\x1B[" + "0m"
-
-
def set_verbose():
global verbose
verbose = True
+def add_salt(salt, msg):
+ if not salt:
+ return msg
+ else:
+ return '[%s] ' % salt + str(msg)
+
+
class BaseLoggerAdapter(logging.LoggerAdapter):
"""
Upper layer of original logging module.
@@ -132,6 +147,12 @@ class BaseLoggerAdapter(logging.LoggerAdapter):
def dts_ixia_output(self, msg, *args, **kwargs):
self.log(logging.DTS_IXIA_OUTPUT, msg, *args, **kwargs)
+ def dts_virtdut_cmd(self, msg, *args, **kwargs):
+ self.log(logging.DTS_VIRTDUT_CMD, msg, *args, **kwargs)
+
+ def dts_virtdut_output(self, msg, *args, **kwargs):
+ self.log(logging.DTS_VIRTDUT_OUTPUT, msg, *args, **kwargs)
+
class ColorHandler(logging.StreamHandler):
"""
@@ -150,6 +171,8 @@ class ColorHandler(logging.StreamHandler):
logging.SUITE_TESTER_CMD: '', # SYSTEM
logging.DTS_IXIA_CMD: '', # SYSTEM
logging.DTS_IXIA_OUTPUT: '', # SYSTEM
+ logging.DTS_VIRTDUT_CMD: '', # SYSTEM
+ logging.DTS_VIRTDUT_OUTPUT: '', # SYSTEM
logging.WARN: '\033[01;33m', # BOLD YELLOW
logging.DTS_DUT_RESULT: '\033[01;34m', # BOLD BLUE
logging.DTS_TESTER_RESULT: '\033[01;34m', # BOLD BLUE
@@ -178,7 +201,7 @@ class DTSLOG(BaseLoggerAdapter):
self.debug_lvl = logging.DEBUG
if log_dir is None:
- self.log_path = os.getcwd() + "/../output"
+ self.log_path = os.getcwd() + "/../" + FOLDERS['Output']
else:
self.log_path = log_dir # log dir should contain tag/crb global value and mod in dts
self.dts_log = "dts.log"
@@ -189,9 +212,16 @@ class DTSLOG(BaseLoggerAdapter):
self.crb = crb
super(DTSLOG, self).__init__(self.logger, dict(crb=self.crb))
+ self.salt = ''
+
self.fh = None
self.ch = None
+ # add default log file
+ fh = logging.FileHandler(self.log_path + "/" + self.dts_log)
+ ch = ColorHandler()
+ self.__log_hander(fh, ch)
+
def __log_hander(self, fh, ch):
"""
Config stream handler and file handler.
@@ -221,24 +251,28 @@ class DTSLOG(BaseLoggerAdapter):
"""
DTS warnning level log function.
"""
+ message = add_salt(self.salt, message)
self.logger.log(self.warn_lvl, message)
def info(self, message):
"""
DTS information level log function.
"""
+ message = add_salt(self.salt, message)
self.logger.log(self.info_lvl, message)
def error(self, message):
"""
DTS error level log function.
"""
+ message = add_salt(self.salt, message)
self.logger.log(self.error_lvl, message)
def debug(self, message):
"""
DTS debug level log function.
"""
+ message = add_salt(self.salt, message)
self.logger.log(self.debug_lvl, message)
def set_logfile_path(self, path):
@@ -270,17 +304,34 @@ class DTSLOG(BaseLoggerAdapter):
ch = ColorHandler()
self.__log_hander(fh, ch)
- if crb == "dut":
+ def set_salt(crb, start_flag):
+ if LOG_NAME_SEP in crb:
+ old = '%s%s' % (start_flag, LOG_NAME_SEP)
+ if not self.salt:
+ self.salt = crb.replace(old, '', 1)
+
+ if crb.startswith('dut'):
self.info_lvl = logging.DTS_DUT_CMD
self.debug_lvl = logging.DTS_DUT_OUTPUT
self.warn_lvl = logging.DTS_DUT_RESULT
- elif crb == "tester":
+
+ set_salt(crb, 'dut')
+ elif crb.startswith('tester'):
self.info_lvl = logging.DTS_TESTER_CMD
self.debug_lvl = logging.DTS_TESTER_OUTPUT
self.warn_lvl = logging.DTS_TESTER_RESULT
- elif crb == "ixia":
+
+ set_salt(crb, 'tester')
+ elif crb.startswith('ixia'):
self.info_lvl = logging.DTS_IXIA_CMD
self.debug_lvl = logging.DTS_IXIA_OUTPUT
+
+ set_salt(crb, 'ixia')
+ elif crb.startswith('virtdut'):
+ self.info_lvl = logging.DTS_VIRTDUT_CMD
+ self.debug_lvl = logging.DTS_VIRTDUT_OUTPUT
+
+ set_salt(crb, 'virtdut')
else:
self.error_lvl = logging.ERROR
self.warn_lvl = logging.WARNING
@@ -296,15 +347,18 @@ class DTSLOG(BaseLoggerAdapter):
ch = ColorHandler()
self.__log_hander(fh, ch)
- if crb == "dut":
+ if crb == 'dut':
self.info_lvl = logging.SUITE_DUT_CMD
self.debug_lvl = logging.SUITE_DUT_OUTPUT
- elif crb == "tester":
+ elif crb == 'tester':
self.info_lvl = logging.SUITE_TESTER_CMD
self.debug_lvl = logging.SUITE_TESTER_OUTPUT
- elif crb == "ixia":
+ elif crb == 'ixia':
self.info_lvl = logging.DTS_IXIA_CMD
self.debug_lvl = logging.DTS_IXIA_OUTPUT
+ elif crb == 'virtdut':
+ self.info_lvl = logging.DTS_VIRTDUT_CMD
+ self.debug_lvl = logging.DTS_VIRTDUT_OUTPUT
def logger_exit(self):
"""
diff --git a/framework/main.py b/framework/main.py
index 3e467d0..de49e82 100755
--- a/framework/main.py
+++ b/framework/main.py
@@ -63,6 +63,7 @@ def git_build_package(gitLabel, pkgName, depot="dep"):
if ret is not 0:
raise EnvironmentError
+
# Read cmd-line args
parser = argparse.ArgumentParser(description='DPDK test framework.')
@@ -83,7 +84,7 @@ parser.add_argument('--snapshot',
help='snapshot .tgz file to use as input')
parser.add_argument('--output',
- default='output',
+ default='',
help='Output directory where dts log and result saved')
parser.add_argument('-s', '--skip-setup',
@@ -106,7 +107,7 @@ parser.add_argument('--suite-dir',
help='Test suite directory where test suites will be imported')
parser.add_argument('-t', '--test-cases',
- nargs='+',
+ action='append',
help='executes only the followings test cases')
parser.add_argument('-d', '--dir',
@@ -117,10 +118,18 @@ parser.add_argument('-v', '--verbose',
action='store_true',
help='enable verbose output, all message output on screen')
+parser.add_argument('--virttype',
+ default='kvm',
+ help='set virt type,support kvm, libvirtd')
+
parser.add_argument('--debug',
action='store_true',
help='enable debug mode, user can enter debug mode in process')
+parser.add_argument('--debugcase',
+ action='store_true',
+ help='enable debug mode in the first case, user can further debug')
+
args = parser.parse_args()
@@ -136,4 +145,5 @@ if args.git is not None:
dts.run_all(args.config_file, args.snapshot, args.git,
args.patch, args.skip_setup, args.read_cache,
args.project, args.suite_dir, args.test_cases,
- args.dir, args.output, args.verbose, args.debug)
+ args.dir, args.output, args.verbose,args.virttype,
+ args.debug, args.debugcase)
diff --git a/framework/net_device.py b/framework/net_device.py
new file mode 100644
index 0000000..9afa6ca
--- /dev/null
+++ b/framework/net_device.py
@@ -0,0 +1,752 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import os
+import re
+from functools import wraps
+import time
+
+
+import settings
+from crb import Crb
+from settings import TIMEOUT
+
+
+class NetDevice(object):
+
+ """
+ Abstract the device which is PF or VF.
+ """
+
+ def __init__(self, crb, bus_id, devfun_id):
+ if not isinstance(crb, Crb):
+ raise Exception(" Please input the instance of Crb!!!")
+ self.crb = crb
+ self.bus_id = bus_id
+ self.devfun_id = devfun_id
+ self.pci = bus_id + ':' + devfun_id
+ self.pci_id = self.get_pci_id(bus_id, devfun_id)
+ self.default_driver = settings.get_nic_driver(self.pci_id)
+
+ if self.nic_is_pf():
+ self.default_vf_driver = ''
+ self.get_interface_name()
+ self.socket = self.get_nic_socket()
+
+ def __send_expect(self, cmds, expected, timeout=TIMEOUT, alt_session=True):
+ """
+ Wrap the crb`s session as private session for sending expect.
+ """
+ return self.crb.send_expect(cmds, expected, timeout=timeout, alt_session=alt_session)
+
+ def __get_os_type(self):
+ """
+ Get OS type.
+ """
+ return self.crb.get_os_type()
+
+ def nic_is_pf(self):
+ """
+ It is the method that you can check if the nic is PF.
+ """
+ return True
+
+ def nic_has_driver(func):
+ """
+ Check if the NIC has a driver.
+ """
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ nic_instance = args[0]
+ nic_instance.current_driver = nic_instance.get_nic_driver()
+ if not nic_instance.current_driver:
+ return ''
+ return func(*args, **kwargs)
+ return wrapper
+
+ def get_nic_driver(self):
+ """
+ Get the NIC driver.
+ """
+ return self.crb.get_pci_dev_driver(self.bus_id, self.devfun_id)
+
+ def get_nic_socket(self):
+ """
+ Get socket id of specified pci device.
+ """
+ get_nic_socket = getattr(
+ self, 'get_nic_socket_%s' %
+ self.__get_os_type())
+ return get_nic_socket(self.bus_id, self.devfun_id)
+
+ def get_nic_socket_linux(self, bus_id, devfun_id):
+ command = ('cat /sys/bus/pci/devices/0000\:%s\:%s/numa_node' %
+ (bus_id, devfun_id))
+ try:
+ out = self.__send_expect(command, '# ')
+ socket = int(out)
+ except:
+ socket = -1
+ return socket
+
+ def get_nic_socket_freebsd(self, bus_id, devfun_id):
+ NotImplemented
+
+ @nic_has_driver
+ def get_interface_name(self):
+ """
+ Get interface name of specified pci device.
+ Cal this function will update intf_name everytime
+ """
+ get_interface_name = getattr(
+ self, 'get_interface_name_%s' %
+ self.__get_os_type())
+ out = get_interface_name(self.bus_id, self.devfun_id, self.current_driver)
+ if "No such file or directory" in out:
+ self.intf_name = 'N/A'
+ else:
+ self.intf_name = out
+
+ return self.intf_name
+
+ def get_interface_name_linux(self, bus_id, devfun_id, driver):
+ """
+ Get interface name of specified pci device on linux.
+ """
+ driver_alias = driver.replace('-', '_')
+ try:
+ get_interface_name_linux = getattr(
+ self,
+ 'get_interface_name_linux_%s' %
+ driver_alias)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_interface_name_linux = getattr(self,
+ 'get_interface_name_linux_%s' % generic_driver)
+
+ return get_interface_name_linux(bus_id, devfun_id)
+
+ def get_interface_name_linux_virtio_pci(self, bus_id, devfun_id):
+ """
+ Get virtio device interface name by the default way on linux.
+ """
+ command = 'ls --color=never /sys/bus/pci/devices/0000\:%s\:%s/virtio*/net' % (
+ bus_id, devfun_id)
+ return self.__send_expect(command, '# ')
+
+ def get_interface_name_linux_generic(self, bus_id, devfun_id):
+ """
+ Get the interface name by the default way on linux.
+ """
+ command = 'ls --color=never /sys/bus/pci/devices/0000\:%s\:%s/net' % (
+ bus_id, devfun_id)
+ return self.__send_expect(command, '# ')
+
+ def get_interface_name_freebsd(self, bus_id, devfun_id, driver):
+ """
+ Get interface name of specified pci device on Freebsd.
+ """
+ try:
+ get_interface_name_freebsd = getattr(self,
+ 'get_interface_name_freebsd_%s' % driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_interface_name_freebsd = getattr(self,
+ 'get_interface_name_freebsd_%s' % generic_driver)
+
+ return get_interface_name_freebsd(bus_id, devfun_id)
+
+ def get_interface_name_freebsd_generic(self, bus_id, devfun_id):
+ """
+ Get the interface name by the default way on freebsd.
+ """
+ out = self.__send_expect("pciconf -l", "# ")
+ rexp = r"(\w*)@pci0:%s" % bus_id
+ pattern = re.compile(rexp)
+ match = pattern.findall(out)
+ if len(match) == 0:
+ return "No such file"
+ return match[0]
+
+ @nic_has_driver
+ def get_mac_addr(self):
+ """
+ Get mac address of specified pci device.
+ """
+ get_mac_addr = getattr(self, 'get_mac_addr_%s' % self.__get_os_type())
+ out = get_mac_addr(self.intf_name, self.bus_id, self.devfun_id, self.current_driver)
+ if "No such file or directory" in out:
+ return 'N/A'
+ else:
+ return out
+
+ def get_mac_addr_linux(self, intf, bus_id, devfun_id, driver):
+ """
+ Get mac address of specified pci device on linux.
+ """
+ driver_alias = driver.replace('-', '_')
+ try:
+ get_mac_addr_linux = getattr(
+ self,
+ 'get_mac_addr_linux_%s' %
+ driver_alias)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_mac_addr_linux = getattr(
+ self,
+ 'get_mac_addr_linux_%s' %
+ generic_driver)
+
+ return get_mac_addr_linux(intf, bus_id, devfun_id, driver)
+
+ def get_pci_id(self, bus_id, devfun_id):
+ command = ('cat /sys/bus/pci/devices/0000\:%s\:%s/vendor' %
+ (bus_id, devfun_id))
+ out = self.__send_expect(command, '# ')
+ vender = out[2:]
+ command = ('cat /sys/bus/pci/devices/0000\:%s\:%s/device' %
+ (bus_id, devfun_id))
+ out = self.__send_expect(command, '# ')
+ device = out[2:]
+ return "%s:%s" % (vender, device)
+
+ def get_mac_addr_linux_generic(self, intf, bus_id, devfun_id, driver):
+ """
+ Get MAC by the default way on linux.
+ """
+ command = ('cat /sys/bus/pci/devices/0000\:%s\:%s/net/%s/address' %
+ (bus_id, devfun_id, intf))
+ return self.__send_expect(command, '# ')
+
+ def get_mac_addr_linux_virtio_pci(self, intf, bus_id, devfun_id, driver):
+ """
+ Get MAC by the default way on linux.
+ """
+ virtio_cmd = ('ls /sys/bus/pci/devices/0000\:%s\:%s/ | grep --color=never virtio' %
+ (bus_id, devfun_id))
+ virtio = self.__send_expect(virtio_cmd, '# ')
+
+ command = ('cat /sys/bus/pci/devices/0000\:%s\:%s/%s/net/%s/address' %
+ (bus_id, devfun_id, virtio, intf))
+ return self.__send_expect(command, '# ')
+
+ def get_mac_addr_freebsd(self, intf, bus_id, devfun_id, driver):
+ """
+ Get mac address of specified pci device on Freebsd.
+ """
+ try:
+ get_mac_addr_freebsd = getattr(
+ self,
+ 'get_mac_addr_freebsd_%s' %
+ driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_mac_addr_freebsd = getattr(
+ self,
+ 'get_mac_addr_freebsd_%s' %
+ generic_driver)
+
+ return get_mac_addr_freebsd(intf, bus_id, devfun_id)
+
+ def get_mac_addr_freebsd_generic(self, intf, bus_id, devfun_id):
+ """
+ Get the MAC by the default way on Freebsd.
+ """
+ out = self.__send_expect('ifconfig %s' % intf, '# ')
+ rexp = r"ether ([\da-f:]*)"
+ pattern = re.compile(rexp)
+ match = pattern.findall(out)
+ return match[0]
+
+ @nic_has_driver
+ def get_ipv4_addr(self):
+ """
+ Get ipv4 address of specified pci device.
+ """
+ get_ipv4_addr = getattr(
+ self, 'get_ipv4_addr_%s' % self.__get_os_type())
+ return get_ipv4_addr(self.intf_name, self.currenct_driver)
+
+ def get_ipv4_addr_linux(self, intf, driver):
+ """
+ Get ipv4 address of specified pci device on linux.
+ """
+ try:
+ get_ipv4_addr_linux = getattr(self, 'get_ipv4_linux_%s' % driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_ipv4_addr_linux = getattr(
+ self, 'get_ipv4_linux_%s' %
+ generic_driver)
+
+ return get_ipv4_addr_linux(intf, bus_id, devfun_id, driver)
+
+ def get_ipv4_addr_linux_generic(self, intf):
+ """
+ Get IPv4 address by the default way on linux.
+ """
+ out = self.__send_expect("ip -family inet address show dev %s | awk '/inet/ { print $2 }'"
+ % intf, "# ")
+ return out.split('/')[0]
+
+ def get_ipv4_addr_freebsd(self, intf, driver):
+ """
+ Get ipv4 address of specified pci device on Freebsd.
+ """
+ try:
+ get_ipv4_addr_freebsd = getattr(
+ self,
+ 'get_ipv4_addr_freebsd_%s' %
+ driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_ipv4_addr_freebsd = getattr(
+ self,
+ 'get_ipv4_addr_freebsd_%s' %
+ generic_driver)
+
+ return get_ipv4_addr_freebsd(intf, bus_id, devfun_id)
+
+ def get_ipv4_addr_freebsd_generic(self, intf):
+ """
+ Get the IPv4 address by the default way on Freebsd.
+ """
+ out = self.__send_expect('ifconfig %s' % intf, '# ')
+ rexp = r"inet ([\d:]*)%"
+ pattern = re.compile(rexp)
+ match = pattern.findall(out)
+ if len(match) == 0:
+ return None
+
+ return match[0]
+
+ @nic_has_driver
+ def enable_ipv6(self):
+ """
+ Enable ipv6 address of specified pci device.
+ """
+ if self.current_driver != self.default_driver:
+ return
+
+ enable_ipv6 = getattr(
+ self, 'enable_ipv6_%s' % self.__get_os_type())
+ return enable_ipv6(self.intf_name)
+
+ def enable_ipv6_linux(self, intf):
+ """
+ Enable ipv6 address of specified pci device on linux.
+ """
+ self.__send_expect("sysctl net.ipv6.conf.%s.disable_ipv6=0" %
+ intf, "# ")
+ # FVL interface need down and up for re-enable ipv6
+ if self.default_driver == 'i40e':
+ self.__send_expect("ifconfig %s down" % intf, "# ")
+ self.__send_expect("ifconfig %s up" % intf, "# ")
+
+ def enable_ipv6_freebsd(self, intf):
+ pass
+
+ @nic_has_driver
+ def disable_ipv6(self):
+ """
+ Disable ipv6 address of specified pci device.
+ """
+ if self.current_driver != self.default_driver:
+ return
+ disable_ipv6 = getattr(
+ self, 'disable_ipv6_%s' % self.__get_os_type())
+ return disable_ipv6(self.intf_name)
+
+ def disable_ipv6_linux(self, intf):
+ """
+ Disable ipv6 address of specified pci device on linux.
+ """
+ self.__send_expect("sysctl net.ipv6.conf.%s.disable_ipv6=1" %
+ intf, "# ")
+
+ def disable_ipv6_freebsd(self, intf):
+ pass
+
+ @nic_has_driver
+ def get_ipv6_addr(self):
+ """
+ Get ipv6 address of specified pci device.
+ """
+ get_ipv6_addr = getattr(
+ self, 'get_ipv6_addr_%s' % self.__get_os_type())
+ return get_ipv6_addr(self.intf_name, self.current_driver)
+
+ @nic_has_driver
+ def get_ipv6_addr(self):
+ """
+ Get ipv6 address of specified pci device.
+ """
+ get_ipv6_addr = getattr(
+ self, 'get_ipv6_addr_%s' % self.__get_os_type())
+ return get_ipv6_addr(self.intf_name, self.current_driver)
+
+ def get_ipv6_addr_linux(self, intf, driver):
+ """
+ Get ipv6 address of specified pci device on linux.
+ """
+ try:
+ get_ipv6_addr_linux = getattr(
+ self,
+ 'get_ipv6_addr_linux_%s' %
+ driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_ipv6_addr_linux = getattr(
+ self,
+ 'get_ipv6_addr_linux_%s' %
+ generic_driver)
+
+ return get_ipv6_addr_linux(intf)
+
+ def get_ipv6_addr_linux_generic(self, intf):
+ """
+ Get the IPv6 address by the default way on linux.
+ """
+ out = self.__send_expect("ip -family inet6 address show dev %s | awk '/inet6/ { print $2 }'"
+ % intf, "# ")
+ return out.split('/')[0]
+
+ def get_ipv6_addr_freebsd(self, intf, driver):
+ """
+ Get ipv6 address of specified pci device on Freebsd.
+ """
+ try:
+ get_ipv6_addr_freebsd = getattr(
+ self,
+ 'get_ipv6_addr_freebsd_%s' %
+ driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_ipv6_addr_freebsd = getattr(
+ self,
+ 'get_ipv6_addr_freebsd_%s' %
+ generic_driver)
+
+ return get_ipv6_addr_freebsd(intf)
+
+ def get_ipv6_addr_freebsd_generic(self, intf):
+ """
+ Get the IPv6 address by the default way on Freebsd.
+ """
+ out = self.__send_expect('ifconfig %s' % intf, '# ')
+ rexp = r"inet6 ([\da-f:]*)%"
+ pattern = re.compile(rexp)
+ match = pattern.findall(out)
+ if len(match) == 0:
+ return None
+
+ return match[0]
+
+ def get_nic_numa(self):
+ """
+ Get numa number of specified pci device.
+ """
+ self.crb.get_nic_numa(self.bus_id, self.devfun_id)
+
+ def get_card_type(self):
+ """
+ Get card type of specified pci device.
+ """
+ return self.crb.get_pci_dev_id(self.bus_id, self.devfun_id)
+
+ @nic_has_driver
+ def get_sriov_vfs_pci(self):
+ """
+ Get all SRIOV VF pci bus of specified pci device.
+ """
+ get_sriov_vfs_pci = getattr(
+ self, 'get_sriov_vfs_pci_%s' % self.__get_os_type())
+ return get_sriov_vfs_pci(self.bus_id, self.devfun_id, self.current_driver)
+
+ def get_sriov_vfs_pci_linux(self, bus_id, devfun_id, driver):
+ """
+ Get all SRIOV VF pci bus of specified pci device on linux.
+ """
+ try:
+ get_sriov_vfs_pci_linux = getattr(
+ self,
+ 'get_sriov_vfs_pci_linux_%s' %
+ driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ get_sriov_vfs_pci_linux = getattr(
+ self,
+ 'get_sriov_vfs_pci_linux_%s' %
+ generic_driver)
+
+ return get_sriov_vfs_pci_linux(bus_id, devfun_id)
+
+ def get_sriov_vfs_pci_linux_generic(self, bus_id, devfun_id):
+ """
+ Get all the VF PCIs of specified PF by the default way on linux.
+ """
+ sriov_numvfs = self.__send_expect(
+ "cat /sys/bus/pci/devices/0000\:%s\:%s/sriov_numvfs" %
+ (bus_id, devfun_id), "# ")
+ sriov_vfs_pci = []
+
+ if "No such file" in sriov_numvfs:
+ return sriov_vfs_pci
+
+ if int(sriov_numvfs) == 0:
+ pass
+ else:
+ try:
+ virtfns = self.__send_expect(
+ "ls -d /sys/bus/pci/devices/0000\:%s\:%s/virtfn*" %
+ (bus_id, devfun_id), "# ")
+ for virtfn in virtfns.split():
+ vf_uevent = self.__send_expect(
+ "cat %s" %
+ os.path.join(virtfn, "uevent"), "# ")
+ vf_pci = re.search(
+ r"PCI_SLOT_NAME=0000:([0-9a-f]+:[0-9a-f]+\.[0-9a-f]+)",
+ vf_uevent).group(1)
+ sriov_vfs_pci.append(vf_pci)
+ except Exception as e:
+ print "Scan linux port [0000:%s.%s] sriov vf failed: %s" % (bus_id, devfun_id, e)
+
+ return sriov_vfs_pci
+
+ @nic_has_driver
+ def generate_sriov_vfs(self, vf_num):
+ """
+ Generate some numbers of SRIOV VF.
+ """
+ if vf_num == 0:
+ self.bind_vf_driver()
+ generate_sriov_vfs = getattr(
+ self, 'generate_sriov_vfs_%s' %
+ self.__get_os_type())
+ generate_sriov_vfs(
+ self.bus_id,
+ self.devfun_id,
+ vf_num,
+ self.current_driver)
+ if vf_num != 0:
+ self.sriov_vfs_pci = self.get_sriov_vfs_pci()
+
+ vf_pci = self.sriov_vfs_pci[0]
+ addr_array = vf_pci.split(':')
+ bus_id = addr_array[0]
+ devfun_id = addr_array[1]
+
+ self.default_vf_driver = self.crb.get_pci_dev_driver(
+ bus_id, devfun_id)
+ else:
+ self.sriov_vfs_pci = []
+ time.sleep(1)
+
+ def generate_sriov_vfs_linux(self, bus_id, devfun_id, vf_num, driver):
+ """
+ Generate some numbers of SRIOV VF.
+ """
+ try:
+ generate_sriov_vfs_linux = getattr(
+ self,
+ 'generate_sriov_vfs_linux_%s' %
+ driver)
+ except Exception as e:
+ generic_driver = 'generic'
+ generate_sriov_vfs_linux = getattr(
+ self,
+ 'generate_sriov_vfs_linux_%s' %
+ generic_driver)
+
+ return generate_sriov_vfs_linux(bus_id, devfun_id, vf_num)
+
+ def generate_sriov_vfs_linux_generic(self, bus_id, devfun_id, vf_num):
+ """
+ Generate SRIOV VFs by the default way on linux.
+ """
+ nic_driver = self.get_nic_driver()
+
+ if not nic_driver:
+ return None
+
+ vf_reg_file = "sriov_numvfs"
+ vf_reg_path = os.path.join("/sys/bus/pci/devices/0000:%s:%s" %
+ (bus_id, devfun_id), vf_reg_file)
+ self.__send_expect("echo %d > %s" %
+ (int(vf_num), vf_reg_path), "# ")
+
+ def generate_sriov_vfs_linux_igb_uio(self, bus_id, devfun_id, vf_num):
+ """
+ Generate SRIOV VFs by the special way of igb_uio driver on linux.
+ """
+ nic_driver = self.get_nic_driver()
+
+ if not nic_driver:
+ return None
+
+ vf_reg_file = "max_vfs"
+ if self.default_driver == 'i40e':
+ regx_reg_path = "find /sys -name %s | grep %s:%s" % (vf_reg_file, bus_id, devfun_id)
+ vf_reg_path = self.__send_expect(regx_reg_path, "# ")
+ else:
+ vf_reg_path = os.path.join("/sys/bus/pci/devices/0000:%s:%s" %
+ (bus_id, devfun_id), vf_reg_file)
+ self.__send_expect("echo %d > %s" %
+ (int(vf_num), vf_reg_path), "# ")
+
+ def destroy_sriov_vfs(self):
+ """
+ Destroy the SRIOV VFs.
+ """
+ self.generate_sriov_vfs(0)
+
+ def bind_vf_driver(self, pci='', driver=''):
+ """
+ Bind the specified driver to VF.
+ """
+ bind_vf_driver = getattr(self, 'bind_driver_%s' % self.__get_os_type())
+ if not driver:
+ if not self.default_vf_driver:
+ print "Must specify a driver because default VF driver is NULL!"
+ return
+ driver = self.default_vf_driver
+
+ if not pci:
+ if not self.sriov_vfs_pci:
+ print "No VFs on the nic [%s]!" % self.pci
+ return
+ for vf_pci in self.sriov_vfs_pci:
+ addr_array = vf_pci.split(':')
+ bus_id = addr_array[0]
+ devfun_id = addr_array[1]
+
+ bind_vf_driver(bus_id, devfun_id, driver)
+ else:
+ addr_array = pci.split(':')
+ bus_id = addr_array[0]
+ devfun_id = addr_array[1]
+
+ bind_vf_driver(bus_id, devfun_id, driver)
+
+ def bind_driver(self, driver=''):
+ """
+ Bind specified driver to PF.
+ """
+ bind_driver = getattr(self, 'bind_driver_%s' % self.__get_os_type())
+ if not driver:
+ if not self.default_driver:
+ print "Must specify a driver because default driver is NULL!"
+ return
+ driver = self.default_driver
+ ret = bind_driver(self.bus_id, self.devfun_id, driver)
+ time.sleep(1)
+ return ret
+
+ def bind_driver_linux(self, bus_id, devfun_id, driver):
+ """
+ Bind NIC port to specified driver on linux.
+ """
+ driver_alias = driver.replace('-', '_')
+ try:
+ bind_driver_linux = getattr(
+ self,
+ 'bind_driver_linux_%s' %
+ driver_alias)
+ return bind_driver_linux(bus_id, devfun_id)
+ except Exception as e:
+ driver_alias = 'generic'
+ bind_driver_linux = getattr(
+ self,
+ 'bind_driver_linux_%s' %
+ driver_alias)
+ return bind_driver_linux(bus_id, devfun_id, driver)
+
+ def bind_driver_linux_generic(self, bus_id, devfun_id, driver):
+ """
+ Bind NIC port to specified driver by the default way on linux.
+ """
+ new_id = self.pci_id.replace(':', ' ')
+ nic_pci_num = ':'.join(['0000', bus_id, devfun_id])
+ self.__send_expect(
+ "echo %s > /sys/bus/pci/drivers/%s/new_id" % (new_id, driver), "# ")
+ self.__send_expect(
+ "echo %s > /sys/bus/pci/devices/0000\:%s\:%s/driver/unbind" %
+ (nic_pci_num, bus_id, devfun_id), "# ")
+ self.__send_expect(
+ "echo %s > /sys/bus/pci/drivers/%s/bind" %
+ (nic_pci_num, driver), "# ")
+
+ def bind_driver_linux_pci_stub(self, bus_id, devfun_id):
+ """
+ Bind NIC port to the pci-stub driver on linux.
+ """
+ new_id = self.pci_id.replace(':', ' ')
+ self.__send_expect(
+ "echo %s > /sys/bus/pci/drivers/pci-stub/new_id" % new_id, "# ")
+ self.__send_expect(
+ "echo %s > /sys/bus/pci/devices/0000\:%s\:%s/driver/unbind" %
+ (nic_pci_num, bus_id, devfun_id), "# ")
+ self.__send_expect(
+ "echo %s > /sys/bus/pci/drivers/pci-stub/bind" %
+ nic_pci_num, "# ")
+
+ @nic_has_driver
+ def unbind_driver(self, driver=''):
+ """
+ Unbind driver.
+ """
+ unbind_driver = getattr(
+ self, 'unbind_driver_%s' %
+ self.__get_os_type())
+ if not driver:
+ driver = 'generic'
+ ret = unbind_driver(self.bus_id, self.devfun_id, driver)
+ time.sleep(1)
+ return ret
+
+ def unbind_driver_linux(self, bus_id, devfun_id, driver):
+ """
+ Unbind driver on linux.
+ """
+ driver_alias = driver.replace('-', '_')
+
+ unbind_driver_linux = getattr(
+ self, 'unbind_driver_linux_%s' % driver_alias)
+ return unbind_driver_linux(bus_id, devfun_id)
+
+ def unbind_driver_linux_generic(self, bus_id, devfun_id):
+ """
+ Unbind driver by the default way on linux.
+ """
+ nic_pci_num = ':'.join(['0000', bus_id, devfun_id])
+ cmd = "echo %s > /sys/bus/pci/devices/0000\:%s\:%s/driver/unbind"
+ self.send_expect(cmd % (nic_pci_num, bus_id, devfun_id), "# ")
diff --git a/framework/pmd_output.py b/framework/pmd_output.py
index 473339d..23d4c0d 100644
--- a/framework/pmd_output.py
+++ b/framework/pmd_output.py
@@ -32,6 +32,7 @@
import os
import re
import dts
+from settings import TIMEOUT
class PmdOutput():
@@ -42,6 +43,7 @@ class PmdOutput():
def __init__(self, dut):
self.dut = dut
+ self.dut.testpmd = self
self.rx_pkts_prefix = "RX-packets:"
self.rx_missed_prefix = "RX-missed:"
self.rx_bytes_prefix = "RX-bytes:"
@@ -63,17 +65,16 @@ class PmdOutput():
return None
else:
return int(m.group(2))
-
+
def set_default_corelist(self):
"""
set default cores for start testpmd
- """
+ """
core_number = len(self.dut.cores)
if core_number < 2:
raise
else:
self.default_cores = "1S/2C/1T"
-
def get_pmd_stats(self, portid):
stats = {}
@@ -103,7 +104,9 @@ class PmdOutput():
if "--txqflags" not in param:
param += " --txqflags=0"
- if cores == "Default":
+ if type(cores) == list:
+ core_list = cores
+ elif cores == "Default":
core_list = self.dut.get_core_list(self.default_cores)
else:
core_list = self.dut.get_core_list(cores, socket)
@@ -113,3 +116,93 @@ class PmdOutput():
out = self.dut.send_expect(command, "testpmd> ", 120)
self.command = command
return out
+
+ def execute_cmd(self, pmd_cmd, expected='testpmd> ', timeout=TIMEOUT,
+ alt_session=False):
+ return self.dut.send_expect('%s' % pmd_cmd, expected, timeout=timeout,
+ alt_session=alt_session)
+
+ def get_value_from_string(self, key_str, regx_str, string):
+ """
+ Get some values from the given string by the regular expression.
+ """
+ pattern = r"(?<=%s)%s" % (key_str, regx_str)
+ s = re.compile(pattern)
+ res = s.search(string)
+ if type(res).__name__ == 'NoneType':
+ return ' '
+ else:
+ return res.group(0)
+
+ def get_detail_from_port_info(self, key_str, regx_str, port):
+ """
+ Get the detail info from the output of pmd cmd 'show port info <port num>'.
+ """
+ out = self.dut.send_expect("show port info %d" % port, "testpmd> ")
+ find_value = self.get_value_from_string(key_str, regx_str, out)
+ return find_value
+
+ def get_port_mac(self, port_id):
+ """
+ Get the specified port MAC.
+ """
+ return self.get_detail_from_port_info("MAC address: ", "([0-9A-F]{2}:){5}[0-9A-F]{2}", port_id)
+
+ def get_port_connect_socket(self, port_id):
+ """
+ Get the socket id which the specified port is connectting with.
+ """
+ return self.get_detail_from_port_info("Connect to socket: ", "\d+", port_id)
+
+ def get_port_memory_socket(self, port_id):
+ """
+ Get the socket id which the specified port memory is allocated on.
+ """
+ return self.get_detail_from_port_info("memory allocation on the socket: ", "\d+", port_id)
+
+ def get_port_link_status(self, port_id):
+ """
+ Get the specified port link status now.
+ """
+ return self.get_detail_from_port_info("Link status: ", "\d+", port_id)
+
+ def get_port_link_speed(self, port_id):
+ """
+ Get the specified port link speed now.
+ """
+ return self.get_detail_from_port_info("Link speed: ", "\d+", port_id)
+
+ def get_port_link_duplex(self, port_id):
+ """
+ Get the specified port link mode, duplex or siplex.
+ """
+ return self.get_detail_from_port_info("Link duplex: ", "\S+", port_id)
+
+ def get_port_promiscuous_mode(self, port_id):
+ """
+ Get the promiscuous mode of port.
+ """
+ return self.get_detail_from_port_info("Promiscuous mode: ", "\S+", port_id)
+
+ def get_port_allmulticast_mode(self, port_id):
+ """
+ Get the allmulticast mode of port.
+ """
+ return self.get_detail_from_port_info("Allmulticast mode: ", "\S+", port_id)
+
+ def get_port_vlan_offload(self, port_id):
+ """
+ Function: get the port vlan settting info.
+ return value:
+ 'strip':'on'
+ 'filter':'on'
+ 'qinq':'off'
+ """
+ vlan_info = {}
+ vlan_info['strip'] = self.get_detail_from_port_info(
+ "strip ", '\S+', port_id)
+ vlan_info['filter'] = self.get_detail_from_port_info(
+ 'filter', '\S+', port_id)
+ vlan_info['qinq'] = self.get_detail_from_port_info(
+ 'qinq\(extend\) ', '\S+', port_id)
+ return vlan_info
diff --git a/framework/project_dpdk.py b/framework/project_dpdk.py
index 8963924..7b6e1ae 100644
--- a/framework/project_dpdk.py
+++ b/framework/project_dpdk.py
@@ -39,7 +39,7 @@ from crb import Crb
from dut import Dut
from tester import Tester
from logger import getLogger
-from settings import IXIA
+from settings import IXIA, accepted_nic
class DPDKdut(Dut):
@@ -50,16 +50,17 @@ class DPDKdut(Dut):
"""
def __init__(self, crb, serializer):
- self.NAME = 'dut'
super(DPDKdut, self).__init__(crb, serializer)
+ self.testpmd = None
- def set_target(self, target):
+ def set_target(self, target, bind_dev=True):
"""
Set env variable, these have to be setup all the time. Some tests
need to compile example apps by themselves and will fail otherwise.
Set hugepage on DUT and install modules required by DPDK.
Configure default ixgbe PMD function.
"""
+ self.target = target
self.set_toolchain(target)
# set env variable
@@ -75,7 +76,7 @@ class DPDKdut(Dut):
self.setup_memory()
self.setup_modules(target)
- if self.get_os_type() == 'linux':
+ if bind_dev and self.get_os_type() == 'linux':
self.bind_interfaces_linux(dts.drivername)
def setup_modules(self, target):
@@ -100,6 +101,7 @@ class DPDKdut(Dut):
if "igb_uio" in out:
self.send_expect("rmmod -f igb_uio", "#", 70)
self.send_expect("insmod ./" + target + "/kmod/igb_uio.ko", "#", 60)
+
out = self.send_expect("lsmod | grep igb_uio", "#")
assert ("igb_uio" in out), "Failed to insmod igb_uio"
@@ -110,7 +112,7 @@ class DPDKdut(Dut):
binding_list = ''
for (pci_bus, pci_id) in self.pci_devices_info:
- if dts.accepted_nic(pci_id):
+ if accepted_nic(pci_id):
binding_list += '%s,' % (pci_bus)
self.send_expect("kldunload if_ixgbe.ko", "#")
@@ -124,22 +126,22 @@ class DPDKdut(Dut):
Set default RX/TX PMD function, now only take effect on ixgbe.
"""
[arch, machine, env, toolchain] = self.target.split('-')
- if 'mode' not in self.crb:
+ if dts.rx_mode is None:
mode = 'default'
else:
- mode = self.crb['mode']
+ mode = dts.rx_mode
- if mode is 'scalar':
+ if mode == 'scalar':
self.send_expect("sed -i -e 's/CONFIG_RTE_IXGBE_INC_VECTOR=.*$/"
+ "CONFIG_RTE_IXGBE_INC_VECTOR=n/' config/common_%s" % env, "# ", 30)
self.send_expect("sed -i -e 's/CONFIG_RTE_LIBRTE_IXGBE_RX_ALLOW_BULK_ALLOC=.*$/"
+ "CONFIG_RTE_LIBRTE_IXGBE_RX_ALLOW_BULK_ALLOC=y/' config/common_%s" % env, "# ", 30)
- if mode is 'full':
+ if mode == 'full':
self.send_expect("sed -i -e 's/CONFIG_RTE_IXGBE_INC_VECTOR=.*$/"
+ "CONFIG_RTE_IXGBE_INC_VECTOR=n/' config/common_%s" % env, "# ", 30)
self.send_expect("sed -i -e 's/CONFIG_RTE_LIBRTE_IXGBE_RX_ALLOW_BULK_ALLOC=.*$/"
+ "CONFIG_RTE_LIBRTE_IXGBE_RX_ALLOW_BULK_ALLOC=n/' config/common_%s" % env, "# ", 30)
- if mode is 'vector':
+ if mode == 'vector':
self.send_expect("sed -i -e 's/CONFIG_RTE_IXGBE_INC_VECTOR=.*$/"
+ "CONFIG_RTE_IXGBE_INC_VECTOR=y/' config/common_%s" % env, "# ", 30)
self.send_expect("sed -i -e 's/CONFIG_RTE_LIBRTE_IXGBE_RX_ALLOW_BULK_ALLOC=.*$/"
@@ -191,10 +193,7 @@ class DPDKdut(Dut):
assert ("Error" not in out), "Compilation error..."
assert ("No rule to make" not in out), "No rule to make error..."
- def prerequisites(self, pkgName, patch):
- """
- Copy DPDK package to DUT and apply patch files.
- """
+ def prepare_package(self, pkgName, patch):
if not self.skip_setup:
assert (os.path.isfile(pkgName) is True), "Invalid package"
@@ -249,6 +248,11 @@ class DPDKdut(Dut):
(self.base_dir, dst_dir + p), "# ")
assert "****" not in out
+ def prerequisites(self, pkgName, patch):
+ """
+ Copy DPDK package to DUT and apply patch files.
+ """
+ self.prepare_package(pkgName, patch)
self.dut_prerequisites()
def bind_interfaces_linux(self, driver='igb_uio', nics_to_bind=None):
@@ -354,7 +358,7 @@ class DPDKtester(Tester):
total_huge_pages = self.get_total_huge_pages()
if total_huge_pages == 0:
self.mount_huge_pages()
- self.set_huge_pages(4096)
+ self.set_huge_pages(1024)
self.session.copy_file_to("dep/tgen.tgz")
self.session.copy_file_to("dep/tclclient.tgz")
@@ -386,10 +390,10 @@ class DPDKtester(Tester):
"""
hugepages_size = self.send_expect("awk '/Hugepagesize/ {print $2}' /proc/meminfo", "# ")
- if int(hugepages_size) < (1024 * 1024):
- arch_huge_pages = hugepages if hugepages > 0 else 4096
+ if int(hugepages_size) < (2048 * 2048):
+ arch_huge_pages = hugepages if hugepages > 0 else 2048
total_huge_pages = self.get_total_huge_pages()
- self.mount_huge_pages()
- if total_huge_pages != arch_huge_pages:
- self.set_huge_pages(arch_huge_pages)
+ self.mount_huge_pages()
+ if total_huge_pages != arch_huge_pages:
+ self.set_huge_pages(arch_huge_pages)
diff --git a/framework/qemu_kvm.py b/framework/qemu_kvm.py
new file mode 100644
index 0000000..fd4be20
--- /dev/null
+++ b/framework/qemu_kvm.py
@@ -0,0 +1,1107 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import time
+import re
+import os
+
+from virt_base import VirtBase
+from exception import StartVMFailedException
+from settings import get_host_ip
+
+# This name is derictly defined in the qemu guest serivce
+# So you can not change it except it is changed by the service
+QGA_DEV_NAME = 'org.qemu.guest_agent.0'
+# This path defines an socket path on the host connected with
+# a specified VM
+QGA_SOCK_PATH_TEMPLATE = '/tmp/%(vm_name)s_qga0.sock'
+
+
+class QEMUKvm(VirtBase):
+
+ DEFAULT_BRIDGE = 'br0'
+ QEMU_IFUP = "#!/bin/sh\n\n" + \
+ "set -x\n\n" + \
+ "switch=%(switch)s\n\n" + \
+ "if [ -n '$1' ];then\n" + \
+ " tunctl -t $1\n" + \
+ " ip link set $1 up\n" + \
+ " sleep 0.5s\n" + \
+ " brctl addif $switch $1\n" + \
+ " exit 0\n" + \
+ "else\n" + \
+ " echo 'Error: no interface specified'\n" + \
+ " exit 1\n" + \
+ "fi"
+
+ QEMU_IFUP_PATH = '/etc/qemu-ifup'
+
+ def __init__(self, dut, vm_name, suite_name):
+ super(QEMUKvm, self).__init__(dut, vm_name, suite_name)
+
+ # initialize qemu emulator, example: qemu-system-x86_64
+ self.qemu_emulator = self.get_qemu_emulator()
+
+ # initialize qemu boot command line
+ # example: qemu-system-x86_64 -name vm1 -m 2048 -vnc :1 -daemonize
+ self.qemu_boot_line = ''
+
+ # initialize some resource used by guest.
+ self.init_vm_request_resource()
+
+ QGA_CLI_PATH = '-r dep/QMP/'
+ self.host_session.copy_file_to(QGA_CLI_PATH)
+
+ # charater and network device default index
+ self.char_idx = 0
+ self.netdev_idx = 0
+ self.pt_idx = 0
+ self.cuse_id = 0
+ # devices pass-through into vm
+ self.pt_devices = []
+ self.pci_maps = []
+
+ # default login user,password
+ self.username = dut.crb['user']
+ self.password = dut.crb['pass']
+
+ # internal variable to track whether default nic has been added
+ self.__default_nic = False
+
+ # set some default values for vm,
+ # if there is not the values of the specified options
+ self.set_vm_default()
+
+ def set_vm_default(self):
+ self.set_vm_name(self.vm_name)
+ self.set_vm_enable_kvm()
+ self.set_vm_qga()
+ self.set_vm_daemon()
+ self.set_vm_monitor()
+
+ if not self.__default_nic:
+ # add default control interface
+ def_nic = {'type': 'nic', 'opt_vlan': '0', 'opt_addr': '1f'}
+ self.set_vm_net(**def_nic)
+ def_net = {'type': 'user', 'opt_vlan': '0'}
+ self.set_vm_net(**def_net)
+ self.__default_nic = True
+
+ def init_vm_request_resource(self):
+ """
+ initialize some resource used by VM.
+ examples: CPU, PCIs, so on.
+ CPU:
+ initialize vcpus what will be pinned to the VM.
+ If specify this param, the specified vcpus will
+ be pinned to VM by the command 'taskset' when
+ starting the VM.
+ example:
+ vcpus_pinned_to_vm = '1 2 3 4'
+ taskset -c 1,2,3,4 qemu-boot-command-line
+ """
+ self.vcpus_pinned_to_vm = ''
+
+ # initialize assigned PCI
+ self.assigned_pcis = []
+
+ def get_virt_type(self):
+ """
+ Get the virtual type.
+ """
+ return 'KVM'
+
+ def get_qemu_emulator(self):
+ """
+ Get the qemu emulator based on the crb.
+ """
+ arch = self.host_session.send_expect('uname -m', '# ')
+ return 'qemu-system-' + arch
+
+ def set_qemu_emulator(self, qemu_emulator_path):
+ """
+ Set the qemu emulator in the specified path explicitly.
+ """
+ out = self.host_session.send_expect(
+ 'ls %s' % qemu_emulator_path, '# ')
+ if 'No such file or directory' in out:
+ self.host_logger.error("No emulator [ %s ] on the DUT [ %s ]" %
+ (qemu_emulator_path, self.host_dut.get_ip_address()))
+ return None
+ out = self.host_session.send_expect("[ -x %s ];echo $?" % qemu_emulator_path, '# ')
+ if out != '0':
+ self.host_logger.error("Emulator [ %s ] not executable on the DUT [ %s ]" %
+ (qemu_emulator_path, self.host_dut.get_ip_address()))
+ return None
+ self.qemu_emulator = qemu_emulator_path
+
+ def add_vm_qemu(self, **options):
+ """
+ path: absolute path for qemu emulator
+ """
+ if 'path' in options.keys():
+ self.set_qemu_emulator(options['path'])
+
+ def has_virtual_ability(self):
+ """
+ Check if host has the virtual ability.
+ """
+ out = self.host_session.send_expect('cat /proc/cpuinfo | grep flags', '# ')
+ rgx = re.search(' vmx ', out)
+ if rgx:
+ pass
+ else:
+ self.host_logger.warning("Hardware virtualization disabled on host!!!")
+ return False
+
+ out = self.host_session.send_expect('lsmod | grep kvm', '# ')
+ if 'kvm' in out and 'kvm_intel' in out:
+ return True
+ else:
+ self.host_logger.warning("kvm or kvm_intel not insmod!!!")
+ return False
+
+ def enable_virtual_ability(self):
+ """
+ Load the virutal module of kernel to enable the virutal ability.
+ """
+ self.host_session.send_expect('modprobe kvm', '# ')
+ self.host_session.send_expect('modprobe kvm_intel', '# ')
+ return True
+
+ def disk_image_is_ok(self, image):
+ """
+ Check if the image is OK and no error.
+ """
+ pass
+
+ def image_is_used(self, image_path):
+ """
+ Check if the image has been used on the host.
+ """
+ qemu_cmd_lines = self.host_session.send_expect(
+ "ps aux | grep qemu | grep -v grep", "# ")
+
+ image_name_flag = '/' + image_path.strip().split('/')[-1] + ' '
+ if image_path in qemu_cmd_lines or \
+ image_name_flag in qemu_cmd_lines:
+ return True
+ return False
+
+ def __add_boot_line(self, option_boot_line):
+ """
+ Add boot option into the boot line.
+ """
+ separator = ' '
+ self.qemu_boot_line += separator + option_boot_line
+
+ def set_vm_enable_kvm(self, enable='yes'):
+ """
+ Set VM boot option to enable the option 'enable-kvm'.
+ """
+ index = self.find_option_index('enable_kvm')
+ if index:
+ self.params[index] = {'enable_kvm': [{'enable': '%s' % enable}]}
+ else:
+ self.params.append({'enable_kvm': [{'enable': '%s' % enable}]})
+
+ def add_vm_enable_kvm(self, **options):
+ """
+ 'enable': 'yes'
+ """
+ if 'enable' in options.keys() and \
+ options['enable'] == 'yes':
+ enable_kvm_boot_line = '-enable-kvm'
+ self.__add_boot_line(enable_kvm_boot_line)
+
+ def set_vm_name(self, vm_name):
+ """
+ Set VM name.
+ """
+ index = self.find_option_index('name')
+ if index:
+ self.params[index] = {'name': [{'name': '%s' % vm_name}]}
+ else:
+ self.params.append({'name': [{'name': '%s' % vm_name}]})
+
+ def add_vm_name(self, **options):
+ """
+ name: vm1
+ """
+ if 'name' in options.keys() and \
+ options['name']:
+ name_boot_line = '-name %s' % options['name']
+ self.__add_boot_line(name_boot_line)
+
+ def add_vm_cpu(self, **options):
+ """
+ model: [host | core2duo | ...]
+ usage:
+ choose model value from the command
+ qemu-system-x86_64 -cpu help
+ number: '4' #number of vcpus
+ cpupin: '3 4 5 6' # host cpu list
+ """
+ if 'model' in options.keys() and \
+ options['model']:
+ cpu_boot_line = '-cpu %s' % options['model']
+ self.__add_boot_line(cpu_boot_line)
+ if 'number' in options.keys() and \
+ options['number']:
+ smp_cmd_line = '-smp %d' % int(options['number'])
+ self.__add_boot_line(smp_cmd_line)
+ if 'cpupin' in options.keys() and \
+ options['cpupin']:
+ self.vcpus_pinned_to_vm = str(options['cpupin'])
+
+ def add_vm_mem(self, **options):
+ """
+ size: 1024
+ """
+ if 'size' in options.keys():
+ mem_boot_line = '-m %s' % options['size']
+ self.__add_boot_line(mem_boot_line)
+ if 'hugepage' in options.keys():
+ if options['hugepage'] == 'yes':
+ mem_boot_huge = '-object memory-backend-file,' \
+ + 'id=mem,size=%sM,mem-path=%s,share=on' \
+ % (options['size'], self.host_dut.hugepage_path)
+
+ self.__add_boot_line(mem_boot_huge)
+ mem_boot_huge_opt = "-numa node,memdev=mem -mem-prealloc"
+ self.__add_boot_line(mem_boot_huge_opt)
+
+ def add_vm_disk(self, **options):
+ """
+ file: /home/image/test.img
+ """
+ if 'file' in options.keys():
+ disk_boot_line = '-drive file=%s' % options['file']
+ self.__add_boot_line(disk_boot_line)
+
+ def add_vm_login(self, **options):
+ """
+ user: login username of virtual machine
+ password: login password of virtual machine
+ """
+ if 'user' in options.keys():
+ user = options['user']
+ self.username = user
+
+ if 'password' in options.keys():
+ password = options['password']
+ self.password = password
+
+ def get_vm_login(self):
+ return (self.username, self.password)
+
+ def set_vm_net(self, **options):
+ index = self.find_option_index('net')
+ if index:
+ self.params[index]['net'].append(options)
+ else:
+ self.params.append({'net': [options]})
+
+ def add_vm_net(self, **options):
+ """
+ Add VM net device.
+ type: [nic | user | tap | bridge | ...]
+ opt_[vlan | fd | br | mac | ...]
+ note:the sub-option will be decided according to the net type.
+ """
+ if 'type' in options.keys():
+ if 'opt_vlan' not in options.keys():
+ options['opt_vlan'] = '0'
+ if options['type'] == 'nic':
+ self.__add_vm_net_nic(**options)
+ if options['type'] == 'user':
+ self.__add_vm_net_user(**options)
+ if options['type'] == 'tap':
+ self.__add_vm_net_tap(**options)
+
+ if options['type'] == 'user':
+ self.net_type = 'hostfwd'
+ elif options['type'] in ['tap', 'bridge']:
+ self.net_type = 'bridge'
+
+ def __add_vm_net_nic(self, **options):
+ """
+ type: nic
+ opt_vlan: 0
+ note: Default is 0.
+ opt_macaddr: 00:00:00:00:01:01
+ note: if creating a nic, it`s better to specify a MAC,
+ else it will get a random number.
+ opt_model:["e1000" | "virtio" | "i82551" | ...]
+ note: Default is e1000.
+ opt_name: 'nic1'
+ opt_addr: ''
+ note: PCI cards only.
+ opt_vectors:
+ note: This option currently only affects virtio cards.
+ """
+ net_boot_line = '-net nic'
+ separator = ','
+ if 'opt_vlan' in options.keys() and \
+ options['opt_vlan']:
+ net_boot_line += separator + 'vlan=%s' % options['opt_vlan']
+
+ # add MAC info
+ if 'opt_macaddr' in options.keys() and \
+ options['opt_macaddr']:
+ mac = options['opt_macaddr']
+ else:
+ mac = self.generate_unique_mac()
+ net_boot_line += separator + 'macaddr=%s' % mac
+
+ if 'opt_model' in options.keys() and \
+ options['opt_model']:
+ net_boot_line += separator + 'model=%s' % options['opt_model']
+ if 'opt_name' in options.keys() and \
+ options['opt_name']:
+ net_boot_line += separator + 'name=%s' % options['opt_name']
+ if 'opt_addr' in options.keys() and \
+ options['opt_addr']:
+ net_boot_line += separator + 'addr=%s' % options['opt_addr']
+ if 'opt_vectors' in options.keys() and \
+ options['opt_vectors']:
+ net_boot_line += separator + 'vectors=%s' % options['opt_vectors']
+
+ if self.__string_has_multi_fields(net_boot_line, separator):
+ self.__add_boot_line(net_boot_line)
+
+ def __add_vm_net_user(self, **options):
+ """
+ type: user
+ opt_vlan: 0
+ note: default is 0.
+ opt_hostfwd: [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport
+ """
+ net_boot_line = '-net user'
+ separator = ','
+ if 'opt_vlan' in options.keys() and \
+ options['opt_vlan']:
+ net_boot_line += separator + 'vlan=%s' % options['opt_vlan']
+ if 'opt_hostfwd' in options.keys() and \
+ options['opt_hostfwd']:
+ self.__check_net_user_opt_hostfwd(options['opt_hostfwd'])
+ opt_hostfwd = options['opt_hostfwd']
+ else:
+ opt_hostfwd = '::-:'
+ hostfwd_line = self.__parse_net_user_opt_hostfwd(opt_hostfwd)
+ net_boot_line += separator + 'hostfwd=%s' % hostfwd_line
+
+ if self.__string_has_multi_fields(net_boot_line, separator):
+ self.__add_boot_line(net_boot_line)
+
+ def __check_net_user_opt_hostfwd(self, opt_hostfwd):
+ """
+ Use regular expression to check if hostfwd value format is correct.
+ """
+ regx_ip = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
+ regx_hostfwd = r'["tcp" | "udp"]?:%s?:\d+-%s?:\d+' % (regx_ip, regx_ip)
+ if not re.match(regx_hostfwd, opt_hostfwd):
+ raise Exception("Option opt_hostfwd format is not correct,\n" +
+ "it is %s,\n " % opt_hostfwd +
+ "it should be [tcp|udp]:[hostaddr]:hostport-" +
+ "[guestaddr]:guestport.\n")
+
+ def __parse_net_user_opt_hostfwd(self, opt_hostfwd):
+ """
+ Parse the boot option 'hostfwd'.
+ """
+ separator = ':'
+ field = lambda option, index, separator=':': \
+ option.split(separator)[index]
+
+ # get the forword type
+ fwd_type = field(opt_hostfwd, 0)
+ if not fwd_type:
+ fwd_type = 'tcp'
+
+ # get the host addr
+ host_addr = field(opt_hostfwd, 1)
+ if not host_addr:
+ addr = str(self.host_dut.get_ip_address())
+ host_addr = get_host_ip(addr)
+
+ # get the host port in the option
+ host_port = field(opt_hostfwd, 2).split('-')[0]
+ if not host_port:
+ host_port = str(self.virt_pool.alloc_port(self.vm_name))
+ self.redir_port = host_port
+
+ # get the guest addr
+ try:
+ guest_addr = str(field(opt_hostfwd, 2).split('-')[1])
+ except IndexError as e:
+ guest_addr = ''
+
+ # get the guest port in the option
+ guest_port = str(field(opt_hostfwd, 3))
+ if not guest_port:
+ guest_port = '22'
+
+ hostfwd_line = fwd_type + separator + \
+ host_addr + separator + \
+ host_port + \
+ '-' + \
+ guest_addr + separator + \
+ guest_port
+
+ # init the redirect incoming TCP or UDP connections
+ # just combine host address and host port, it is enough
+ # for using ssh to connect with VM
+ self.hostfwd_addr = host_addr + separator + host_port
+
+ return hostfwd_line
+
+ def __add_vm_net_tap(self, **options):
+ """
+ type: tap
+ opt_vlan: 0
+ note: default is 0.
+ opt_br: br0
+ note: if choosing tap, need to specify bridge name,
+ else it will be br0.
+ opt_script: QEMU_IFUP_PATH
+ note: if not specified, default is self.QEMU_IFUP_PATH.
+ opt_downscript: QEMU_IFDOWN_PATH
+ note: if not specified, default is self.QEMU_IFDOWN_PATH.
+ """
+ net_boot_line = '-net tap'
+ separator = ','
+
+ # add bridge info
+ if 'opt_br' in options.keys() and \
+ options['opt_br']:
+ bridge = options['opt_br']
+ else:
+ bridge = self.DEFAULT_BRIDGE
+ self.__generate_net_config_script(str(bridge))
+
+ if 'opt_vlan' in options.keys() and \
+ options['opt_vlan']:
+ net_boot_line += separator + 'vlan=%s' % options['opt_vlan']
+
+ # add network configure script path
+ if 'opt_script' in options.keys() and \
+ options['opt_script']:
+ script_path = options['opt_script']
+ else:
+ script_path = self.QEMU_IFUP_PATH
+ net_boot_line += separator + 'script=%s' % script_path
+
+ # add network configure downscript path
+ if 'opt_downscript' in options.keys() and \
+ options['opt_downscript']:
+ net_boot_line += separator + \
+ 'downscript=%s' % options['opt_downscript']
+
+ if self.__string_has_multi_fields(net_boot_line, separator):
+ self.__add_boot_line(net_boot_line)
+
+ def __generate_net_config_script(self, switch=DEFAULT_BRIDGE):
+ """
+ Generate a script for qemu emulator to build a tap device
+ between host and guest.
+ """
+ qemu_ifup = self.QEMU_IFUP % {'switch': switch}
+ file_name = os.path.basename(self.QEMU_IFUP_PATH)
+ tmp_file_path = '/tmp/%s' % file_name
+ self.host_dut.create_file(qemu_ifup, tmp_file_path)
+ self.host_session.send_expect('mv -f ~/%s %s' % (file_name,
+ self.QEMU_IFUP_PATH), '# ')
+ self.host_session.send_expect(
+ 'chmod +x %s' % self.QEMU_IFUP_PATH, '# ')
+
+ def set_vm_device(self, driver='pci-assign', **opts):
+ """
+ Set VM device with specified driver.
+ """
+ opts['driver'] = driver
+ index = self.find_option_index('device')
+ if index:
+ self.params[index]['device'].append(opts)
+ else:
+ self.params.append({'device': [opts]})
+
+ def add_vm_device(self, **options):
+ """
+ driver: [pci-assign | virtio-net-pci | ...]
+ opt_[host | addr | ...]: value
+ note:the sub-opterty will be decided according to the driver.
+ """
+ if 'driver' in options.keys() and \
+ options['driver']:
+ if options['driver'] == 'pci-assign':
+ self.__add_vm_pci_assign(**options)
+ elif options['driver'] == 'virtio-net-pci':
+ self.__add_vm_virtio_net_pci(**options)
+ elif options['driver'] == 'vhost-user':
+ self.__add_vm_virtio_user_pci(**options)
+ elif options['driver'] == 'vhost-cuse':
+ self.__add_vm_virtio_cuse_pci(**options)
+
+ def __add_vm_pci_assign(self, **options):
+ """
+ driver: pci-assign
+ opt_host: 08:00.0
+ opt_addr: 00:00:00:00:01:02
+ """
+ dev_boot_line = '-device pci-assign'
+ separator = ','
+ if 'opt_host' in options.keys() and \
+ options['opt_host']:
+ dev_boot_line += separator + 'host=%s' % options['opt_host']
+ dev_boot_line += separator + 'id=pt_%d' % self.pt_idx
+ self.pt_idx += 1
+ self.pt_devices.append(options['opt_host'])
+ if 'opt_addr' in options.keys() and \
+ options['opt_addr']:
+ dev_boot_line += separator + 'addr=%s' % options['opt_addr']
+ self.assigned_pcis.append(options['opt_addr'])
+
+ if self.__string_has_multi_fields(dev_boot_line, separator):
+ self.__add_boot_line(dev_boot_line)
+
+ def __add_vm_virtio_user_pci(self, **options):
+ """
+ driver virtio-net-pci
+ opt_path: /tmp/vhost-net
+ opt_mac: 00:00:20:00:00:00
+ """
+ separator = ','
+ # chardev parameter
+ if 'opt_path' in options.keys() and \
+ options['opt_path']:
+ dev_boot_line = '-chardev socket'
+ char_id = 'char%d' % self.char_idx
+ dev_boot_line += separator + 'id=%s' % char_id + separator + 'path=%s' % options['opt_path']
+ self.char_idx += 1
+ self.__add_boot_line(dev_boot_line)
+ # netdev parameter
+ netdev_id = 'netdev%d' % self.netdev_idx
+ self.netdev_idx += 1
+ dev_boot_line = '-netdev type=vhost-user,id=%s,chardev=%s,vhostforce' % (netdev_id, char_id)
+ self.__add_boot_line(dev_boot_line)
+ # device parameter
+ opts = {'opt_netdev': '%s' % netdev_id}
+ if 'opt_mac' in options.keys() and \
+ options['opt_mac']:
+ opts['opt_mac'] = options['opt_mac']
+
+ self.__add_vm_virtio_net_pci(**opts)
+
+ def __add_vm_virtio_cuse_pci(self, **options):
+ """
+ driver virtio-net-pci
+ opt_mac: 52:54:00:00:00:01
+ """
+ separator = ','
+ dev_boot_line = '-netdev tap'
+ cuse_id = 'vhost%d' % self.cuse_id
+ dev_boot_line += separator + 'id=%s' % cuse_id + separator + 'ifname=tap_%s' % cuse_id + separator + "vhost=on" + separator + "script=no"
+ self.cuse_id += 1
+ self.__add_boot_line(dev_boot_line)
+ # device parameter
+ opts = {'opt_netdev': '%s' % cuse_id,
+ 'opt_id': '%s_net' % cuse_id}
+ if 'opt_mac' in options.keys() and options['opt_mac']:
+ opts['opt_mac'] = options['opt_mac']
+ if 'opt_settings' in options.keys() and options['opt_settings']:
+ opts['opt_settings'] = options['opt_settings']
+
+ self.__add_vm_virtio_net_pci(**opts)
+
+ def __add_vm_virtio_net_pci(self, **options):
+ """
+ driver: virtio-net-pci
+ opt_netdev: mynet1
+ opt_id: net1
+ opt_mac: 00:00:00:00:01:03
+ opt_bus: pci.0
+ opt_addr: 0x3
+ opt_settings: csum=off,gso=off,guest_csum=off
+ """
+ dev_boot_line = '-device virtio-net-pci'
+ separator = ','
+ if 'opt_netdev' in options.keys() and \
+ options['opt_netdev']:
+ dev_boot_line += separator + 'netdev=%s' % options['opt_netdev']
+ if 'opt_id' in options.keys() and \
+ options['opt_id']:
+ dev_boot_line += separator + 'id=%s' % options['opt_id']
+ if 'opt_mac' in options.keys() and \
+ options['opt_mac']:
+ dev_boot_line += separator + 'mac=%s' % options['opt_mac']
+ if 'opt_bus' in options.keys() and \
+ options['opt_bus']:
+ dev_boot_line += separator + 'bus=%s' % options['opt_bus']
+ if 'opt_addr' in options.keys() and \
+ options['opt_addr']:
+ dev_boot_line += separator + 'addr=%s' % options['opt_addr']
+ if 'opt_settings' in options.keys() and \
+ options['opt_settings']:
+ dev_boot_line += separator + '%s' % options['opt_settings']
+
+ if self.__string_has_multi_fields(dev_boot_line, separator):
+ self.__add_boot_line(dev_boot_line)
+
+ def __string_has_multi_fields(self, string, separator, field_num=2):
+ """
+ Check if string has multiple fields which is splited with
+ specified separator.
+ """
+ fields = string.split(separator)
+ number = 0
+ for field in fields:
+ if field:
+ number += 1
+ if number >= field_num:
+ return True
+ else:
+ return False
+
+ def set_vm_monitor(self):
+ """
+ Set VM boot option to enable qemu monitor.
+ """
+ index = self.find_option_index('monitor')
+ if index:
+ self.params[index] = {'monitor': [{'path': '/tmp/%s_monitor.sock' %
+ (self.vm_name)}]}
+ else:
+ self.params.append({'monitor': [{'path': '/tmp/%s_monitor.sock' %
+ (self.vm_name)}]})
+
+ def add_vm_monitor(self, **options):
+ """
+ path: if adding monitor to vm, need to specify unix socket patch
+ """
+ if 'path' in options.keys():
+ monitor_boot_line = '-monitor unix:%s,server,nowait' % options['path']
+ self.__add_boot_line(monitor_boot_line)
+ self.monitor_sock_path = options['path']
+ else:
+ self.monitor_sock_path = None
+
+ def set_vm_qga(self, enable='yes'):
+ """
+ Set VM qemu-guest-agent.
+ """
+ index = self.find_option_index('qga')
+ if index:
+ self.params[index] = {'qga': [{'enable': '%s' % enable}]}
+ else:
+ self.params.append({'qga': [{'enable': '%s' % enable}]})
+ QGA_SOCK_PATH = QGA_SOCK_PATH_TEMPLATE % {'vm_name': self.vm_name}
+ self.qga_sock_path = QGA_SOCK_PATH
+
+ def add_vm_qga(self, **options):
+ """
+ enable: 'yes'
+ Make sure qemu-guest-agent servie up in vm
+ """
+ QGA_DEV_ID = '%(vm_name)s_qga0' % {'vm_name': self.vm_name}
+ QGA_SOCK_PATH = QGA_SOCK_PATH_TEMPLATE % {'vm_name': self.vm_name}
+
+ separator = ' '
+
+ if 'enable' in options.keys():
+ if options['enable'] == 'yes':
+ qga_boot_block = '-chardev socket,path=%(SOCK_PATH)s,server,nowait,id=%(ID)s' + \
+ separator + '-device virtio-serial' + separator + \
+ '-device virtserialport,chardev=%(ID)s,name=%(DEV_NAME)s'
+ qga_boot_line = qga_boot_block % {'SOCK_PATH': QGA_SOCK_PATH,
+ 'DEV_NAME': QGA_DEV_NAME,
+ 'ID': QGA_DEV_ID}
+ self.__add_boot_line(qga_boot_line)
+ self.qga_sock_path = QGA_SOCK_PATH
+ else:
+ self.qga_sock_path = ''
+
+ def add_vm_serial_port(self, **options):
+ """
+ enable: 'yes'
+ """
+ SERAIL_SOCK_PATH = "/tmp/%s_serial.sock" % self.vm_name
+ if 'enable' in options.keys():
+ if options['enable'] == 'yes':
+ serial_boot_line = '-serial unix:%s,server,nowait' % SERIAL_SOCK_PATH
+ self.__add_boot_line(serial_boot_line)
+ else:
+ pass
+
+ def add_vm_vnc(self, **options):
+ """
+ displayNum: 1
+ """
+ if 'displayNum' in options.keys() and \
+ options['displayNum']:
+ display_num = options['displayNum']
+ else:
+ display_num = self.virt_pool.alloc_vnc_num(self.vm_name)
+
+ vnc_boot_line = '-vnc :%d' % int(display_num)
+ self.__add_boot_line(vnc_boot_line)
+
+ def set_vm_daemon(self, enable='yes'):
+ """
+ Set VM daemon option.
+ """
+ index = self.find_option_index('daemon')
+ if index:
+ self.params[index] = {'daemon': [{'enable': '%s' % enable}]}
+ else:
+ self.params.append({'daemon': [{'enable': '%s' % enable}]})
+
+ def add_vm_daemon(self, **options):
+ """
+ enable: 'yes'
+ note:
+ By default VM will start with the daemonize status.
+ Not support starting it on the stdin now.
+ """
+ if 'daemon' in options.keys() and \
+ options['enable'] == 'no':
+ pass
+ else:
+ daemon_boot_line = '-daemonize'
+ self.__add_boot_line(daemon_boot_line)
+
+ def add_vm_usercmd(self, **options):
+ """
+ usercmd: user self defined command line.
+ This command will be add into qemu boot command.
+ """
+ if 'cmd' in options.keys():
+ cmd = options['cmd']
+ self.__add_boot_line(cmd)
+
+ def _start_vm(self):
+ """
+ Start VM.
+ """
+ self.__alloc_assigned_pcis()
+
+ qemu_boot_line = self.generate_qemu_boot_line()
+
+ # Start VM using the qemu command
+ ret = self.host_session.send_expect(qemu_boot_line, '# ', verify=True)
+ if type(ret) is int and ret != 0:
+ raise StartVMFailedException('Start VM failed!!!')
+ out = self.__control_session('ping', '120')
+ if "Not responded" in out:
+ raise StartVMFailedException('Not response in 60 seconds!!!')
+
+ self.__get_pci_mapping()
+ self.__wait_vmnet_ready()
+
+ def generate_qemu_boot_line(self):
+ """
+ Generate the whole QEMU boot line.
+ """
+ qemu_emulator = self.qemu_emulator
+
+ if self.vcpus_pinned_to_vm.strip():
+ vcpus = self.__alloc_vcpus()
+
+ if vcpus.strip():
+ qemu_boot_line = 'taskset -c %s ' % vcpus + \
+ qemu_emulator + ' ' + \
+ self.qemu_boot_line
+ else:
+ qemu_boot_line = qemu_emulator + ' ' + \
+ self.qemu_boot_line
+
+ return qemu_boot_line
+
+ def __wait_vmnet_ready(self):
+ """
+ wait for 120 seconds for vm net ready
+ 10.0.2.* is the default ip address allocated by qemu
+ """
+ count = 20
+ while count:
+ out = self.__control_session('ifconfig')
+ if "10.0.2" in out:
+ return True
+ time.sleep(6)
+ count -= 1
+
+ raise StartVMFailedException('Virtual machine control net not ready in 120 seconds!!!')
+
+ def __alloc_vcpus(self):
+ """
+ Allocate virtual CPUs for VM.
+ """
+ req_cpus = self.vcpus_pinned_to_vm.split()
+ cpus = self.virt_pool.alloc_cpu(vm=self.vm_name, corelist=req_cpus)
+
+ if len(req_cpus) != len(cpus):
+ self.host_logger.warning("VCPUs not enough, required [ %s ], just [ %s ]" %
+ (req_cpus, cpus))
+ raise Exception("No enough required vcpus!!!")
+
+ vcpus_pinned_to_vm = ''
+ for cpu in cpus:
+ vcpus_pinned_to_vm += ',' + cpu
+ vcpus_pinned_to_vm = vcpus_pinned_to_vm.lstrip(',')
+
+ return vcpus_pinned_to_vm
+
+ def __alloc_assigned_pcis(self):
+ """
+ Record the PCI device info
+ Struct: {dev pci: {'is_vf': [True | False],
+ 'pf_pci': pci}}
+ example:
+ {'08:10.0':{'is_vf':True, 'pf_pci': 08:00.0}}
+ """
+ assigned_pcis_info = {}
+ for pci in self.assigned_pcis:
+ assigned_pcis_info[pci] = {}
+ if self.__is_vf_pci(pci):
+ assigned_pcis_info[pci]['is_vf'] = True
+ pf_pci = self.__map_vf_to_pf(pci)
+ assgined_pcis_info[pci]['pf_pci'] = pf_pci
+ if self.virt_pool.alloc_vf_from_pf(vm=self.vm_name,
+ pf_pci=pf_pci,
+ *[pci]):
+ port = self.__get_vf_port(pci)
+ port.unbind_driver()
+ port.bind_driver('pci-stub')
+ else:
+ # check that if any VF of specified PF has been
+ # used, raise exception
+ vf_pci = self.__vf_has_been_assinged(pci, **assinged_pcis_info)
+ if vf_pci:
+ raise Exception(
+ "Error: A VF [%s] generated by PF [%s] has " %
+ (vf_pci, pci) +
+ "been assigned to VM, so this PF can not be " +
+ "assigned to VM again!")
+ # get the port instance of PF
+ port = self.__get_net_device_by_pci(pci)
+
+ if self.virt_pool.alloc_pf(vm=self.vm_name,
+ *[pci]):
+ port.unbind_driver()
+
+ def __is_vf_pci(self, dev_pci):
+ """
+ Check if the specified PCI dev is a VF.
+ """
+ for port_info in self.host_dut.ports_info:
+ if 'sriov_vfs_pci' in port_info.keys():
+ if dev_pci in port_info['sriov_vfs_pci']:
+ return True
+ return False
+
+ def __map_vf_to_pf(self, dev_pci):
+ """
+ Map the specified VF to PF.
+ """
+ for port_info in self.host_dut.ports_info:
+ if 'sriov_vfs_pci' in port_info.keys():
+ if dev_pci in port_info['sriov_vfs_pci']:
+ return port_info['pci']
+ return None
+
+ def __get_vf_port(self, dev_pci):
+ """
+ Get the NetDevice instance of specified VF.
+ """
+ for port_info in self.host_dut.ports_info:
+ if 'vfs_port' in port_info.keys():
+ for port in port_info['vfs_port']:
+ if dev_pci == port.pci:
+ return port
+ return None
+
+ def __vf_has_been_assigned(self, pf_pci, **assigned_pcis_info):
+ """
+ Check if the specified VF has been used.
+ """
+ for pci in assigned_pcis_info.keys():
+ if assigned_pcis_info[pci]['is_vf'] and \
+ assigned_pcis_info[pci]['pf_pci'] == pf_pci:
+ return pci
+ return False
+
+ def __get_net_device_by_pci(self, net_device_pci):
+ """
+ Get NetDevice instance by the specified PCI bus number.
+ """
+ port_info = self.host_dut.get_port_info(net_device_pci)
+ return port_info['port']
+
+ def get_vm_ip(self):
+ """
+ Get VM IP.
+ """
+ get_vm_ip = getattr(self, "get_vm_ip_%s" % self.net_type)
+ return get_vm_ip()
+
+ def get_vm_ip_hostfwd(self):
+ """
+ Get IP which VM is connected by hostfwd.
+ """
+ return self.hostfwd_addr
+
+ def get_vm_ip_bridge(self):
+ """
+ Get IP which VM is connected by bridge.
+ """
+ out = self.__control_session('ping', '60')
+ if not out:
+ time.sleep(10)
+ out = self.__control_session('ifconfig')
+ ips = re.findall(r'inet (\d+\.\d+\.\d+\.\d+)', out)
+
+ if '127.0.0.1' in ips:
+ ips.remove('127.0.0.1')
+
+ num = 3
+ for ip in ips:
+ out = self.host_session.send_expect(
+ 'ping -c %d %s' % (num, ip), '# ')
+ if '0% packet loss' in out:
+ return ip
+ return ''
+
+ def __get_pci_mapping(self):
+ devices = self.__strip_guest_pci()
+ for hostpci in self.pt_devices:
+ index = self.pt_devices.index(hostpci)
+ pt_id = 'pt_%d' % index
+ pci_map = {}
+ for device in devices:
+ if device['id'] == pt_id:
+ pci_map['hostpci'] = hostpci
+ pci_map['guestpci'] = device['pci']
+ self.pci_maps.append(pci_map)
+
+ def get_pci_mappings(self):
+ """
+ Return guest and host pci devices mapping structure
+ """
+ return self.pci_maps
+
+ def __monitor_session(self, command, *args):
+ """
+ Connect the qemu montior session, send command and return output message.
+ """
+ if not self.monitor_sock_path:
+ self.host_logger.info(
+ "No monitor between on host [ %s ] for guest [ %s ]" %
+ (self.host_dut.NAME, self.vm_name))
+ return None
+
+ self.host_session.send_expect('nc -U %s' % self.monitor_sock_path, '(qemu)', 2)
+
+ cmd = command
+ for arg in args:
+ cmd += ' ' + str(arg)
+
+ out = self.host_session.send_expect('%s' % cmd, '(qemu)')
+ self.host_session.send_expect('^C', "# ")
+ return out
+
+ def __strip_guest_pci(self):
+ """
+ Strip all pci-passthrough device information, based on qemu monitor
+ """
+ pci_reg = r'^.*Bus(\s+)(\d+), device(\s+)(\d+), function (\d+)'
+ id_reg = r'^.*id \"(.*)\"'
+
+ pcis = []
+ out = self.__monitor_session('info', 'pci')
+
+ if out is None:
+ return pcis
+
+ lines = out.split("\r\n")
+
+ for line in lines:
+ m = re.match(pci_reg, line)
+ n = re.match(id_reg, line)
+ if m:
+ pci = "%02d:%02d.%d" % (int(m.group(2)), int(m.group(4)), int(m.group(5)))
+ if n:
+ dev_id = n.group(1)
+ if dev_id != '':
+ pt_dev = {}
+ pt_dev['pci'] = pci
+ pt_dev['id'] = dev_id
+ pcis.append(pt_dev)
+
+ return pcis
+
+ def __control_session(self, command, *args):
+ """
+ Use the qemu guest agent service to control VM.
+ Note:
+ :command: there are these commands as below:
+ cat, fsfreeze, fstrim, halt, ifconfig, info,\
+ ping, powerdown, reboot, shutdown, suspend
+ :args: give different args by the different commands.
+ """
+ if not self.qga_sock_path:
+ self.host_logger.info(
+ "No QGA service between host [ %s ] and guest [ %s ]" %
+ (self.host_dut.NAME, self.vm_name))
+ return None
+
+ cmd_head = '~/QMP/' + \
+ "qemu-ga-client " + \
+ "--address=%s %s" % \
+ (self.qga_sock_path, command)
+
+ cmd = cmd_head
+ for arg in args:
+ cmd = cmd_head + ' ' + str(arg)
+
+ if command is "ping":
+ out = self.host_session.send_expect(cmd, '# ', int(args[0]))
+ else:
+ out = self.host_session.send_expect(cmd, '# ')
+
+ return out
+
+ def _stop_vm(self):
+ """
+ Stop VM.
+ """
+ self.__control_session('powerdown')
+ time.sleep(5)
diff --git a/framework/qemu_libvirt.py b/framework/qemu_libvirt.py
new file mode 100644
index 0000000..de69d8f
--- /dev/null
+++ b/framework/qemu_libvirt.py
@@ -0,0 +1,515 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import time
+import re
+import os
+
+import dts
+from dut import Dut
+from ssh_connection import SSHConnection
+from virt_base import VirtBase
+from virt_resource import VirtResource
+from logger import getLogger
+from config import VirtConf
+from config import VIRTCONF
+from exception import StartVMFailedException
+import xml.etree.ElementTree as ET
+from xml.etree.ElementTree import ElementTree
+
+
+class LibvirtKvm(VirtBase):
+
+ def __init__(self, dut, name, suite):
+ # initialize virtualization base module
+ super(LibvirtKvm, self).__init__(dut, name, suite)
+
+ # initialize qemu emulator, example: qemu-system-x86_64
+ self.qemu_emulator = self.get_qemu_emulator()
+
+ # disk and pci device default index
+ self.diskindex = 'a'
+ self.pciindex = 10
+
+ # configure root element
+ self.root = ElementTree()
+ self.domain = ET.Element('domain')
+ # replace root element
+ self.root._setroot(self.domain)
+ # add xml header
+ self.domain.set('type', 'kvm')
+ self.domain.set('xmlns:qemu',
+ 'http://libvirt.org/schemas/domain/qemu/1.0')
+ ET.SubElement(self.domain, 'name').text = name
+
+ # devices pass-through into vm
+ self.pci_maps = []
+
+ # default login user,password
+ self.username = self.host_dut.crb['user']
+ self.password = self.host_dut.crb['pass']
+
+ # internal variable to track whether default nic has been added
+ self.__default_nic = False
+
+ # set some default values for vm,
+ # if there is not the values of the specified options
+ self.set_vm_default()
+
+ def get_qemu_emulator(self):
+ """
+ Get the qemu emulator based on the crb.
+ """
+ arch = self.host_session.send_expect('uname -m', '# ')
+ return '/usr/bin/qemu-system-' + arch
+
+ def get_virt_type(self):
+ return 'LIBVIRT'
+
+ def has_virtual_ability(self):
+ """
+ check and setup host virtual ability
+ """
+ out = self.host_session.send_expect('cat /proc/cpuinfo | grep flags',
+ '# ')
+ rgx = re.search(' vmx ', out)
+ if rgx:
+ pass
+ else:
+ self.host_logger.warning("Hardware virtualization "
+ "disabled on host!!!")
+ return False
+
+ out = self.host_session.send_expect('lsmod | grep kvm', '# ')
+ if 'kvm' not in out or 'kvm_intel' not in out:
+ return False
+
+ out = self.host_session.send_expect('service libvirtd status', "# ")
+ if 'active (running)' not in out:
+ return False
+
+ return True
+
+ def load_virtual_mod(self):
+ self.host_session.send_expect('modprobe kvm', '# ')
+ self.host_session.send_expect('modprobe kvm_intel', '# ')
+
+ def unload_virtual_mod(self):
+ self.host_session.send_expect('rmmod kvm_intel', '# ')
+ self.host_session.send_expect('rmmod kvm', '# ')
+
+ def disk_image_is_ok(self, image):
+ """
+ Check if the image is OK and no error.
+ """
+ pass
+
+ def add_vm_mem(self, **options):
+ """
+ Options:
+ size : memory size, measured in MB
+ hugepage : guest memory allocated using hugepages
+ """
+ if 'size' in options.keys():
+ memory = ET.SubElement(self.domain, 'memory', {'unit': 'MB'})
+ memory.text = options['size']
+ if 'hugepage' in options.keys():
+ memoryBacking = ET.SubElement(self.domain, 'memoryBacking')
+ ET.SubElement(memoryBacking, 'hugepages')
+
+ def set_vm_cpu(self, **options):
+ """
+ Set VM cpu.
+ """
+ index = self.find_option_index('cpu')
+ if index:
+ self.params[index] = {'cpu': [options]}
+ else:
+ self.params.append({'cpu': [options]})
+
+ def add_vm_cpu(self, **options):
+ """
+ 'number' : '4' #number of vcpus
+ 'cpupin' : '3 4 5 6' # host cpu list
+ """
+ vcpu = 0
+ if 'number' in options.keys():
+ vmcpu = ET.SubElement(self.domain, 'vcpu', {'placement': 'static'})
+ vmcpu.text = options['number']
+ if 'cpupin' in options.keys():
+ cputune = ET.SubElement(self.domain, 'cputune')
+ # cpu resource will be allocated
+ req_cpus = options['cpupin'].split()
+ cpus = self.virt_pool.alloc_cpu(vm=self.vm_name, corelist=req_cpus)
+ for cpu in cpus:
+ ET.SubElement(cputune, 'vcpupin', {
+ 'vcpu': '%d' % vcpu, 'cpuset': cpu})
+ vcpu += 1
+ else: # request cpu from vm resource pool
+ cpus = self.virt_pool.alloc_cpu(
+ self.vm_name, number=int(options['number']))
+ for cpu in cpus:
+ ET.SubElement(cputune, 'vcpupin', {
+ 'vcpu': '%d' % vcpu, 'cpuset': cpu})
+ vcpu += 1
+
+ def get_vm_cpu(self):
+ cpus = self.virt_pool.get_cpu_on_vm(self.vm_name)
+ return cpus
+
+ def add_vm_qga(self, options):
+ qemu = ET.SubElement(self.domain, 'qemu:commandline')
+ ET.SubElement(qemu, 'qemu:arg', {'value': '-chardev'})
+ ET.SubElement(qemu, 'qemu:arg',
+ {'value': 'socket,path=/tmp/' +
+ '%s_qga0.sock,' % self.vm_name +
+ 'server,nowait,id=%s_qga0' % self.vm_name})
+ ET.SubElement(qemu, 'qemu:arg', {'value': '-device'})
+ ET.SubElement(qemu, 'qemu:arg', {'value': 'virtio-serial'})
+ ET.SubElement(qemu, 'qemu:arg', {'value': '-device'})
+ ET.SubElement(qemu, 'qemu:arg',
+ {'value': 'virtserialport,' +
+ 'chardev=%s_qga0' % self.vm_name +
+ ',name=org.qemu.guest_agent.0'})
+ self.qga_sock_path = '/tmp/%s_qga0.sock' % self.vm_name
+
+ def set_vm_default(self):
+ os = ET.SubElement(self.domain, 'os')
+ type = ET.SubElement(
+ os, 'type', {'arch': 'x86_64', 'machine': 'pc-i440fx-1.6'})
+ type.text = 'hvm'
+ ET.SubElement(os, 'boot', {'dev': 'hd'})
+ features = ET.SubElement(self.domain, 'features')
+ ET.SubElement(features, 'acpi')
+ ET.SubElement(features, 'apic')
+ ET.SubElement(features, 'pae')
+
+ ET.SubElement(self.domain, 'cpu', {'mode': 'host-passthrough'})
+
+ # qemu-kvm for emulator
+ device = ET.SubElement(self.domain, 'devices')
+ ET.SubElement(device, 'emulator').text = self.qemu_emulator
+
+ # graphic device
+ ET.SubElement(device, 'graphics', {
+ 'type': 'vnc', 'port': '-1', 'autoport': 'yes'})
+ # qemu guest agent
+ self.add_vm_qga(None)
+
+ # add default control interface
+ if not self.__default_nic:
+ def_nic = {'type': 'nic', 'opt_hostfwd': '', 'opt_addr': '00:1f.0'}
+ self.add_vm_net(**def_nic)
+ self.__default_nic = True
+
+ def set_qemu_emulator(self, qemu_emulator_path):
+ """
+ Set the qemu emulator in the specified path explicitly.
+ """
+ out = self.host_session.send_expect(
+ 'ls %s' % qemu_emulator_path, '# ')
+ if 'No such file or directory' in out:
+ self.host_logger.error("No emulator [ %s ] on the DUT" %
+ (qemu_emulator_path))
+ return None
+ out = self.host_session.send_expect("[ -x %s ];echo $?" %
+ (qemu_emulator_path), '# ')
+ if out != '0':
+ self.host_logger.error("Emulator [ %s ] " % qemu_emulator_path +
+ "not executable on the DUT")
+ return None
+ self.qemu_emulator = qemu_emulator_path
+
+ def add_vm_qemu(self, **options):
+ """
+ Options:
+ path: absolute path for qemu emulator
+ """
+ if 'path' in options.keys():
+ self.set_qemu_emulator(options['path'])
+ # update emulator config
+ devices = self.domain.find('devices')
+ ET.SubElement(devices, 'emulator').text = self.qemu_emulator
+
+ def add_vm_disk(self, **options):
+ """
+ Options:
+ file: absolute path of disk image file
+ type: image file formats
+ """
+ devices = self.domain.find('devices')
+ disk = ET.SubElement(
+ devices, 'disk', {'type': 'file', 'device': 'disk'})
+
+ if 'file' not in options:
+ return False
+
+ ET.SubElement(disk, 'source', {'file': options['file']})
+ if 'type' not in options:
+ disk_type = 'raw'
+ else:
+ disk_type = options['type']
+
+ ET.SubElement(disk, 'driver', {'name': 'qemu', 'type': disk_type})
+
+ ET.SubElement(
+ disk, 'target', {'dev': 'vd%c' % self.diskindex, 'bus': 'virtio'})
+
+ self.diskindex = chr(ord(self.diskindex) + 1)
+
+ def add_vm_login(self, **options):
+ """
+ options:
+ user: login username of virtual machine
+ password: login password of virtual machine
+ """
+ if 'user' in options.keys():
+ user = options['user']
+ self.username = user
+
+ if 'password' in options.keys():
+ password = options['password']
+ self.password = password
+
+ def get_vm_login(self):
+ return (self.username, self.password)
+
+ def __parse_pci(self, pci_address):
+ pci_regex = r"([0-9a-fA-F]{1,2}):([0-9a-fA-F]{1,2})" + \
+ ".([0-9a-fA-F]{1,2})"
+ m = re.match(pci_regex, pci_address)
+ if m is None:
+ return None
+ bus = m.group(1)
+ slot = m.group(2)
+ func = m.group(3)
+
+ return (bus, slot, func)
+
+ def add_vm_device(self, **options):
+ """
+ options:
+ pf_idx: device index of pass-through device
+ guestpci: assigned pci address in vm
+ """
+ devices = self.domain.find('devices')
+ hostdevice = ET.SubElement(devices, 'hostdev', {
+ 'mode': 'subsystem', 'type': 'pci',
+ 'managed': 'yes'})
+
+ if 'pf_idx' not in options.keys():
+ print dts.RED("Missing device index for device option!!!")
+ return False
+
+ pf = int(options['pf_idx'])
+ if pf > len(self.host_dut.ports_info):
+ print dts.RED("PF device index over size!!!")
+ return False
+
+ pci_addr = self.host_dut.ports_info[pf]['pci']
+
+ pci = self.__parse_pci(pci_addr)
+ if pci is None:
+ return False
+ bus, slot, func = pci
+
+ source = ET.SubElement(hostdevice, 'source')
+ ET.SubElement(source, 'address', {
+ 'domain': '0x0', 'bus': '0x%s' % bus,
+ 'slot': '0x%s' % slot,
+ 'function': '0x%s' % func})
+ if 'guestpci' in options.keys():
+ pci = self.__parse_pci(options['guestpci'])
+ if pci is None:
+ return False
+ bus, slot, func = pci
+ ET.SubElement(hostdevice, 'address', {
+ 'type': 'pci', 'domain': '0x0', 'bus': '0x%s' % bus,
+ 'slot': '0x%s' % slot, 'function': '0x%s' % func})
+ # save host and guest pci address mapping
+ pci_map = {}
+ pci_map['hostpci'] = pci_addr
+ pci_map['guestpci'] = options['guestpci']
+ self.pci_maps.append(pci_map)
+ else:
+ print dts.RED('Host device pass-through need guestpci option!!!')
+
+ def add_vm_net(self, **options):
+ """
+ Options:
+ default: create e1000 netdev and redirect ssh port
+ """
+ if 'type' in options.keys():
+ if options['type'] == 'nic':
+ self.__add_vm_net_nic(**options)
+
+ def __add_vm_net_nic(self, **options):
+ """
+ type: nic
+ opt_model: ["e1000" | "virtio" | "i82551" | ...]
+ Default is e1000.
+ opt_addr: ''
+ note: PCI cards only.
+ """
+ if 'opt_model' in options.keys():
+ model = options['opt_model']
+ else:
+ model = 'e1000'
+
+ if 'opt_hostfwd' in options.keys():
+ port = self.virt_pool.alloc_port(self.vm_name)
+ if port is None:
+ return
+ dut_ip = self.host_dut.crb['IP']
+ self.vm_ip = '%s:%d' % (dut_ip, port)
+
+ qemu = ET.SubElement(self.domain, 'qemu:commandline')
+ ET.SubElement(qemu, 'qemu:arg', {'value': '-net'})
+ if 'opt_addr' in options.keys():
+ pci = self.__parse_pci(options['opt_addr'])
+ if pci is None:
+ return False
+ bus, slot, func = pci
+ ET.SubElement(qemu, 'qemu:arg',
+ {'value': 'nic,model=e1000,addr=0x%s' % slot})
+ else:
+ ET.SubElement(qemu, 'qemu:arg',
+ {'value': 'nic,model=e1000,addr=0x%x'
+ % self.pciindex})
+ self.pciindex += 1
+
+ if 'opt_hostfwd' in options.keys():
+ ET.SubElement(qemu, 'qemu:arg', {'value': '-net'})
+ ET.SubElement(qemu, 'qemu:arg', {'value': 'user,hostfwd='
+ 'tcp:%s:%d-:22' % (dut_ip, port)})
+
+ def add_vm_virtio_serial_channel(self, **options):
+ """
+ Options:
+ path: virtio unix socket absolute path
+ name: virtio serial name in vm
+ """
+ devices = self.domain.find('devices')
+ channel = ET.SubElement(devices, 'channel', {'type': 'unix'})
+ for opt in ['path', 'name']:
+ if opt not in options.keys():
+ print "invalid virtio serial channel setting"
+ return
+
+ ET.SubElement(
+ channel, 'source', {'mode': 'bind', 'path': options['path']})
+ ET.SubElement(
+ channel, 'target', {'type': 'virtio', 'name': options['name']})
+ ET.SubElement(channel, 'address', {'type': 'virtio-serial',
+ 'controller': '0', 'bus': '0',
+ 'port': '%d' % self.pciindex})
+ self.pciindex += 1
+
+ def get_vm_ip(self):
+ return self.vm_ip
+
+ def get_pci_mappings(self):
+ """
+ Return guest and host pci devices mapping structure
+ """
+ return self.pci_maps
+
+ def __control_session(self, command, *args):
+ """
+ Use the qemu guest agent service to control VM.
+ Note:
+ :command: there are these commands as below:
+ cat, fsfreeze, fstrim, halt, ifconfig, info,\
+ ping, powerdown, reboot, shutdown, suspend
+ :args: give different args by the different commands.
+ """
+ if not self.qga_sock_path:
+ self.host_logger.info(
+ "No QGA service between host [ %s ] and guest [ %s ]" %
+ (self.host_dut.Name, self.vm_name))
+ return None
+
+ cmd_head = '~/QMP/' + \
+ "qemu-ga-client " + \
+ "--address=%s %s" % \
+ (self.qga_sock_path, command)
+
+ cmd = cmd_head
+ for arg in args:
+ cmd = cmd_head + ' ' + str(arg)
+
+ if command is "ping":
+ out = self.host_session.send_expect(cmd, '# ', int(args[0]))
+ else:
+ out = self.host_session.send_expect(cmd, '# ')
+
+ return out
+
+ def _start_vm(self):
+ xml_file = "/tmp/%s.xml" % self.vm_name
+ try:
+ os.remove(xml_file)
+ except:
+ pass
+ self.root.write(xml_file)
+ self.host_session.copy_file_to(xml_file)
+ time.sleep(2)
+
+ self.host_session.send_expect("virsh", "virsh #")
+ self.host_session.send_expect(
+ "create /root/%s.xml" % self.vm_name, "virsh #")
+ self.host_session.send_expect("quit", "# ")
+ out = self.__control_session('ping', '120')
+
+ if "Not responded" in out:
+ raise StartVMFailedException("Not response in 120 seconds!!!")
+
+ self.__wait_vmnet_ready()
+
+ def __wait_vmnet_ready(self):
+ """
+ wait for 120 seconds for vm net ready
+ 10.0.2.* is the default ip address allocated by qemu
+ """
+ count = 20
+ while count:
+ out = self.__control_session('ifconfig')
+ if "10.0.2" in out:
+ return True
+ time.sleep(6)
+ count -= 1
+
+ raise StartVMFailedException("Virtual machine control net not ready " +
+ "in 120 seconds!!!")
+
+ def stop(self):
+ self.__control_session("shutdown")
+ time.sleep(5)
diff --git a/framework/settings.py b/framework/settings.py
index feb6fa5..631bd32 100644
--- a/framework/settings.py
+++ b/framework/settings.py
@@ -31,10 +31,16 @@
"""
Folders for framework running enviornment.
"""
+import re
+import socket
+import dts
+
FOLDERS = {
'Framework': 'framework',
'Testscripts': 'tests',
'Configuration': 'conf',
+ 'Depends': 'dep',
+ 'Output': 'output',
}
"""
@@ -48,6 +54,7 @@ NICS = {
'powerville': '8086:1521',
'ophir': '8086:105e',
'niantic': '8086:10fb',
+ 'niantic_vf': '8086:10ed',
'ironpond': '8086:151c',
'twinpond': '8086:1528',
'twinville': '8086:1512',
@@ -77,6 +84,7 @@ DRIVERS = {
'powerville': 'igb',
'ophir': 'igb',
'niantic': 'ixgbe',
+ 'niantic_vf': 'ixgbevf',
'ironpond': 'ixgbe',
'twinpond': 'ixgbe',
'twinville': 'ixgbe',
@@ -85,7 +93,7 @@ DRIVERS = {
'82540EM': 'igb',
'springville': 'igb',
'springfountain': 'ixgbe',
- 'virtio': 'igb',
+ 'virtio': 'virtio-pci',
'avoton': 'igb',
'avoton2c5': 'igb',
'I217V': 'igb',
@@ -122,7 +130,8 @@ HEADER_SIZE = {
'ip': 20,
'ipv6': 40,
'udp': 8,
- 'tcp': 20
+ 'tcp': 20,
+ 'vxlan': 8,
}
@@ -137,6 +146,17 @@ Global macro for dts.
"""
IXIA = "ixia"
+"""
+The root path of framework configs.
+"""
+CONFIG_ROOT_PATH = "./conf/"
+
+"""
+The log name seperater.
+"""
+LOG_NAME_SEP = '.'
+
+
def nic_name_from_type(type):
"""
strip nic code name by nic type
@@ -145,3 +165,57 @@ def nic_name_from_type(type):
if nic_type == type:
return name
return 'Unknown'
+
+
+def get_nic_driver(pci_id):
+ """
+ Return linux driver for specified pci device
+ """
+ driverlist = dict(zip(NICS.values(), DRIVERS.keys()))
+ try:
+ driver = DRIVERS[driverlist[pci_id]]
+ except Exception as e:
+ driver = None
+ return driver
+
+
+def accepted_nic(pci_id):
+ """
+ Return True if the pci_id is a known NIC card in the settings file and if
+ it is selected in the execution file, otherwise it returns False.
+ """
+ if pci_id not in NICS.values():
+ return False
+
+ if dts.nic is 'any':
+ return True
+
+ else:
+ if pci_id == NICS[dts.nic]:
+ return True
+
+ return False
+
+def get_netdev(crb, pci):
+ for port in crb.ports_info:
+ if pci == port['pci']:
+ return port['port']
+ if 'vfs_port' in port.keys():
+ for vf in port['vfs_port']:
+ if pci == vf.pci:
+ return vf
+
+ return None
+
+def get_host_ip(address):
+ ip_reg = r'\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}'
+ m = re.match(ip_reg, address)
+ if m:
+ return address
+ else:
+ try:
+ result=socket.gethostbyaddr(address)
+ return result[2][0]
+ except:
+ print "couldn't look up %s" % address
+ return ''
diff --git a/framework/ssh_connection.py b/framework/ssh_connection.py
index 18a6517..63b8785 100644
--- a/framework/ssh_connection.py
+++ b/framework/ssh_connection.py
@@ -53,7 +53,6 @@ class SSHConnection(object):
def init_log(self, logger):
self.logger = logger
- self.logger.config_execution(self.name)
self.session.init_log(logger, self.name)
def send_expect(self, cmds, expected, timeout=15, verify=False):
@@ -62,8 +61,19 @@ class SSHConnection(object):
self.logger.debug(out)
return out
+ def get_session_before(self, timeout=15):
+ out = self.session.get_session_before(timeout)
+ self.logger.debug(out)
+ return out
+
def close(self):
self.session.close()
+ connection = {}
+ connection[self.name] = self.session
+ try:
+ CONNECTIONS.remove(connection)
+ except:
+ pass
def isalive(self):
return self.session.isalive()
diff --git a/framework/ssh_pexpect.py b/framework/ssh_pexpect.py
index 735df44..2951cf3 100644
--- a/framework/ssh_pexpect.py
+++ b/framework/ssh_pexpect.py
@@ -2,7 +2,8 @@ import time
import pexpect
import pxssh
from debugger import ignore_keyintr, aware_keyintr
-from exception import TimeoutException, SSHConnectionException
+from exception import TimeoutException, SSHConnectionException, SSHSessionDeadException
+from utils import RED, GREEN
"""
Module handle ssh sessions between tester and DUT.
@@ -14,24 +15,36 @@ Aslo support transfer files to tester or DUT.
class SSHPexpect(object):
def __init__(self, host, username, password):
- self.magic_prompt = "[MAGIC PROMPT]"
+ self.magic_prompt = "MAGIC PROMPT"
try:
self.session = pxssh.pxssh()
- self.username = username
self.host = host
+ self.username = username
self.password = password
- self.session.login(self.host, self.username,
- self.password, original_prompt='[$#>]')
+ if ':' in host:
+ self.ip = host.split(':')[0]
+ self.port = int(host.split(':')[1])
+ self.session.login(self.ip, self.username,
+ self.password, original_prompt='[$#>]',
+ port=self.port, login_timeout=20)
+ else:
+ self.session.login(self.host, self.username,
+ self.password, original_prompt='[$#>]')
self.send_expect('stty -echo', '# ', timeout=2)
- except Exception:
+ except Exception, e:
+ print RED(e)
+ if getattr(self, 'port', None):
+ suggestion = "\nSuggession: Check if the fireware on [ %s ] " % \
+ self.ip + "is stoped\n"
+ print GREEN(suggestion)
+
raise SSHConnectionException(host)
def init_log(self, logger, name):
self.logger = logger
- self.logger.config_execution(name)
self.logger.info("ssh %s@%s" % (self.username, self.host))
- def send_expect_base(self, command, expected, timeout=15):
+ def send_expect_base(self, command, expected, timeout):
ignore_keyintr()
self.__flush() # clear buffer
self.session.PROMPT = expected
@@ -45,30 +58,54 @@ class SSHPexpect(object):
def send_expect(self, command, expected, timeout=15, verify=False):
ret = self.send_expect_base(command, expected, timeout)
if verify:
- ret_status = self.send_expect_base("echo $?", expected)
+ ret_status = self.send_expect_base("echo $?", expected, timeout)
if not int(ret_status):
return ret
else:
self.logger.error("Command: %s failure!" % command)
- return -1
+ self.logger.error(ret)
+ return int(ret_status)
else:
return ret
- def __flush(self):
+ def get_session_before(self, timeout=15):
+ """
+ Get all output before timeout
+ """
+ ignore_keyintr()
self.session.PROMPT = self.magic_prompt
- self.session.prompt(0.1)
+ try:
+ self.session.prompt(timeout)
+ except Exception as e:
+ pass
+
+ aware_keyintr()
+ before = self.get_output_before()
+ self.__flush()
+ return before
+
+ def __flush(self):
+ """
+ Clear all session buffer
+ """
+ self.session.buffer = ""
+ self.session.before = ""
def __prompt(self, command, timeout):
if not self.session.prompt(timeout):
raise TimeoutException(command, self.get_output_all())
def __sendline(self, command):
+ if not self.isalive():
+ raise SSHSessionDeadException(self.host)
if len(command) == 2 and command.startswith('^'):
self.session.sendcontrol(command[1])
else:
self.session.sendline(command)
def get_output_before(self):
+ if not self.isalive():
+ raise SSHSessionDeadException(self.host)
self.session.flush()
before = self.session.before.rsplit('\r\n', 1)
if before[0] == "[PEXPECT]":
@@ -104,6 +141,12 @@ class SSHPexpect(object):
Sends a local file to a remote place.
"""
command = 'scp {0} {1}@{2}:{3}'.format(src, self.username, self.host, dst)
+ if ':' in self.host:
+ command = 'scp -P {0} -o NoHostAuthenticationForLocalhost=yes {1} {2}@{3}:{4}'.format(
+ str(self.port), src, self.username, self.ip, dst)
+ else:
+ command = 'scp {0} {1}@{2}:{3}'.format(
+ src, self.username, self.host, dst)
if password == '':
self._spawn_scp(command, self.password)
else:
diff --git a/framework/test_case.py b/framework/test_case.py
index 3d2e2dc..5013123 100644
--- a/framework/test_case.py
+++ b/framework/test_case.py
@@ -40,15 +40,19 @@ from settings import DRIVERS, NICS, nic_name_from_type
class TestCase(object):
- def __init__(self, dut, tester, target):
+ def __init__(self, dut, tester, target, suite):
self.dut = dut
self.tester = tester
self.target = target
+ self.suite = suite
self.nics = []
for portid in range(len(self.dut.ports_info)):
nic_type = self.dut.ports_info[portid]['type']
self.nics.append(nic_name_from_type(nic_type))
- self.nic = self.nics[0]
+ if len(self.nics):
+ self.nic = self.nics[0]
+ else:
+ self.nic = ''
def set_up_all(self):
pass
diff --git a/framework/test_result.py b/framework/test_result.py
index 79faee1..9cef34c 100644
--- a/framework/test_result.py
+++ b/framework/test_result.py
@@ -157,6 +157,12 @@ class Result(object):
"""
self.__set_test_case_result(result='PASSED', message='')
+ def test_case_skip(self,message):
+ """
+ set last test case add as N/A
+ """
+ self.__set_test_case_result(result='N/A', message=message)
+
def test_case_failed(self, message):
"""
Set last test case added as FAILED
diff --git a/framework/tester.py b/framework/tester.py
index aba0356..de0bc24 100644
--- a/framework/tester.py
+++ b/framework/tester.py
@@ -38,6 +38,7 @@ from time import sleep
from settings import NICS
from ssh_connection import SSHConnection
from crb import Crb
+from net_device import NetDevice
from etgen import IxiaPacketGenerator, SoftwarePacketGenerator
from logger import getLogger
from settings import IXIA
@@ -64,7 +65,8 @@ class Tester(Crb):
self.NAME, self.get_password())
self.session.init_log(self.logger)
self.alt_session = SSHConnection(self.get_ip_address(),
- self.NAME + '_alt', self.get_password())
+ self.NAME + '_alt',
+ self.get_password())
self.alt_session.init_log(self.logger)
self.bgProcIsRunning = False
@@ -152,6 +154,7 @@ class Tester(Crb):
index += 1
if pci == port['pci']:
return index
+ return -1
def get_pci(self, localPort):
"""
@@ -163,6 +166,9 @@ class Tester(Crb):
"""
Return tester local port interface name.
"""
+ if 'intf' not in self.ports_info[localPort]:
+ return 'N/A'
+
return self.ports_info[localPort]['intf']
def get_mac(self, localPort):
@@ -194,6 +200,9 @@ class Tester(Crb):
"""
Restore Linux interfaces.
"""
+ if self.skip_setup:
+ return
+
self.send_expect("modprobe igb", "# ", 20)
self.send_expect("modprobe ixgbe", "# ", 20)
self.send_expect("modprobe e1000e", "# ", 20)
@@ -202,26 +211,66 @@ class Tester(Crb):
try:
for (pci_bus, pci_id) in self.pci_devices_info:
addr_array = pci_bus.split(':')
- itf = self.get_interface_name(addr_array[0], addr_array[1])
+ port = NetDevice(self, addr_array[0], addr_array[1])
+ itf = port.get_interface_name()
+ self.enable_ipv6(itf)
self.send_expect("ifconfig %s up" % itf, "# ")
except Exception as e:
self.logger.error(" !!! Restore ITF: " + e.message)
+ sleep(2)
+
+ def load_serializer_ports(self):
+ cached_ports_info = self.serializer.load(self.PORT_INFO_CACHE_KEY)
+ if cached_ports_info is None:
+ return
+
+ # now not save netdev object, will implemented later
+ self.ports_info = cached_ports_info
+
+ def save_serializer_ports(self):
+ cached_ports_info = []
+ for port in self.ports_info:
+ port_info = {}
+ for key in port.keys():
+ if type(port[key]) is str:
+ port_info[key] = port[key]
+ # need save netdev objects
+ cached_ports_info.append(port_info)
+ self.serializer.save(self.PORT_INFO_CACHE_KEY, cached_ports_info)
+
def scan_ports(self):
"""
Scan all ports on tester and save port's pci/mac/interface.
"""
if self.read_cache:
- self.ports_info = self.serializer.load(self.PORT_INFO_CACHE_KEY)
+ self.load_serializer_ports()
+ self.scan_ports_cached()
if not self.read_cache or self.ports_info is None:
self.scan_ports_uncached()
if self.it_uses_external_generator():
self.ports_info.extend(self.ixia_packet_gen.get_ports())
- self.serializer.save(self.PORT_INFO_CACHE_KEY, self.ports_info)
+ self.save_serializer_ports()
+
+ for port_info in self.ports_info:
+ self.logger.info(port_info)
- self.logger.info(self.ports_info)
+ def scan_ports_cached(self):
+ if self.ports_info is None:
+ return
+
+ for port_info in self.ports_info:
+ if port_info['type'] == 'ixia':
+ continue
+
+ port = NetDevice(self, port_info['pci'], port_info['type'])
+ intf = port.get_interface_name()
+
+ self.logger.info("Tester cached: [000:%s %s] %s" % (
+ port_info['pci'], port_info['type'], intf))
+ port_info['port'] = port
def scan_ports_uncached(self):
"""
@@ -240,7 +289,8 @@ class Tester(Crb):
bus_id = addr_array[0]
devfun_id = addr_array[1]
- intf = self.get_interface_name(bus_id, devfun_id)
+ port = NetDevice(self, bus_id, devfun_id)
+ intf = port.get_interface_name()
if "No such file" in intf:
self.logger.info("Tester: [000:%s %s] %s" % (pci_bus, pci_id,
@@ -248,13 +298,17 @@ class Tester(Crb):
continue
self.logger.info("Tester: [000:%s %s] %s" % (pci_bus, pci_id, intf))
- macaddr = self.get_mac_addr(intf, bus_id, devfun_id)
+ macaddr = port.get_mac_addr()
+
+ ipv6 = port.get_ipv6_addr()
# store the port info to port mapping
- self.ports_info.append({'pci': pci_bus,
+ self.ports_info.append({'port': port,
+ 'pci': pci_bus,
'type': pci_id,
'intf': intf,
- 'mac': macaddr})
+ 'mac': macaddr,
+ 'ipv6': ipv6})
def send_ping6(self, localPort, ipv6, mac):
"""
@@ -413,6 +467,18 @@ class Tester(Crb):
"""
Close ssh session and IXIA tcl session.
"""
- super(Tester, self).close()
+ if self.session:
+ self.session.close()
+ self.session = None
+ if self.alt_session:
+ self.alt_session.close()
+ self.alt_session = None
if self.it_uses_external_generator():
self.ixia_packet_gen.close()
+
+ def crb_exit(self):
+ """
+ Close all resource before crb exit
+ """
+ self.logger.logger_exit()
+ self.close()
diff --git a/framework/utils.py b/framework/utils.py
new file mode 100644
index 0000000..dd45e9e
--- /dev/null
+++ b/framework/utils.py
@@ -0,0 +1,100 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import json # json format
+import re
+
+
+def RED(text):
+ return "\x1B[" + "31;1m" + str(text) + "\x1B[" + "0m"
+
+
+def BLUE(text):
+ return "\x1B[" + "36;1m" + str(text) + "\x1B[" + "0m"
+
+
+def GREEN(text):
+ return "\x1B[" + "32;1m" + str(text) + "\x1B[" + "0m"
+
+
+def pprint(some_dict):
+ """
+ Print JSON format dictionary object.
+ """
+ return json.dumps(some_dict, sort_keys=True, indent=4)
+
+
+def regexp(s, to_match, allString=False):
+ """
+ Ensure that the re `to_match' only has one group in it.
+ """
+
+ scanner = re.compile(to_match, re.DOTALL)
+ if allString:
+ return scanner.findall(s)
+ m = scanner.search(s)
+ if m is None:
+ print RED("Failed to match " + to_match + " in the string " + s)
+ return None
+ return m.group(1)
+
+
+def get_obj_funcs(obj, func_name_regex):
+ """
+ Return function list which name matched regex.
+ """
+ for func_name in dir(obj):
+ func = getattr(obj, func_name)
+ if callable(func) and re.match(func_name_regex, func.__name__):
+ yield func
+
+
+def remove_old_rsa_key(crb, ip):
+ """
+ Remove the old RSA key of specified IP on crb.
+ """
+ if ':' not in ip:
+ ip = ip.strip()
+ port = ''
+ else:
+ addr = ip.split(':')
+ ip = addr[0].strip()
+ port = addr[1].strip()
+
+ rsa_key_path = "~/.ssh/known_hosts"
+ if port:
+ remove_rsa_key_cmd = "sed -i '/^\[%s\]:%d/d' %s" % \
+ (ip.strip(), int(
+ port), rsa_key_path)
+ else:
+ remove_rsa_key_cmd = "sed -i '/^%s/d' %s" % \
+ (ip.strip(), rsa_key_path)
+ crb.send_expect(remove_rsa_key_cmd, "# ")
diff --git a/framework/virt_base.py b/framework/virt_base.py
new file mode 100644
index 0000000..16e6d24
--- /dev/null
+++ b/framework/virt_base.py
@@ -0,0 +1,368 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import sys
+import traceback
+from random import randint
+from itertools import imap
+
+import dts
+import exception
+from dut import Dut
+from config import VirtConf
+from config import VIRTCONF
+from logger import getLogger
+from settings import CONFIG_ROOT_PATH
+from virt_dut import VirtDut
+from utils import remove_old_rsa_key
+
+
+class VirtBase(object):
+ """
+ Basic module for customer special virtual type. This module implement
+ functions configurated and composed the VM boot command. With these
+ function, we can get and set the VM boot command, and instantiate the VM.
+ """
+
+ def __init__(self, dut, vm_name, suite_name):
+ """
+ Initialize the VirtBase.
+ dut: the instance of Dut
+ vm_name: the name of VM which you have confiured in the configure
+ suite_name: the name of test suite
+ """
+ self.host_dut = dut
+ self.vm_name = vm_name
+ self.suite = suite_name
+
+ # init the host session and logger for VM
+ self.host_dut.init_host_session()
+
+ # replace dut session
+ self.host_session = self.host_dut.host_session
+ self.host_logger = self.host_dut.logger
+ # base_dir existed for host dut has prepared it
+ self.host_session.send_expect("cd %s" % self.host_dut.base_dir, "# ")
+
+ # init the host resouce pool for VM
+ self.virt_pool = self.host_dut.virt_pool
+
+ if not self.has_virtual_ability():
+ if not self.enable_virtual_ability():
+ raise Exception(
+ "Dut [ %s ] cannot have the virtual ability!!!")
+
+ self.virt_type = self.get_virt_type()
+
+ self.params = []
+
+ # default call back function is None
+ self.callback = None
+
+ def get_virt_type(self):
+ """
+ Get the virtual type, such as KVM, XEN or LIBVIRT.
+ """
+ NotImplemented
+
+ def has_virtual_ability(self):
+ """
+ Check if the host have the ability of virtualization.
+ """
+ NotImplemented
+
+ def enable_virtual_ability(self):
+ """
+ Enalbe the virtual ability on the DUT.
+ """
+ NotImplemented
+
+ def load_global_config(self):
+ """
+ Load global configure in the path DTS_ROOT_PAHT/conf.
+ """
+ conf = VirtConf(VIRTCONF)
+ conf.load_virt_config(self.virt_type)
+ global_conf = conf.get_virt_config()
+ for param in global_conf:
+ for key in param.keys():
+ if self.find_option_index(key) is None:
+ self.__save_local_config(key, param[key])
+
+ def load_local_config(self, suite_name):
+ """
+ Load local configure in the path DTS_ROOT_PATH/conf.
+ """
+ # load local configuration by suite and vm name
+ conf = VirtConf(CONFIG_ROOT_PATH + suite_name + '.cfg')
+ conf.load_virt_config(self.vm_name)
+ local_conf = conf.get_virt_config()
+ # replace global configurations with local configurations
+ for param in local_conf:
+ if 'mem' in param.keys():
+ self.__save_local_config('mem', param['mem'])
+ continue
+ if 'cpu' in param.keys():
+ self.__save_local_config('cpu', param['cpu'])
+ continue
+ # save local configurations
+ for key in param.keys():
+ self.__save_local_config(key, param[key])
+
+ def __save_local_config(self, key, value):
+ """
+ Save the local config into the global dict self.param.
+ """
+ for param in self.params:
+ if key in param.keys():
+ param[key] = value
+ return
+
+ self.params.append({key: value})
+
+ def compose_boot_param(self):
+ """
+ Compose all boot param for starting the VM.
+ """
+ for param in self.params:
+ key = param.keys()[0]
+ value = param[key]
+ try:
+ param_func = getattr(self, 'add_vm_' + key)
+ if callable(param_func):
+ for option in value:
+ param_func(**option)
+ else:
+ print dts.RED("Virt %s function not callable!!!" % key)
+ except AttributeError:
+ print dts.RED("Virt %s function not implemented!!!" % key)
+ except Exception:
+ raise exception.VirtConfigParamException(key)
+
+ def find_option_index(self, option):
+ """
+ Find the boot option in the params which is generated from
+ the global and local configures, and this function will
+ return the index by which option can be indexed in the
+ param list.
+ """
+ index = 0
+ for param in self.params:
+ key = param.keys()[0]
+ if key.strip() == option.strip():
+ return index
+ index += 1
+
+ return None
+
+ def generate_unique_mac(self):
+ """
+ Generate a unique MAC based on the DUT.
+ """
+ mac_head = '00:00:00:'
+ mac_tail = ':'.join(
+ ['%02x' % x for x in imap(lambda x:randint(0, 255), range(3))])
+ return mac_head + mac_tail
+
+ def get_vm_ip(self):
+ """
+ Get the VM IP.
+ """
+ NotImplemented
+
+ def get_pci_mappings(self):
+ """
+ Get host and VM pass-through device mapping
+ """
+ NotImplemented
+
+ def isalive(self):
+ """
+ Check whether VM existed.
+ """
+ vm_status = self.host_session.send_expect(
+ "ps aux | grep qemu | grep 'name %s '| grep -v grep"
+ % self.vm_name, "# ")
+
+ if self.vm_name in vm_status:
+ return True
+ else:
+ return False
+
+ def load_config(self):
+ """
+ Load configurations for VM
+ """
+ # load global and suite configuration file
+ self.load_global_config()
+ self.load_local_config(self.suite)
+
+ def start(self, load_config=True, set_target=True, auto_portmap=True, bind_dev=True):
+ """
+ Start VM and instantiate the VM with VirtDut.
+ """
+ try:
+ if load_config is True:
+ self.load_config()
+ # compose boot command for different hypervisors
+ self.compose_boot_param()
+
+ # start virutal machine
+ self._start_vm()
+
+ # connect vm dut and init running environment
+ vm_dut = self.instantiate_vm_dut(set_target, auto_portmap)
+ except Exception as vm_except:
+ if self.handle_exception(vm_except):
+ print dts.RED("Handled expection " + str(type(vm_except)))
+ else:
+ print dts.RED("Unhandled expection " + str(type(vm_except)))
+
+ if callable(self.callback):
+ self.callback()
+
+ return None
+ return vm_dut
+
+ def handle_exception(self, vm_except):
+ # show exception back trace
+ exc_type, exc_value, exc_traceback = sys.exc_info()
+ traceback.print_exception(exc_type, exc_value, exc_traceback,
+ limit=2, file=sys.stdout)
+ if type(vm_except) is exception.ConfigParseException:
+ # nothing to handle just return True
+ return True
+ elif type(vm_except) is exception.VirtConfigParseException:
+ # nothing to handle just return True
+ return True
+ elif type(vm_except) is exception.VirtConfigParamException:
+ # nothing to handle just return True
+ return True
+ elif type(vm_except) is exception.StartVMFailedException:
+ # start vm failure
+ return True
+ elif type(vm_except) is exception.VirtDutConnectException:
+ # need stop vm
+ self._stop_vm()
+ return True
+ elif type(vm_except) is exception.VirtDutInitException:
+ # need close session
+ vm_except.vm_dut.close()
+ # need stop vm
+ self.stop()
+ return True
+ else:
+ return False
+
+ def _start_vm(self):
+ """
+ Start VM.
+ """
+ NotImplemented
+
+ def _stop_vm(self):
+ """
+ Stop VM.
+ """
+ NotImplemented
+
+ def instantiate_vm_dut(self, set_target=True, auto_portmap=True, bind_dev=True):
+ """
+ Instantiate the Dut class for VM.
+ """
+ crb = self.host_dut.crb.copy()
+ crb['bypass core0'] = False
+ vm_ip = self.get_vm_ip()
+ crb['IP'] = vm_ip
+ username, password = self.get_vm_login()
+ crb['user'] = username
+ crb['pass'] = password
+
+ # remove default key
+ remove_old_rsa_key(self.host_dut.tester, crb['IP'])
+
+ serializer = self.host_dut.serializer
+
+ try:
+ vm_dut = VirtDut(
+ self,
+ crb,
+ serializer,
+ self.virt_type,
+ self.vm_name,
+ self.suite)
+ except:
+ raise exception.VirtDutConnectException
+ return None
+
+ vm_dut.nic_type = 'any'
+ vm_dut.tester = self.host_dut.tester
+ vm_dut.host_dut = self.host_dut
+ vm_dut.host_session = self.host_session
+ vm_dut.init_log()
+
+ read_cache = False
+ skip_setup = self.host_dut.skip_setup
+ base_dir = self.host_dut.base_dir
+ vm_dut.set_speedup_options(read_cache, skip_setup)
+ func_only = self.host_dut.want_func_tests
+ perf_only = self.host_dut.want_perf_tests
+ vm_dut.set_test_types(func_tests=func_only, perf_tests=perf_only)
+ # base_dir should be set before prerequisites
+ vm_dut.set_directory(base_dir)
+
+ try:
+ # setting up dpdk in vm, must call at last
+ vm_dut.prerequisites(dts.Package, dts.Patches, auto_portmap)
+ if set_target:
+ target = self.host_dut.target
+ vm_dut.set_target(target, bind_dev)
+ except:
+ raise exception.VirtDutInitException(vm_dut)
+ return None
+
+ self.vm_dut = vm_dut
+ return vm_dut
+
+ def stop(self):
+ """
+ Stop the VM.
+ """
+ self.vm_dut.close()
+ self.vm_dut.logger.logger_exit()
+ self.vm_dut = None
+ self._stop_vm()
+ self.virt_pool.free_all_resource(self.vm_name)
+
+ def register_exit_callback(self, callback):
+ """
+ Call register exit call back function
+ """
+ self.callback = callback
diff --git a/framework/virt_dut.py b/framework/virt_dut.py
new file mode 100644
index 0000000..9404be6
--- /dev/null
+++ b/framework/virt_dut.py
@@ -0,0 +1,344 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import re
+import time
+import dts
+import settings
+from config import PortConf
+from settings import NICS, LOG_NAME_SEP, get_netdev
+from ssh_connection import SSHConnection
+from project_dpdk import DPDKdut
+from dut import Dut
+from net_device import NetDevice
+from logger import getLogger
+
+
+class VirtDut(DPDKdut):
+
+ """
+ A connection to the CRB under test.
+ This class sends commands to the CRB and validates the responses. It is
+ implemented using either ssh for linuxapp or the terminal server for
+ baremetal.
+ All operations are in fact delegated to an instance of either CRBLinuxApp
+ or CRBBareMetal.
+ """
+
+ def __init__(self, hyper, crb, serializer, virttype, vm_name, suite):
+ self.vm_name = vm_name
+ self.hyper = hyper
+ super(Dut, self).__init__(crb, serializer)
+ self.vm_ip = self.get_ip_address()
+ self.NAME = 'virtdut' + LOG_NAME_SEP + '%s' % self.vm_ip
+ # load port config from suite cfg
+ self.suite = suite
+ self.logger = getLogger(self.NAME)
+ self.session = SSHConnection(self.vm_ip, self.NAME,
+ self.get_password())
+ self.session.init_log(self.logger)
+
+ # if redirect ssh port, there's only one session enabled
+ self.alt_session = SSHConnection(self.vm_ip, self.NAME + '_alt',
+ self.get_password())
+ self.alt_session.init_log(self.logger)
+
+ self.number_of_cores = 0
+ self.tester = None
+ self.cores = []
+ self.architecture = None
+ self.ports_info = None
+ self.ports_map = []
+ self.virttype = virttype
+
+ def init_log(self):
+ self.logger.config_suite(self.host_dut.test_classname, 'virtdut')
+
+ def close(self):
+ if self.session:
+ self.session.close()
+ if self.alt_session:
+ self.alt_session.close()
+
+ def set_nic_type(self, nic_type):
+ """
+ Set CRB NICS ready to validated.
+ """
+ self.nic_type = nic_type
+ # vm_dut config will load from vm configuration file
+
+ def load_portconf(self):
+ """
+ Load port config for this virtual machine
+ """
+ self.conf = PortConf()
+ self.conf.load_ports_config(self.vm_name)
+ self.ports_cfg = self.conf.get_ports_config()
+
+ return
+
+ def create_portmap(self):
+ port_num = len(self.ports_info)
+ self.ports_map = [-1] * port_num
+ for key in self.ports_cfg.keys():
+ index = int(key)
+ if index >= port_num:
+ print dts.RED("Can not found [%d ]port info" % index)
+ continue
+
+ if 'peer' in self.ports_cfg[key].keys():
+ tester_pci = self.ports_cfg[key]['peer']
+ # find tester_pci index
+ pci_idx = self.tester.get_local_index(tester_pci)
+ self.ports_map[index] = pci_idx
+
+ def set_target(self, target, bind_dev=True):
+ """
+ Set env variable, these have to be setup all the time. Some tests
+ need to compile example apps by themselves and will fail otherwise.
+ Set hugepage on DUT and install modules required by DPDK.
+ Configure default ixgbe PMD function.
+ """
+ self.set_toolchain(target)
+
+ # set env variable
+ # These have to be setup all the time. Some tests need to compile
+ # example apps by themselves and will fail otherwise.
+ self.send_expect("export RTE_TARGET=" + target, "#")
+ self.send_expect("export RTE_SDK=`pwd`", "#")
+
+ if not self.skip_setup:
+ self.build_install_dpdk(target)
+
+ self.setup_memory(hugepages=512)
+ self.setup_modules(target)
+
+ if bind_dev:
+ self.bind_interfaces_linux('igb_uio')
+
+ def prerequisites(self, pkgName, patch, auto_portmap):
+ """
+ Prerequest function should be called before execute any test case.
+ Will call function to scan all lcore's information which on DUT.
+ Then call pci scan function to collect nic device information.
+ At last setup DUT' environment for validation.
+ """
+ if not self.skip_setup:
+ self.prepare_package(pkgName, patch)
+
+ self.send_expect("cd %s" % self.base_dir, "# ")
+ self.send_expect("alias ls='ls --color=none'", "#")
+
+ if self.get_os_type() == 'freebsd':
+ self.send_expect('alias make=gmake', '# ')
+ self.send_expect('alias sed=gsed', '# ')
+
+ self.init_core_list()
+ self.pci_devices_information()
+
+ # scan ports before restore interface
+ self.scan_ports()
+ # restore dut ports to kernel
+ if self.virttype != 'XEN':
+ self.restore_interfaces()
+ else:
+ self.restore_interfaces_domu()
+ # rescan ports after interface up
+ self.rescan_ports()
+
+ # no need to rescan ports for guest os just bootup
+ # load port infor from config file
+ if auto_portmap is False:
+ self.load_portconf()
+
+ # enable tester port ipv6
+ self.host_dut.enable_tester_ipv6()
+ self.mount_procfs()
+
+ if auto_portmap:
+ # auto detect network topology
+ self.map_available_ports()
+ else:
+ self.create_portmap()
+
+ # disable tester port ipv6
+ self.host_dut.disable_tester_ipv6()
+
+ # print latest ports_info
+ for port_info in self.ports_info:
+ self.logger.info(port_info)
+
+ def init_core_list(self):
+ self.cores = []
+ cpuinfo = self.send_expect("grep --color=never \"processor\""
+ " /proc/cpuinfo", "#", alt_session=False)
+ cpuinfo = cpuinfo.split('\r\n')
+ for line in cpuinfo:
+ m = re.search("processor\t: (\d+)", line)
+ if m:
+ thread = m.group(1)
+ socket = 0
+ core = thread
+ self.cores.append(
+ {'thread': thread, 'socket': socket, 'core': core})
+
+ self.number_of_cores = len(self.cores)
+
+ def restore_interfaces_domu(self):
+ """
+ Restore Linux interfaces.
+ """
+ for port in self.ports_info:
+ pci_bus = port['pci']
+ pci_id = port['type']
+ driver = settings.get_nic_driver(pci_id)
+ if driver is not None:
+ addr_array = pci_bus.split(':')
+ bus_id = addr_array[0]
+ devfun_id = addr_array[1]
+ port = NetDevice(self, bus_id, devfun_id)
+ itf = port.get_interface_name()
+ self.send_expect("ifconfig %s up" % itf, "# ")
+ time.sleep(30)
+ print self.send_expect("ip link ls %s" % itf, "# ")
+ else:
+ self.logger.info(
+ "NOT FOUND DRIVER FOR PORT (%s|%s)!!!" % (pci_bus, pci_id))
+
+ def pci_devices_information(self):
+ self.pci_devices_information_uncached()
+
+ def get_memory_channels(self):
+ """
+ Virtual machine has no memory channel concept, so always return 1
+ """
+ return 1
+
+ def check_ports_available(self, pci_bus, pci_id):
+ """
+ Check that whether auto scanned ports ready to use
+ """
+ pci_addr = "%s:%s" % (pci_bus, pci_id)
+ if pci_id == "8086:100e":
+ return False
+ return True
+ # load vm port conf need another function
+ # need add vitrual function device into NICS
+
+ def scan_ports(self):
+ """
+ Scan ports information, for vm will always scan
+ """
+ self.scan_ports_uncached()
+
+ def scan_ports_uncached(self):
+ """
+ Scan ports and collect port's pci id, mac adress, ipv6 address.
+ """
+ scan_ports_uncached = getattr(
+ self, 'scan_ports_uncached_%s' % self.get_os_type())
+ return scan_ports_uncached()
+
+ def map_available_ports(self):
+ """
+ Load or generate network connection mapping list.
+ """
+ self.map_available_ports_uncached()
+ self.logger.warning("VM DUT PORT MAP: " + str(self.ports_map))
+
+ def map_available_ports_uncached(self):
+ """
+ Generate network connection mapping list.
+ """
+ nrPorts = len(self.ports_info)
+ if nrPorts == 0:
+ return
+
+ remove = []
+ self.ports_map = [-1] * nrPorts
+
+ hits = [False] * len(self.tester.ports_info)
+
+ for vmPort in range(nrPorts):
+ vmpci = self.ports_info[vmPort]['pci']
+ peer = self.get_peer_pci(vmPort)
+ # if peer pci configured
+ if peer is not None:
+ for remotePort in range(len(self.tester.ports_info)):
+ if self.tester.ports_info[remotePort]['pci'] == peer:
+ hits[remotePort] = True
+ self.ports_map[vmPort] = remotePort
+ break
+ if self.ports_map[vmPort] == -1:
+ self.logger.error("CONFIGURED TESTER PORT CANNOT FOUND!!!")
+ else:
+ continue # skip ping6 map
+
+ # strip pci address on host for pass-through device
+ hostpci = 'N/A'
+ for pci_map in self.hyper.pci_maps:
+ if vmpci == pci_map['guestpci']:
+ hostpci = pci_map['hostpci']
+ break
+
+ # auto ping port map
+ for remotePort in range(len(self.tester.ports_info)):
+ # for two vfs connected to same tester port
+ # need skip ping from devices on same pf device
+ remotepci = self.tester.ports_info[remotePort]['pci']
+ port_type = self.tester.ports_info[remotePort]['type']
+ # IXIA port should not check whether has vfs
+ if port_type != 'ixia':
+ remoteport = self.tester.ports_info[remotePort]['port']
+ vfs = []
+ # vm_dut and tester in same dut
+ host_ip = self.crb['IP'].split(':')[0]
+ if self.crb['tester IP'] == host_ip:
+ vfs = remoteport.get_sriov_vfs_pci()
+ # if hostpci is vf of tester port
+ if hostpci == remotepci or hostpci in vfs:
+ print dts.RED("Skip ping from same PF device")
+ continue
+
+ ipv6 = self.get_ipv6_address(vmPort)
+ if ipv6 == "Not connected":
+ continue
+
+ out = self.tester.send_ping6(
+ remotePort, ipv6, self.get_mac_address(vmPort))
+
+ if ('64 bytes from' in out):
+ self.logger.info(
+ "PORT MAP: [dut %d: tester %d]" % (vmPort, remotePort))
+ self.ports_map[vmPort] = remotePort
+ hits[remotePort] = True
+ continue
diff --git a/framework/virt_resource.py b/framework/virt_resource.py
new file mode 100644
index 0000000..b830f4e
--- /dev/null
+++ b/framework/virt_resource.py
@@ -0,0 +1,494 @@
+#!/usr/bin/python
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+from random import randint
+
+from utils import get_obj_funcs
+
+INIT_FREE_PORT = 6060
+
+
+class VirtResource(object):
+
+ """
+ Class handle dut resource, like cpu, memory, net devices
+ """
+
+ def __init__(self, dut):
+ self.dut = dut
+
+ self.cores = [int(core['thread']) for core in dut.cores]
+ # initialized unused cores
+ self.unused_cores = self.cores[:]
+ # initialized used cores
+ self.used_cores = [-1] * len(self.unused_cores)
+
+ self.ports_info = dut.ports_info
+ # initialized unused ports
+ self.ports = [port['pci'] for port in dut.ports_info]
+ self.unused_ports = self.ports[:]
+ # initialized used ports
+ self.used_ports = ['unused'] * len(self.unused_ports)
+
+ # initialized vf ports
+ self.vfs_info = []
+ self.vfs = []
+ self.unused_vfs = []
+ self.used_vfs = []
+
+ # save allocated cores and related vm
+ self.allocated_info = {}
+
+ def __port_used(self, pci):
+ index = self.ports.index(pci)
+ self.used_ports[index] = pci
+ self.unused_ports[index] = 'used'
+
+ def __port_unused(self, pci):
+ index = self.ports.index(pci)
+ self.unused_ports[index] = pci
+ self.used_ports[index] = 'unused'
+
+ def __port_on_socket(self, pci, socket):
+ for port in self.ports_info:
+ if port['pci'] == pci:
+ if socket is -1:
+ return True
+
+ if port['numa'] == socket:
+ return True
+ else:
+ return False
+
+ return False
+
+ def __vf_used(self, pci):
+ index = self.vfs.index(pci)
+ self.used_vfs[index] = pci
+ self.unused_vfs[index] = 'used'
+
+ def __vf_unused(self, pci):
+ index = self.vfs.index(pci)
+ self.used_vfs[index] = 'unused'
+ self.unused_vfs[index] = pci
+
+ def __core_used(self, core):
+ core = int(core)
+ index = self.cores.index(core)
+ self.used_cores[index] = core
+ self.unused_cores[index] = -1
+
+ def __core_unused(self, core):
+ core = int(core)
+ index = self.cores.index(core)
+ self.unused_cores[index] = core
+ self.used_cores[index] = -1
+
+ def __core_on_socket(self, core, socket):
+ for dut_core in self.dut.cores:
+ if int(dut_core['thread']) == core:
+ if socket is -1:
+ return True
+
+ if int(dut_core['socket']) == socket:
+ return True
+ else:
+ return False
+
+ return False
+
+ def __core_isused(self, core):
+ index = self.cores.index(core)
+ if self.used_cores[index] != -1:
+ return True
+ else:
+ return False
+
+ def reserve_cpu(self, coremask=''):
+ """
+ Reserve dpdk used cpus by mask
+ """
+ val = int(coremask, base=16)
+ cpus = []
+ index = 0
+ while val != 0:
+ if val & 0x1:
+ cpus.append(index)
+
+ val = val >> 1
+ index += 1
+
+ for cpu in cpus:
+ self.__core_used(cpu)
+
+ def alloc_cpu(self, vm='', number=-1, socket=-1, corelist=None):
+ """
+ There're two options for request cpu resouce for vm.
+ If number is not -1, just allocate cpu from not used cores.
+ If list is not None, will allocate cpu after checked.
+ """
+ cores = []
+
+ if vm == '':
+ print "Alloc cpu request vitual machine name!!!"
+ return cores
+
+ # if vm has been alloacted cores, just return them
+ if self.__vm_has_resource(vm, 'cores'):
+ return self.allocated_info[vm]['cores']
+
+ if number != -1:
+ for core in self.unused_cores:
+ if core != -1 and number != 0:
+ if self.__core_on_socket(core, socket) is True:
+ self.__core_used(core)
+ cores.append(str(core))
+ number = number - 1
+ if number != 0:
+ print "Can't allocated requested cpu!!!"
+
+ if corelist is not None:
+ for core in corelist:
+ if self.__core_isused(int(core)) is True:
+ print "Core %s has been used!!!" % core
+ else:
+ if self.__core_on_socket(int(core), socket) is True:
+ self.__core_used(int(core))
+ cores.append(core)
+
+ if vm not in self.allocated_info:
+ self.allocated_info[vm] = {}
+
+ self.allocated_info[vm]['cores'] = cores
+ return cores
+
+ def __vm_has_resource(self, vm, resource=''):
+ if vm == '':
+ self.dut.logger.info("VM name cannt be NULL!!!")
+ raise Exception("VM name cannt be NULL!!!")
+ if vm not in self.allocated_info:
+ self.dut.logger.info(
+ "There is no resource allocated to VM [%s]." % vm)
+ return False
+ if resource == '':
+ return True
+ if resource not in self.allocated_info[vm]:
+ self.dut.logger.info(
+ "There is no resource [%s] allocated to VM [%s] " %
+ (resource, vm))
+ return False
+ return True
+
+ def free_cpu(self, vm):
+ if self.__vm_has_resource(vm, 'cores'):
+ for core in self.allocated_info[vm]['cores']:
+ self.__core_unused(core)
+ self.allocated_info[vm].pop('cores')
+
+ def alloc_pf(self, vm='', number=-1, socket=-1, pflist=[]):
+ """
+ There're two options for request pf devices for vm.
+ If number is not -1, just allocate pf device from not used pfs.
+ If list is not None, will allocate pf devices after checked.
+ """
+ ports = []
+
+ if number != -1:
+ for pci in self.unused_ports:
+ if pci != 'unused' and number != 0:
+ if self.__port_on_socket(pci, socket) is True:
+ self.__port_used(pci)
+ ports.append(pci)
+ number = number - 1
+ if number != 0:
+ print "Can't allocated requested PF devices!!!"
+
+ if pflist is not None:
+ for pci in pflist:
+ if self.__port_isused(pci) is True:
+ print "Port %s has been used!!!" % pci
+ else:
+ if self.__port_on_socket(pci, socket) is True:
+ self.__port_used(core)
+ ports.append(core)
+
+ if vm not in self.allocated_info:
+ self.allocated_info[vm] = {}
+
+ self.allocated_info[vm]['ports'] = ports
+ return ports
+
+ def free_pf(self, vm):
+ if self.__vm_has_resource(vm, 'ports'):
+ for pci in self.allocated_info[vm]['ports']:
+ self.__port_unused(pci)
+ self.allocated_info[vm].pop('ports')
+
+ def alloc_vf_from_pf(self, vm='', pf_pci='', number=-1, vflist=[]):
+ """
+ There're two options for request vf devices of pf device.
+ If number is not -1, just allocate vf device from not used vfs.
+ If list is not None, will allocate vf devices after checked.
+ """
+ vfs = []
+ if vm == '':
+ print "Alloc VF request vitual machine name!!!"
+ return vfs
+
+ if pf_pci == '':
+ print "Alloc VF request PF pci address!!!"
+ return vfs
+
+ for vf_info in self.vfs_info:
+ if vf_info['pf_pci'] == pf_pci:
+ if vf_info['pci'] in vflist:
+ vfs.append(vf_info['pci'])
+ continue
+
+ if number > 0:
+ vfs.append(vf_info['pci'])
+ number = number - 1
+
+ for vf in vfs:
+ self.__vf_used(vf)
+
+ if vm not in self.allocated_info:
+ self.allocated_info[vm] = {}
+
+ self.allocated_info[vm]['vfs'] = vfs
+ return vfs
+
+ def free_vf(self, vm):
+ if self.__vm_has_resource(vm, 'vfs'):
+ for pci in self.allocated_info[vm]['vfs']:
+ self.__vf_unused(pci)
+ self.allocated_info[vm].pop('vfs')
+
+ def add_vf_on_pf(self, pf_pci='', vflist=[]):
+ """
+ Add vf devices generated by specified pf devices.
+ """
+ # add vfs into vf info list
+ vfs = []
+ for vf in vflist:
+ if vf not in self.vfs:
+ self.vfs_info.append({'pci': vf, 'pf_pci': pf_pci})
+ vfs.append(vf)
+ used_vfs = ['unused'] * len(vflist)
+ self.unused_vfs += vfs
+ self.used_vfs += used_vfs
+ self.vfs += vfs
+
+ def del_vf_on_pf(self, pf_pci='', vflist=[]):
+ """
+ Remove vf devices generated by specified pf devices.
+ """
+ vfs = []
+ for vf in vflist:
+ for vfs_info in self.vfs_info:
+ if vfs_info['pci'] == vf:
+ vfs.append(vf)
+
+ for vf in vfs:
+ try:
+ index = self.vfs.index(vf)
+ except:
+ continue
+ del self.vfs_info[index]
+ del self.unused_vfs[index]
+ del self.used_vfs[index]
+ del self.vfs[index]
+
+ def alloc_port(self, vm=''):
+ """
+ Allocate unused host port for vm
+ """
+ if vm == '':
+ print "Alloc host port request vitual machine name!!!"
+ return None
+
+ port_start = INIT_FREE_PORT + randint(1, 100)
+ port_step = randint(1, 10)
+ port = None
+ count = 20
+ while True:
+ if self.dut.check_port_occupied(port_start) is False:
+ port = port_start
+ break
+ count -= 1
+ if count < 0:
+ print 'No available port on the host!!!'
+ break
+ port_start += port_step
+
+ if vm not in self.allocated_info:
+ self.allocated_info[vm] = {}
+
+ self.allocated_info[vm]['hostport'] = port
+ return port
+
+ def free_port(self, vm):
+ if self.__vm_has_resource(vm, 'hostport'):
+ self.allocated_info[vm].pop('hostport')
+
+ def alloc_vnc_num(self, vm=''):
+ """
+ Allocate unused host VNC display number for VM.
+ """
+ if vm == '':
+ print "Alloc vnc display number request vitual machine name!!!"
+ return None
+
+ max_vnc_display_num = self.dut.get_maximal_vnc_num()
+ free_vnc_display_num = max_vnc_display_num + 1
+
+ if vm not in self.allocated_info:
+ self.allocated_info[vm] = {}
+
+ self.allocated_info[vm]['vnc_display_num'] = free_vnc_display_num
+
+ return free_vnc_display_num
+
+ def free_vnc_num(self, vm):
+ if self.__vm_has_resource(vm, 'vnc_display_num'):
+ self.allocated_info[vm].pop('vnc_display_num')
+
+ def free_all_resource(self, vm):
+ """
+ Free all resource VM has been allocated.
+ """
+ self.free_port(vm)
+ self.free_vnc_num(vm)
+ self.free_vf(vm)
+ self.free_pf(vm)
+ self.free_cpu(vm)
+
+ if self.__vm_has_resource(vm):
+ self.allocated_info.pop(vm)
+
+ def get_cpu_on_vm(self, vm=''):
+ """
+ Return core list on specifid VM.
+ """
+ if vm in self.allocated_info:
+ if "cores" in self.allocated_info[vm]:
+ return self.allocated_info[vm]['cores']
+
+ def get_vfs_on_vm(self, vm=''):
+ """
+ Return vf device list on specifid VM.
+ """
+ if vm in self.allocated_info:
+ if 'vfs' in self.allocated_info[vm]:
+ return self.allocated_info[vm]['vfs']
+
+ def get_pfs_on_vm(self, vm=''):
+ """
+ Return pf device list on specifid VM.
+ """
+ if vm in self.allocated_info:
+ if 'ports' in self.allocated_info[vm]:
+ return self.allocated_info[vm]['ports']
+
+
+class simple_dut(object):
+
+ def __init__(self):
+ self.ports_info = []
+ self.cores = []
+
+ def check_port_occupied(self, port):
+ return False
+
+if __name__ == "__main__":
+ dut = simple_dut()
+ dut.cores = [{'thread': '1', 'socket': '0'}, {'thread': '2', 'socket': '0'},
+ {'thread': '3', 'socket': '0'}, {'thread': '4', 'socket': '0'},
+ {'thread': '5', 'socket': '0'}, {'thread': '6', 'socket': '0'},
+ {'thread': '7', 'socket': '1'}, {'thread': '8', 'socket': '1'},
+ {'thread': '9', 'socket': '1'}, {'thread': '10', 'socket': '1'},
+ {'thread': '11', 'socket': '1'}, {'thread': '12', 'socket': '1'}]
+
+ dut.ports_info = [{'intf': 'p786p1', 'source': 'cfg', 'mac': '90:e2:ba:69:e5:e4',
+ 'pci': '08:00.0', 'numa': 0, 'ipv6': 'fe80::92e2:baff:fe69:e5e4',
+ 'peer': 'IXIA:6.5', 'type': '8086:10fb'},
+ {'intf': 'p786p2', 'source': 'cfg', 'mac': '90:e2:ba:69:e5:e5',
+ 'pci': '08:00.1', 'numa': 0, 'ipv6': 'fe80::92e2:baff:fe69:e5e5',
+ 'peer': 'IXIA:6.6', 'type': '8086:10fb'},
+ {'intf': 'p787p1', 'source': 'cfg', 'mac': '90:e2:ba:69:e5:e6',
+ 'pci': '84:00.0', 'numa': 1, 'ipv6': 'fe80::92e2:baff:fe69:e5e6',
+ 'peer': 'IXIA:6.7', 'type': '8086:10fb'},
+ {'intf': 'p787p2', 'source': 'cfg', 'mac': '90:e2:ba:69:e5:e7',
+ 'pci': '84:00.1', 'numa': 1, 'ipv6': 'fe80::92e2:baff:fe69:e5e7',
+ 'peer': 'IXIA:6.8', 'type': '8086:10fb'}]
+
+ virt_pool = VirtResource(dut)
+ print "Alloc two PF devices on socket 1 from VM"
+ print virt_pool.alloc_pf(vm='test1', number=2, socket=1)
+
+ virt_pool.add_vf_on_pf(pf_pci='08:00.0', vflist=[
+ '08:10.0', '08:10.2', '08:10.4', '08:10.6'])
+ virt_pool.add_vf_on_pf(pf_pci='08:00.1', vflist=[
+ '08:10.1', '08:10.3', '08:10.5', '08:10.7'])
+ print "Add VF devices to resource pool"
+ print virt_pool.vfs_info
+
+ print "Alloc VF device from resource pool"
+ print virt_pool.alloc_vf_from_pf(vm='test1', pf_pci='08:00.0', number=2)
+ print virt_pool.used_vfs
+ print "Alloc VF device from resource pool"
+ print virt_pool.alloc_vf_from_pf(vm='test2', pf_pci='08:00.1', vflist=['08:10.3', '08:10.5'])
+ print virt_pool.used_vfs
+
+ print "Del VF devices from resource pool"
+ virt_pool.del_vf_on_pf(pf_pci='08:00.0', vflist=['08:10.4', '08:10.2'])
+ print virt_pool.vfs_info
+
+ virt_pool.reserve_cpu('e')
+ print "Reserve three cores from resource pool"
+ print virt_pool.unused_cores
+ print "Alloc two cores on socket1 for VM-test1"
+ print virt_pool.alloc_cpu(vm="test1", number=2, socket=1)
+ print "Alloc two cores in list for VM-test2"
+ print virt_pool.alloc_cpu(vm="test2", corelist=['4', '5'])
+ print "Alloc two cores for VM-test3"
+ print virt_pool.alloc_cpu(vm="test3", number=2)
+ print "Alloc port for VM-test1"
+ print virt_pool.alloc_port(vm='test1')
+ print "Alloc information after allcated"
+ print virt_pool.allocated_info
+
+ print "Get cores on VM-test1"
+ print virt_pool.get_cpu_on_vm("test1")
+ print "Get pfs on VM-test1"
+ print virt_pool.get_pfs_on_vm("test1")
+ print "Get vfs on VM-test2"
+ print virt_pool.get_vfs_on_vm("test2")
diff --git a/framework/virt_scene.py b/framework/virt_scene.py
new file mode 100644
index 0000000..b201541
--- /dev/null
+++ b/framework/virt_scene.py
@@ -0,0 +1,535 @@
+#!/usr/bin/python
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+import time
+import dts
+
+from settings import CONFIG_ROOT_PATH, get_netdev
+from config import VirtConf
+from config import VIRTCONF
+from exception import *
+from qemu_kvm import QEMUKvm
+from pmd_output import PmdOutput
+
+# scenario module for handling scenario
+# 1. load configurations
+# config saved in conf/scenarios/name.cfg
+# load configurations will saved in vm list
+# 2. handle special config
+# pf_idx=0,vf_num=2,driver=default;
+# PF0 igb_uio, create 2VFs by default driver
+# 3. create scenario
+# allocate hareware resource for this vm
+# cpu, memory, pf devices, vf devices
+# configuration vm
+# run pre_vm commands
+# create vm
+# run post_vm commands
+
+
+class VirtScene(object):
+
+ def __init__(self, dut, tester, scene_name):
+ self.name = scene_name
+ self.host_dut = dut
+ self.tester_dut = tester
+ self.pre_cmds = []
+ self.post_cmds = []
+
+ self.vm_dut_enable = False
+ self.auto_portmap = True
+ self.vm_type = 'kvm'
+ self.def_target = "x86_64-native-linuxapp-gcc"
+ self.host_bound = False
+
+ # for vm dut init_log
+ self.host_dut.test_classname = 'dts'
+
+ def load_config(self):
+ try:
+ self.vm_confs = {}
+ conf = VirtConf(CONFIG_ROOT_PATH + 'scene/' + self.name + '.cfg')
+ self.sections = conf.virt_conf.get_sections()
+ for vm in self.sections:
+ conf.load_virt_config(vm)
+ vm_conf = conf.get_virt_config()
+ self.vm_confs[vm] = vm_conf
+ except:
+ raise VirtConfigParseException
+
+ def prepare_vm(self):
+ host_cfg = None
+ for conf in self.vm_confs.keys():
+ if conf == 'scene':
+ for cfg in self.vm_confs['scene']:
+ if 'suite' in cfg.keys():
+ self.prepare_suite(cfg['suite'])
+ if 'host' in cfg.keys():
+ self.host_bound = True
+ host_cfg = cfg['host'][0]
+ self.vm_confs.pop('scene')
+ else:
+ vm_name = conf
+ vm_conf = self.vm_confs[vm_name]
+ self.prepare_cpu(vm_name, vm_conf)
+ self.prepare_devices(vm_conf)
+ self.prepare_vmdevice(vm_conf)
+
+ # dpdk should start after vf devices created
+ if host_cfg:
+ self.prepare_host(**host_cfg)
+
+ def cleanup_vm(self):
+ # reload config for has been changed when handle config
+ self.load_config()
+ for conf in self.vm_confs.keys():
+ if conf != 'scene':
+ vm_name = conf
+ vm_conf = self.vm_confs[vm_name]
+ self.cleanup_devices(vm_conf)
+
+ def prepare_suite(self, conf):
+ for param in conf:
+ if 'dut' in param.keys():
+ if param['dut'] == 'vm_dut':
+ self.vm_dut_enable = True
+ if 'type' in param.keys():
+ if param['type'] == 'xen':
+ self.vm_type = 'xen'
+ # not implement yet
+ if param['type'] == 'vmware':
+ self.vm_type = 'vmware'
+ # not implement yet
+ if param['type'] == 'container':
+ self.vm_type = 'container'
+ if 'portmap' in param.keys():
+ if param['portmap'] == 'cfg':
+ self.auto_portmap = False
+
+ def prepare_host(self, **opts):
+ if 'dpdk' not in opts.keys():
+ print dts.RED("Scenario host parameter request dpdk option!!!")
+ raise VirtConfigParamException('host')
+
+ if 'cores' not in opts.keys():
+ print dts.RED("Scenario host parameter request cores option!!!")
+ raise VirtConfigParamException('host')
+
+ if 'target' in opts.keys():
+ target = opts['target']
+ else:
+ target = self.def_target
+
+ self.host_dut.set_target(target, bind_dev=True)
+
+ if opts['dpdk'] == 'testpmd':
+ self.pmdout = PmdOutput(self.host_dut)
+ cores = opts['cores'].split()
+ out = self.pmdout.start_testpmd(cores)
+ if 'Error' in out:
+ raise VirtHostPrepareException()
+
+ def prepare_cpu(self, vm_name, conf):
+ cpu_param = {}
+ for params in conf:
+ if 'cpu' in params.keys():
+ cpu_conf = params['cpu'][0]
+ break
+
+ if 'skipcores' in cpu_conf.keys():
+ cpus = cpu_conf['skipcores'].split()
+ # remove invalid configured core
+ for cpu in cpus:
+ if int(cpu) not in self.host_dut.virt_pool.cores:
+ cpus.remove(cpu)
+ # create core mask for reserver cores
+ core_mask = dts.create_mask(cpus)
+ # reserve those skipped cores
+ self.host_dut.virt_pool.reserve_cpu(core_mask)
+
+ if 'numa' in cpu_conf.keys():
+ if cpu_conf['numa'] == 'auto':
+ numa = self.host_dut.ports_info[0]['port'].socket
+ else:
+ numa = int(cpu_conf['numa'])
+ else:
+ numa = 0
+
+ if 'number' in cpu_conf.keys():
+ num = int(cpu_conf['number'])
+ else:
+ num = 2
+
+ if 'model' in cpu_conf.keys():
+ model = cpu_conf['model']
+ else:
+ model = 'host'
+
+ cores = self.host_dut.virt_pool.alloc_cpu(vm=vm_name, number=num,
+ socket=numa)
+ core_cfg = ''
+ for core in cores:
+ core_cfg += '%s ' % core
+ core_cfg = core_cfg[:-1]
+
+ cpu_param['number'] = num
+ cpu_param['model'] = model
+ cpu_param['cpupin'] = core_cfg
+
+ # replace with allocated cpus
+ params['cpu'] = [cpu_param]
+
+ def prepare_devices(self, conf):
+ for params in conf:
+ if 'dev_gen' in params.keys():
+ index = conf.index(params)
+ for param in params['dev_gen']:
+ self.handle_dev_gen(**param)
+ # remove handled 'dev_gen' configuration
+ conf.remove(conf[index])
+
+ def cleanup_devices(self, conf):
+ for params in conf:
+ if 'dev_gen' in params.keys():
+ for param in params['dev_gen']:
+ self.handle_dev_destroy(**param)
+
+ def prepare_vmdevice(self, conf):
+ for params in conf:
+ if 'device' in params.keys():
+ for param in params['device']:
+ if 'vf_idx' in param.keys():
+ new_param = self.prepare_vf_conf(param)
+ index = params['device'].index(param)
+ params['device'][index] = new_param
+ elif 'pf_idx' in param.keys():
+ new_param = self.prepare_pf_conf(param)
+ index = params['device'].index(param)
+ params['device'][index] = new_param
+
+ for param in params['device']:
+ netdev = get_netdev(self.host_dut, param['opt_host'])
+ if netdev is not None:
+ netdev.bind_driver('pci-stub')
+
+ def prepare_pf_conf(self, param):
+ pf_param = {}
+ # strip pf pci id
+ pf = int(param['pf_idx'])
+ if pf >= len(self.host_dut.ports_info):
+ raise VirtDeviceCreateException
+ pf_pci = self.host_dut.ports_info[pf]['pci']
+ pf_param['driver'] = 'pci-assign'
+ pf_param['opt_host'] = pf_pci
+ if param['guestpci'] != 'auto':
+ pf_param['opt_addr'] = param['guestpci']
+
+ return pf_param
+
+ def prepare_vf_conf(self, param):
+ vf_param = {}
+ # strip vf pci id
+ if 'pf_dev' in param.keys():
+ pf = int(param['pf_dev'])
+ vfs = self.host_dut.ports_info[pf]['vfs_port']
+ vf_idx = int(param['vf_idx'])
+ if vf_idx >= len(vfs):
+ raise VirtDeviceCreateException
+ vf_pci = vfs[vf_idx].pci
+ vf_param['driver'] = 'pci-assign'
+ vf_param['opt_host'] = vf_pci
+ if param['guestpci'] != 'auto':
+ vf_param['opt_addr'] = param['guestpci']
+ else:
+ print dts.RED("Invalid vf device config, request pf_dev")
+
+ return vf_param
+
+ def reset_pf_cmds(self, port):
+ command = {}
+ command['type'] = 'host'
+ if not self.host_bound:
+ intf = self.host_dut.ports_info[port]['intf']
+ command['command'] = 'ifconfig %s up' % intf
+ self.reg_postvm_cmds(command)
+
+ def handle_dev_gen(self, **opts):
+ if 'pf_idx' in opts.keys():
+ port = int(opts['pf_idx'])
+ if 'vf_num' in opts.keys():
+ vf_num = int(opts['vf_num'])
+ else:
+ print dts.RED("No vf_num for port %d, assum one VF" % port)
+ vf_num = 1
+ if 'driver' in opts.keys():
+ driver = opts['driver']
+
+ try:
+ print dts.GREEN("create vf %d %d %s" % (port, vf_num, driver))
+ self.host_dut.generate_sriov_vfs_by_port(port, vf_num, driver)
+ self.reset_pf_cmds(port)
+ except:
+ print dts.RED("Failed to create vf as requested!!!")
+ raise VirtDeviceCreateException
+
+ def handle_dev_destroy(self, **opts):
+ if 'pf_idx' in opts.keys():
+ port = int(opts['pf_idx'])
+
+ try:
+ print dts.GREEN("destroy vfs on port %d" % port)
+ self.host_dut.destroy_sriov_vfs_by_port(port)
+ except:
+ print dts.RED("Failed to destroy vf as requested!!!")
+
+ def reg_prevm_cmds(self, command):
+ """
+ command: {'type':'host/tester/vm',
+ define which crb command progress
+ 'command':'XXX',
+ command send to crb
+ 'expect':'XXX',
+ expected output for command
+ 'timeout': 60,
+ 'verify': True or False
+ check whether command sucessfully
+ }
+ """
+ self.pre_cmds.append(command)
+
+ def run_pre_cmds(self):
+ for cmd in self.pre_cmds:
+ if cmd['type'] == 'vm':
+ print dts.RED("Can't run vm command when vm not ready")
+ elif cmd['type'] == 'host':
+ crb = self.host_dut
+ elif cmd['type'] == 'tester':
+ crb = self.tester
+ else:
+ crb = self.host_dut
+
+ if 'expect' not in cmd.keys():
+ expect = "# "
+ else:
+ expect = cmd['expect']
+
+ if 'verify' not in cmd.keys():
+ verify = False
+ else:
+ verify = cmd['verify']
+
+ if 'timeout' not in cmd.keys():
+ timeout = 5
+ else:
+ timeout = cmd['timeout']
+
+ ret = crb.send_expect(cmd['command'], expect, timeout=timeout,
+ verify=verify)
+
+ if type(ret) is int and ret != 0:
+ print dts.RED("Failed to run command %s" % cmd['command'])
+ raise VirtVmOperationException
+
+ def reg_postvm_cmds(self, command):
+ """
+ command: {'type':'host/tester/vm',
+ define which crb command progress
+ 'command':'XXX',
+ command send to crb
+ 'expect':'XXX',
+ expected output for command
+ 'verify':'yes or no'
+ check whether command sucessfully
+ """
+ self.post_cmds.append(command)
+ pass
+
+ def run_post_cmds(self):
+ for cmd in self.post_cmds:
+ if cmd['type'] == 'vm':
+ crb = self.vm_dut
+ elif cmd['type'] == 'host':
+ crb = self.host_dut
+ elif cmd['type'] == 'tester':
+ crb = self.tester
+ else:
+ crb = self.host_dut
+
+ if 'expect' not in cmd.keys():
+ expect = "# "
+ else:
+ expect = cmd['expect']
+
+ if 'verify' not in cmd.keys():
+ verify = False
+ else:
+ verify = cmd['verify']
+
+ if 'timeout' not in cmd.keys():
+ timeout = 5
+ else:
+ timeout = cmd['timeout']
+
+ ret = crb.send_expect(cmd['command'], expect, timeout=timeout,
+ verify=verify)
+
+ if type(ret) is int and ret != 0:
+ print dts.RED("Failed to run command %s" % cmd['command'])
+ raise VirtVmOperationException
+
+ def merge_params(self, vm, params):
+ for param in params:
+ index = vm.find_option_index(param.keys()[0])
+ if index is not None:
+ vm.params[index] = param
+ else:
+ vm.params.append(param)
+ index = vm.find_option_index('name')
+ # update vm name
+ vm.params[index]['name'][0]['name'] = vm.vm_name
+
+ def start_vms(self):
+ self.vms = []
+ if self.vm_type == 'kvm':
+ for vm_name in self.vm_confs.keys():
+ # tricky here, QEMUKvm based on suite and vm name
+ # suite is virt_global, vm_name just the type
+ vm = QEMUKvm(self.host_dut, self.vm_type.upper(),
+ 'virt_global')
+ vm.load_config()
+ vm.vm_name = vm_name
+ vm.set_vm_default()
+ # merge default config and scene config
+ scene_params = self.vm_confs[vm_name]
+ # reload merged configurations
+ self.merge_params(vm, scene_params)
+ try:
+ vm_dut = vm.start(load_config=False, set_target=False,
+ auto_portmap=self.auto_portmap)
+ if vm_dut is None:
+ raise Exception("Set up VM ENV failed!")
+
+ vm_info = {}
+ vm_info[vm_name] = vm
+ vm_info[vm_name + '_session'] = vm_dut
+ self.vms.append(vm_info)
+
+ except Exception as e:
+ print dts.RED("Failure for %s" % str(e))
+
+ def get_vm_duts(self):
+ duts = []
+ for vm_info in self.vms:
+ for vm_obj in vm_info.keys():
+ if 'session' in vm_obj:
+ duts.append(vm_info[vm_obj])
+
+ return duts
+
+ def create_scene(self):
+ self.prepare_vm()
+ self.run_pre_cmds()
+ self.start_vms()
+ self.run_post_cmds()
+ pass
+
+ def set_target(self, target):
+ for vm_info in self.vms:
+ for vm_obj in vm_info.keys():
+ if 'session' in vm_obj:
+ vm_info[vm_obj].set_target(target)
+
+ def destroy_scene(self):
+ for vm_info in self.vms:
+ for vm_obj in vm_info.keys():
+ if 'session' in vm_obj:
+ vm_info[vm_obj].kill_all()
+ vm_info[vm_obj].close()
+ vm_info[vm_obj].logger.logger_exit()
+ for vm_obj in vm_info.keys():
+ if 'session' not in vm_obj:
+ vm_info[vm_obj].stop()
+ vm_info[vm_obj] = None
+ self.cleanup_vm()
+
+
+if __name__ == "__main__":
+
+ class QEMUKvm():
+
+ def __init__(self, dut, vm_name, suite_name):
+ print vm_name
+ print suite_name
+
+ def start(self):
+ print self.params
+ return True
+
+ class simple_dev(object):
+
+ def __init__(self, pci):
+ self.pci = pci
+ self.socket = 1
+
+ emu_dev1 = simple_dev("00:00.1")
+ emu_dev2 = simple_dev("00:00.2")
+ emu_dev3 = simple_dev("00:00.3")
+ emu_dev4 = simple_dev("00:00.4")
+
+ class simple_dut(object):
+
+ def __init__(self):
+ self.ports_info = [
+ {'vfs_port': [emu_dev1, emu_dev2]},
+ {'vfs_port': [emu_dev3, emu_dev4]},
+ ]
+ self.virt_pool = simple_resource()
+
+ def send_expect(self, cmds, expected, timeout=5,
+ alt_session=False, verify=False):
+ print cmds + "---" + expected
+
+ class simple_resource(object):
+
+ def __init__(self):
+ pass
+
+ def reserve_cpu(self, coremask):
+ print "reserve " + coremask
+
+ def alloc_cpu(self, vm='', number=-1, socket=-1, corelist=None):
+ print "alloc %s num %d on socket %d" % (vm, number, socket)
+
+ dut = simple_dut()
+ scene = VirtScene(dut, None, "vf_passthrough")
+ scene.load_config()
+ scene.create_scene()
+ scene.destroy_scene()
diff --git a/test_plans/dual_vlan_test_plan.rst b/test_plans/dual_vlan_test_plan.rst
new file mode 100644
index 0000000..fa434cc
--- /dev/null
+++ b/test_plans/dual_vlan_test_plan.rst
@@ -0,0 +1,394 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+==========================================================
+Support of Dual VLAN Offload Features by Poll Mode Drivers
+==========================================================
+
+The support of Dual VLAN offload features by Poll Mode Drivers consists in:
+
+- dynamically enable/disable inner VLAN filtering on an interface on 82576/82599,
+- dynamically enable/disable extended VLAN mode on 82576/82599,
+- dynamically configure outer VLAN TPID value, i.e. S-TPID value, on 82576/82599.
+
+Prerequisites
+=============
+
+In this feature, Only 82576 and 82599 are supported.
+
+Support igb_uio and vfio driver, if used vfio, kernel need 3.6+ and enable vt-d in bios.
+When used vfio , used "modprobe vfio" and "modprobe vfio-pci" insmod vfiod driver, then used
+"./tools/dpdk_nic_bind.py --bind=vfio-pci device_bus_id" to bind vfio driver to test driver.
+Assuming that ports ``0`` and ``1`` are connected to the traffic generator's port ``A`` and ``B``,
+launch the ``testpmd`` with the following arguments::
+
+ ./build/app/testpmd -c ffffff -n 3 -- -i --burst=1 --txpt=32 \
+ --txht=8 --txwt=0 --txfreet=0 --rxfreet=64 --mbcache=250 --portmask=0x3
+
+The -n command is used to select the number of memory channels. It should match the number of memory channels on that setup.
+
+Test Case: Enable/Disable VLAN packets filtering
+================================================
+
+Setup the ``mac`` forwarding mode::
+
+ testpmd> set fwd mac
+ Set mac packet forwarding mode
+
+Enable vlan filtering on port 0::
+
+ testpmd> vlan set filter on 0
+
+Check whether the mode is setted successful::
+
+ testpmd> show port info 0
+
+ ********************* Infos for port 0 *********************
+ MAC address: 90:E2:BA:1B:DF:60
+ Link status: up
+ Link speed: 10000 Mbps
+ Link duplex: full-duplex
+ Promiscuous mode: enabled
+ Allmulticast mode: disabled
+ Maximum number of MAC addresses: 127
+ VLAN offload:
+ strip off
+ filter on
+ qinq(extend) off
+
+start forwarding packets::
+
+ testpmd> start
+ mac packet forwarding - CRC stripping disabled - packets/burst=32
+ nb forwarding cores=1 - nb forwarding ports=10
+ RX queues=1 - RX desc=128 - RX free threshold=64
+ RX threshold registers: pthresh=8 hthresh=8 wthresh=4
+ TX queues=1 - TX desc=512 - TX free threshold=0
+ TX threshold registers: pthresh=32 hthresh=8 wthresh=8
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+ ``1`` and send 1 packet on port ``A``.Verify that the VLAN packet cannot
+ been received in port ``B``.
+
+Disable vlan filtering on port ``0``::
+
+ testpmd> vlan set filter off 0
+
+Check whether the mode is setted successful::
+
+ testpmd> show port info 0
+
+ ********************* Infos for port 0 *********************
+ MAC address: 90:E2:BA:1B:DF:60
+ Link status: up
+ Link speed: 10000 Mbps
+ Link duplex: full-duplex
+ Promiscuous mode: enabled
+ Allmulticast mode: disabled
+ Maximum number of MAC addresses: 127
+ VLAN offload:
+ strip off
+ filter off
+ qinq(extend) off
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+ ``1`` and send 1 packet on port ``A``.Verify that the VLAN packet can been
+ received in port ``B`` with VLAN Tag Identifier ``1``.
+
+Test Case: Add/Remove VLAN Tag Identifier pass VLAN filtering
+=============================================================
+
+Enable VLAN filtering on port ``0``::
+
+ testpmd> vlan set filter on 0
+
+Add a VLAN Tag Identifier ``1`` on port ``0``::
+
+ testpmd> rx_vlan add 1 0
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+ ``1`` and send 1 packet on port ``A``.Verify that the VLAN packet can been
+ received in port ``B``.
+
+Remove the VLAN Tag Identifier ``1`` on port ``0``::
+
+ testpmd> rx_vlan rm 1 0
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+ ``1`` and send 1 packet on port ``A``.Verify that the VLAN packet cannot been
+ received in port ``B``.
+
+Test Case: Enable/Disable VLAN header striping
+==============================================
+
+Enable vlan packet forwarding on port ``0`` first::
+
+ testpmd> vlan set filter off 0
+
+Enable vlan header striping on port ``0``::
+
+ testpmd> vlan set strip on 0
+
+Check whether the mode is setted successful::
+
+ testpmd> show port info 0
+
+ ********************* Infos for port 0 *********************
+ MAC address: 90:E2:BA:1B:DF:60
+ Link status: up
+ Link speed: 10000 Mbps
+ Link duplex: full-duplex
+ Promiscuous mode: enabled
+ Allmulticast mode: disabled
+ Maximum number of MAC addresses: 127
+ VLAN offload:
+ strip on
+ filter off
+ qinq(extend) off
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+``1`` and send 1 packet on port ``A``. Verify that the packet without VLAN Tag
+Identifier can been received in port ``B``.
+
+Disable vlan header striping on port ``0``::
+
+ testpmd> vlan set strip off 0
+
+Check whether the mode is setted successfully::
+
+ testpmd> show port info 0
+
+ ********************* Infos for port 0 *********************
+ MAC address: 90:E2:BA:1B:DF:60
+ Link status: up
+ Link speed: 10000 Mbps
+ Link duplex: full-duplex
+ Promiscuous mode: enabled
+ Allmulticast mode: disabled
+ Maximum number of MAC addresses: 127
+ VLAN offload:
+ strip off
+ filter off
+ qinq(extend) off
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+``1`` and send 1 packet on port ``A``. Verify that the packet with VLAN Tag
+Identifier ``1`` can been received in port ``B``.
+
+Test Case: Enable/Disable VLAN header striping in queue
+=======================================================
+
+Enable vlan packet forwarding on port ``0`` first::
+
+ testpmd> vlan set filter off 0
+
+Disable vlan header striping on port ``0``::
+
+ testpmd> vlan set strip off 0
+
+Disable vlan header striping in queue 0 on port ``0``::
+
+ testpmd> vlan set stripq off 0,0
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+``1`` and send 1 packet on port ``A``. Verify that the packet with VLAN Tag
+Identifier ``1`` can been received in port ``B``.
+
+
+Enable vlan header striping in queue 0 on port ``0``::
+
+ testpmd> vlan set stripq on 0,0
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+``1`` and send 1 packet on port ``A``. Verify that the packet without VLAN Tag
+Identifier ``1`` can been received in port ``B``.
+
+Enable vlan header striping on port ``0``.
+
+ MISSING COMMAND
+
+Configure the traffic generator to send VLAN packets with the Tag Identifier
+``1`` and send 1 packet on port ``A``. Verify that the packet without VLAN Tag
+Identifier ``1`` can been received in port ``B``.
+
+Test Case: Enable/Disable VLAN header inserting
+===============================================
+
+Enable vlan packet forwarding on port ``0`` first::
+
+ testpmd> vlan set filter off 0
+
+Insert VLAN Tag Identifier ``1`` on port ``1``::
+
+ testpmd> tx_vlan set 1 1
+
+Configure the traffic generator to send VLAN packet without VLAN Tag Identifier
+and send 1 packet on port ``A``. Verify that the packet can been received on port
+``B`` with VLAN Tag Identifier ``1``.
+
+Delete the VLAN Tag Identifier ``1`` on port ``1``::
+
+ testpmd> tx_vlan reset 1
+
+Configure the traffic generator to send VLAN packet without VLAN Tag Identifier
+and send 1 packet on port ``A``. Verify that the packet can been received on port
+``B`` without VLAN Tag Identifier.
+
+
+Test Case: Configure receive port outer VLAN TPID
+=================================================
+
+Enable vlan header QinQ on port ``0`` firstly to support set TPID::
+
+ testpmd> vlan set qinq on 0
+
+Check whether the mode is setted successfully::
+
+ testpmd> show port info 0
+
+ ********************* Infos for port 0 *********************
+ MAC address: 90:E2:BA:1B:DF:60
+ Link status: up
+ Link speed: 10000 Mbps
+ Link duplex: full-duplex
+ Promiscuous mode: enabled
+ Allmulticast mode: disabled
+ Maximum number of MAC addresses: 127
+ VLAN offload:
+ strip off
+ filter off
+ qinq(extend) on
+
+Set Tag Protocol ID ``0x1234`` on port ``0``::
+
+ testpmd> vlan set tpid 0x1234 0
+
+Enable vlan packet filtering and strip on port ``0`` ::
+
+ testpmd> vlan set filter on 0
+ testpmd> vlan set strip on 0
+
+Configure the traffic generator to send VLAN packet whose outer vlan tag is ``0x1``,
+inter vlan tag is ``0x2`` and outer Tag Protocol ID is ``0x8100`` and send 1 packet
+on port ``A``. Verify that one packet whose vlan header has not been strip has been
+received on port ``B``.
+
+Set Tag Protocol ID ``0x8100`` on port ``0``::
+
+ testpmd> vlan set tpid 0x8100 0
+
+Configure the traffic generator to send VLAN packet whose outer vlan tag is ``0x1``,
+inter vlan tag is ``0x2`` and outer Tag Protocol ID is ``0x8100`` and send 1 packet
+on port ``A``. Verify that no packets has been received on port ``B``
+
+Test Case: Strip/Filter/Extend/Insert enable/disable synthetic test
+===================================================================
+
+Do the synthetic test following the below table and check the result is the same
+as the table(the inserted VLAN Tag Identifier is limited to ``0x3``, and all modes
+except insert are setted on rx port).
+
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| Outer | Inner | Vlan | Vlan | Vlan | Vlan | Pass/ | Outer | Inner |
+| vlan | vlan | strip | filter | extend | insert | Drop | vlan | vlan |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | no | no | no | pass | 0x1 | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | no | no | no | pass | no | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x1 | no | no | pass | 0x1 | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x2 | no | no | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x1 | no | no | pass | no | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x2 | no | no | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | no | yes | no | pass | 0x1 | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | no | yes | no | pass | no | 0x1 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x1 | yes | no | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x2 | yes | no | pass | 0x1 | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x1 | yes | no | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x2 | yes | no | pass | no | 0x1 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | no | no | yes | pass | 0x3 | 0x1 |
+| | | | | | | | | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | no | no | yes | pass | 0x3 | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x1 | no | yes | pass | 0x3 | 0x1 |
+| | | | | | | | | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x2 | no | yes | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x1 | no | yes | pass | 0x3 | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x2 | no | yes | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | no | yes | yes | pass | 0x3 | 0x1 |
+| | | | | | | | | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | no | yes | yes | pass | 0x3 | 0x1 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x1 | yes | yes | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | no | yes,0x2 | yes | yes | pass | 0x3 | 0x1 |
+| | | | | | | | | 0x2 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x1 | yes | yes | drop | no | no |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+| 0x1 | 0x2 | yes | yes,0x2 | yes | yes | pass | 0x3 | 0x1 |
++-------+-------+--------+------------+--------+--------+-------+-------+-------+
+
+Test Case: Strip/Filter/Extend/Insert enable/disable random test
+================================================================
+
+Chooce the above table's item randomly 30 times and verify that the result is right.
+
+At last, stop packet forwarding and quit the application::
+ testpmd> stop
+ testpmd> quit
+
+
+
+
+
+
+
+
+
+
diff --git a/test_plans/dynamic_config_test_plan.rst b/test_plans/dynamic_config_test_plan.rst
new file mode 100644
index 0000000..f1dbd1b
--- /dev/null
+++ b/test_plans/dynamic_config_test_plan.rst
@@ -0,0 +1,199 @@
+.. Copyright (c) <2010, 2011>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=======================================
+Change driver configuration dynamically
+=======================================
+
+The purpose of this test is to check that it is possible to change the
+configuration of a port dynamically. The following command can be used
+to change the promiscuous mode of a specific port::
+
+ set promisc PORTID on|off
+
+A traffic generator sends traffic with a different destination mac
+address than the one that is configured on the port. Once the
+``testpmd`` application is started, it is possible to display the
+statistics of a port using::
+
+ show port stats PORTID
+
+When promiscuous mode is disabled, packet must not be received. When
+it is enabled, packets must be received. The change occurs without
+stopping the device or restarting the application.
+
+
+Prerequisites
+=============
+
+Support igb_uio and vfio driver, if used vfio, kernel need 3.6+ and enable vt-d in bios.
+When used vfio , used "modprobe vfio" and "modprobe vfio-pci" insmod vfiod driver, then used
+"./tools/dpdk_nic_bind.py --bind=vfio-pci device_bus_id" to bind vfio driver to test driver.
+
+Connect the traffic generator to one of the ports (8 in this example).
+The size of the packets is not important, in this example it was 64.
+
+Start the testpmd application.
+
+Use the 'show port' command to see the MAC address and promiscuous mode for port 8.
+The default value for promosuous mode should be enabled::
+
+ testpmd> show port info 8
+
+ ********************* Infos for port 8 *********************
+ MAC address: 00:1B:21:6D:A3:6E
+ Link status: up
+ Link speed: 1000 Mbps
+ Link duplex: full-duplex
+ Promiscuous mode: enabled
+ Allmulticast mode: disabled
+
+
+Test Case: Default Mode
+=======================
+
+The promiscuous mode should be enabled by default.
+In promiscuous mode all packets should be received.
+
+Read the stats for port 8 before sending packets.::
+
+ testpmd> show port stats 8
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 1 RX-errors: 0 RX-bytes: 64
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+
+Send a packet with destination MAC address different than the port 8 address.::
+
+ testpmd> show port stats 8
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 2 RX-errors: 0 RX-bytes: 128
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+
+Verify that the packet was received (RX-packets incremented).
+Send a packet with with destination MAC address equal with the port 8 address.::
+
+ testpmd> show port stats 8
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 3 RX-errors: 0 RX-bytes: 192
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+
+Verify that the packet was received (RX-packets incremented).
+
+
+Test Case: Disable Promiscuous Mode
+===================================
+
+Disable promiscuous mode and verify that the packets are received only for the
+packet with destination address matching the port 8 address.::
+
+ testpmd> set promisc 8 off
+
+Send a packet with destination MAC address different than the port 8 address.::
+
+ testpmd> show port stats 8
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 3 RX-errors: 0 RX-bytes: 192
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+
+Verify that no packet was received (RX-packets is the same).
+
+Send a packet with destination MAC address equal to the port 8 address.::
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 4 RX-errors: 0 RX-bytes: 256
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+
+Verify that the packet was received (RX-packets incremented).
+
+
+
+Test Case: Enable Promiscuous Mode
+==================================
+
+Verify that promiscous mode is still disabled:::
+
+ testpmd> show port info 8
+
+ ********************* Infos for port 8 *********************
+ MAC address: 00:1B:21:6D:A3:6E
+ Link status: up
+ Link speed: 1000 Mbps
+ Link duplex: full-duplex
+ Promiscuous mode: disabled
+ Allmulticast mode: disabled
+
+Enable promiscuous mode and verify that the packets are received for any
+destination MAC address.::
+
+ testpmd> set promisc 8 on
+ testpmd> show port stats 8
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 4 RX-errors: 0 RX-bytes: 256
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+ testpmd> show port stats 8
+
+Send a packet with destination MAC address different than the port 8 address.::
+
+ testpmd> show port stats 8
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 5 RX-errors: 0 RX-bytes: 320
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+
+Verify that the packet was received (RX-packets incremented).
+
+Send a packet with with destination MAC address equal with the port 8 address.::
+
+ testpmd> show port stats 8
+
+ ######################## NIC statistics for port 8 ########################
+ RX-packets: 6 RX-errors: 0 RX-bytes: 384
+ TX-packets: 0 TX-errors: 0 TX-bytes: 0
+ ############################################################################
+
+Verify that the packet was received (RX-packets incremented).
+
+
+
+
diff --git a/test_plans/generic_filter_test_plan.rst b/test_plans/generic_filter_test_plan.rst
new file mode 100644
index 0000000..511e5bc
--- /dev/null
+++ b/test_plans/generic_filter_test_plan.rst
@@ -0,0 +1,483 @@
+ .. Copyright (c) <2015>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Description
+=====================================================
+This document provides the plan for testing the generic filter feature of 10GbE and 1GbE Ethernet Controller.In `testpmd`, app provides Generic Filter API to manage filter rules for kinds of packets, and calls the API to manage HW filters in HW, or SW filters in SW table.
+
+* A generic filter provides an ability to identify specific flows or sets of flows and routes them to dedicated queues.
+* Based on the Generic Filter mechanism, all the SYN packets are placed in an assigned queue.
+* Based on the Generic Filter mechanism, all packets belonging to L3/L4 flows to be placed in a specific HW queue.Each filter consists of a 5-tuple (protocol, source and destination IP addresses, source and destination TCP/UDP/SCTP port) and routes packets into one of the Rx queues
+* L2 Ethertype Filters provides an ability to identify packets by their L2 Ethertype and assigns them to receive queues.
+`Testpmd` app is used to test all types of HW filters. Case 1~9 are the function test for the above app while case 11,12 are the performance test for Niantic, I350, 82580 and 82576.
+
+
+Prerequisites
+===================================================
+Assuming that ports ``0`` and ``1`` are connected to a traffic generator's port ``A`` and ``B``.
+
+Setup for ``testpmd``
+-----------------------------------------------------------------
+Launch the app ``testpmd`` with the following arguments::
+
+ ./testpmd -c fffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=16 --nb-ports=2
+
+The -n command is used to select the number of memory channels. It should be matched with the number of memory channels on that setup. The value of rxq and txq is 1 by default, it's necessary to increase them, and make sure rxq and txq more than one. At the same time rss is enable by default, so disable it. Map port queues to statistic counter registers. forvtill not support this function::
+
+ testpmd>set stat_qmap rx 0 0 0
+ testpmd>set stat_qmap rx 0 1 1
+ testpmd>set stat_qmap rx 0 2 2
+ testpmd>set stat_qmap rx 0 3 3
+Setup for receive all packet and disable vlan strip function::
+
+ testpmd>vlan set strip off 0
+ testpmd>vlan set strip off 1
+ testpmd>vlan set filter off 0
+ testpmd>vlan set filter off 1
+ testpmd>set flush_rx on
+
+
+Test Case 1: SYN filter
+===================================================================
+SYN filters might routes TCP packets with their SYN flag set into an assigned queue. By filtering such packets to an assigned queue, security software can monitor and
+act on SYN attacks.
+
+Enable SYN filters with queue 2 on port 0.::
+
+ testpmd> syn_filter 0 add priority high queue 2
+
+Then setup for receive::
+
+ testpmd> start
+Configure the traffic generator to send 5 SYN packets and 5 non-SYN packets .
+Reading the stats for port 0 after sending packets.::
+
+ testpmd> stop
+Verify that the packets are received (RX-packets incremented)on the queue 2.
+Set off SYN filter::
+
+ testpmd>syn_filter 0 del priority high queue 2
+ testpmd>start
+Send 5 SYN packets, then reading the stats for port 0 after sending packets.::
+
+ testpmd> stop
+Verify that the packets are not received (RX-packets do not increased)on the queue 2 and syn filter is removed.
+
+
+Test Case 2: 5-tuple Filter
+===================================================================
+This filter identifies specific L3/L4 flows or sets of L3/L4 flows and routes them to dedicated queues. Each filter consists of a 5-tuple (protocol, source and destination IP addresses, source and destination TCP/UDP/SCTP port) and routes packets into one of the Rx queues.
+The 5-tuple filters are configured via `dst_ip`, `src_ip`, `dst_port`, `src_port`, `protocol` and Mask.This case supports two type NIC(niantic, 82576), and their command line are different. niantic and 82576 register are different, for niantic TCP flags not need config,so used 0, 82576 must config tcp flags, the tcp flags means the package is a SYN package.
+Enable the 5-tuple Filter with queue 3 on port 0 for niantic. ::
+
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f tcp_flags 0x0 priority 3 queue 3
+
+Enable the 5-tuple Filter with queue 3 on port 0 for 82576. ::
+
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f flags 0x02 priority 3 queue 3
+
+Then setup for receive::
+
+ testpmd> start
+If the NIC type is niantic, then send different type packets such as (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp) and arp. ::
+
+ testpmd> stop
+Verify that the packets (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp)or (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp, `flags` = 0x2) are received (RX-packets doesn't incremented)on the queue 3.Remove L3/L4 5-tuple filter.
+Disable 5-tuple Filters::
+
+ testpmd> 5tuple_filter 0 del dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f flags 0x02 priority 3 queue 3
+ testpmd> start
+Send packets(`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp) or (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp `flags` = 0x2) .Then reading the stats for port 0 after sending packets.::
+
+ testpmd> stop
+Verify that the packets are not received (RX-packets do not increased)on the queue 3. A 5-bit field that masks each of the fields in the 5-tuple (L4 protocol, IP addresses, TCP/UDP ports).
+If 5-tuple fields are masked with 0x0 (`mask` = 0x0), the filter will routes all the packets(ip) on the assigned queue.For instance, enable the 5-tuple Filters with queue 3 on port 0 for niantic. however, the value of mask is set 0x0::
+
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol tcp mask 0x0 flags 0x0 priority 3 queue 3
+
+Test Case 3: ethertype filter
+===================================================================
+Enable the receipt of ARP packets with queue 2 on port 0::
+
+ testpmd> ethertype_filter 0 add ethertype 0x0806 priority disable 0 queue 2
+Then setup for receive::
+
+ testpmd> start
+Configure the traffic generator to send 15 ARP packets and 15 non ARP packets::
+
+ testpmd> stop
+Verify that the arp packets are received (RX-packets incremented)on the queue 2 .
+remove ethertype filter::
+
+ testpmd> ethertype_filter 0 del ethertype 0x0806 priority disable 0 queue 2
+ testpmd> start
+Configure the traffic generator to send 15 ARP packets.
+
+ testpmd> stop
+Also, you can change the value of priority to set a new filter except the case the value of ethertype is 0x0800 with priority enable .The rest of steps are same.
+For instance, enable priority filter(just support niantic)::
+
+ testpmd> ethertype_filter 0 add ethertype 0x0806 priority enable 1 queue 2
+
+Test Case 4: 10GB Multiple filters
+===================================================================
+Enable ethertype filter, SYN filter and 5-tuple Filter on the port 0 at same time. Assigning different filters to different queues on port 0::
+
+ testpmd> syn_filter 0 add priority high queue 1
+ testpmd> ethertype_filter 0 add ethertype 0x0806 priority disable 0 queue 3
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol tcp mask 0x1f priority 3 queue 3
+ testpmd> start
+
+Configure the traffic generator to send different packets. Such as,SYN packets, ARP packets, IP packets and packets with(`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp)::
+
+ testpmd> stop
+Verify that different packets are received (RX-packets incremented)on the assigned queue.
+Remove ethertype filter::
+
+ testpmd> ethertype_filter 0 del ethertype 0x0806 priority disable 0 queue 3
+ testpmd>start
+Send SYN packets, ARP packets and packets with (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp).::
+
+ testpmd> stop
+Verify that all packets are received (RX-packets incremented)on the assigned queue except arp packets, remove 5-tuple filter::
+
+ testpmd>5tuple_filter 0 del dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol tcp mask 0x1f priority 3 queue 3
+ testpmd> start
+Send different packets such as,SYN packets, ARP packets, packets with (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp)::
+
+ testpmd>stop
+Verify that only SYN packets are received (RX-packets incremented)on the assigned queue
+set off SYN filter::
+
+ testpmd>syn_filter 0 del priority high queue 1
+ testpmd>start
+Configure the traffic generator to send 5 SYN packets::
+
+ testpmd>stop
+Verify that the packets are not received (RX-packets do not increased)on the queue 1.
+
+
+Test Case 5: 2-tuple filter
+===================================================================
+This case is designed for NIC type:I350, 82580.
+Enable the receipt of udp packets with queue 1 on port 0::
+
+ testpmd> 2tuple_filter 0 add protocol 0x11 1 dst_port 64 1 flags 0 priority 3 queue 1
+Then setup for receive::
+
+ testpmd> start
+Send 15 udp packets(`dst_port` = 15, `protocol` = udp) and 15 non udp packets.Reading the stats for port 0 after sending packets::
+
+ testpmd> stop
+
+Verify that the udp packets are received (RX-packets incremented)on the queue 1.
+Remove 2tuple filter::
+
+ testpmd> 2tuple_filter 0 del protocol 0x11 1 dst_port 64 1 flags 0 priority 3 queue 1
+ testpmd> start
+Configure the traffic generator to send udp packets(`dst_port` = 15, `protocol` = udp).
+Reading the stats for port 0 after sending packets::
+
+ testpmd> stop
+Verify that the packets are not received (RX-packets do not increased)on the queue 1.
+Also, you can change the value of protocol or dstport or flags to set a new filter.the rest of steps are same.For example::
+
+Enable the receipt of UDP packets with queue 1 on port 1::
+
+ testpmd> 2tuple_filter 1 add protocol 0x011 1 dst_port 64 1 flags 0 priority 3 queue 2
+
+Enable the receipt of TCP packets with flags on queue 1 of port 1::
+
+ testpmd> 2tuple_filter 1 add protocol 0x06 1 dst_port 64 1 flags 0x3F priority 3 queue 3
+
+
+Test Case 6: flex filter
+===================================================================
+This case is designed for NIC type:I350, 82576,82580.
+Enable the receipt of packets(context) with queue 1 on port 0::
+
+ testpmd> flex_filter 0 add len 16 bytes 0x0123456789abcdef0000000008060000 mask 000C priority 3 queue 1
+
+If flex Filter is added successfully, it displays::
+ bytes[0]:01 bytes[1]:23 bytes[2]:45 bytes[3]:67 bytes[4]:89 bytes[5]:ab bytes[6]:cd bytes[7]:ef bytes[8]:00 bytes[9]:00 bytes[10]:00 bytes[11]:00 bytes[12]:08 bytes[13]:06 bytes[14]:00 bytes[15]:00
+ mask[0]:00 mask[1]:0c
+Then setup for receive::
+
+ testpmd> start
+Configure the traffic generator to send packets(context) and arp packtes.
+Reading the stats for port 0 after sending packets::
+
+ testpmd> stop
+Verify that the arp packets are received (RX-packets incremented)on the queue 1.
+Remove flex filter::
+
+ testpmd> flex_filter 0 add len 16 bytes 0x0123456789abcdef0000000008060000 mask 000C priority 3 queue 1
+ testpmd> start
+Configure the traffic generator to send packets(context).Reading the stats for port 0 after sending packets::
+
+ testpmd> stop
+Verify that the packets are not received (RX-packets do not increased)on the queue 1. Also, you can change the value of length or context or mask to set a new filter.the rest of steps are same.::
+
+ testpmd> flex_filter 0 add len 32 bytes 0x0123456789abcdef00000000080600000123456789abcdef0000000008060000 mask 000C000C priority 1 queue 2
+
+Test Case 7: priority filter
+===================================================================
+This case is designed for NIC (niantic,I350, 82576 and 82580). If packets are match on different filters with same type, the filter with high priority will be receive packets. For example, packets are match on two five-tuple filters with different priority, the filter with high priority will be receive packets. if packets are match on different filters with different type, packets based on the above criteria and the following order.when syn set priority high, syn filter has highest priority than others filter. And flex filter has higher priority than 2-tuple filter.
+If the Nic is niantic, enable the 5-tuple filter::
+
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f flags 0x0 priority 2 queue 2
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 2 src_port 2 protocol 0x06 mask 0x18 flags 0x0 priority 3 queue 3
+ testpmd> start
+Configure the traffic generator to send packets (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp).
+
+ testpmd> stop
+packets are received (RX-packets be increased)on the queue 2.
+Remove the 5tuple filter with high priority::
+
+ testpmd>5tuple_filter 0 del dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f flags 0x0 priority 2 queue 2
+ testpmd> start
+Configure the traffic generator to send packets (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp)
+
+ testpmd> stop
+packets are received (RX-packets be increased)on the queue 3.
+If the Nic is I350 or 82580, enable the 2-tuple and flex filters::
+
+ testpmd> flex_filter 0 add len 16 bytes 0x0123456789abcdef0000000008000000 mask 000C priority 2 queue 1
+ testpmd> 2tuple_filter 0 add protocol 0x11 1 dst_port 64 1 flags 0 priority 3 queue 2
+ testpmd> start
+Configure the traffic generator to send packets (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 64 `src_port` = 1 `protocol` = udp).
+
+ testpmd> stop
+packets are received (RX-packets be increased)on the queue 2.
+Remove the 2tuple filter with high priority::
+
+ testpmd> 2tuple_filter 0 add protocol 0x11 1 dst_port 64 1 flags 0 priority 3 queue 2
+ testpmd> start
+Configure the traffic generator to send packets (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 64 `src_port` = 1 `protocol` = udp),
+
+ testpmd> stop
+packets are received (RX-packets be increased)on the queue 1.
+If the Nic is 82576, enable the syn and 2-tuple filter::
+
+ testpmd>5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f flags 0x02 priority 3 queue 3
+ testpmd>syn_filter 0 add priority high queue 2
+ testpmd> start
+Configure the traffic generator to send packets (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp `flags` = "S").
+
+ testpmd>stop
+packets are received (RX-packets be increased)on the queue 2.
+Remove the syn filter with high priority::
+
+ testpmd>syn_filter 0 del priority high queue 2
+ testpmd>start
+Configure the traffic generator to send packets (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 64 `src_port` = 1 `protocol` = tcp `flags` = "S").
+
+ testpmd> stop
+packets are received (RX-packets be increased)on the queue 3.
+
+
+
+Test Case 8: 1GB Multiple filters
+===================================================================
+This case is designed for NIC(I350, 82576,82580). Enable syn filter and ethertype filter on the port 0 at the same time. Assigning different filters to different queues on port 0.Enable the filters::
+
+ testpmd> syn_filter 0 add priority high queue 1
+ testpmd> ethertype_filter 0 add ethertype 0x0806 priority disable 0 queue 3
+ testpmd> start
+
+Configure the traffic generator to send ethertype packets and arp packets . ::
+
+ testpmd> stop
+Then Verify that the packet are received on the queue 1,queue 3.
+Remove all the filter::
+
+ testpmd> syn_filter 0 add priority high queue 1
+ testpmd> ethertype_filter 0 add ethertype 0x0806 priority disable 0 queue 3
+
+Configure the traffic generator to send udp packets and arp packets. Then Verify that the packet are not received on the queue 1 and queue 3 ::
+
+ testpmd> quit
+
+Test Case 9: jumbo framesize filter
+===================================================================
+ This case is designed for NIC (niantic,I350, 82576 and 82580). Since ``Testpmd`` could transmits packets with jumbo frame size , it also could transmit above packets on assigned queue.
+Launch the app ``testpmd`` with the following arguments::
+
+ testpmd -c ffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2 --rxd=1024 --txd=1024 --burst=144 --txpt=32 --txht=8 --txwt=0 --txfreet=0 --rxfreet=64 --mbcache=200 --mbuf-size=2048 --max-pkt-len=9600
+
+ testpmd>set stat_qmap rx 0 0 0
+ testpmd>set stat_qmap rx 0 1 1
+ testpmd>set stat_qmap rx 0 2 2
+ testpmd>vlan set strip off 0
+ testpmd>vlan set strip off 1
+ testpmd>vlan set filter off 0
+ testpmd>vlan set filter off 1
+Enable the syn filters with large size::
+
+ testpmd> syn_filter 0 add priority high queue 1
+ testpmd> start
+
+Configure the traffic generator to send syn packets(framesize=2000) . ::
+
+ testpmd> stop
+Then Verify that the packet are received on the queue 1.
+Remove the filter::
+
+ testpmd> syn_filter 0 del priority high queue 1
+
+Configure the traffic generator to send syn packets and s. Then Verify that the packet are not received on the queue 1 ::
+
+ testpmd> quit
+
+Test Case 10: 128 queues
+===================================================================
+This case is designed for NIC(niantic). Since NIC(niantic) has 128 transmit queues, it should be supports 128 kinds of filter if Hardware have enough cores.
+Launch the app ``testpmd`` with the following arguments::
+
+ ./testpmd -c fffff -n 4 -- -i --disable-rss --rxq=128 --txq=128 --nb-cores=16 --nb-ports=2 --total-num-mbufs=60000
+
+ testpmd>set stat_qmap rx 0 0 0
+ testpmd>set stat_qmap rx 0 64 1
+ testpmd>set stat_qmap rx 0 64 2
+ testpmd>vlan set strip off 0
+ testpmd>vlan set strip off 1
+ testpmd>vlan set filter off 0
+ testpmd>vlan set filter off 1
+Enable the 5-tuple Filters with different queues (64,127) on port 0 for niantic. ::
+
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f flags 0x0 priority 3 queue 64 index 1
+ testpmd> 5tuple_filter 0 add dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 2 src_port 1 protocol 0x06 mask 0x1f flags 0x0 priority 3 queue 127 index 1
+Send packets(`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 1 `src_port` = 1 `protocol` = tcp) and (`dst_ip` = 2.2.2.5 `src_ip` = 2.2.2.4 `dst_port` = 2 `src_port` = 1 `protocol` = tcp ) . Then reading the stats for port 0 after sending packets. packets are received on the queue 64 and queue 127
+ When setting 5-tuple Filter with queue(128), it will display failure because the number of queues no more than 128.
+
+
+
+Test Case 11: 10G NIC Performance
+===================================================================
+This case is designed for Niantic. It provides the performance data with and without generic filter. ::
+ Launch app without filter
+ ./testpmd -c fffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=16 --nb-ports=2
+ testpmd> start
+
+Send the packets stream from packet generator::
+
+ testpmd> quit
+Enable the filters on app::
+
+ ./testpmd -c fffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=16 --nb-ports=2
+
+ testpmd>set stat_qmap rx 0 0 0
+ testpmd>set stat_qmap rx 0 1 1
+ testpmd>set stat_qmap rx 0 2 2
+ testpmd>set stat_qmap rx 0 3 3
+ testpmd>set flush_rx on
+ testpmd> add_syn_filter 0 priority high queue 1
+ testpmd> add_ethertype_filter 0 ethertype 0x0806 priority disable 0 queue 2 index 1
+ testpmd> add_5tuple_filter 0 dst_ip 2.2.2.5 src_ip 2.2.2.4 dst_port 1 src_port 1 protocol 0x06 mask 0x1f flags 0x02 priority 3 queue 3 index 1
+ testpmd> start
+
+Send the packets stream from packet generator::
+
+ testpmd> quit
+
+
+
++-------+---------+---------+
+| Frame | disable | enable |
+| Size | filter | filter |
++-------+---------+---------+
+| 64 | | |
++-------+---------+---------+
+| 128 | | |
++-------+---------+---------+
+| 256 | | |
++-------+---------+---------+
+| 512 | | |
++-------+---------+---------+
+| 1024 | | |
++-------+---------+---------+
+| 1280 | | |
++-------+---------+---------+
+| 1518 | | |
++-------+---------+---------+
+
+
+Test Case 12: 1G NIC Performance
+===================================================================
+This case is designed for NIC (I350, 82580, and 82576). It provides the performance data with and without generic filter.::
+
+ ./testpmd -c fffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=16 --nb-ports=2
+ testpmd> start
+
+Send the packets stream from packet generator::
+
+ testpmd> quit
+
+Enable the filter ::
+
+ ./testpmd -c fffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=16 --nb-ports=2
+
+ testpmd>set stat_qmap rx 0 0 0
+ testpmd>set stat_qmap rx 0 1 1
+ testpmd>set stat_qmap rx 0 2 2
+ testpmd>set stat_qmap rx 0 3 3
+ testpmd>set flush_rx on
+ testpmd> add_syn_filter 0 priority high queue 1
+ testpmd> add_ethertype_filter 0 ethertype 0x0806 priority disable 0 queue 2 index 1
+ testpmd> start
+
+
+Send the packets stream from packet generator::
+
+ testpmd> quit
+
+
+
++-------+---------+---------+
+| Frame | disable | enable |
+| Size | filter | filter |
++-------+---------+---------+
+| 64 | | |
++-------+---------+---------+
+| 128 | | |
++-------+---------+---------+
+| 256 | | |
++-------+---------+---------+
+| 512 | | |
++-------+---------+---------+
+| 1024 | | |
++-------+---------+---------+
+| 1280 | | |
++-------+---------+---------+
+| 1518 | | |
++-------+---------+---------+
diff --git a/test_plans/ipv4_reassembly_test_plan.rst b/test_plans/ipv4_reassembly_test_plan.rst
new file mode 100644
index 0000000..91ba792
--- /dev/null
+++ b/test_plans/ipv4_reassembly_test_plan.rst
@@ -0,0 +1,233 @@
+.. Copyright (c) <2013>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+=============
+IP Reassembly
+=============
+
+This document provides a test plan for benchmarking of the IP Reassembly
+sample application. This is a simple example app featuring packet processing
+using Intel® Data Plane Development Kit (Intel® DPDK) that show-cases the use
+of IP fragmented packets reassembly.
+
+
+
+Prerequisites
+-------------
+
+Support igb_uio and vfio driver, if used vfio, kernel need 3.6+ and enable vt-d in bios.
+When used vfio , used "modprobe vfio" and "modprobe vfio-pci" insmod vfiod driver, then used
+"./tools/dpdk_nic_bind.py --bind=vfio-pci device_bus_id" to bind vfio driver to test driver.
+
+1x Intel® 82599 (Niantic) NICs (1x 10GbE full duplex optical ports per NIC)
+plugged into the available PCIe Gen2 8-lane slots.
+
+
+Test Case: Send 1K packets, 4 fragments each and 1K maxflows
+============================================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1024 --flowttl=10s
+
+Sends 1K packets split in 4 fragments each with a ``maxflows`` of 1K.
+
+It expects:
+
+ - 4K IP packets to be sent to the DUT.
+ - 1K TCP packets being forwarded back to the TESTER.
+ - 1K packets with a valid TCP checksum.
+
+
+Test Case: Send 2K packets, 4 fragments each and 1K maxflows
+============================================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1024 --flowttl=10s
+
+Sends 2K packets split in 4 fragments each with a ``maxflows`` of 1K.
+
+It expects:
+
+ - 8K IP packets to be sent to the DUT.
+ - 1K TCP packets being forwarded back to the TESTER.
+ - 1K packets with a valid TCP checksum.
+
+
+Test Case: Send 4K packets, 7 fragments each and 4K maxflows
+============================================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=4096 --flowttl=10s
+
+Modifies the sample app source code to enable up to 7 fragments per packet.
+Sends 4K packets split in 7 fragments each with a ``maxflows`` of 4K.
+
+It expects:
+
+ - 28K IP packets to be sent to the DUT.
+ - 4K TCP packets being forwarded back to the TESTER.
+ - 4K packets with a valid TCP checksum.
+
+
+Test Case: Send +1K packets and ttl 3s; wait +ttl; send 1K packets
+==================================================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1024 --flowttl=3s
+
+Sends 1100 packets split in 4 fragments each.
+
+It expects:
+
+ - 4400 IP packets to be sent to the DUT.
+ - 1K TCP packets being forwarded back to the TESTER.
+ - 1K packets with a valid TCP checksum.
+
+
+Then waits until the ``flowttl`` timeout and sends 1K packets.
+
+It expects:
+
+ - 4K IP packets to be sent to the DUT.
+ - 1K TCP packets being forwarded back to the TESTER.
+ - 1K packets with a valid TCP checksum.
+
+
+Test Case: Send more packets than maxflows; only maxflows packets are forwarded back
+====================================================================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1023 --flowttl=5s
+
+Sends 1K packets with ``maxflows`` equal to 1023.
+
+It expects:
+
+ - 4092 IP packets to be sent to the DUT.
+ - 1023 TCP packets being forwarded back to the TESTER.
+ - 1023 packets with a valid TCP checksum.
+
+Then sends 1023 packets.
+
+It expects:
+
+ - 4092 IP packets to be sent to the DUT.
+ - 1023 TCP packets being forwarded back to the TESTER.
+ - 1023 packets with a valid TCP checksum.
+
+Finally waits until the ``flowttl`` timeout and re-send 1K packets.
+
+It expects:
+
+ - 4092 IP packets to be sent to the DUT.
+ - 1023 TCP packets being forwarded back to the TESTER.
+ - 1023 packets with a valid TCP checksum.
+
+
+Test Case: Send more fragments than supported
+=============================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1024 --flowttl=10s
+
+Sends 1 packet split in 5 fragments while the maximum number of supported
+fragments per packet is 4.
+
+It expects:
+
+ - 5 IP packets to be sent to the DUT.
+ - 0 TCP packets being forwarded back to the TESTER.
+ - 0 packets with a valid TCP checksum.
+
+
+
+Test Case: Send 3 frames and delay the 4th; no frames are forwarded back
+========================================================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1024 --flowttl=3s
+
+Creates 1 packet split in 4 fragments. Sends the first 3 fragments and waits
+until the ``flowttl`` timeout. Then sends the 4th fragment.
+
+It expects:
+
+ - 4 IP packets to be sent to the DUT.
+ - 0 TCP packets being forwarded back to the TESTER.
+ - 0 packets with a valid TCP checksum.
+
+
+
+Test Case: Send jumbo frames
+============================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1024 --flowttl=10s --enable-jumbo --max-pkt-len=9500
+
+Sets the NIC MTU to 9000 and sends 1K packets of 8900B split in 4 fragments of
+2500B at the most. The reassembled packet size will not be bigger than the
+MTU previously defined.
+
+It expects:
+
+ - 4K IP packets to be sent to the DUT.
+ - 1K TCP packets being forwarded back to the TESTER.
+ - 1K packets with a valid TCP checksum.
+
+
+Test Case: Send jumbo frames without enable them in the app
+===========================================================
+
+Sample command::
+
+ ./examples/ip_reassembly/build/ip_reassembly -c 0x2 -n 4 -- -P -p 0x2 --config "(1,0,1)" --maxflows=1024 --flowttl=10s
+
+Sends jumbo packets in the same way the previous test case does but without
+enabling support within the sample app.
+
+It expects:
+
+ - 4K IP packets to be sent to the DUT.
+ - 0 TCP packets being forwarded back to the TESTER.
+ - 0 packets with a valid TCP checksum.
+
+
diff --git a/test_plans/nvgre_test_plan.rst b/test_plans/nvgre_test_plan.rst
new file mode 100644
index 0000000..4e4a9f4
--- /dev/null
+++ b/test_plans/nvgre_test_plan.rst
@@ -0,0 +1,389 @@
+.. Copyright (c) <2015>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPR ESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+================
+ Fortville NVGRE
+================
+Cloud providers build virtual network overlays over existing network
+infrastructure that provide tenant isolation and scaling. Tunneling
+layers added to the packets carry the virtual networking frames over
+existing Layer 2 and IP networks. Conceptually, this is similar to
+creating virtual private networks over the Internet. Fortville will
+process these tunneling layers by the hardware.
+
+This document provides test plan for Fortville NVGRE packet detecting,
+checksum computing and filtering.
+
+Prerequisites
+=============
+1x Intel� X710 (Fortville) NICs (2x 40GbE full duplex optical ports per NIC)
+plugged into the available PCIe Gen3 8-lane slot.
+
+1x Intel� XL710-DA4 (Eagle Fountain) (1x 10GbE full duplex optical ports per NIC)
+plugged into the avaiable PCIe Gen3 8-lane slot.
+
+DUT board must be two sockets system and each cpu have more than 8 lcores.
+
+Test Case: NVGRE ipv4 packet detect
+===================================
+Start testpmd with tunneling packet type to NVGRE::
+
+ testpmd -c 0xffff -n 4 -- -i --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+
+Send packet as table listed and check dumped packet type the same as column
+"Rx packet type".
+
++-----------+-----------+----------+---------+----------|-----------+----------+-----------+---------------------+-----------+
+| Outer L2 |Outer Vlan | Outer L3 | NVGRE | Inner L2 |Inner Vlan | Inner L3 | Inner L4 | Rx packet type | Pkt Error |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | None | None | None | None | None | PKT_RX_IPV4_HDR | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | Yes | Yes | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | Yes | Yes | None | Ipv4 | Tcp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | Yes | Yes | None | Ipv4 | Sctp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv4 | Yes | Yes | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv4 | Yes | Yes | Yes | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+
+
+
+Test Case: NVGRE ipv6 packet detect
+===================================
+Start testpmd with tunneling packet type to NVGRE::
+
+ testpmd -c 0xffff -n 2 -- -i --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+
+Send ipv6 packet as table listed and check dumped packet type the same as
+column "Rx packet type".
+
++-----------+-----------+----------+---------+----------|-----------+----------+-----------+---------------------+-----------+
+| Outer L2 |Outer Vlan | Outer L3 | NVGRE | Inner L2 |Inner Vlan | Inner L3 | Inner L4 | Rx packet type | Pkt Error |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | None | None | None | None | None | PKT_RX_IPV6_HDR | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | Yes | Yes | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | Yes | Yes | None | Ipv6 | Tcp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | Yes | Yes | None | Ipv6 | Sctp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv6 | Yes | Yes | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv6 | Yes | Yes | Yes | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+
+Test Case: NVGRE IPv4 Filter
+========================
+This test adds NVGRE IPv4 filters to the hardware, and then checks whether
+sent packets match those filters. In order to this, the packet should first
+be sent from ``Scapy`` before the filter is created, to verify that it is not
+matched by a NVGRE IPv4 filter. The filter is then added from the ``testpmd``
+command line and the packet is sent again.
+
+Start testpmd::
+
+ testpmd -c 0xffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+
+Add one new NVGRE filter as table listed first::
+ tunnel_filter add port_id outer_mac inner_mac ip_addr inner_vlan
+ tunnel_type(vxlan|nvgre) filter_type(imac-ivlan|imac-ivlan-tenid|imac-tenid|imac
+ |omac-imac-tenid|iip) tenant_id queue_num
+
+For example:
+ tunnel_filter add 0 11:22:33:44:55:66 00:00:20:00:00:01 192.168.2.2 1
+ NVGRE imac 1 1
+
+Then send one packet and check packet was forwarded into right queue.
+
++-----------+-----------+----------+---------+----------|-----------+----------+-----------+---------------------+-----------+
+| Outer L2 |Outer Vlan | Outer L3 | NVGRE | Inner L2 |Inner Vlan | Inner L3 | Inner L4 | Rx packet type | Pkt Error |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | None | None | None | None | None | PKT_RX_IPV4_HDR | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | Yes | Yes | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | Yes | Yes | None | Ipv4 | Tcp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | Yes | Yes | None | Ipv4 | Sctp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv4 | Yes | Yes | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv4 | Yes | Yes | Yes | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+
+Remove NVGRE filter which has been added. Then send one packet and check
+packet was received in queue 0.
+
+
+Test Case: NVGRE IPv4 Filter invalid
+========================
+This test adds NVGRE IPv6 filters by invalid command, and then checks command
+result.
+
+Start testpmd::
+
+ testpmd -c 0xffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+
+Add NVGRE filter as table listed first::
+ tunnel_filter add port_id outer_mac inner_mac ip_addr inner_vlan
+ tunnel_type(vxlan|nvgre) filter_type(imac-ivlan|imac-ivlan-tenid|imac-tenid|imac
+ |omac-imac-tenid|iip) tenant_id queue_num
+
+Validte the filter command with wrong parameter::
+
+Add Clould filter with invalid Mac address "00:00:00:00:01" will be failed.
+
+Add Clould filter with invalid ip address "192.168.1.256" will be failed.
+
+Add Clould filter with invalid vlan "4097" will be failed.
+
+Add Clould filter with invalid vni "16777216" will be failed.
+
+Add Clould filter with invalid queue id "64" will be failed.
+
+Test Case: NVGRE IPv6 Filter
+========================
+This test adds NVGRE IPv6 filters to the hardware, and then checks whether
+sent packets match those filters. In order to this, the packet should first
+be sent from ``Scapy`` before the filter is created, to verify that it is not
+matched by a NVGRE IPv6 filter. The filter is then added from the ``testpmd``
+command line and the packet is sent again.
+
+Start testpmd::
+
+ testpmd -c 0xffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+
+Add NVGRE filter as table listed first::
+ tunnel_filter add port_id outer_mac inner_mac ip_addr inner_vlan
+ tunnel_type(vxlan|nvgre) filter_type(imac-ivlan|imac-ivlan-tenid|imac-tenid|imac
+ |omac-imac-tenid|iip) tenant_id queue_num
+
+For example:
+ tunnel_filter add 0 11:22:33:44:55:66 00:00:20:00:00:01 192.168.2.2 1
+ NVGRE imac 1 1
+
+Then send one packet and check packet was forwarded into right queue.
+
++-----------+-----------+----------+---------+----------|-----------+----------+-----------+---------------------+-----------+
+| Outer L2 |Outer Vlan | Outer L3 | NVGRE | Inner L2 |Inner Vlan | Inner L3 | Inner L4 | Rx packet type | Pkt Error |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | None | None | None | None | None | PKT_RX_IPV6_HDR | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | Yes | Yes | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | Yes | Yes | None | Ipv6 | Tcp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | Yes | Yes | None | Ipv6 | Sctp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv6 | Yes | Yes | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv6 | Yes | Yes | Yes | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+
+Remove NVGRE filter which has been added. Then send one packet and check
+packet was received in queue 0.
+
+Test Case: NVGRE ipv4 checksum offload
+======================================
+This test validates NVGRE IPv4 checksum by the hardware. In order to this, the packet should first
+be sent from ``Scapy`` with wrong checksum(0x00) value. Then the pmd forward package while checksum
+is modified on DUT tx port by hardware. To verify it, tcpdump captures the
+forwarded packet and checks the forwarded packet checksum correct or not.
+
+Start testpmd with tunneling packet type to NVGRE::
+
+ testpmd -c 0xffff -n 4 -- -i --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2 --enable-rx-cksum
+
+Set csum packet forwarding mode and enable verbose log::
+
+ set fwd csum
+ csum set ip hw <dut tx_port>
+ csum set udp hw <dut tx_port>
+ csum set tcp hw <dut tx_port>
+ csum set sctp hw <dut tx_port>
+ csum set nvgre hw <dut tx_port>
+ csum parse_tunnel on <dut tx_port>
+ set verbose 1
+
+Send packet with invalid checksum first. Then check forwarded packet checksum
+correct or not.
+
++-----------+-----------+----------+---------+----------|-----------+----------+-----------+---------------------+-----------+
+| Outer L2 |Outer Vlan | Outer L3 | NVGRE | Inner L2 |Inner Vlan | Inner L3 | Inner L4 | Rx packet type | Pkt Error |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | None | None | None | None | None | PKT_RX_IPV4_HDR | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4(Bad)| Yes | Yes | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4 | Yes | Yes | None | Ipv4(Bad)| Tcp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv4(Bad)| Yes | Yes | None | Ipv4(Bad)| Sctp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv4(Bad)| Yes | Yes | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv4 | Yes | Yes | Yes | Ipv4(Bad)| Udp | PKT_RX_IPV4_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+
+Test Case: NVGRE ipv6 checksum offload
+======================================
+This test validates NVGRE IPv6 checksum by the hardware. In order to this, the packet should first
+be sent from ``Scapy`` with wrong checksum(0x00) value. Then the pmd forward package while checksum
+is modified on DUT tx port by hardware. To verify it, tcpdump captures the
+forwarded packet and checks the forwarded packet checksum correct or not.
+
+Start testpmd with tunneling packet type::
+
+ testpmd -c ffff -n 4 -- -i --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2 --enable-rx-cksum
+
+Set csum packet forwarding mode and enable verbose log::
+
+ set fwd csum
+ csum set ip hw <dut tx_port>
+ csum set udp hw <dut tx_port>
+ csum set tcp hw <dut tx_port>
+ csum set sctp hw <dut tx_port>
+ csum set nvgre hw <dut tx_port>
+ csum parse_tunnel on <dut tx_port>
+ set verbose 1
+
+Send packet with invalid checksum first. Then check forwarded packet checksum
+correct or not.
+
++-----------+-----------+----------+---------+----------|-----------+----------+-----------+---------------------+-----------+
+| Outer L2 |Outer Vlan | Outer L3 | NVGRE | Inner L2 |Inner Vlan | Inner L3 | Inner L4 | Rx packet type | Pkt Error |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | None | None | None | None | None | PKT_RX_IPV6_HDR | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6(Bad)| Yes | Yes | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6 | Yes | Yes | None | Ipv6(Bad)| Tcp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | None | Ipv6(Bad)| Yes | Yes | None | Ipv6(Bad)| Sctp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv6(Bad)| Yes | Yes | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+| Yes | Yes | Ipv6 | Yes | Yes | Yes | Ipv6(Bad)| Udp | PKT_RX_IPV6_HDR_EXT | None |
++-----------+-----------+----------+---------+----------+-----------+----------+-----------+---------------------+-----------+
+
+
+
+Test Case: NVGRE Checksum Offload Performance Benchmarking
+==========================================================
+
+The throughput is measured for each of these cases for NVGRE tx checksum
+offload of "all by software", "inner l3 offload by hardware", "inner l4
+offload by hardware", "inner l3&l4 offload by hardware", "outer l3 offload
+by hardware", "outer l4 offload by hardware", "outer l3&l4 offload by
+hardware", "all by hardware".
+
+The results are printed in the following table:
+
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| Calculate Type | 1S/1C/1T Mpps | % linerate | 1S/1C/2T Mpps | % linerate | 1S/2C/1T Mpps | % linerate |
++================+===============+============+===============+============+===============+============+
+| SOFTWARE ALL | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| HW OUTER L3 | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| HW OUTER L4 | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| HW OUTER L3&L4 | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| HW INNER L3 | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| HW INNER L4 | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| HW INNER L3&L4 | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+| HARDWARE ALL | | | | | | |
++----------------+---------------+------------+---------------+------------+---------------+------------+
+
+Test Case: NVGRE Tunnel filter Performance Benchmarking
+=======================================================
+The throughput is measured for different NVGRE tunnel filter types.
+Queue single mean there's only one flow and forwarded to the first queue.
+Queue multi mean there're two flows and configure to different queues.
+
++--------+------------------+--------+--------+------------+
+| Packet | Filter | Queue | Mpps | % linerate |
++========+==================+========+========+============+
+| Normal | None | Single | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | None | Single | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac-ivlan | Single | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac-ivlan-tenid | Single | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac-tenid | Single | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac | Single | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | omac-imac-tenid | Single | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac-ivlan | Multi | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac-ivlan-tenid | Multi | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac-tenid | Multi | | |
++--------+------------------+--------+--------+------------+
+| NVGRE | imac | Multi | | |
++--------+------------------+--------+--------+------------+
diff --git a/test_plans/pmdrss_hash_test_plan.rst b/test_plans/pmdrss_hash_test_plan.rst
new file mode 100644
index 0000000..4922d3b
--- /dev/null
+++ b/test_plans/pmdrss_hash_test_plan.rst
@@ -0,0 +1,152 @@
+.. Copyright (c) <2011>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+==================================================================
+Fortville RSS full support - Support configuring hash functions
+==================================================================
+
+This document provides test plan for testing the function of Fortville:
+Support configuring hash functions.
+
+Prerequisites
+-------------
+
+2x Intel® 82599 (Niantic) NICs (2x 10GbE full duplex optical ports per NIC)
+1x Fortville_eagle NIC (4x 10G)
+1x Fortville_spirit NIC (2x 40G)
+2x Fortville_spirit_single NIC (1x 40G)
+
+The four ports of the 82599 connect to the Fortville_eagle;
+The two ports of Fortville_spirit connect to Fortville_spirit_single.
+The three kinds of NICs are the target NICs. the connected NICs can send packets
+to these three NICs using scapy.
+
+Network Traffic
+---------------
+
+The RSS feature is designed to improve networking performance by load balancing
+the packets received from a NIC port to multiple NIC RX queues, with each queue
+handled by a different logical core.
+
+#1. The receive packet is parsed into the header fields used by the hash
+operation (such as IP addresses, TCP port, etc.)
+
+#2. A hash calculation is performed. The Fortville supports four hash function:
+Toeplitz, simple XOR and their Symmetric RSS.
+
+#3. The seven LSBs of the hash result are used as an index into a 128/512 entry
+'redirection table'. Each entry provides a 4-bit RSS output index.
+
+#4. There are four cases to test the four hash function.
+
+Test Case: test_toeplitz
+=========================
+
+Testpmd configuration - 16 RX/TX queues per port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+#1. set up testpmd woth fortville NICs::
+
+ ./testpmd -c fffff -n %d -- -i --coremask=0xffffe --rxq=16 --txq=16
+
+#2. Reta Configuration. 128 reta entries configuration::
+
+ testpmd command: port config 0 rss reta (hash_index,queue_id)
+
+#3. PMD fwd only receive the packets::
+
+ testpmd command: set fwd rxonly
+
+#4. rss recived package type configuration two received packet types configuration::
+
+ testpmd command: port config 0 rss ip/udp
+
+#5. verbose configuration::
+
+ testpmd command: set verbose 8
+
+#6. set hash functions, can choose symmetric or not, chosse port and packet type::
+
+ set_hash_function 0 toeplitz
+
+#7. start packet receive::
+
+ testpmd command: start
+
+tester Configuration
+--------------------
+
+#1. set up scapy
+
+#2. send packets with different type ipv4/ipv4 with tcp/ipv4 with udp/
+ ipv6/ipv6 with tcp/ipv6 with udp::
+
+ sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")
+
+test result
+-----------
+
+The testpmd will print the hash value and actual queue of every packet.
+
+#1. Calaute the queue id: hash value%128or512, then refer to teh redirection table
+ to get the theoretical queue id.
+
+#2. Compare the theoretical queue id with the actual queue id.
+
+
+Test Case: test_toeplitz_symmetric
+===================================
+
+The same with the above steps, pay attention to "set hash function", should use::
+
+ set_hash_function 0 toeplitz
+ set_sym_hash_ena_per_port 0 enable
+ set_sym_hash_ena_per_pctype 0 35 enable
+
+And send packets with the same flow in different direction::
+
+ sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")
+ sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.5", dst="192.168.0.4")], iface="eth3")
+
+And the hash value and queue should be the same for these two flow .
+
+Test Case: test_simple
+=======================
+
+The same as the above two test cases. Just pay attention to set the hash function to "simple xor"
+
+Test Case: test_simple_symmetric
+=================================
+
+The same as the above two test cases. Just pay attention to set the hash function to "simple xor"
+
+
diff --git a/test_plans/pmdrssreta_test_plan.rst b/test_plans/pmdrssreta_test_plan.rst
new file mode 100644
index 0000000..d621d51
--- /dev/null
+++ b/test_plans/pmdrssreta_test_plan.rst
@@ -0,0 +1,178 @@
+.. Copyright (c) <2011>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+================================================================
+reta(Redirection table) benchmark Results of the 82599 10GbE PMD
+================================================================
+
+This document provides test plan for benchmarking of Rss reta(Redirection
+table) updating for the Intel® 82599 10 Gigabit Ethernet Controller
+(Niantic) Poll Mode Driver (PMD) in userland runtime configurations.
+The content of Rss Redirection table are not defined following reset
+of the Memory Configuration registers. System software must initialize
+the table prior to enabling multiple receive queues .It can also update
+the redirection table during run time. Such updates of the table are
+not synchronized with the arrival time of received packets.
+
+Prerequisites
+-------------
+
+2x Intel® 82599 (Niantic) NICs (2x 10GbE full duplex optical ports per NIC)
+plugged into the available PCIe Gen2 8-lane slots. To avoid PCIe bandwidth
+bottlenecks at high packet rates, a single optical port from each NIC is
+connected to the traffic generator.
+
+
+Network Traffic
+---------------
+
+The RSS feature is designed to improve networking performance by load balancing
+the packets received from a NIC port to multiple NIC RX queues, with each queue
+handled by a different logical core.
+
+#1. The receive packet is parsed into the header fields used by the hash
+operation (such as IP addresses, TCP port, etc.)
+
+#2. A hash calculation is performed. The 82599 supports a single hash function,
+as defined by MSFT RSS. The 82599 therefore does not indicate to the device
+driver which hash function is used. The 32-bit result is fed into the packet
+receive descriptor.
+
+#3. The seven LSBs of the hash result are used as an index into a 128-entry
+'redirection table'. Each entry provides a 4-bit RSS output index.
+
+The RSS RETA update feature is designed to make RSS more flexible by allowing
+users to define the correspondence between the seven LSBs of hash result and
+the queue id(RSS output index) by themself.
+
+
+Test Case: Results - IO Forwarding Mode
+========================================
+
+The following RX Ports/Queues configurations have to be benchmarked:
+
+- 1 RX port / 2 RX queues (1P/2Q)
+
+- 1 RX port / 9 RX queues (1P/9Q)
+
+- 1 RX ports / 16 RX queues (1P/16Q)
+
+
+Testpmd configuration - 2 RX/TX queues per port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ testpmd -cffffff -n 3 -b 0000:05:00.1 -- -i --rxd=512 --txd=512 --burst=32 \
+ --txpt=36 --txht=0 --txwt=0 --txfreet=32 --rxfreet=64 --txrst=32 --mbcache=128 \
+ --rxq=2 --txq=2
+
+Testpmd configuration - 9 RX/TX queues per port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ testpmd -cffffff -n 3 -b 0000:05:00.1 -- -i --rxd=512 --txd=512 --burst=32 \
+ --txpt=36 --txht=0 --txwt=0 --txfreet=32 --rxfreet=64 --txrst=32 --mbcache=128 \
+ --rxq=9 --txq=9
+
+Testpmd configuration - 16 RX/TX queues per port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+ testpmd -cffffff -n 3 -b 0000:05:00.1 -- -i --rxd=512 --txd=512 --burst=32 \
+ --txpt=36 --txht=0 --txwt=0 --txfreet=32 --rxfreet=64 --txrst=32 --mbcache=128 \
+ --rxq=16 --txq=16
+
+The -n command is used to select the number of memory channels. It should match the number of memory channels on that setup.
+The -b command is used to prevent the use of pic port to receive packets. It should match the pci number of the pci device.
+
+Testpmd Configuration Options
+-----------------------------
+
+By default, a single logical core runs the test.
+The CPU IDs and the number of logical cores running the test in parallel can
+be manually set with the ``set corelist X,Y`` and the ``set nbcore N``
+interactive commands of the ``testpmd`` application.
+
+#1. Reta Configuration. 128 reta entries configuration::
+
+ testpmd command: port config 0 rss reta (hash_index,queue_id)
+
+#2. PMD fwd only receive the packets::
+
+ testpmd command: set fwd rxonly
+
+#3. rss recived package type configuration two received packet types configuration::
+
+ testpmd command: port config 0 rss ip/udp
+
+#4. verbose configuration::
+
+ testpmd command: set verbose 8
+
+#5. start packet receive::
+
+ testpmd command: start
+
+tester Configuration
+--------------------
+
+#1. In order to make most entries of the reta to be tested,the traffic generator
+has to be configured to randomize the value of the 5-tuple fields of the
+transmitted IP/UDP packets so that RSS hash function output of 5-tuple fileds covers
+most of reta index.
+
+#2. set the package numbers of one burst to a centain value.
+
+
+Example output (1P/2Q) received by the dut):::
+-----------------------------------------------
+
++--------------+-------------+------------+-----------------+------+
+| packet index | hash output | rss output | actual queue id | pass |
++--------------+-------------+------------+-----------------+------+
+| 0 | | | | |
++--------------+-------------+------------+-----------------+------+
+| 1 | | | | |
++--------------+-------------+------------+-----------------+------+
+| 2 | | | | |
++--------------+-------------+------------+-----------------+------+
+| etc. | | | | |
++--------------+-------------+------------+-----------------+------+
+| 125 | | | | |
++--------------+-------------+------------+-----------------+------+
+| 126 | | | | |
++--------------+-------------+------------+-----------------+------+
+| 127 | | | | |
++--------------+-------------+------------+-----------------+------+
diff --git a/test_plans/queue_start_stop_test_plan.rst b/test_plans/queue_start_stop_test_plan.rst
new file mode 100644
index 0000000..5dd99cc
--- /dev/null
+++ b/test_plans/queue_start_stop_test_plan.rst
@@ -0,0 +1,75 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+======================================
+Intel. DPDK Shutdown API Feature Tests
+======================================
+
+This tests for Shutdown API feature can be run on linux userspace. It
+will check if NIC port can be stopped and restarted without exiting the
+application process. Furthermore, it will check if it can reconfigure
+new configurations for a port after the port is stopped, and if it is
+able to restart with those new configurations. It is based on testpmd
+application.
+
+The test is performed by running the testpmd application and using a
+traffic generator. Port/queue configurations can be set interactively,
+and still be set at the command line when launching the application in
+order to be compatible with previous test framework.
+
+Prerequisites
+-------------
+
+Assume port A and B are connected to the remote ports, e.g. packet generator.
+To run the testpmd application in linuxapp environment with 4 lcores,
+4 channels with other default parameters in interactive mode.
+
+ $ ./testpmd -c 0xf -n 4 -- -i
+
+Test Case: queue start/stop
+---------------------------------------
+this case support PF (fortville), VF(fortville,niantic)
+1. update testpmd source code. add a C code "printf("ports %u queue %u revice %u packages\n", fs->rx_port, fs->rx_queue, nb_rx)".
+in ./app/test-pmd/fwdmac.c
+2. compile testpmd again, then run testpmd.
+3. run "set fwd mac" to set fwd type
+4. run "start" to start fwd package
+5. start packet generator to transmit and receive packets
+6. run "port 0 rxq 0 stop" to stop rxq 0 in port 0
+7. start packet generator to transmit and not receive packets
+8. run "port 0 rxq 0 start" to start rxq 0 in port 0
+9. run "port 1 txq 1 stop" to start txq 0 in port 1
+10. start packet generator to transmit and not receive packets but in testpmd it is a "ports 0 queue 0 revice 1 packages" print
+11. run "port 1 txq 1 start" to start txq 0 in port 1
+12 start packet generator to transmit and receive packets
+13 test it again with VF
+successfully
diff --git a/test_plans/scatter_test_plan.rst b/test_plans/scatter_test_plan.rst
new file mode 100644
index 0000000..b1f1299
--- /dev/null
+++ b/test_plans/scatter_test_plan.rst
@@ -0,0 +1,119 @@
+.. Copyright (c) <2010, 2011>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=================================================
+Support of Scattered Packets by Poll Mode Drivers
+=================================================
+
+The support of scattered packets by Poll Mode Drivers consists in making
+it possible to receive and to transmit scattered multi-segments packets
+composed of multiple non-contiguous memory buffers.
+To enforce the receipt of scattered packets, the DMA rings of port RX queues
+must be configured with mbuf data buffers whose size is lower than the maximum
+frame length.
+The forwarding of scattered input packets naturally enforces the transmission
+of scattered packets by PMD transmit functions.
+
+Configuring the size of mbuf data buffers
+=========================================
+
+The size of mbuf data buffers is configured with the parameter ``--mbuf-size``
+that is supplied in the set of parameters when launching the ``testpmd``
+application.
+The default size of the mbuf data buffer is 2048 so that a full 1518-byte
+(CRC included) Ethernet frame can be stored in a mono-segment packet.
+
+Functional Tests of Scattered Packets
+=====================================
+
+Testing the support of scattered packets in Poll Mode Drivers consists in
+sending to the test machine packets whose length is greater than the size
+of mbuf data buffers used to populate the DMA rings of port RX queues.
+
+First, the receipt and the transmission of scattered packets must be tested
+with the ``CRC stripping`` option enabled, which guarantees that scattered
+packets only contain packet data.
+
+In addition, the support of scattered packets must also be performed with
+the ``CRC stripping`` option disabled, to check the special cases of scattered
+input packets whose last buffer only contains the whole CRC or part of it.
+In such cases, PMD receive functions must free the last buffer when removing
+the CRC from the packet before returning it.
+
+As a whole, the following packet lengths (CRC included) must be tested to
+check all packet memory configurations:
+
+#. packet length < mbuf data buffer size
+
+#. packet length = mbuf data buffer size
+
+#. packet length = mbuf data buffer size + 1
+
+#. packet length = mbuf data buffer size + 4
+
+#. packet length = mbuf data buffer size + 5
+
+In cases 1) and 2), the hardware RX engine stores the packet data and the CRC
+in a single buffer.
+In case 3), the hardware RX engine stores the packet data and the 3 first bytes
+of the CRC in the first buffer, and the last byte of the CRC in a second buffer.
+In case 4), the hardware RX engine stores all the packet data in the first
+buffer, and the CRC in a second buffer.
+In case 5), the hardware RX engine stores part of the packet data in the first
+buffer, and the last data byte plus the CRC in a second buffer.
+
+Prerequisites
+=============
+
+Assuming that ports ``0`` and ``1`` of the test target are directly connected
+to a Traffic Generator, launch the ``testpmd`` application with the following
+arguments::
+
+ ./build/app/testpmd -cffffff -n 3 -- -i --rxd=1024 --txd=1024 \
+ --burst=144 --txpt=32 --txht=8 --txwt=8 --txfreet=0 --rxfreet=64 \
+ --mbcache=200 --portmask=0x3 --mbuf-size=1024
+
+The -n command is used to select the number of memory channels. It should match
+the number of memory channels on that setup.
+
+Setting the size of the mbuf data buffer to 1024 makes 1025-bytes input packets
+(CRC included) and larger packets to be stored in two buffers by the hardware
+RX engine.
+
+Test Case: Mbuf 1024 traffic
+============================
+
+Start packet forwarding in the ``testpmd`` application with the ``start`` command.
+Send 5 packets of lengths (CRC included) 1023, 1024, 1025, 1028, and 1029.
+Check that the same amount of frames and bytes are received back by the Traffic
+Generator from its port connected to the target's port 1.
+
diff --git a/test_plans/shutdown_api_test_plan.rst b/test_plans/shutdown_api_test_plan.rst
new file mode 100644
index 0000000..0dd47b9
--- /dev/null
+++ b/test_plans/shutdown_api_test_plan.rst
@@ -0,0 +1,167 @@
+.. <COPYRIGHT_TAG>
+
+======================================
+Intel® DPDK Shutdown API Feature Tests
+======================================
+
+This tests for Shutdown API feature can be run on linux userspace. It
+will check if NIC port can be stopped and restarted without exiting the
+application process. Furthermore, it will check if it can reconfigure
+new configurations for a port after the port is stopped, and if it is
+able to restart with those new configurations. It is based on testpmd
+application.
+
+The test is performed by running the testpmd application and using a
+traffic generator. Port/queue configurations can be set interactively,
+and still be set at the command line when launching the application in
+order to be compatible with previous test framework.
+
+Prerequisites
+-------------
+
+Support igb_uio and vfio driver, if used vfio, kernel need 3.6+ and enable vt-d in bios.
+When used vfio , used "modprobe vfio" and "modprobe vfio-pci" insmod vfiod driver, then used
+"./tools/dpdk_nic_bind.py --bind=vfio-pci device_bus_id" to bind vfio driver to test driver.
+
+Assume port A and B are connected to the remote ports, e.g. packet generator.
+To run the testpmd application in linuxapp environment with 4 lcores,
+4 channels with other default parameters in interactive mode.
+
+ $ ./testpmd -c 0xf -n 4 -- -i
+
+Test Case: Stop and Restart
+---------------------------
+
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "start" to start forwarding packets.
+3. check that testpmd is able to forward traffic.
+4. run "stop" to stop forwarding packets.
+5. run "port stop all" to stop all ports.
+6. check on the tester side that the ports are down using ethtool.
+7. run "port start all" to restart all ports.
+8. check on the tester side that the ports are up using ethtool
+9. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check if testpmd is able to receive and forward packets
+successfully.
+
+Test Case: Reset RX/TX Queues
+-----------------------------
+
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "port stop all" to stop all ports.
+3. run "port config all rxq 2" to change the number of receiving queues to two.
+4. run "port config all txq 2" to change the number of transmiting queues to two.
+5. run "port start all" to restart all ports.
+6. check with "show config rxtx" that the configuration for these parameters changed.
+7. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check if testpmd is able to receive and forward packets
+successfully.
+
+Test Case: Set promiscuous mode
+-------------------------------
+
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if promiscuous mode setting works well after reconfiguring
+it while all ports are stopped
+2. run "port stop all" to stop all ports.
+3. run "set promisc all off" to disable promiscuous mode on all ports.
+4. run "port start all" to restart all ports.
+5. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check that testpmd is NOT able to receive and forward packets
+successfully.
+6. run "port stop all" to stop all ports.
+7. run "set promisc all on" to enable promiscuous mode on all ports.
+8. run "port start all" to restart all ports.
+9. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check that testpmd is able to receive and forward packets
+successfully.
+
+
+
+Test Case: Reconfigure All Ports With The Same Configurations (CRC)
+-------------------------------------------------------------------
+
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "port stop all" to stop all ports.
+3. run "port config all crc-strip on" to enable the CRC stripping mode.
+4. run "port start all" to restart all ports.
+5. check with "show config rxtx" that the configuration for these parameters changed.
+6. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check if testpmd is able to receive and forward packets
+successfully. Check that the packet received is 4 bytes smaller than the packet sent.
+
+Test Case: Change Link Speed
+----------------------------
+
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "port stop all" to stop all ports.
+3. run "port config all speed SPEED duplex HALF/FULL" to select the new config for the link.
+4. run "port start all" to restart all ports.
+5. check on the tester side that the configuration actually changed using ethtool.
+6. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check if testpmd is able to receive and forward packets
+successfully.
+7. repeat this process for every compatible speed depending on the NIC driver.
+
+Test Case: Enable/Disable Jumbo Frame
+-------------------------------------
+
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "port stop all" to stop all ports.
+3. run "port config all max-pkt-len 2048" to set the maximum packet length.
+4. run "port start all" to restart all ports.
+5. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check if testpmd is able to receive and forward packets
+successfully. Check this with the following packet sizes: 2047, 2048 & 2049. Only the third one should fail.
+
+Test Case: Enable/Disable RSS
+-----------------------------
+
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "port stop all" to stop all ports.
+3. run "port config rss ip" to enable RSS.
+4. run "port start all" to restart all ports.
+5. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check if testpmd is able to receive and forward packets
+successfully.
+
+Test Case: Change the Number of rxd/txd
+---------------------------------------
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "port stop all" to stop all ports.
+3. run "port config all rxd 1024" to change the rx descriptors.
+4. run "port config all txd 1024" to change the tx descriptors.
+5. run "port start all" to restart all ports.
+6. check with "show config rxtx" that the descriptors were actually changed.
+6. run "start" again to restart the forwarding, then start packet generator to transmit
+and receive packets, and check if testpmd is able to receive and forward packets
+successfully.
+
+Test Case: link stats
+---------------------------------------
+1. If the testpmd application is not launched, run it as above command. Follow
+below steps to check if it works well after reconfiguring all ports without
+changing any configurations.
+2. run "set fwd mac" to set fwd type.
+3. run "start" to start the forwarding, then start packet generator to transmit
+and receive packets
+4. run "set link-down port X" to set all port link down
+5. check on the tester side that the configuration actually changed using ethtool.
+6. start packet generator to transmit and not receive packets
+7. run "set link-up port X" to set all port link up
+8. start packet generator to transmit and receive packets
+successfully
diff --git a/test_plans/sriov_kvm_test_plan.rst b/test_plans/sriov_kvm_test_plan.rst
new file mode 100644
index 0000000..52dd0ca
--- /dev/null
+++ b/test_plans/sriov_kvm_test_plan.rst
@@ -0,0 +1,756 @@
+.. Copyright (c) <2013>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===============================
+SRIOV and InterVM Communication
+===============================
+
+Some applications such as pipelining of virtual appliances and traffic
+mirroring to virtual appliances require the high performance InterVM
+communications.
+
+The testpmd application is used to configure traffic mirroring, PF VM receive
+mode, PFUTA hash table and control traffic to a VF for inter-VM communication.
+
+The 82599 supports four separate mirroring rules, each associated with a
+destination pool. Each rule is programmed with one of the four mirroring types:
+
+1. Pool mirroring: reflect all the packets received to a pool from the network.
+2. Uplink port mirroring: reflect all the traffic received from the network.
+3. Downlink port mirroring: reflect all the traffic transmitted to the
+ network.
+4. VLAN mirroring: reflect all the traffic received from the network
+ in a set of given VLANs (either from the network or from local VMs).
+
+
+Prerequisites for all 2VMs cases/Mirror 2VMs cases
+==================================================
+
+Create two VF interface VF0 and VF1 from one PF interface and then attach them
+to VM0 and VM1. Suppose PF is 0000:08:00.0.Below are commands which can be
+used to generate 2VFs and make them in pci-stub modes.::
+
+ ./tools/pci_unbind.py --bind=igb_uio 0000:08:00.0
+ echo 2 > /sys/bus/pci/devices/0000\:08\:00.0/max_vfs
+ echo "8086 10ed" > /sys/bus/pci/drivers/pci-stub/new_id
+ echo 0000:08:10.0 >/sys/bus/pci/devices/0000\:08\:10.0/driver/unbind
+ echo 0000:08:10.2 >/sys/bus/pci/devices/0000\:08\:10.2/driver/unbind
+ echo 0000:08:10.0 >/sys/bus/pci/drivers/pci-stub/bind
+ echo 0000:08:10.0 >/sys/bus/pci/drivers/pci-stub/bind
+
+Start PF driver on the Host and skip the VFs.::
+
+ ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -b 0000:08:10.0 -b 0000:08:10.2 -- -i
+
+For VM0 start up command, you can refer to below command.::
+
+ qemu-system-x86_64 -name vm0 -enable-kvm -m 2048 -smp 4 -cpu host -drive file=/root/Downloads/vm0.img -net nic,macaddr=00:00:00:00:00:01 -net tap,script=/etc/qemu-ifup -device pci-assign,host=08:10.0 -vnc :1 --daemonize
+
+The /etc/qemu-ifup can be below script, need you to create first::
+
+ #!/bin/sh
+ set -x
+ switch=br0
+ if [ -n "$1" ];then
+ /usr/sbin/tunctl -u `whoami` -t $1
+ /sbin/ip link set $1 up
+ sleep 0.5s
+ /usr/sbin/brctl addif $switch $1
+ exit 0
+ else
+ echo "Error: no interface specified"
+ exit 1
+ fi
+
+Similar for VM1, please refer to below command for VM1::
+
+ qemu-system-x86_64 -name vm1 -enable-kvm -m 2048 -smp 4 -cpu host -drive file=/root/Downloads/vm1.img -net nic,macaddr=00:00:00:00:00:02 -net tap,script=/etc/qemu-ifup -device pci-assign,host=08:10.2 -vnc :4 -daemonize
+
+If you want to run all common 2VM cases, please run testpmd on VM0 and VM1 and
+start traffic forward on the VM hosts. Some specific prerequisites need to be
+set up in each case::
+
+ VF0 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF0 testpmd-> set fwd rxonly
+ VF0 testpmd-> start
+
+ VF1 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+
+Test Case1: InterVM communication test on 2VMs
+==============================================
+
+Set the VF0 destination mac address to VF1 mac address, packets send from VF0
+will be forwarded to VF1 and then send out::
+
+ VF1 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF1 testpmd-> show port info 0
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+
+ VF0 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- --eth-peer=0,"VF1 mac" -i
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+
+Send 10 packets with VF0 mac address and make sure the packets will be
+forwarded by VF1.
+
+Test Case2: Mirror Traffic between 2VMs with Pool mirroring
+===========================================================
+
+Set up common 2VM prerequisites.
+
+Add one mirror rule that will mirror VM0 income traffic to VM1::
+
+ PF testpmd-> set port 0 mirror-rule 0 pool-mirror 0x1 dst-pool 1 on
+
+Send 10 packets to VM0 and verify the packets has been mirrored to VM1 and
+forwarded the packet.
+
+After test need reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+
+
+Test Case3: Mirror Traffic between 2VMs with Uplink mirroring
+=============================================================
+
+Set up common 2VM prerequisites.
+
+Add one mirror rule that will mirror VM0 income traffic to VM1::
+
+ PF testpmd-> set port 0 mirror-rule 0 uplink-mirror dst-pool 1 on
+
+Send 10 packets to VM0 and verify the packets has been mirrored to VM1 and
+forwarded the packet.
+
+After test need reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+
+Test Case4: Mirror Traffic between 2VMs with Downlink mirroring
+===============================================================
+
+Run testpmd on VM0 and VM1 and start traffic forward on the VM hosts::
+
+ VF0 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF1 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+
+
+Add one mirror rule that will mirror VM0 outcome traffic to VM1::
+
+ PF testpmd-> set port 0 mirror-rule 0 downlink-mirror dst-pool 1 on
+
+Make sure VM1 in receive only mode, VM0 send 16 packets, and verify the VM0
+packets has been mirrored to VM1::
+
+ VF1 testpmd-> set fwd rxonly
+ VF1 testpmd-> start
+ VF0 testpmd-> start tx_first
+
+Note: don't let VF1 fwd packets since downlink mirror will mirror back the
+packets to received packets, which will be an infinite loop.
+
+After test need reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+
+Test Case5: Mirror Traffic between VMs with Vlan mirroring
+==========================================================
+
+Set up common 2VM prerequisites.
+
+Add rx vlan-id 0 on VF0, add one mirror rule that will mirror VM0 income
+traffic with specified vlan to VM1::
+
+ PF testpmd-> rx_vlan add 0 port 0 vf 0x1
+ PF testpmd-> set port 0 mirror-rule 0 vlan-mirror 0 dst-pool 1 on
+
+Send 10 packets with vlan-id0/vm0 MAC to VM0 and verify the packets has been
+mirrored to VM1 and forwarded the packet.
+
+After test need reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+
+Test Case6: Mirror Traffic between 2VMs with Vlan & Pool mirroring
+==================================================================
+
+Set up common 2VM prerequisites.
+
+Add rx vlan-id 3 of VF1, and 2 mirror rules, one is VM0 income traffic to VM1,
+one is VM1 vlan income traffic to VM0::
+
+ PF testpmd-> rx_vlan add 3 port 0 vf 0x2
+ PF testpmd-> set port 0 mirror-rule 0 pool-mirror 0x1 dst-pool 1 on
+ PF testpmd-> set port 0 mirror-rule 1 vlan-mirror 3 dst-pool 0 on
+
+Send 2 flows one by one, first 10 packets with VM0 mac, and the second 100
+packets with VM1 vlan and mac, and verify the first 10 packets has been
+mirrored first to VM1, second 100 packets go to VM0 and the packets have been
+forwarded.
+
+After test need reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+
+Test Case7: Mirror Traffic between 2VMs with Uplink & Downlink mirroring
+========================================================================
+
+Run testpmd on VM0 and VM1 and start traffic forward on the VM hosts::
+
+ VF0 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF1 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+
+Add 2 mirror rules that will mirror VM0 outcome and income traffic to VM1::
+
+ PF testpmd-> set port 0 mirror-rule 0 downlink-mirror dst-pool 1 on
+ PF testpmd-> set port 0 mirror-rule 0 uplink-mirror dst-pool 1 on
+
+Make sure VM1 in receive only mode, VM0 first send 16 packets, and verify the
+VM0 packets has been mirrored to VM1::
+
+ VF1 testpmd-> set fwd rxonly
+ VF1 testpmd-> start
+ VF0 testpmd-> start tx_first
+
+Note: don't let VF1 fwd packets since downlink mirror will mirror back the
+packets to received packets, which will be an infinite loop.
+
+Send 10 packets to VF0 with VF0 MAC from ixia, verify that all VF0 received
+packets and transmitted packets will mirror to VF1::
+
+ VF0 testpmd-> stop
+ VF0 testpmd-> start
+
+After test need reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+
+Test Case8: Mirror Traffic between 2VMs with Vlan & Pool & Uplink & Downlink mirroring
+======================================================================================
+
+Run testpmd on VM0 and VM1 and start traffic forward on the VM hosts::
+
+ VF0 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF1 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+
+
+Add rx vlan-id 0 on VF0 and add 4 mirror rules::
+
+ PF testpmd-> reset port 0 mirror-rule 1
+ PF testpmd-> set port 0 mirror-rule 0 downlink-mirror dst-pool 1 on
+ PF testpmd-> set port 0 mirror-rule 1 uplink-mirror dst-pool 1 on
+ PF testpmd-> rx_vlan add 0 port 0 vf 0x2
+ PF testpmd-> set port 0 mirror-rule 2 vlan-mirror 0 dst-pool 0 on
+ PF testpmd-> set port 0 mirror-rule 3 pool-mirror 0x1 dst-pool 1 on
+
+Make sure VM1 in receive only mode, VM0 first send 16 packets, and verify the
+VM0 packets has been mirrored to VM1, VF1, RX, 16packets (downlink mirror)::
+
+ VF1 testpmd-> set fwd rxonly
+ VF1 testpmd-> start
+ VF0 testpmd-> start tx_first
+
+Note: don't let VF1 fwd packets since downlink mirror will mirror back the
+packets to received packets, which will be an infinite loop.
+
+Send 1 packet to VF0 with VF0 MAC from ixia, check if VF0 RX 1 packet and TX 1
+packet, and VF1 has 2 packets mirror from VF0(uplink mirror/downlink/pool)::
+
+ VF0 testpmd-> stop
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+
+Send 1 packet with VM1 vlan id and mac, and verify that VF0 have 1 RX packet, 1
+TX packet, and VF1 have 2 packets(downlink mirror)::
+
+ VF0 testpmd-> stop
+ VF0 testpmd-> set fwd rxonly
+ VF0 testpmd-> start
+
+After test need reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+ PF testpmd-> reset port 0 mirror-rule 2
+ PF testpmd-> reset port 0 mirror-rule 3
+
+
+Test Case9: Add Multi exact MAC address on VF
+=============================================
+
+Add an exact destination mac address on VF0::
+
+ PF testpmd-> mac_addr add port 0 vf 0 00:11:22:33:44:55
+
+Send 10 packets with dst mac 00:11:22:33:44:55 to VF0 and make sure VF0 will
+receive the packets.
+
+Add another exact destination mac address on VF0::
+
+ PF testpmd-> mac_addr add port 0 vf 0 00:55:44:33:22:11
+
+Send 10 packets with dst mac 00:55:44:33:22:11 to VF0 and make sure VF0 will
+receive the packets.
+
+After test need restart PF and VF for clear exact mac addresss, first quit VF,
+then quit PF.
+
+Test Case10: Enable/Disable one uta MAC address on VF
+=====================================================
+
+Enable PF promisc mode and enable VF0 accept uta packets::
+
+ PF testpmd-> set promisc 0 on
+ PF testpmd-> set port 0 vf 0 rxmode ROPE on
+
+Add an uta destination mac address on VF0::
+
+ PF testpmd-> set port 0 uta 00:11:22:33:44:55 on
+
+Send 10 packets with dst mac 00:11:22:33:44:55 to VF0 and make sure VF0 will
+the packets.
+
+Disable PF promisc mode, repeat step3, check VF0 should not accept uta packets::
+
+ PF testpmd-> set promisc 0 off
+ PF testpmd-> set port 0 vf 0 rxmode ROPE off
+
+Test Case11: Add Multi uta MAC addresses on VF
+==============================================
+
+Add 2 uta destination mac address on VF0::
+
+ PF testpmd-> set port 0 uta 00:55:44:33:22:11 on
+ PF testpmd-> set port 0 uta 00:55:44:33:22:66 on
+
+Send 2 flows, first 10 packets with dst mac 00:55:44:33:22:11, another 100
+packets with dst mac 00:55:44:33:22:66 to VF0 and make sure VF0 will receive
+all the packets.
+
+Test Case12: Add/Remove uta MAC address on VF
+=============================================
+
+Add one uta destination mac address on VF0::
+
+ PF testpmd-> set port 0 uta 00:55:44:33:22:11 on
+
+Send 10 packets with dst mac 00:55:44:33:22:11 to VF0 and make sure VF0 will
+receive the packets.
+
+Remove the uta destination mac address on VF0::
+
+ PF testpmd-> set port 0 uta 00:55:44:33:22:11 off
+
+Send 10 packets with dst mac 00:11:22:33:44:55 to VF0 and make sure VF0 will
+not receive the packets.
+
+Add an uta destination mac address on VF0 again::
+
+ PF testpmd-> set port 0 uta 00:11:22:33:44:55 on
+
+Send packet with dst mac 00:11:22:33:44:55 to VF0 and make sure VF0 will
+receive again and forwarded the packet. This step is to make sure the on/off
+switch is working.
+
+Test Case13: Pause RX Queues
+============================
+
+Pause RX queue of VF0 then send 10 packets to VF0 and make sure VF0 will not
+receive the packets::
+
+ PF testpmd-> set port 0 vf 0 rx off
+
+Enable RX queue of VF0 then send 10 packets to VF0 and make sure VF0 will
+receive the packet::
+
+ PF testpmd-> set port 0 vf 0 rx on
+
+Repeat the off/on twice to check the switch capability, and ensure on/off can
+work stable.
+
+Test Case14: Pause TX Queues
+============================
+
+Pause TX queue of VF0 then send 10 packets to VF0 and make sure VF0 will not
+forward the packet::
+
+ PF testpmd-> set port 0 vf 0 tx off
+
+Enable RX queue of VF0 then send 10 packets to VF0 and make sure VF0 will
+forward the packet::
+
+ PF testpmd-> set port 0 vf 0 tx on
+
+Repeat the off/on twice to check the switch capability, and ensure on/off can
+work stable.
+
+Test Case15: Prevent Rx of Broadcast on VF
+==========================================
+
+Disable VF0 rx broadcast packets then send broadcast packet to VF0 and make
+sure VF0 will not receive the packet::
+
+ PF testpmd-> set port 0 vf 0 rxmode BAM off
+
+Enable VF0 rx broadcast packets then send broadcast packet to VF0 and make sure
+VF0 will receive and forward the packet::
+
+ PF testpmd-> set port 0 vf 0 rxmode BAM on
+
+Repeat the off/on twice to check the switch capability, and ensure on/off can
+work stable.
+
+Test Case16: Negative input to commands
+=======================================
+
+Input invalid commands on PF/VF to make sure the commands can't work::
+
+ 1. PF testpmd-> set port 0 vf 65 tx on
+ 2. PF testpmd-> set port 2 vf -1 tx off
+ 3. PF testpmd-> set port 0 vf 0 rx oneee
+ 4. PF testpmd-> set port 0 vf 0 rx offdd
+ 5. PF testpmd-> set port 0 vf 0 rx oneee
+ 6. PF testpmd-> set port 0 vf 64 rxmode BAM on
+ 7. PF testpmd-> set port 0 vf 64 rxmode BAM off
+ 8. PF testpmd-> set port 0 uta 00:11:22:33:44 on
+ 9. PF testpmd-> set port 7 uta 00:55:44:33:22:11 off
+ 10. PF testpmd-> set port 0 vf 34 rxmode ROPE on
+ 11. PF testpmd-> mac_addr add port 0 vf 65 00:55:44:33:22:11
+ 12. PF testpmd-> mac_addr add port 5 vf 0 00:55:44:88:22:11
+ 13. PF testpmd-> set port 0 mirror-rule 0 pool-mirror 65 dst-pool 1 on
+ 14. PF testpmd-> set port 0 mirror-rule 0xf uplink-mirror dst-pool 1 on
+ 15. PF testpmd-> set port 0 mirror-rule 2 vlan-mirror 9 dst-pool 1 on
+ 16. PF testpmd-> set port 0 mirror-rule 0 downlink-mirror 0xf dst-pool 2 off
+ 17. PF testpmd-> reset port 0 mirror-rule 4
+ 18. PF testpmd-> reset port 0xff mirror-rule 0
+
+Prerequisites for Scaling 4VFs per 1PF
+======================================
+
+Create 4VF interface VF0, VF1, VF2, VF3 from one PF interface and then attach
+them to VM0, VM1, VM2 and VM3.Start PF driver on the Host and skip the VF
+driver will has been already attached to VMs::
+
+ On PF ./tools/pci_unbind.py --bind=igb_uio 0000:08:00.0
+ echo 2 > /sys/bus/pci/devices/0000\:08\:00.0/max_vfs
+ ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -b 0000:08:10.0 -b 0000:08:10.2 -b 0000:08:10.4 -b 0000:08:10.6 -- -i
+
+If you want to run all common 4VM cases, please run testpmd on VM0, VM1, VM2
+and VM3 and start traffic forward on the VM hosts. Some specific prerequisites
+are set up in each case::
+
+ VF0 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF1 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF2 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF3 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+
+Test Case17: Scaling Pool Mirror on 4VFs
+========================================
+
+Make sure prerequisites for Scaling 4VFs per 1PF is set up.
+
+Add one mirror rules that will mirror VM0/VM1/VM2 income traffic to VM3::
+
+ PF testpmd-> set port 0 mirror-rule 0 pool-mirror 0x7 dst-pool 3 on
+ VF0 testpmd-> set fwd rxonly
+ VF0 testpmd-> start
+ VF1 testpmd-> set fwd rxonly
+ VF1 testpmd-> start
+ VF2 testpmd-> set fwd rxonly
+ VF2 testpmd-> start
+ VF3 testpmd-> set fwd rxonly
+ VF3 testpmd-> start
+
+Send 3 flows to VM0/VM1/VM2, one with VM0 mac, one with VM1 mac, one with VM2
+mac, and verify the packets has been mirrored to VM3.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+
+Set another 2 mirror rules. VM0/VM1 income traffic mirror to VM2 and VM3::
+
+ PF testpmd-> set port 0 mirror-rule 0 pool-mirror 0x3 dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 1 pool-mirror 0x3 dst-pool 3 on
+
+Send 2 flows to VM0/VM1, one with VM0 mac, one with VM1 mac and verify the
+packets has been mirrored to VM2/VM3 and VM2/VM3 have forwarded these packets.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+
+Test Case18: Scaling Uplink Mirror on 4VFs
+==========================================
+
+Make sure prerequisites for Scaling 4VFs per 1PF is set up.
+
+Add one mirror rules that will mirror all income traffic to VM2 and VM3::
+
+ PF testpmd-> set port 0 mirror-rule 0 uplink-mirror dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 1 uplink-mirror dst-pool 3 on
+ VF0 testpmd-> set fwd rxonly
+ VF0 testpmd-> start
+ VF1 testpmd-> set fwd rxonly
+ VF1 testpmd-> start
+ VF2 testpmd-> set fwd rxonly
+ VF2 testpmd-> start
+ VF3 testpmd-> set fwd rxonly
+ VF3 testpmd-> start
+
+Send 4 flows to VM0/VM1/VM2/VM3, one packet with VM0 mac, one packet with VM1
+mac, one packet with VM2 mac, and one packet with VM3 mac and verify the
+income packets has been mirrored to VM2 and VM3. Make sure VM2/VM3 will have 4
+packets.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+
+Test Case19: Scaling Downlink Mirror on 4VFs
+============================================
+
+Make sure prerequisites for scaling 4VFs per 1PF is set up.
+
+Add one mirror rules that will mirror all outcome traffic to VM2 and VM3::
+
+ PF testpmd-> set port 0 mirror-rule 0 downlink-mirror dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 1 downlink-mirror dst-pool 3 on
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+ VF2 testpmd-> set fwd rxonly
+ VF2 testpmd-> start
+ VF3 testpmd-> set fwd rxonly
+ VF3 testpmd-> start
+
+Send 2 flows to VM0/VM1, one with VM0 mac, one with VM1 mac, and verify VM0/VM1
+will forward these packets. And verify the VM0/VM1 outcome packets have been
+mirrored to VM2 and VM3.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+
+Test Case20: Scaling Vlan Mirror on 4VFs
+========================================
+
+Make sure prerequisites for scaling 4VFs per 1PF is set up.
+
+Add 3 mirror rules that will mirror VM0/VM1/VM2 vlan income traffic to VM3::
+
+ PF testpmd-> rx_vlan add 1 port 0 vf 0x1
+ PF testpmd-> rx_vlan add 2 port 0 vf 0x2
+ PF testpmd-> rx_vlan add 3 port 0 vf 0x4
+ PF testpmd-> set port 0 mirror-rule 0 vlan-mirror 1,2,3 dst-pool 3 on
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+ VF2 testpmd-> set fwd mac
+ VF2 testpmd-> start
+ VF3 testpmd-> set fwd mac
+ VF3 testpmd-> start
+
+Send 3 flows to VM0/VM1/VM2, one with VM0 mac/vlanid, one with VM1 mac/vlanid,
+one with VM2 mac/vlanid,and verify the packets has been mirrored to VM3 and
+VM3 has forwards these packets.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+
+Set another 2 mirror rules. VM0/VM1 income traffic mirror to VM2 and VM3::
+
+ PF testpmd-> set port 0 mirror-rule 0 vlan-mirror 1 dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 1 vlan-mirror 2 dst-pool 3 on
+
+Send 2 flows to VM0/VM1, one with VM0 mac/vlanid, one with VM1 mac/vlanid and
+verify the packets has been mirrored to VM2 and VM3, then VM2 and VM3 have
+forwarded these packets.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+
+Test Case21: Scaling Vlan Mirror & Pool Mirror on 4VFs
+======================================================
+
+Make sure prerequisites for scaling 4VFs per 1PF is set up.
+
+Add 3 mirror rules that will mirror VM0/VM1 vlan income traffic to VM2, VM0/VM1
+pool will come to VM3::
+
+ PF testpmd-> rx_vlan add 1 port 0 vf 0x1
+ PF testpmd-> rx_vlan add 2 port 0 vf 0x2
+ PF testpmd-> set port 0 mirror-rule 0 vlan-mirror 1 dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 1 vlan-mirror 2 dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 2 pool-mirror 0x3 dst-pool 3 on
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+ VF2 testpmd-> set fwd mac
+ VF2 testpmd-> start
+ VF3 testpmd-> set fwd mac
+ VF3 testpmd-> start
+
+Send 2 flows to VM0/VM1, one with VM0 mac/vlanid, one with VM1 mac/vlanid, and
+verify the packets has been mirrored to VM2 and VM3, and VM2/VM3 have
+forwarded these packets.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+ PF testpmd-> reset port 0 mirror-rule 2
+
+Set 3 mirror rules. VM0/VM1 income traffic mirror to VM2, VM2 traffic will
+mirror to VM3::
+
+ PF testpmd-> set port 0 mirror-rule 0 vlan-mirror 1,2 dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 2 pool-mirror 0x2 dst-pool 3 on
+
+Send 2 flows to VM0/VM1, one with VM0 mac/vlanid, one with VM1 mac/vlanid and
+verify the packets has been mirrored to VM2, VM2 traffic will be mirrored to
+VM3, then VM2 and VM3 have forwarded these packets.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+ PF testpmd-> reset port 0 mirror-rule 2
+
+Test Case22: Scaling Uplink Mirror & Downlink Mirror on 4VFs
+============================================================
+
+Make sure prerequisites for scaling 4VFs per 1PF is set up.
+
+Add 2 mirror rules that will mirror all income traffic to VM2, all outcome
+traffic to VM3. Make sure VM2 and VM3 rxonly::
+
+ PF testpmd-> set port 0 mirror-rule 0 uplink-mirror dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 1 downlink-mirror dst-pool 3 on
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+ VF2 testpmd-> set fwd rxonly
+ VF2 testpmd-> start
+ VF3 testpmd-> set fwd rxonly
+ VF3 testpmd-> start
+
+Send 2 flows to VM0/VM1, one with VM0 mac, one with VM1 mac and make sure
+VM0/VM1 will forward packets. Verify the income packets have been mirrored to
+VM2, the outcome packets has been mirrored to VM3.
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+
+Test Case23: Scaling Pool & Vlan & Uplink & Downlink Mirror on 4VFs
+===================================================================
+
+Make sure prerequisites for scaling 4VFs per 1PF is set up.
+
+Add mirror rules that VM0 vlan mirror to VM1, all income traffic mirror to VM2,
+all outcome traffic mirror to VM3, all VM1 traffic will mirror to VM0. Make
+sure VM2 and VM3 rxonly::
+
+ PF testpmd-> rx_vlan add 1 port 0 vf 0x1
+ PF testpmd-> set port 0 mirror-rule 0 vlan-mirror 1 dst-pool 1 on
+ PF testpmd-> set port 0 mirror-rule 1 pool-mirror 0x2 dst-pool 0 on
+ PF testpmd-> set port 0 mirror-rule 2 uplink-mirror dst-pool 2 on
+ PF testpmd-> set port 0 mirror-rule 3 downlink-mirror dst-pool 3 on
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+ VF2 testpmd-> set fwd rxonly
+ VF2 testpmd-> start
+ VF3 testpmd-> set fwd rxonly
+ VF3 testpmd-> start
+
+Send 10 packets to VM0 with VM0 mac/vlanid, verify that VM1 will be mirrored
+and packets will be forwarded, VM2 will have all income traffic mirrored, VM3
+will have all outcome traffic mirrored
+
+Send 10 packets to VM1 with VM1 mac, verify that VM0 will be mirrored and
+packets will be forwarded, VM2 will have all income traffic mirrored; VM3 will
+have all outcome traffic mirrored
+
+Reset mirror rule::
+
+ PF testpmd-> reset port 0 mirror-rule 0
+ PF testpmd-> reset port 0 mirror-rule 1
+ PF testpmd-> reset port 0 mirror-rule 2
+ PF testpmd-> reset port 0 mirror-rule 3
+
+Test Case24: Scaling InterVM communication on 4VFs
+==================================================
+
+Set the VF0 destination mac address to VF1 mac address, packets send from VF0
+will be forwarded to VF1 and then send out. Similar for VF2 and VF3::
+
+ VF1 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF1 testpmd-> show port info 0
+ VF1 testpmd-> set fwd mac
+ VF1 testpmd-> start
+
+ VF0 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- --eth-peer=0,"VF1 mac" -i
+ VF0 testpmd-> set fwd mac
+ VF0 testpmd-> start
+
+ VF3 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- -i
+ VF3 testpmd-> show port info 0
+ VF3 testpmd-> set fwd mac
+ VF3 testpmd-> start
+
+ VF2 ./x86_64-default-linuxapp-gcc/app/testpmd -c f -n 4 -- --eth-peer=0,"VF3 mac" -i
+ VF2 testpmd-> set fwd mac
+ VF2 testpmd-> start
+
+Send 2 flows, one with VF0 mac address and make sure the packets will be
+forwarded by VF1, another with VF2 mac address and make sure the packets will
+be forwarded by VF3.
+
+
diff --git a/test_plans/tso_test_plan.rst b/test_plans/tso_test_plan.rst
new file mode 100644
index 0000000..8375607
--- /dev/null
+++ b/test_plans/tso_test_plan.rst
@@ -0,0 +1,184 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+==============================================
+Testing of TSO Support in DPDK
+==============================================
+
+
+Description
+===========
+
+This document provides the plan for testing the TSO(Transmit Segmentation
+Offload, also called Large Send offload - LSO) feature of
+Intel Ethernet Controller, including Intel 82599 10GbE Ethernet Controller and
+Fortville 40GbE Ethernet Controller. TSO enables the TCP/IP stack to
+pass to the network device a larger ULP datagram than the Maximum Transmit
+Unit Size (MTU). NIC divides the large ULP datagram to multiple segments
+according to the MTU size.
+
+
+Prerequisites
+=============
+
+The DUT must take one of the Ethernet controller ports connected to a port on another
+device that is controlled by the Scapy packet generator.
+
+The Ethernet interface identifier of the port that Scapy will use must be known.
+On tester, all offload feature should be disabled on tx port, and start rx port capture:
+ ethtool -K <tx port> rx off tx off tso off gso off gro off lro off
+ ip l set <tx port> up
+ tcpdump -n -e -i <rx port> -s 0 -w /tmp/cap
+
+
+On DUT, run pmd with parameter "--enable-rx-cksum". Then enable TSO on tx port
+and checksum on rx port. The test commands is below:
+ #enable hw checksum on rx port
+ tx_checksum set ip hw 0
+ tx_checksum set udp hw 0
+ tx_checksum set tcp hw 0
+ tx_checksum set sctp hw 0
+ set fwd csum
+
+ # enable TSO on tx port
+ *tso set 800 1
+
+
+Test case: csum fwd engine, use TSO
+====================================================
+
+This test uses ``Scapy`` to send out one large TCP package. The dut forwards package
+with TSO enable on tx port while rx port turns checksum on. After package send out
+by TSO on tx port, the tester receives multiple small TCP package.
+
+Turn off tx port by ethtool on tester::
+ ethtool -K <tx port> rx off tx off tso off gso off gro off lro off
+ ip l set <tx port> up
+capture package rx port on tester::
+ tcpdump -n -e -i <rx port> -s 0 -w /tmp/cap
+
+Launch the userland ``testpmd`` application on DUT as follows::
+./x86_64-native-linuxapp-gcc/app/testpmd -c 0xffffffff -n 2 -- -i --rxd=512 --txd=512
+--burst=32 --rxfreet=64 --mbcache=128 --portmask=0x3 --txpt=36 --txht=0 --txwt=0
+--txfreet=32 --txrst=32 --enable-rx-cksum
+ testpmd> set verbose 1
+
+ # enable hw checksum on rx port
+ testpmd> tx_checksum set ip hw 0
+ testpmd> tx_checksum set udp hw 0
+ testpmd> tx_checksum set tcp hw 0
+ testpmd> tx_checksum set sctp hw 0
+ # enable TSO on tx port
+ testpmd> tso set 800 1
+ # set fwd engine and start
+ testpmd> set fwd csum
+ testpmd> start
+
+Test IPv4() in scapy:
+ sendp([Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/UDP(sport=1021,dport=1021)/Raw(load="\x50"*%s)], iface="%s")
+
+Test IPv6() in scapy:
+ sendp([Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="FE80:0:0:0:200:1FF:FE00:200", dst="3555:5555:6666:6666:7777:7777:8888:8888")/UDP(sport=1021,dport=1021)/Raw(load="\x50"*%s)], iface="%s"
+
+Test case: csum fwd engine, use TSO tunneling
+====================================================
+
+This test uses ``Scapy`` to send out one large TCP package. The dut forwards package
+with TSO enable on tx port while rx port turns checksum on. After package send out
+by TSO on tx port, the tester receives multiple small TCP package.
+
+Turn off tx port by ethtool on tester::
+ ethtool -K <tx port> rx off tx off tso off gso off gro off lro off
+ ip l set <tx port> up
+capture package rx port on tester::
+ tcpdump -n -e -i <rx port> -s 0 -w /tmp/cap
+
+Launch the userland ``testpmd`` application on DUT as follows::
+./x86_64-native-linuxapp-gcc/app/testpmd -c 0xffffffff -n 2 -- -i --rxd=512 --txd=512
+--burst=32 --rxfreet=64 --mbcache=128 --portmask=0x3 --txpt=36 --txht=0 --txwt=0
+--txfreet=32 --txrst=32 --enable-rx-cksum
+ testpmd> set verbose 1
+
+ # enable hw checksum on rx port
+ testpmd> tx_checksum set ip hw 0
+ testpmd> tx_checksum set udp hw 0
+ testpmd> tx_checksum set tcp hw 0
+ testpmd> tx_checksum set sctp hw 0
+ testpmd> tx_checksum set vxlan hw 0
+ testpmd> tx_checksum set nvgre hw 0
+ # enable TSO on tx port
+ testpmd> tso set 800 1
+ # set fwd engine and start
+ testpmd> set fwd csum
+ testpmd> start
+
+Test vxlan() in scapy:
+ sendp([Ether(dst="%s",src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/UDP(sport=1021,dport=4789)/VXLAN(vni=1234)/Ether(dst=%s,src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/UDP(sport=1021,dport=1021)/Raw(load="\x50"*%s)], iface="%s"
+
+Test nvgre() in scapy:
+ sendp([Ether(dst="%s",src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2",proto=47)/NVGRE()/Ether(dst=%s,src="52:00:00:00:00:00")/IP(src="192.168.1.1",dst="192.168.1.2")/TCP(sport="1021",dport="1021")/("X"*%s)], iface="%s")
+
+Test case: TSO performance
+====================================================
+Set the packet stream to be sent out from packet generater before testing as
+below.
+
++-------+---------+---------+---------+----------+----------+
+| Frame | 1S/1C/1T| 1S/1C/1T| 1S/2C/1T| 1S/2C/2T | 1S/2C/2T |
+| Size | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 64 | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 65 | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 128 | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 256 | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 512 | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 1024 | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 1280 | | | | | |
++-------+---------+---------+---------+----------+----------+
+| 1518 | | | | | |
++-------+---------+---------+---------+----------+----------+
+
+Then run the test application as below::
+./x86_64-native-linuxapp-gcc/app/testpmd -c 0xffffffff -n 2 -- -i --rxd=512 --txd=512
+--burst=32 --rxfreet=64 --mbcache=128 --portmask=0x3 --txpt=36 --txht=0 --txwt=0
+--txfreet=32 --txrst=32 --enable-rx-cksum
+The -n command is used to select the number of memory channels. It should match the
+number of memory channels on that setup.
+
+
diff --git a/test_plans/uni_pkt_test_plan.rst b/test_plans/uni_pkt_test_plan.rst
new file mode 100644
index 0000000..c42308b
--- /dev/null
+++ b/test_plans/uni_pkt_test_plan.rst
@@ -0,0 +1,832 @@
+.. Copyright (c) <2015>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPR ESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===================
+Unified Packet Type
+===================
+Unified packet type flag is supposed to recognize packet types and support all
+possible PMDs.
+
+This 32 bits of packet_type can be divided into several sub fields to
+indicate different packet type information of a packet. The initial design
+is to divide those bits into fields for L2 types, L3 types, L4 types, tunnel
+types, inner L2 types, inner L3 types and inner L4 types. All PMDs should
+translate the offloaded packet types into these 7 fields of information, for
+user applications.
+
+Prerequisites
+=============
+Enable ABI and disable vector ixgbe driver in dpdk configuration file.
+Plug in three different types of nic on the board.
+1x Intel® XL710-DA2 (Eagle Fountain)
+1x Intel® 82599 Gigabit Ethernet Controller
+1x Intel® I350 Gigabit Network Connection
+
+Start testpmd and then enable rxonly and verbose mode::
+ ./x86_64-native-linuxapp-gcc/app/testpmd -c f -n 4 -- -i --txqflags=0x0
+ set fwd rxonly
+ set verbose 1
+ start
+
+Test Case: L2 Packet detect
+===========================
+This case checked that whether Timesync, ARP, LLDP detection supported by
+Fortville.
+
+Send time sync packet from tester::
+ sendp([Ether(dst='FF:FF:FF:FF:FF:FF',type=0x88f7)/"\\x00\\x02"],
+ iface=txItf)
+
+Check below message dumped by testpmd::
+ (outer) L2 type: ETHER_Timesync
+
+Send ARP packet from tester::
+ sendp([Ether(dst='FF:FF:FF:FF:FF:FF')/ARP()],
+ iface=txItf)
+
+Check below message dumped by testpmd::
+ (outer) L2 type: ETHER_ARP
+
+Send LLDP packet from tester::
+ sendp([Ether()/LLDP()/LLDPManagementAddress()], iface=txItf)
+
+Check below message dumped by testpmd::
+ (outer) L2 type: ETHER_LLDP
+
+Test Case: IPv4&L4 packet type detect
+=====================================
+This case checked that whether L3 and L4 packet can be normally detected.
+Niantic and i350 will shown that L2 type is MAC.
+Only Fortville can detect icmp packet.
+Only niantic and i350 can detect ipv4 extension packet.
+Fortville did not detect whether packet contian ipv4 header options, so L3
+type will be shown as IPV4_EXT_UNKNOWN.
+Fortville will identify all unrecognized L4 packet as L4_NONFRAG.
+Only Fortville can inentify L4 fragement packet.
+
+Send IP only packet and verify L2/L3/L4 corrected::
+ sendp([Ether()/IP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV4
+ (outer) L4 type: Unknown
+
+Send IP+UDP packet and verify L2/L3/L4 corrected::
+ sendp([Ether()/IP()/UDP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L4 type: UDP
+
+Send IP+TCP packet and verify L2/L3/L4 corrected::
+ sendp([Ether()/IP()/TCP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L4 type: TCP
+
+Send IP+SCTP packet and verify L2/L3/L4 corrected::
+ sendp([Ether()/IP()/SCTP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L4 type: SCTP
+
+Send IP+ICMP packet and verify L2/L3/L4 corrected(Fortville)::
+ sendp([Ether()/IP()/ICMP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L4 type: ICMP
+
+Send IP fragment+TCP packet and verify L2/L3/L4 corrected(Fortville)::
+ sendp([Ether()/IP(frag=5)/TCP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV4_EXT_UNKNOWN
+ (outer) L4 type: L4_FRAG
+
+Send IP extension packet and verify L2/L3 corrected(Niantic,i350)::
+ sendp([Ether()/IP(ihl=10)/Raw('\0'*40)],iface=txItf)
+
+ (outer) L3 type: IPV4_EXT
+ (outer) L4 type: Unknown
+
+Send IP extension+SCTP packet and verify L2/L3/L4 corrected(Niantic,i350)::
+ sendp([Ether()/IP(ihl=10)/SCTP()/Raw('\0'*40)],iface=txItf)
+
+ (outer) L3 type: IPV4_EXT
+ (outer) L4 type: SCTP
+
+Test Case: IPv6&L4 packet type detect
+=====================================
+This case checked that whether IPv6 and L4 packet can be normally detected.
+Niantic and i350 will shown that L2 type is MAC.
+Fortville did not detect whether packet contian ipv6 extension options, so L3
+type will be shown as IPV6_EXT_UNKNOWN.
+Fortville will identify all unrecognized L4 packet as L4_NONFRAG.
+Only Fortville can inentify L4 fragement packet.
+
+Send IPv6 only packet and verify L2/L3/L4 corrected::
+ sendp([Ether()/IPv6()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV6
+ (outer) L4 type: Unknown
+
+Send IPv6+UDP packet and verify L2/L3/L4 corrected::
+ sendp([Ether()/IPv6()/UDP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L4 type: UDP
+
+Send IPv6+TCP packet and verify L2/L3/L4 corrected::
+ sendp([Ether()/IPv6()/TCP()/Raw('\0'*60)], iface=txItf)
+
+ (outer) L4 type: TCP
+
+Send IPv6 fragment packet and verify L2/L3/L4 corrected(Fortville)::
+ sendp([Ether()/IPv6()/IPv6ExtHdrFragment()/Raw('\0'*60)],iface=txItf)
+
+ (outer) L3 type: IPV6_EXT_UNKNOWN
+ (outer) L4 type: L4_FRAG
+
+Send IPv6 fragment packet and verify L2/L3/L4 corrected(Niantic,i350)::
+ sendp([Ether()/IPv6()/IPv6ExtHdrFragment()/Raw('\0'*60)],iface=txItf)
+
+ (outer) L3 type: IPV6_EXT
+ (outer) L4 type: Unknown
+
+Test Case: IP in IPv4 tunnel packet type detect
+===============================================
+This case checked that whether IP in IPv4 tunnel packet can be normally
+detected by Fortville.
+
+Send IPv4+IPv4 fragment packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP(frag=5)/UDP()/Raw('\0'*40)], iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV4_EXT_UNKNOWN
+ (outer) L4 type: Unknown
+ Tunnel type: IP
+ Inner L2 type: Unknown
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+IPv4 packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+IPv4+UDP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/UDP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+IPv4+TCP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/TCP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+IPv4+SCTP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/SCTP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPv4+IPv4+ICMP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/SCTP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: ICMP
+
+Send IPv4+IPv6 fragment packet and inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/IPv6ExtHdrFragment()/Raw('\0'*40)],iface=txItf)
+
+ Inner L3 type: IPV6_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+IPv6 packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+IPv6+UDP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/UDP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+IPv6+TCP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/TCP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+IPv6+SCTP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6(nh=132)/SCTP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPv4+IPv6+ICMP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6(nh=58)/ICMP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: ICMP
+
+Test Case: IPv6 in IPv4 tunnel packet type detect by niantic and i350
+=====================================================================
+This case checked that whether IPv4 in IPv6 tunnel packet can be normally
+detected by Niantic and i350.
+
+Send IPv4+IPv6 packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/Raw('\0'*40)], iface=txItf)
+
+ (outer) L2 type: MAC
+ (outer) L3 type: IPV4
+ (outer) L4 type: Unknown
+ Tunnel type: IP
+ Inner L2 type: Unknown
+ Inner L3 type: IPV6
+ Inner L4 type: Unknown
+
+Send IPv4+IPv6_EXT packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/IPv6ExtHdrRouting()/Raw('\0'*40)], iface=txItf)
+
+ Inner L3 type: IPV6_EXT
+
+Send IPv4+IPv6+UDP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/UDP()/Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+IPv6+TCP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/TCP()/Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+IPv6_EXT+UDP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/IPv6ExtHdrRouting()/UDP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L3 type: IPV6_EXT
+ Inner L4 type: UDP
+
+Send IPv4+IPv6_EXT+TCP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/IPv6ExtHdrRouting()/TCP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L3 type: IPV6_EXT
+ Inner L4 type: TCP
+
+
+Test Case: IP in IPv6 tunnel packet type detect
+===============================================
+This case checked that whether IP in IPv6 tunnel packet can be normally
+detected by Fortville.
+
+Send IPv4+IPv4 fragment packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP(frag=5)/UDP()/Raw('\0'*40)],iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV4_EXT_UNKNOWN
+ (outer) L4 type: Unknown
+ Tunnel type: IP
+ Inner L2 type: Unknown
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+IPv4 packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+IPv4+UDP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/UDP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+IPv4+TCP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/TCP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+IPv4+SCTP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/SCTP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPv4+IPv4+ICMP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IP()/SCTP()/Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: ICMP
+
+Send IPv4+IPv6 fragment packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/IPv6ExtHdrFragment()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L3 type: IPV6_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+IPv6 packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+IPv6+UDP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/UDP()/Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+IPv6+TCP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6()/TCP()/Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+IPv6+SCTP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6(nh=132)/SCTP()/Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPv4+IPv6+ICMP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/IPv6(nh=58)/ICMP()/Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: ICMP
+
+
+Test Case: NVGRE tunnel packet type detect
+==========================================
+This case checked that whether NVGRE tunnel packet can be normally detected
+by Fortville.
+Fortville did not distinguish GRE/Teredo/Vxlan packets, all those types will
+be displayed as GRENAT.
+
+Send IPv4+NVGRE fragment packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/IP(frag=5)/Raw('\0'*40)],
+ iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV4_EXT_UNKNOWN
+ (outer) L4 type: Unknown
+ Tunnel type: GRENAT
+ Inner L2 type: ETHER
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+
+Send IPV4+NVGRE+MAC packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/IP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+NVGRE+MAC_VLAN packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/Raw('\0'*40)], iface=txItf)
+
+ Inner L2 type: ETHER_VLAN
+ Inner L4 type: Unknown
+
+Send IPv4+NVGRE+MAC_VLAN+IPv4 fragment packet and verify inner and outer
+L2/L3/L4 corrected::
+
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IP(frag=5)/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+NVGRE+MAC_VLAN+IPv4 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+NVGRE+MAC_VLAN+IPv4+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IP()/UDP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+NVGRE+MAC_VLAN+IPv4+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IP()/TCP()/Raw('\0'*40)],
+ iface=txItf)
+ Inner L4 type: TCP
+
+Send IPv4+NVGRE+MAC_VLAN+IPv4+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IP()/SCTP()/Raw('\0'*40)],
+ iface=txItf)
+ Inner L4 type: SCTP
+
+Send IPv4+NVGRE+MAC_VLAN+IPv4+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IP()/ICMP()/Raw('\0'*40)],
+ iface=txItf)
+ Inner L4 type: ICMP
+
+Send IPv4+NVGRE+MAC_VLAN+IPv6+IPv6 fragment acket and verify inner and outer
+L2/L3/L4 corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IPv6()/IPv6ExtHdrFragment()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L3 type: IPV6_EXT_UNKOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+NVGRE+MAC_VLAN+IPv6 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IPv6()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+NVGRE+MAC_VLAN+IPv6+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IPv6()/UDP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: UDP
+Send IPv4+NVGRE+MAC_VLAN+IPv6+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IPv6()/TCP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+NVGRE+MAC_VLAN+IPv6+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IPv6(nh=132)/SCTP()/
+ Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPv4+NVGRE+MAC_VLAN+IPv6+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/NVGRE()/Ether()/Dot1Q()/IPv6(nh=58)/ICMP()/
+ Raw('\0'*40)],iface=txItf)
+
+ Inner L4 type: ICMP
+
+Test Case: NVGRE in IPv6 tunnel packet type detect
+==================================================
+This case checked that whether NVGRE in IPv6 tunnel packet can be normally
+detected by Fortville.
+Fortville did not distinguish GRE/Teredo/Vxlan packets, all those types will
+be displayed as GRENAT.
+
+Send IPV6+NVGRE+MAC packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Raw('\0'*18)], iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV6_EXT_UNKNOWN
+ (outer) L4 type: Unknown
+ Tunnel type: GRENAT
+ Inner L2 type: ETHER
+ Inner L3 type: Unkown
+ Inner L4 type: Unknown
+
+Send IPV6+NVGRE+MAC+IPv4 fragment packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IP(frag=5)/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPV6+NVGRE+MAC+IPv4 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPV6+NVGRE+MAC+IPv4+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IP()/UDP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPV6+NVGRE+MAC+IPv4+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IP()/TCP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPV6+NVGRE+MAC+IPv4+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IP()/SCTP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPV6+NVGRE+MAC+IPv4+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IP()/ICMP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: ICMP
+
+Send IPV6+NVGRE+MAC+IPv6 fragment packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IPv6()/IPv6ExtHdrFragment()
+ /Raw('\0'*40)],iface=txItf)
+
+ Inner L3 type: IPV6_EXT_UNKOWN
+ Inner L4 type: L4_FRAG
+
+Send IPV6+NVGRE+MAC+IPv6 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IPv6()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPV6+NVGRE+MAC+IPv6+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IPv6()/UDP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPV6+NVGRE+MAC+IPv6+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IPv6()/TCP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPV6+NVGRE+MAC+IPv6+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IPv6(nh=132)/SCTP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPV6+NVGRE+MAC+IPv6+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/IPv6(nh=58)/ICMP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: ICMP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv4 fragment packet and inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IP(frag=5)/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L2 type: ETHER_VLAN
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPV6+NVGRE+MAC_VLAN+IPv4 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPV6+NVGRE+MAC_VLAN+IPv4+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IP()/UDP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv4+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IP()/TCP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv4+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IP()/SCTP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv4+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IP()/ICMP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: ICMP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv6 fragment packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IPv6()/
+ IPv6ExtHdrFragment()/Raw('\0'*40)], iface=txItf)
+
+ Inner L3 type: IPV6_EXT_UNKOWN
+ Inner L4 type: L4_FRAG
+
+Send IPV6+NVGRE+MAC_VLAN+IPv6 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IPv6()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPV6+NVGRE+MAC_VLAN+IPv6+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IPv6()/UDP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv6+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IPv6()/TCP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv6+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IPv6(nh=132)/SCTP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPV6+NVGRE+MAC_VLAN+IPv6+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IPv6(nh=47)/NVGRE()/Ether()/Dot1Q()/IPv6(nh=58)/ICMP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: ICMP
+
+Test Case: GRE tunnel packet type detect
+========================================
+This case checked that whether GRE tunnel packet can be normally detected by
+Fortville.
+Fortville did not distinguish GRE/Teredo/Vxlan packets, all those types will
+be displayed as GRENAT.
+
+Send IPv4+GRE+IPv4 fragment packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/GRE()/IP(frag=5)/Raw('x'*40)], iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV4_EXT_UNKNOWN
+ (outer) L4 type: Unknown
+ Tunnel type: GRENAT
+ Inner L2 type: Unknown
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+GRE+IPv4 packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/GRE()/IP()/Raw('x'*40)], iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+GRE+IPv4+UDP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/GRE()/IP()/UDP()/Raw('x'*40)], iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+GRE+IPv4+TCP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/GRE()/IP()/TCP()/Raw('x'*40)], iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+GRE+IPv4+SCTP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/GRE()/IP()/SCTP()/Raw('x'*40)], iface=txItf)
+
+ Inner L4 type: SCTP
+Send IPv4+GRE+IPv4+ICMP packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/GRE()/IP()/ICMP()/Raw('x'*40)], iface=txItf)
+
+ Inner L4 type: ICMP
+Send IPv4+GRE packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/GRE()/Raw('x'*40)], iface=txItf)
+
+ Inner L3 type: Unkown
+ Inner L4 type: Unknown
+
+Test Case: Vxlan tunnel packet type detect
+==========================================
+This case checked that whether Vxlan tunnel packet can be normally detected by
+Fortville.
+Fortville did not distinguish GRE/Teredo/Vxlan packets, all those types
+will be displayed as GRENAT.
+
+Add vxlan tunnle port filter on receive port::
+ rx_vxlan_port add 4789 0
+Send IPv4+Vxlan+MAC+IPv4 fragment packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IP(frag=5)/Raw('\0'*40)],
+ iface=txItf)
+
+ (outer) L2 type: ETHER
+ (outer) L3 type: IPV4_EXT_UNKNOWN
+ (outer) L4 type: Unknown
+ Tunnel type: GRENAT
+ Inner L2 type: ETHER
+ Inner L3 type: IPV4_EXT_UNKNOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+Vxlan+MAC+IPv4 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+Vxlan+MAC+IPv4+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IP()/UDP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+Vxlan+MAC+IPv4+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IP()/TCP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+Vxlan+MAC+IPv4+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IP()/SCTP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPv4+Vxlan+MAC+IPv4+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IP()/ICMP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: ICMP
+
+Send IPv4+Vxlan+MAC+IPv6 fragment packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6()/IPv6ExtHdrFragment()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L3 type: IPV6_EXT_UNKOWN
+ Inner L4 type: L4_FRAG
+
+Send IPv4+Vxlan+MAC+IPv6 packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: L4_NONFRAG
+
+Send IPv4+Vxlan+MAC+IPv6+UDP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6()/UDP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: UDP
+
+Send IPv4+Vxlan+MAC+IPv6+TCP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6()/TCP()/Raw('\0'*40)],
+ iface=txItf)
+
+ Inner L4 type: TCP
+
+Send IPv4+Vxlan+MAC+IPv6+SCTP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6(nh=132)/SCTP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: SCTP
+
+Send IPv4+Vxlan+MAC+IPv6+ICMP packet and verify inner and outer L2/L3/L4
+corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6(nh=28)/ICMP()/
+ Raw('\0'*40)], iface=txItf)
+
+ Inner L4 type: ICMP
+
+Send IPv4+Vxlan+MAC packet and verify inner and outer L2/L3/L4 corrected::
+ sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/Raw('\0'*40)], iface=txItf)
+
+ Inner L3 type: Unkown
+ Inner L4 type: Unknown
diff --git a/test_plans/unit_tests_cmdline_test_plan.rst b/test_plans/unit_tests_cmdline_test_plan.rst
new file mode 100644
index 0000000..85ed33b
--- /dev/null
+++ b/test_plans/unit_tests_cmdline_test_plan.rst
@@ -0,0 +1,54 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+==================
+Cmdline Autotests
+==================
+This is the test plan for the Intel® DPDK Random Early Detection feature.
+
+This section explains how to run the unit tests for cmdline. The test can be launched
+independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> cmdline_autotest
+
+The final output of the test has to be "Test OK"
+
diff --git a/test_plans/unit_tests_dump_test_plan.rst b/test_plans/unit_tests_dump_test_plan.rst
new file mode 100644
index 0000000..23dd993
--- /dev/null
+++ b/test_plans/unit_tests_dump_test_plan.rst
@@ -0,0 +1,169 @@
+.. Copyright (c) <2014>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=========================
+Dump log history Autotest
+=========================
+
+This is the test plan for dump history log of Intel® DPDK .
+
+This section explains how to run the unit tests for dump history log. The test
+can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> dump_log_history
+
+The final output of the test will be the initial log of DPDK.
+
+==================
+Dump ring Autotest
+==================
+
+This is the test plan for dump the elements of Intel® DPDK ring.
+
+This section explains how to run the unit tests for dump elements of ring.
+The test can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> dump_ring
+
+The final output of the test will be detail elements of DPDK ring.
+
+=====================
+Dump mempool Autotest
+=====================
+
+This is the test plan for dump the elements of Intel® DPDK mempool.
+
+This section explains how to run the unit tests for dump elements of mempool.
+The test can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> dump_mempool
+
+The final output of the test will be detail elements of DPDK mempool.
+
+=============================
+Dump Physical memory Autotest
+=============================
+
+This is the test plan for dump the elements of Intel® DPDK physical memory.
+
+This section explains how to run the unit tests for dump elements of memory.
+The test can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> dump_physmem
+
+The final output of the test will be detail elements of DPDK physical memory.
+
+=====================
+Dump Memzone Autotest
+=====================
+
+This is the test plan for dump the elements of Intel® DPDK memzone.
+
+This section explains how to run the unit tests for dump elements of memzone.
+The test can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> dump_memzone
+
+The final output of the test will be detail elements of DPDK memzone.
+
+================
+Dump Struct size
+================
+
+This is the test plan for dump the size of Intel® DPDK structure.
+
+This section explains how to run the unit tests for dump structure size.
+The test can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> dump_struct_sizes
+
+The final output of the test will be the size of DPDK structure.
diff --git a/test_plans/unit_tests_eal_test_plan.rst b/test_plans/unit_tests_eal_test_plan.rst
new file mode 100644
index 0000000..c1f8950
--- /dev/null
+++ b/test_plans/unit_tests_eal_test_plan.rst
@@ -0,0 +1,315 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=============
+EAL Autotests
+=============
+
+This section describes the tests that are done to validate the EAL. Each
+test can be launched independently using the command line
+interface. These tests are implemented as a linuxapp environment
+application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+Version
+=======
+
+To Be Filled
+
+
+Common
+=======
+
+To Be Filled
+
+Eal_fs
+======
+
+To Be Filled
+
+Memory
+======
+
+- Dump the mapped memory. The python-expect script checks that at
+ least one line is dumped.
+
+- Check that memory size is different than 0.
+
+- Try to read all memory; it should not segfault.
+
+PCI
+===
+
+- Register a driver with a ``devinit()`` function.
+
+- Dump all PCI devices.
+
+- Check that the ``devinit()`` function is called at least once.
+
+Per-lcore Variables and lcore Launch
+====================================
+
+- Use ``rte_eal_mp_remote_launch()`` to call ``assign_vars()`` on
+ every available lcore. In this function, a per-lcore variable is
+ assigned to the lcore_id.
+
+- Use ``rte_eal_mp_remote_launch()`` to call ``display_vars()`` on
+ every available lcore. The function checks that the variable is
+ correctly set, or returns -1.
+
+- If at least one per-core variable was not correct, the test function
+ returns -1.
+
+Spinlock
+========
+
+- There is a global spinlock and a table of spinlocks (one per lcore).
+
+- The test function takes all of these locks and launches the
+ ``test_spinlock_per_core()`` function on each core (except the master).
+
+ - The function takes the global lock, displays something, then releases
+ the global lock.
+ - The function takes the per-lcore lock, displays something, then releases
+ the per-core lock.
+
+- The main function unlocks the per-lcore locks sequentially and
+ waits between each lock. This triggers the display of a message
+ for each core, in the correct order. The autotest script checks that
+ this order is correct.
+
+Rwlock
+======
+
+- There is a global rwlock and a table of rwlocks (one per lcore).
+
+- The test function takes all of these locks and launches the
+ ``test_rwlock_per_core()`` function on each core (except the master).
+
+ - The function takes the global write lock, display something,
+ then releases the global lock.
+ - Then, it takes the per-lcore write lock, display something, and
+ releases the per-core lock.
+ - Finally, a read lock is taken during 100 ms, then released.
+
+- The main function unlocks the per-lcore locks sequentially and
+ waits between each lock. This triggers the display of a message
+ for each core, in the correct order.
+
+ Then, it tries to take the global write lock and display the last
+ message. The autotest script checks that the message order is correct.
+
+Atomic Variables
+================
+
+- The main test function performs three subtests. The first test
+ checks that the usual inc/dec/add/sub functions are working
+ correctly:
+
+ - Initialize 32-bit and 64-bit atomic variables to specific
+ values.
+
+ - These variables are incremented and decremented on each core at
+ the same time in ``test_atomic_usual()``.
+
+ - The function checks that once all lcores finish their function,
+ the value of the atomic variables are still the same.
+
+- The second test verifies the behavior of "test and set" functions.
+
+ - Initialize 32-bit and 64-bit atomic variables to zero.
+
+ - Invoke ``test_atomic_tas()`` on each lcore before doing anything
+ else. The cores are awaiting synchronizatioin using the ``while
+ (rte_atomic32_read(&val) == 0)`` statement which is triggered by the
+ main test function. Then all cores do an
+ ``rte_atomicXX_test_and_set()`` at the same time. If it is successful,
+ it increments another atomic counter.
+
+ - The main function checks that the atomic counter was incremented
+ twice only (one for 32-bit and one for 64-bit values).
+
+- Test "add/sub and return"
+
+ - Initialize 32-bit and 64-bit atomic variables to zero.
+
+ - Invoke ``test_atomic_addsub_return()`` on each lcore. Before doing
+ anything else, the cores are waiting a synchro. Each lcore does
+ this operation several times::
+
+ tmp = atomic_add_return(&a, 1);
+ atomic_add(&count, tmp);
+ tmp = atomic_sub_return(&a, 1);
+ atomic_sub(&count, tmp+1);
+
+ - At the end of the test, the *count* value must be 0.
+
+Prefetch
+========
+
+Just test that the macro can be called and validate the compilation.
+The test always return success.
+
+Byteorder functions
+===================
+
+Check the result of optimized byte swap functions for each size (16-,
+32- and 64-bit).
+
+Cycles Test
+===========
+
+- Loop N times and check that the timer alway increments and
+ never decrements during this loop.
+
+- Wait one second using rte_usleep() and check that the increment
+ of cycles is correct with regard to the frequency of the timer.
+
+Logs
+====
+
+- Enable log types.
+- Set log level.
+- Execute logging functions with different types and levels; some should
+ not be displayed.
+
+Memzone
+=======
+
+- Search for three reserved zones or reserve them if they do not exist:
+
+ - One is on any socket id.
+ - The second is on socket 0.
+ - The last one is on socket 1 (if socket 1 exists).
+
+- Check that the zones exist.
+
+- Check that the zones are cache-aligned.
+
+- Check that zones do not overlap.
+
+- Check that the zones are on the correct socket id.
+
+- Check that a lookup of the first zone returns the same pointer.
+
+- Check that it is not possible to create another zone with the
+ same name as an existing zone.
+
+Memcpy
+======
+
+Create two buffers, and initialise one with random values. These are copied
+to the second buffer and then compared to see if the copy was successfull.
+The bytes outside the copied area are also checked to make sure they were not
+changed.
+
+This is repeated for a number of different sizes and offsets, with
+the second buffer being cleared before each test.
+
+Debug test
+==========
+
+- Call rte_dump_stack() and rte_dump_registers().
+
+Alarm
+=====
+
+- Check that the callback for the alarm can to be called.
+- Check that it is not possible to set alarm with invalid time value.
+- Check that it is not possible to set alarm without a callback.
+- Check that it is not possible to cancel alarm without a callback pointer.
+- Check that multiple callbacks for the alarm can be called.
+- Check that the number of removed and unremoved alarms are correct.
+- Check that no callback is called if all alarm removed.
+- Check that it is not possible to cancel an alarm within the callback itself.
+- Check that the callback which is the head of all is able to be removed.
+- Check that all alarms for the same callback can be cancelled.
+
+
+CPU flags
+=========
+
+- Using the rte_cpu_get_flag_enabled() checks for CPU features from different CPUID tables
+- Checks if rte_cpu_get_flag_enabled() properly fails on trying to check for invalid feature
+
+
+Errno
+=====
+
+Performs validation on the error message strings provided by the rte_strerror() call, to ensure that suitable strings are returned for the rte-specific error codes, as well as ensuring that for standard error codes the correct error message is returned.
+
+Interrupts
+==========
+- Check that the callback for the specific interrupt can be called.
+- Check that it is not possible to register a callback to an invalid interrupt handle.
+- Check that it is not possible to register no callback to an interrupt handle.
+- Check that it is not possible to unregister a callback to an invalid interrupt handle.
+- Check that multiple callbacks are registered to the same interrupt handle.
+- Check that it is not possible to unregister a callback with invalid parameter.
+- Check that it is not possible to enable an interrupt with invalid handle or wrong handle type.
+- Check that it is not possible to disable an interrupt with invalid handle or wrong handle type.
+
+
+Multiprocess
+============
+
+Validates that a secondary Intel DPDK instance can be run alongside a primary when the appropriate EAL command-line flags are passed. Also validates that secondary processes cannot interfere with primary processes by creating memory objects, such as mempools or rings.
+
+String
+======
+
+Performs validation on the new string functions provided in rte_string_fns.h, ensuring that all values returned are NULL terminated, and that suitable errors are returned when called with invalid parameters.
+
+Tailq
+=====
+
+Validates that we can create and perform lookups on named tail queues within the EAL for various object types. Also ensures appropriate error codes are returned from the functions if invalid parameters are passed.
+
+Devargs
+=======
+To Be Filled
+
+Kvargs
+======
+To Be Filled
+
+Acl
+===
+To Be Filled
+
+Link_bonding
+============
+To Be Filled
diff --git a/test_plans/unit_tests_ivshmem_test_plan.rst b/test_plans/unit_tests_ivshmem_test_plan.rst
new file mode 100644
index 0000000..b393b19
--- /dev/null
+++ b/test_plans/unit_tests_ivshmem_test_plan.rst
@@ -0,0 +1,54 @@
+.. Copyright (c) <2014>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+================
+Ivshmem Autotest
+================
+
+This is the test plan for the Intel® DPDK Inter-VM shared memory feature.
+
+This section explains how to run the unit tests for ivshmem. The test can be
+launched independently using the command line interface.
+This test is implemented as a ivshmem linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> ivshmem_autotest
+
+The final output of the test has to be "Test OK" \ No newline at end of file
diff --git a/test_plans/unit_tests_kni_test_plan.rst b/test_plans/unit_tests_kni_test_plan.rst
new file mode 100644
index 0000000..9dec43a
--- /dev/null
+++ b/test_plans/unit_tests_kni_test_plan.rst
@@ -0,0 +1,60 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=============
+KNI Autotests
+=============
+
+This is the test plan for the Intel® DPDK KNI library.
+
+This section explains how to run the unit tests for KNI. The test can be
+launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # insmod ./<TARGET>/kmod/igb_uio.ko
+ # insmod ./<TARGET>/kmod/rte_kni.ko
+ # ./app/test/test -n 1 -c ffff
+ RTE>> kni_autotest
+ RTE>> quit
+ # rmmod rte_kni
+ # rmmod igb_uio
+
+
+The final output of the test has to be "Test OK"
diff --git a/test_plans/unit_tests_lpm_test_plan.rst b/test_plans/unit_tests_lpm_test_plan.rst
new file mode 100644
index 0000000..cf76a26
--- /dev/null
+++ b/test_plans/unit_tests_lpm_test_plan.rst
@@ -0,0 +1,80 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=================
+LPM Autotest
+=================
+
+This is the test plan for the Intel® DPDK LPM Method.
+
+This section explains how to run the unit tests for LPM.The test can be
+launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> lpm_autotest
+
+
+The final output of the test has to be "Test OK"
+
+=================
+LPM_ipv6 Autotest
+=================
+
+This is the test plan for the Intel® DPDK LPM Method in IPv6.
+
+This section explains how to run the unit tests for LPM in IPv6.The test can be
+launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> lpm6_autotest
+
+
+The final output of the test has to be "Test OK"
+
diff --git a/test_plans/unit_tests_mbuf_test_plan.rst b/test_plans/unit_tests_mbuf_test_plan.rst
new file mode 100644
index 0000000..3b0d568
--- /dev/null
+++ b/test_plans/unit_tests_mbuf_test_plan.rst
@@ -0,0 +1,70 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+==============
+Mbuf Autotests
+==============
+
+This is the test plan for the Intel® DPDK mbuf library.
+
+Description
+===========
+
+#. Allocate a mbuf pool.
+
+ - The pool contains NB_MBUF elements, where each mbuf is MBUF_SIZE
+ bytes long.
+
+#. Test multiple allocations of mbufs from this pool.
+
+ - Allocate NB_MBUF and store pointers in a table.
+ - If an allocation fails, return an error.
+ - Free all these mbufs.
+ - Repeat the same test to check that mbufs were freed correctly.
+
+#. Test data manipulation in pktmbuf.
+
+ - Alloc an mbuf.
+ - Append data using rte_pktmbuf_append().
+ - Test for error in rte_pktmbuf_append() when len is too large.
+ - Trim data at the end of mbuf using rte_pktmbuf_trim().
+ - Test for error in rte_pktmbuf_trim() when len is too large.
+ - Prepend a header using rte_pktmbuf_prepend().
+ - Test for error in rte_pktmbuf_prepend() when len is too large.
+ - Remove data at the beginning of mbuf using rte_pktmbuf_adj().
+ - Test for error in rte_pktmbuf_adj() when len is too large.
+ - Check that appended data is not corrupt.
+ - Free the mbuf.
+ - Between all these tests, check data_len and pkt_len, and
+ that the mbuf is contiguous.
+ - Repeat the test to check that allocation operations
+ reinitialize the mbuf correctly.
diff --git a/test_plans/unit_tests_mempool_test_plan.rst b/test_plans/unit_tests_mempool_test_plan.rst
new file mode 100644
index 0000000..2f4b8d6
--- /dev/null
+++ b/test_plans/unit_tests_mempool_test_plan.rst
@@ -0,0 +1,75 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=================
+Mempool Autotests
+=================
+
+This is the test plan for the Intel® DPDK mempool library.
+
+Description
+===========
+
+#. Basic tests: done on one core with and without cache:
+
+ - Get one object, put one object
+ - Get two objects, put two objects
+ - Get all objects, test that their content is not modified and
+ put them back in the pool.
+
+#. Performance tests:
+
+ Each core get *n_keep* objects per bulk of *n_get_bulk*. Then,
+ objects are put back in the pool per bulk of *n_put_bulk*.
+
+ This sequence is done during TIME_S seconds.
+
+ This test is done on the following configurations:
+
+ - Cores configuration (*cores*)
+
+ - One core with cache
+ - Two cores with cache
+ - Max. cores with cache
+ - One core without cache
+ - Two cores without cache
+ - Max. cores without cache
+
+ - Bulk size (*n_get_bulk*, *n_put_bulk*)
+
+ - Bulk get from 1 to 32
+ - Bulk put from 1 to 32
+
+ - Number of kept objects (*n_keep*)
+
+ - 32
+ - 128
diff --git a/test_plans/unit_tests_pmd_perf_test_plan.rst b/test_plans/unit_tests_pmd_perf_test_plan.rst
new file mode 100644
index 0000000..c9d066f
--- /dev/null
+++ b/test_plans/unit_tests_pmd_perf_test_plan.rst
@@ -0,0 +1,79 @@
+.. Copyright (c) <2014>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Prerequisites
+=============
+One 10Gb Ethernet port of the DUT is directly connected and link is up.
+
+===========================
+Continuous Mode Performance
+===========================
+
+This is the test plan for unit test to measure cycles/packet in NIC loopback
+mode.
+
+This section explains how to run the unit tests for pmd performance with
+continues stream control mode.
+The test can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The final output of the test will be average cycles of IO used per packet.
+
+======================
+Burst Mode Performance
+======================
+
+This is the test plan for unit test to measure cycles/packet in NIC loopback
+mode.
+
+This section explains how to run the unit tests for pmd performance with
+burst stream control mode. For get accurate scalar fast performance, need
+disable INC_VECTOR in configuration file first.
+
+
+The test can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The final output of the test will be matrix of average cycles of IO used per
+packet.
+
+ +--------+------+--------+--------+
+ | Mode | rxtx | rxonly | txonly |
+ +========+======+========+========+
+ | vector | 58 | 34 | 23 |
+ +--------+------+--------+--------+
+ | scalar | 89 | 51 | 38 |
+ +--------+------+--------+--------+
+ | full | 73 | 31 | 42 |
+ +--------+------+--------+--------+
+ | hybrid | 59 | 35 | 23 |
+ +--------+------+--------+--------+
diff --git a/test_plans/unit_tests_power_test_plan.rst b/test_plans/unit_tests_power_test_plan.rst
new file mode 100644
index 0000000..9e42444
--- /dev/null
+++ b/test_plans/unit_tests_power_test_plan.rst
@@ -0,0 +1,80 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===============
+Power Autotests
+===============
+
+This is the test plan for the Intel® DPDK Power library.
+
+Description
+===========
+
+This section explains how to run the unit tests for Power features. The test
+can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> power_autotest
+
+
+The final output of the test has to be "Test OK"
+
+==================
+ACPI CPU Frequency
+==================
+
+This section explains how to run the unit tests for Power features. The test
+can be launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> power_acpi_cpufreq_autotest
+
+The final output of the test has to be "Test OK"
diff --git a/test_plans/unit_tests_qos_test_plan.rst b/test_plans/unit_tests_qos_test_plan.rst
new file mode 100644
index 0000000..397c06a
--- /dev/null
+++ b/test_plans/unit_tests_qos_test_plan.rst
@@ -0,0 +1,100 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+============
+RED Autotest
+============
+
+This is the test plan for the Intel® DPDK Random Early Detection feature.
+
+This section explains how to run the unit tests for RED. The test can be launched
+independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> red_autotest
+
+The final output of the test has to be "Test OK"
+
+==============
+Meter Autotest
+==============
+
+This is the test plan for the Intel® DPDK Metering feature.
+
+This section explains how to run the unit tests for Meter. The test can be launched
+independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> meter_autotest
+
+The final output of the test has to be "Test OK"
+
+==================
+Scheduler Autotest
+==================
+
+This is the test plan for the Intel® DPDK Scheduler feature.
+
+This section explains how to run the unit tests for Scheduler. The test can be
+launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> sched_autotest
+
+The final output of the test has to be "Test OK" \ No newline at end of file
diff --git a/test_plans/unit_tests_ring_test_plan.rst b/test_plans/unit_tests_ring_test_plan.rst
new file mode 100644
index 0000000..9a0b2ed
--- /dev/null
+++ b/test_plans/unit_tests_ring_test_plan.rst
@@ -0,0 +1,123 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+==============
+Ring Autotests
+==============
+
+This is the test plan for the Intel® DPDK ring library.
+
+Description
+===========
+
+#. Basic tests (done on one core)
+
+ - Using single producer/single consumer functions:
+
+ - Enqueue one object, two objects, MAX_BULK objects
+ - Dequeue one object, two objects, MAX_BULK objects
+ - Check that dequeued pointers are correct
+
+ - Using multi producers/multi consumers functions:
+
+ - Enqueue one object, two objects, MAX_BULK objects
+ - Dequeue one object, two objects, MAX_BULK objects
+ - Check that dequeued pointers are correct
+
+ - Test watermark and default bulk enqueue/dequeue:
+
+ - Set watermark
+ - Set default bulk value
+ - Enqueue objects, check that -EDQUOT is returned when
+ watermark is exceeded
+ - Check that dequeued pointers are correct
+
+#. Check quota and watermark
+
+ - Start a loop on another lcore that will enqueue and dequeue
+ objects in a ring. It will monitor the value of quota (default
+ bulk count) and watermark.
+ - At the same time, change the quota and the watermark on the
+ master lcore.
+ - The slave lcore will check that bulk count changes from 4 to
+ 8, and watermark changes from 16 to 32.
+
+#. Performance tests
+
+ This test is done on the following configurations:
+
+ - One core enqueuing, one core dequeuing
+ - One core enqueuing, other cores dequeuing
+ - One core dequeuing, other cores enqueuing
+ - Half of the cores enqueuing, the other half dequeuing
+
+ When only one core enqueues/dequeues, the test is done with the
+ SP/SC functions in addition to the MP/MC functions.
+
+ The test is done with different bulk size.
+
+ On each core, the test enqueues or dequeues objects during
+ TIME_S seconds. The number of successes and failures are stored on
+ each core, then summed and displayed.
+
+ The test checks that the number of enqueues is equal to the
+ number of dequeues.
+
+#. Change watermark and quota
+
+ Use the command line to change the value of quota and
+ watermark. Then dump the status of ring to check that the values
+ are correctly updated in the ring structure.
+
+=========================
+Ring Performance Autotest
+=========================
+
+This is the test plan for the Intel® DPDK LPM Method in IPv6.
+
+This section explains how to run the unit tests for LPM in IPv6.The test can be
+launched independently using the command line interface.
+This test is implemented as a linuxapp environment application.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff
+ RTE>> ring_perf_autotest
+
+
+The final output of the test has to be "Test OK"
diff --git a/test_plans/unit_tests_ringpmd_test_plan.rst b/test_plans/unit_tests_ringpmd_test_plan.rst
new file mode 100644
index 0000000..18f780c
--- /dev/null
+++ b/test_plans/unit_tests_ringpmd_test_plan.rst
@@ -0,0 +1,60 @@
+.. Copyright (c) <2014>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+=================
+Ring Pmd Autotest
+=================
+
+This is the test plan for the Intel® DPDK Ring poll mode driver feature.
+
+This section explains how to run the unit tests for ring pmd. The test can be
+launched independently using the command line interface.
+This test is implemented as a linuxapp environment application and config
+RTE_LIBRTE_PMD_RING should be modified to 'Y'.
+
+The complete test suite is launched automatically using a python-expect
+script (launched using ``make test``) that sends commands to
+the application and checks the results. A test report is displayed on
+stdout.
+
+Ring pmd unit test required two pair of virtual ethernet devices and one
+virtual ethernet devices with full rx&tx functions.
+
+The steps to run the unit test manually are as follow::
+
+ # make -C ./app/test/
+ # ./app/test/test -n 1 -c ffff --vdev='eth_ring0,nodeaction=:0:CREATE'
+ --vdev='eth_ring0,nodeaction=:0:ATTACH' --vdev='eth_ring1,nodeaction=:0:CREATE'
+ --vdev='eth ring2,nodeaction=:0:CREATE' --vdev='eth_ring2,nodeaction=:0:ATTACH'
+ RTE>> ring_pmd_autotest
+
+The final output of the test has to be "Test OK"
diff --git a/test_plans/unit_tests_timer_test_plan.rst b/test_plans/unit_tests_timer_test_plan.rst
new file mode 100644
index 0000000..5bf96c5
--- /dev/null
+++ b/test_plans/unit_tests_timer_test_plan.rst
@@ -0,0 +1,98 @@
+.. Copyright (c) <2010>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===============
+Timer Autotests
+===============
+
+This section describes the test plan for the timer library.
+
+Description
+===========
+
+#. Stress tests.
+
+ The objective of the timer stress tests is to check that there are no
+ race conditions in list and status management. This test launches,
+ resets and stops the timer very often on many cores at the same
+ time.
+
+ - Only one timer is used for this test.
+ - On each core, the rte_timer_manage() function is called from the main loop
+ every 3 microseconds.
+ - In the main loop, the timer may be reset (randomly, with a
+ probability of 0.5 %) 100 microseconds later on a random core, or
+ stopped (with a probability of 0.5 % also).
+ - In callback, the timer is can be reset (randomly, with a
+ probability of 0.5 %) 100 microseconds later on the same core or
+ on another core (same probability), or stopped (same
+ probability).
+
+#. Basic test.
+
+ This test performs basic functional checks of the timers. The test
+ uses four different timers that are loaded and stopped under
+ specific conditions in specific contexts.
+
+ - Four timers are used for this test.
+ - On each core, the rte_timer_manage() function is called from main loop
+ every 3 microseconds.
+
+ The autotest python script checks that the behavior is correct:
+
+ - timer0
+
+ - At initialization, timer0 is loaded by the master core, on master core in
+ "single" mode (time = 1 second).
+ - In the first 19 callbacks, timer0 is reloaded on the same core,
+ then, it is explicitly stopped at the 20th call.
+ - At t=25s, timer0 is reloaded once by timer2.
+
+ - timer1
+
+ - At initialization, timer1 is loaded by the master core, on the
+ master core in "single" mode (time = 2 seconds).
+ - In the first 9 callbacks, timer1 is reloaded on another
+ core. After the 10th callback, timer1 is not reloaded anymore.
+
+ - timer2
+
+ - At initialization, timer2 is loaded by the master core, on the
+ master core in "periodical" mode (time = 1 second).
+ - In the callback, when t=25s, it stops timer3 and reloads timer0
+ on the current core.
+
+ - timer3
+
+ - At initialization, timer3 is loaded by the master core, on
+ another core in "periodical" mode (time = 1 second).
+ - It is stopped at t=25s by timer2.
diff --git a/test_plans/vm_power_manager_test_plan.rst b/test_plans/vm_power_manager_test_plan.rst
new file mode 100644
index 0000000..dff8197
--- /dev/null
+++ b/test_plans/vm_power_manager_test_plan.rst
@@ -0,0 +1,304 @@
+.. Copyright (c) <2015>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+===================
+VM Power Management
+===================
+
+This test plan is for the test and validation of feature VM Power Management
+of DPDK 1.8.
+
+VM Power Manager would use a hint based mechanism by which a VM can
+communicate to a host based governor about its current processing
+requirements. By mapping VMs virtual CPUs to physical CPUs the Power Manager
+can then make decisions according to some policy as to what power state the
+physical CPUs can transition to.
+
+VM Agent shall have the ability to send the following hints to host:
+- Scale frequency down
+- Scale frequency up
+- Reduce frequency to min
+- Increase frequency to max
+
+The Power manager is responsible for enabling the Linux userspace power
+governor and interacting via its sysfs entries to get/set frequencies.
+
+The power manager will manage the file handles for each core(<n>) below:
+- /sys/devices/system/cpu/cpu<n>/cpufreq/scaling_governor
+- /sys/devices/system/cpu/cpu<n>/cpufreq/scaling_available_frequencies
+- /sys/devices/system/cpu/cpu<n>/cpufreq/scaling_cur_freq
+- /sys/devices/system/cpu/cpu<n>/cpufreq/scaling_setspeed
+
+Prerequisites
+=============
+1. Hardware:
+ - CPU: Haswell, IVB(CrownPass)
+ - NIC: Niantic 82599
+
+2. BIOS:
+ - Enable VT-d and VT-x
+ - Enable Enhanced Intel SpeedStep(R) Tech
+ - Disable Intel(R) Turbo Boost Technology
+ - Enable Processor C3
+ - Enable Processor C6
+ - Enable Intel(R) Hyper-Threading Tech
+
+3. OS and Kernel:
+ - Fedora 20
+ - Enable Kernel features Huge page, UIO, IOMMU, KVM
+ - Enable Intel IOMMU in kernel commnand
+ - Disable Selinux
+
+3. Virtualization:
+ - QEMU emulator version 1.6.1
+ - libvirtd (libvirt) 1.1.3.5
+ - Add virio-serial port
+
+4. IXIA Traffic Generator Configuration
+ LPM table used for packet routing is:
+
+ +---------+------------------------+----+
+ | Entry # | LPM prefix (IP/length) | |
+ +---------+------------------------+----+
+ | 0 | 1.1.1.0/24 | P0 |
+ +---------+------------------------+----+
+ | 1 | 2.1.1.0/24 | P1 |
+ +---------+------------------------+----+
+
+
+ The flows should be configured and started by the traffic generator.
+
+ +------+---------+------------+---------+------+-------+--------+
+ | Flow | Traffic | IPv4 | IPv4 | Port | Port | L4 |
+ | | Gen. | Src. | Dst. | Src. | Dest. | Proto. |
+ | | Port | Address | Address | | | |
+ +------+---------+------------+---------+------+-------+--------+
+ | 1 | TG0 | 0.0.0.0 | 2.1.1.0 | any | any | UDP |
+ +------+---------+------------+---------+------+-------+--------+
+ | 2 | TG1 | 0.0.0.0 | 1.1.1.0 | any | any | UDP |
+ +------+---------+------------+---------+------+-------+--------+
+
+
+
+Test Case 1: VM Power Management Channel
+========================================
+1. Configure VM XML to pin VCPUs/CPUs:
+
+ <vcpu placement='static'>5</vcpu>
+ <cputune>
+ <vcpupin vcpu='0' cpuset='1'/>
+ <vcpupin vcpu='1' cpuset='2'/>
+ <vcpupin vcpu='2' cpuset='3'/>
+ <vcpupin vcpu='3' cpuset='4'/>
+ <vcpupin vcpu='4' cpuset='5'/>
+ </cputune>
+
+2. Configure VM XML to set up virtio serial ports
+
+ Create temporary folder for vm_power socket.
+
+ mkdir /tmp/powermonitor
+
+ Setup one serial port for every one vcpu in VM.
+
+ <channel type='unix'>
+ <source mode='bind' path='/tmp/powermonitor/<vm_name>.<channel_num>'/>
+ <target type='virtio' name='virtio.serial.port.poweragent.<channel_num>'/>
+ <address type='virtio-serial' controller='0' bus='0' port='4'/>
+ </channel>
+
+3. Run power-manager in Host
+
+ ./build/vm_power_mgr -c 0x3 -n 4
+
+4. Startup VM and run guest_vm_power_mgr
+
+ guest_vm_power_mgr -c 0x1f -n 4 -- -i
+5. Add vm in host and check vm_power_mgr can get frequency normally
+
+ vmpower> add_vm <vm_name>
+ vmpower> add_channels <vm_name> all
+ vmpower> show_cpu_freq <core_num>
+6. Check vcpu/cpu mapping can be detected normally
+
+ vmpower> show_vm <vm_name>
+ VM:
+ vCPU Refresh: 1
+ Channels 5
+ [0]: /tmp/powermonitor/<vm_name>.0, status = 1
+ [1]: /tmp/powermonitor/<vm_name>.1, status = 1
+ [2]: /tmp/powermonitor/<vm_name>.2, status = 1
+ [3]: /tmp/powermonitor/<vm_name>.3, status = 1
+ [4]: /tmp/powermonitor/<vm_name>.4, status = 1
+ Virtual CPU(s): 5
+ [0]: Physical CPU Mask 0x2
+ [1]: Physical CPU Mask 0x4
+ [2]: Physical CPU Mask 0x8
+ [3]: Physical CPU Mask 0x10
+ [4]: Physical CPU Mask 0x20
+
+7. Run vm_power_mgr in vm
+
+ guest_cli/build/vm_power_mgr -c 0x1f -n 4
+ Check monitor channel for all cores has been connected.
+
+Test Case 2: VM Power Management Numa
+=====================================
+1.Get core and socket information by cpu_layout
+
+ ./tools/cpu_layout.py
+2. Configure VM XML to pin VCPUs on Socket1:
+3. Repeat Case1 steps 3-7 sequentially
+4. Check vcpu/cpu mapping can be detected normally
+
+Test Case 3: VM Scale CPU Frequency Down
+========================================
+1. Setup VM power management environment
+2. Send cpu frequency down hints to Host
+
+ vmpower(guest)> set_cpu_freq 0 down
+3. Verify the frequency of physical CPU has been set down correctly
+
+ vmpower> show_cpu_freq 1
+ Core 1 frequency: 2700000
+
+4. Check other CPUs' frequency is not affected by change above
+5. check if the other VM works fine (if they use different CPUs)
+6. Repeat step2-5 several times
+
+
+Test Case 4: VM Scale CPU Frequency UP
+======================================
+1. Setup VM power management environment
+2. Send cpu frequency down hints to Host
+
+ vmpower(guest)> set_cpu_freq 0 up
+
+3. Verify the frequency of physical CPU has been set up correctly
+
+ vmpower> show_cpu_freq 1
+ Core 1 frequency: 2800000
+4. Check other CPUs' frequency is not affected by change above
+5. check if the other VM works fine (if they use different CPUs)
+6. Repeat step2-5 several times
+
+Test Case 5: VM Scale CPU Frequency to Min
+==========================================
+1. Setup VM power management environment
+2. Send cpu frequency scale to minimum hints.
+
+ vmpower(guest)> set_cpu_freq 0 min
+3. Verify the frequency of physical CPU has been scale to min correctly
+
+ vmpower> show_cpu_freq 1
+ Core 1 frequency: 1200000
+4. Check other CPUs' frequency is not affected by change above
+5. check if the other VM works fine (if they use different CPUs)
+
+Test Case 6: VM Scale CPU Frequency to Max
+==========================================
+1. Setup VM power management environment
+2. Send cpu frequency down hints to Host
+
+ vmpower(guest)> set_cpu_freq 0 max
+3. Verify the frequency of physical CPU has been set to max correctly
+
+ vmpower> show_cpu_freq 1
+ Core 1 frequency: 2800000
+4. Check other CPUs' frequency is not affected by change above
+5. check if the other VM works fine (if they use different CPUs)
+
+Test Case 7: VM Power Management Multi VMs
+==========================================
+1. Setup VM power management environment for VM1
+2. Setup VM power management environment for VM2
+3. Run power-manager in Host
+
+ ./build/vm_power_mgr -c 0x3 -n 4
+4. Startup VM1 and VM2
+5. Add VM1 in host and check vm_power_mgr can get frequency normally
+
+ vmpower> add_vm <vm1_name>
+ vmpower> add_channels <vm1_name> all
+ vmpower> show_cpu_freq <core_num>
+6. Add VM2 in host and check vm_power_mgr can get frequency normally
+
+ vmpower> add_vm <vm2_name>
+ vmpower> add_channels <vm2_name> all
+ vmpower> show_cpu_freq <core_num>
+7. Run Case3-6 and check VM1 and VM2 cpu frequency can by modified by guest_cli
+8. Poweroff VM2 and remove VM2 from host vm_power_mgr
+
+ vmpower> rm_vm <vm2_name>
+
+Test Case 8: VM l3fwd-power Latency
+===================================
+1. Connect two physical ports to IXIA
+2. Start VM and run l3fwd-power
+
+ l3fwd-power -c 6 -n 4 -- -p 0x3 --config
+ '(P0,0,C{1.1.0}),(P1,0,C{1.2.0})'
+
+3. Configure packet flow in IxiaNetwork
+4. Start to send packets from IXIA and check the receiving packets and latency
+5. Record the latency of frame sizes 128
+6. Compare latency value with sample l3fwd
+
+Test Case 9: VM l3fwd-power Performance
+=======================================
+Start VM and run l3fwd-power
+
+ l3fwd-power -c 6 -n 4 -- -p 0x3 --config
+ '(P0,0,C{1.1.0}),(P1,0,C{1.2.0})'
+
+Input traffic linerate varied from 0 to 100%, in order to see cpu frequency
+changes.
+
+The test report should provide the throughput rate measurements (in Mpps and %
+of the line rate for 2x NIC ports) and cpu frequency as listed in the table
+below:
+
+ +---------------+---------------+-----------+
+ | % Tx linerate | Rx % linerate | Cpu freq |
+ +---------------+---------------+-----------+
+ | 0 | | |
+ +---------------+---------------+-----------+
+ | 20 | | |
+ +---------------+---------------+-----------+
+ | 40 | | |
+ +---------------+---------------+-----------+
+ | 60 | | |
+ +---------------+---------------+-----------+
+ | 80 | | |
+ +---------------+---------------+-----------+
+ | 100 | | |
+ +---------------+---------------+-----------+
diff --git a/test_plans/vxlan_sample_test_plan.rst b/test_plans/vxlan_sample_test_plan.rst
new file mode 100644
index 0000000..f440148
--- /dev/null
+++ b/test_plans/vxlan_sample_test_plan.rst
@@ -0,0 +1,255 @@
+.. Copyright (c) <2015>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPR ESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+============
+Vxlan Sample
+============
+Vxlan sample simulates a VXLAN Tunnel Endpoint (VTEP) termination in DPDK.
+It is used to demonstrate the offload and filtering capabilities of i40 NIC
+for VXLAN packet.
+
+Vxlan sample uses the basic virtio devices management function from vHOST
+example, and the US-vHost interface and tunnel filtering mechanism to direct
+the traffic to/from a specific VM.
+
+Vxlan sample is also designed to show how tunneling protocols can be handled.
+
+Prerequisites
+=============
+1x Intel X710 (Fortville) NICs (2x 40GbE full duplex optical ports per NIC)
+plugged into the available PCIe Gen3 8-lane slot.
+
+2x Intel XL710-DA4 (Eagle Fountain) (1x 10GbE full duplex optical ports per NIC)
+plugged into the avaiable PCIe Gen3 8-lane slot.
+
+DUT board must be two sockets system and each cpu have more than 8 lcores.
+
+Update qemu-system-x86_64 to version 2.2.0 which support hugepage based memory.
+Prepare vhost-use requested modules::
+
+ modprobe fuse
+ modprobe cuse
+ insmod lib/librte_vhost/eventfd_link/eventfd_link.ko
+
+Allocate 4096*2M hugepages for vm and dpdk::
+
+ echo 4096 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
+
+Test Case: Vxlan Sample Encap packet
+====================================
+Start vxlan sample with only encapsulation enable::
+
+ tep_termination -c 0xf -n 3 --socket-mem 2048,2048 -- -p 0x1 \
+ --udp-port 4789 --nb-devices 2 --filter-type 3 --tx-checksum 0 \
+ --encap 1 --decap 0
+
+Wait for vhost-net socket device created and message dumped::
+
+ VHOST_CONFIG: bind to vhost-net
+
+Start virtual machine with hugepage based memory and two vhost-user devices::
+
+ qemu-system-x86_64 -name vm0 -enable-kvm -daemonize \
+ -cpu host -smp 4 -m 4096 \
+ -object memory-backend-file,id=mem,size=4096M,mem-path=/mnt/huge,share=on \
+ -numa node,memdev=mem -mem-prealloc \
+ -chardev socket,id=char0,path=./dpdk/vhost-net \
+ -netdev type=vhost-user,id=netdev0,chardev=char0,vhostforce \
+ -device virtio-net-pci,netdev=netdev0,mac=00:00:20:00:00:20 \
+ -chardev socket,id=char1,path=./dpdk/vhost-net \
+ -netdev type=vhost-user,id=netdev1,chardev=char1,vhostforce \
+ -device virtio-net-pci,netdev=netdev1,mac=00:00:20:00:00:21 \
+ -drive file=/storage/vm-image/vm0.img -vnc :1
+Login into virtual machine and start testpmd with additional arguments::
+
+ testpmd -c f -n 3 -- -i --txqflags=0xf00 --disable-hw-vlan
+
+Start packet forward of testpmd and transit several packets for mac learning::
+
+ testpmd> set fwd mac
+ testpmd> start tx_first
+
+Make sure virtIO port registered normally::
+
+ VHOST_CONFIG: virtio is now ready for processing.
+ VHOST_DATA: (1) Device has been added to data core 56
+ VHOST_DATA: (1) MAC_ADDRESS 00:00:20:00:00:21 and VNI 1000 registered
+ VHOST_DATA: (0) MAC_ADDRESS 00:00:20:00:00:20 and VNI 1000 registered
+
+Send normal udp packet to PF device and packet dmac match PF device
+Verify packet has been recevied in virtIO port0 and forwarded by port1::
+
+ testpmd> show port stats all
+
+Verify encapsulated packet received on PF device
+
+Test Case: Vxlan Sample Decap packet
+====================================
+Start vxlan sample with only de-capsulation enable::
+
+ tep_termination -c 0xf -n 3 --socket-mem 2048,2048 -- -p 0x1 \
+ --udp-port 4789 --nb-devices 2 --filter-type 3 --tx-checksum 0 \
+ --encap 0 --decap 1
+
+Start vhost-user test environment like case vxlan_sample_encap.
+
+Send vxlan packet Ether(dst=PF mac)/IP/UDP/vni(1000)/
+ Ether(dst=virtIO port0)/IP/UDP to PF device::
+
+Verify that packet received by virtIO port0 and forwarded by virtIO port1::
+
+ testpmd> show port stats all
+
+Verify that PF received packet just the same as inner packet
+
+Send vxlan packet Ether(dst=PF mac)/IP/UDP/vni(1000)/
+ Ether(dst=virtIO port1)/IP/UDP to PF device
+
+Verify that packet received by virtIO port1 and forwarded by virtIO port0::
+
+ testpmd> show port stats all
+
+Make sure PF received packet received inner packet with mac reversed.
+
+Test Case: Vxlan Sample Encap and Decap
+=======================================
+Start vxlan sample with only de-capsulation enable::
+
+ tep_termination -c 0xf -n 3 --socket-mem 2048,2048 -- -p 0x1 \
+ --udp-port 4789 --nb-devices 2 --filter-type 3 --tx-checksum 0 \
+ --encap 1 --decap 1
+
+Start vhost-user test environment like case vxlan_sample_encap
+
+Send vxlan packet Ether(dst=PF mac)/IP/UDP/vni(1000)/
+ Ether(dst=virtIO port0)/IP/UDP to PF device
+
+Verify that packet received by virtIO port0 and forwarded by virtIO port1::
+
+ testpmd> show port stats all
+
+Verify encapsulated packet received on PF device.
+Verify that inner packet src and dst mac address have been conversed.
+
+Test Case: Vxlan Sample Checksum
+================================
+Start vxlan sample with only decapsulation enable::
+
+ tep_termination -c 0xf -n 3 --socket-mem 2048,2048 -- -p 0x1 \
+ --udp-port 4789 --nb-devices 2 --filter-type 3 --tx-checksum 1 \
+ --encap 1 --decap 1
+
+Start vhost-user test environment like case vxlan_sample_encap
+
+Send vxlan packet with Ether(dst = PF mac)/IP/UDP/vni(1000)/
+ Ether(dst = virtIO port0)/IP wrong chksum/ UDP wrong chksum
+
+Verify that packet recevied by virtIO port0 and forwarded by virtIO port1::
+
+ testpmd> show port stats all
+
+Verify encapsulated packet received on PF device.
+Verify that inner packet src and dst mac address have been conversed.
+Verify that inner packet ip checksum and udp checksum were corrected.
+
+Send vxlan packet with Ether(dst = PF mac)/IP/UDP/vni(1000)/
+ Ether(dst = virtIO port0)/IP wrong chksum/ TCP wrong chksum
+
+Verify that packet recevied by virtIO port0 and forwarded by virtIO port1::
+
+ testpmd> show port stats all
+
+Verify encapsulated packet received on PF device.
+Verify that inner packet src and dst mac address have been conversed.
+Verify that inner packet ip checksum and tcp checksum were corrected.
+
+Send vxlan packet with Ether(dst = PF mac)/IP/UDP/vni(1000)/
+ Ether(dst = virtIO port0)/IP wrong chksum/ SCTP wrong chksum
+
+Verify that packet received by virtIO port0 and forwarded by virtIO port1::
+
+ testpmd> show port stats all
+
+Verify encapsulated packet received on PF device.
+Verify that inner packet src and dst mac address have been conversed.
+Verify that inner packet ip checksum and sctp checksum were corrected.
+
+Test Case: Vxlan Sample TSO
+===========================
+Start vxlan sample with tso enable, tx checksum must enable too.
+For hardware limitation, tso segment size must be larger 256::
+
+ tep_termination -c 0xf -n 3 --socket-mem 2048,2048 -- -p 0x1 \
+ --udp-port 4789 --nb-devices 2 --filter-type 3 --tx-checksum 1 \
+ --encap 1 --decap 1 --tso-segsz 256
+
+Start vhost-user test environment like case vxlan_sample_encap
+
+Send vxlan packet with Ether(dst = PF mac)/IP/UDP/vni(1000)/
+ Ether(dst = virtIO port0)/TCP/892 Bytes data, total length will be 1000
+
+Verify that packet recevied by virtIO port0 and forwarded by virtIO port1::
+
+ testpmd> show port stats all
+
+Verify that four separated vxlan packets received on PF devices.
+Make sure tcp packet payload is 256, 256, 256 and 124.
+
+Test Case: Vxlan Sample Performance Benchmarking
+================================================
+The throughput is measured for different operations taken by vxlan sample.
+Virtio single mean there's only one flow and forwarded by single port in vm.
+Virtio two mean there're two flows and forwarded by both two ports in vm.
+
++================+===========+=======+============+
+| Function | VirtIO | Mpps | % linerate |
++================+===========+=======+============+
+| Decap | Single | | |
++----------------+-----------+-------+------------+
+| Encap | Single | | |
++----------------+-----------+-------+------------+
+| Decap&Encap | Single | | |
++----------------+-----------+-------+------------+
+| Checksum | Single | | |
++----------------+-----------+-------+------------+
+| Checksum&Decap | Single | | |
++----------------+-----------+-------+------------+
+| Decap | Two Ports | | |
++----------------+-----------+-------+------------+
+| Encap | Two Ports | | |
++----------------+-----------+-------+------------+
+| Decap&Encap | Two Ports | | |
++----------------+-----------+-------+------------+
+| Checksum | Two Ports | | |
++----------------+-----------+-------+------------+
+| Checksum&Decap | Two Ports | | |
++----------------+-----------+-------+------------+
diff --git a/test_plans/vxlan_test_plan.rst b/test_plans/vxlan_test_plan.rst
new file mode 100644
index 0000000..b7961f9
--- /dev/null
+++ b/test_plans/vxlan_test_plan.rst
@@ -0,0 +1,394 @@
+.. Copyright (c) <2014>, Intel Corporation
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Intel Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPR ESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ OF THE POSSIBILITY OF SUCH DAMAGE.
+
+================
+ Fortville Vxlan
+================
+Cloud providers build virtual network overlays over existing network
+infrastructure that provide tenant isolation and scaling. Tunneling
+layers added to the packets carry the virtual networking frames over
+existing Layer 2 and IP networks. Conceptually, this is similar to
+creating virtual private networks over the Internet. Fortville will
+process these tunneling layers by the hardware.
+
+This document provides test plan for Fortville vxlan packet detecting,
+checksum computing and filtering.
+
+Prerequisites
+=============
+1x Intel X710 (Fortville) NICs (2x 40GbE full duplex optical ports per NIC)
+plugged into the available PCIe Gen3 8-lane slot.
+
+1x Intel XL710-DA4 (Eagle Fountain) (1x 10GbE full duplex optical ports per NIC)
+plugged into the avaiable PCIe Gen3 8-lane slot.
+
+DUT board must be two sockets system and each cpu have more than 8 lcores.
+
+Test Case: Vxlan ipv4 packet detect
+===================================
+Start testpmd with tunneling packet type to vxlan::
+
+ testpmd -c ffff -n 4 -- -i --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2 --txqflags=0x0
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+ rx_vxlan_port add 4789 0
+
+Send packet as table listed and check dumped packet type the same as column
+"Rx packet type".
+
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Inner L4 | Rx packet type | Pkt Error |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv4 | None | None | None | None | PKT_RX_IPV4_HDR | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv4 | Vxlan | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv4 | Vxlan | None | Ipv4 | Tcp | PKT_RX_IPV4_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv4 | Vxlan | None | Ipv4 | Sctp | PKT_RX_IPV4_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| Yes | Ipv4 | Vxlan | None | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| Yes | Ipv4 | Vxlan | Yes | Ipv4 | Udp | PKT_RX_IPV4_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+
+
+
+Test Case: Vxlan ipv6 packet detect
+===================================
+Start testpmd with tunneling packet type to vxlan::
+
+ testpmd -c ffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2 --txqflags=0x0
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+ rx_vxlan_port add 4789 0
+
+Send ipv6 packet as table listed and check dumped packet type the same as
+column "Rx packet type".
+
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Innter L4 | Rx packet type | Pkt Error |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv6 | None | None | None | None | PKT_RX_IPV6_HDR | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv6 | Vxlan | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv6 | Vxlan | None | Ipv6 | Tcp | PKT_RX_IPV6_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| No | Ipv6 | Vxlan | None | Ipv6 | Sctp | PKT_RX_IPV6_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| Yes | Ipv6 | Vxlan | None | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+| Yes | Ipv6 | Vxlan | Yes | Ipv6 | Udp | PKT_RX_IPV6_HDR_EXT | None |
++------------+----------+-----------+------------+----------+-----------+---------------------+-----------+
+
+
+Test Case: Vxlan ipv4 checksum offload
+======================================
+
+Start testpmd with tunneling packet type to vxlan::
+
+ testpmd -c ffff -n 4 -- -i --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2 --txqflags=0x0
+
+Set csum packet forwarding mode and enable verbose log::
+
+ set fwd csum
+ set verbose 1
+ rx_vxlan_port add 4789 0
+
+Enable VXLAN protocal on ports::
+
+ rx_vxlan_port add 4789 0
+ rx_vxlan_port add 4789 1
+
+Enable IP,UDP,TCP,SCTP,OUTER-IP checksum offload::
+
+ csum parse_tunnel on 0
+ csum parse_tunnel on 1
+ csum set ip hw 0
+ csum set udp hw 0
+ csum set tcp hw 0
+ csum set stcp hw 0
+ csum set outer-ip hw 0
+
+Send packet with valid checksum and check there's no chksum error counter
+increased.
+
++------------+----------+-----------+------------+----------+-----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Innter L4 | Pkt Error |
++------------+----------+-----------+------------+----------+-----------+-----------+
+| No | Ipv4 | None | None | None | None | None |
++------------+----------+-----------+------------+----------+-----------+-----------+
+
+Send packet with invalid l3 checksum first. Then check forwarded packet checksum
+corrected and there's correct l3 chksum error counter increased.
+
++------------+----------+-----------+------------+----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Innter L4 |
++------------+----------+-----------+------------+----------+-----------+
+| No | Bad Ipv4 | None | None | None | None |
++------------+----------+-----------+------------+----------+-----------+
+| No | Ipv4 | Vxlan | None | Bad Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+| No | Bad Ipv4 | Vxlan | None | Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+| No | Bad Ipv4 | Vxlan | None | Bad Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+
+Send packet with invalid l4 checksum first. Then check forwarded packet checksum
+corrected and there's correct l4 chksum error counter increased.
+
++------------+----------+-----------+------------+----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Innter L4 |
++------------+----------+-----------+------------+----------+-----------+
+| No | Ipv4 | Vxlan | None | Ipv4 | Bad Udp |
++------------+----------+-----------+------------+----------+-----------+
+| No | Ipv4 | Vxlan | None | Ipv4 | Bad Tcp |
++------------+----------+-----------+------------+----------+-----------+
+| No | Ipv4 | Vxlan | None | Ipv4 | Bad Sctp |
++------------+----------+-----------+------------+----------+-----------+
+
+Send vlan packet with invalid l3 checksum first. Then check forwarded packet
+checksum corrected and there's correct l3 chksum error counter increased.
+
++------------+----------+-----------+------------+----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Innter L4 |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Bad Ipv4 | Vxlan | None | Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv4 | Vxlan | None | Bad Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Bad Ipv4 | Vxlan | None | Bad Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Bad Ipv4 | Vxlan | Yes | Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv4 | Vxlan | Yes | Bad Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Bad Ipv4 | Vxlan | Yes | Bad Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+
+Send vlan packet with invalid l4 checksum first. Then check forwarded packet
+checksum corrected and there's correct l4 chksum error counter increased.
+
++------------+----------+-----------+------------+----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Innter L4 |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv4 | Vxlan | None | Ipv4 | Bad Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv4 | Vxlan | None | Ipv4 | Bad Tcp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv4 | Vxlan | None | Ipv4 | Bad Sctp |
++------------+----------+-----------+------------+----------+-----------+
+
+
+Test Case: Vxlan ipv6 checksum offload
+======================================
+Start testpmd with tunneling packet type::
+
+ testpmd -c ffff -n 4 -- -i --tunnel-type=1 --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2
+
+Set csum packet forwarding mode and enable verbose log::
+
+ set fwd csum
+ set verbose 1
+
+
+Enable VXLAN protocal on ports::
+
+ rx_vxlan_port add 4789 0
+ rx_vxlan_port add 4789 1
+
+Enable IP,UDP,TCP,SCTP,VXLAN checksum offload::
+
+ csum parse_tunnel on 0
+ csum parse_tunnel on 1
+ csum set ip hw 0
+ csum set udp hw 0
+ csum set tcp hw 0
+ csum set stcp hw 0
+ csum set outer-ip hw 0
+
+Send ipv6 packet with valid checksum and check there's no chksum error counter
+increased.
+
++------------+----------+-----------+------------+----------+-----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Innter L4 | Pkt Error |
++------------+----------+-----------+------------+----------+-----------+-----------+
+| No | Ipv6 | None | None | None | None | None |
++------------+----------+-----------+------------+----------+-----------+-----------+
+
+
+Send ipv6 packet with invalid l3 checksum first. Then check forwarded packet
+checksum corrected and there's correct l3 chksum error counter increased.
+
++------------+----------+-----------+------------+----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Inner L4 |
++------------+----------+-----------+------------+----------+-----------+
+| No | Ipv6 | Vxlan | None | Ipv4 | None |
++------------+----------+-----------+------------+----------+-----------+
+| No | Ipv6 | Vxlan | None | Bad Ipv4 | Udp |
++------------+----------+-----------+------------+----------+-----------+
+
+Send vlan+ipv6 packet with invalid l4 checksum first. Then check forwarded
+packet checksum corrected and there's correct l4 chksum error counter
+increased.
+
++------------+----------+-----------+------------+----------+-----------+
+| Outer Vlan | Outer IP | Outer UDP | Inner Vlan | Inner L3 | Inner L4 |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv6 | Vxlan | None | Ipv4 | Bad Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv6 | Vxlan | None | Ipv4 | Bad Tcp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv6 | Vxlan | None | Ipv4 | Bad Sctp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv6 | Vxlan | Yes | Ipv4 | Bad Udp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv6 | Vxlan | Yes | Ipv4 | Bad Tcp |
++------------+----------+-----------+------------+----------+-----------+
+| Yes | Ipv6 | Vxlan | Yes | Ipv4 | Bad Sctp |
++------------+----------+-----------+------------+----------+-----------+
+
+Test Case: Clould Filter
+========================
+Start testpmd with tunneling packet type to vxlan and disable receive side
+scale for hardware limitation::
+
+ testpmd -c ffff -n 4 -- -i --disable-rss --rxq=4 --txq=4 --nb-cores=8 --nb-ports=2 --txqflags=0x0
+
+Set rxonly packet forwarding mode and enable verbose log::
+
+ set fwd rxonly
+ set verbose 1
+
+Add one new Cloud filter as table listed first::
+
+ tunnel_filter add 0 11:22:33:44:55:66 00:00:20:00:00:01 192.168.2.2 1 vxlan imac-ivlan 1 3
+
+Then send one packet and check packet was forwarded into right queue.
+
++------------+------------+------------+----------+----------+--------+-------+
+| Outer Mac | Inner Mac | Inner Vlan | Outer Ip | Inner Ip | Vni ID | Queue |
++------------+------------+------------+----------+----------+--------+-------+
+| No | Yes | Yes | No | No | No | 1 |
++------------+------------+------------+----------+----------+--------+-------+
+| No | Yes | Yes | No | No | Yes | 1 |
++------------+------------+------------+----------+----------+--------+-------+
+| No | Yes | No | No | No | Yes | 1 |
++------------+------------+------------+----------+----------+--------+-------+
+| No | Yes | No | No | No | No | 1 |
++------------+------------+------------+----------+----------+--------+-------+
+| Yes | Yes | No | No | Yes | Yes | 1 |
++------------+------------+------------+----------+----------+--------+-------+
+| No | No | No | No | Yes | No | 1 |
++------------+------------+------------+----------+----------+--------+-------+
+
+
+Add Clould filter to max number will be failed.
+
+Remove Clould filter which has been added. Then send one packet and check
+packet was received in queue 0.
+
+Add Clould filter with invalid Mac address "00:00:00:00:01" will be failed.
+
+Add Clould filter with invalid ip address "192.168.1.256" will be failed.
+
+Add Clould filter with invalid vlan "4097" will be failed.
+
+Add Clould filter with invalid vni "16777216" will be failed.
+
+Add Clould filter with invalid queue id "64" will be failed.
+
+Test Case: Vxlan Checksum Offload Performance Benchmarking
+==========================================================
+
+The throughput is measured for each of these cases for vxlan tx checksum
+offload of "all by software", "L3 offload by hardware", "L4 offload by
+hardware", "l3&l4 offload by hardware".
+
+The results are printed in the following table:
+
++----------------+--------+--------+------------+
+| Calculate Type | Queues | Mpps | % linerate |
++================+========+========+============+
+| SOFTWARE ALL | Single | | |
++----------------+--------+--------+------------+
+| HW L4 | Single | | |
++----------------+--------+--------+------------+
+| HW L3&L4 | Single | | |
++----------------+--------+--------+------------+
+| SOFTWARE ALL | Multi | | |
++----------------+--------+--------+------------+
+| HW L4 | Multi | | |
++----------------+--------+--------+------------+
+| HW L3&L4 | Multi | | |
++----------------+--------+--------+------------+
+
+Test Case: Vxlan Tunnel filter Performance Benchmarking
+=======================================================
+The throughput is measured for different Vxlan tunnel filter types.
+Queue single mean there's only one flow and forwarded to the first queue.
+Queue multi mean there're two flows and configure to different queues.
+
++--------+------------------+--------+--------+------------+
+| Packet | Filter | Queue | Mpps | % linerate |
++========+==================+========+========+============+
+| Normal | None | Single | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | None | Single | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac-ivlan | Single | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac-ivlan-tenid | Single | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac-tenid | Single | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac | Single | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | omac-imac-tenid | Single | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac-ivlan | Multi | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac-ivlan-tenid | Multi | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac-tenid | Multi | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | imac | Multi | | |
++--------+------------------+--------+--------+------------+
+| Vxlan | omac-imac-tenid | Multi | | |
++--------+------------------+--------+--------+------------+
diff --git a/tests/TestSuite_blacklist.py b/tests/TestSuite_blacklist.py
index 04425ba..ba39b36 100644
--- a/tests/TestSuite_blacklist.py
+++ b/tests/TestSuite_blacklist.py
@@ -101,7 +101,7 @@ class TestBlackList(TestCase):
Run testpmd with one port blacklisted.
"""
self.dut.kill_all()
- out = self.pmdout.start_testpmd("Default", eal_param="-b 0000:%s -- -i" % self.dut.ports_info[0]['pci'])
+ out = self.pmdout.start_testpmd("Default", eal_param="-b 0000:%s" % self.dut.ports_info[0]['pci'])
self.check_blacklisted_ports(out, self.ports[1:])
def test_bl_allbutoneportblacklisted(self):
diff --git a/tests/TestSuite_checksum_offload.py b/tests/TestSuite_checksum_offload.py
index 9c65563..abfebb6 100644
--- a/tests/TestSuite_checksum_offload.py
+++ b/tests/TestSuite_checksum_offload.py
@@ -44,28 +44,18 @@ import rst
from test_case import TestCase
from pmd_output import PmdOutput
-
class TestChecksumOffload(TestCase):
def set_up_all(self):
"""
Run at the start of each test suite.
-
Checksum offload prerequisites.
"""
# Based on h/w type, choose how many ports to use
- self.dut_ports = self.dut.get_ports()
-
+ self.dut_ports = self.dut.get_ports(self.nic)
# Verify that enough ports are available
self.verify(len(self.dut_ports) >= 2, "Insufficient ports for testing")
-
- # Verify that enough threads are available
- cores = self.dut.get_core_list("1S/2C/2T")
- self.verify(cores is not None, "Insufficient cores for speed testing")
-
self.pmdout = PmdOutput(self.dut)
-
- self.coreMask = dts.create_mask(cores)
self.portMask = dts.create_mask([self.dut_ports[0], self.dut_ports[1]])
self.ports_socket = self.dut.get_numa_id(self.dut_ports[0])
@@ -74,7 +64,8 @@ class TestChecksumOffload(TestCase):
Run before each test case.
"""
if self.dut.want_func_tests:
- self.pmdout.start_testpmd("1S/2C/2T", "--portmask=%s " % (self.portMask) + "--disable-hw-vlan --enable-rx-cksum --crc-strip --txqflags=0")
+ self.pmdout.start_testpmd("Default", "--portmask=%s " %
+ (self.portMask) + "--disable-hw-vlan --enable-rx-cksum --crc-strip", socket=self.ports_socket)
self.dut.send_expect("set verbose 1", "testpmd>")
self.dut.send_expect("set fwd csum", "testpmd>")
@@ -169,32 +160,25 @@ class TestChecksumOffload(TestCase):
Do not insert IPv4/IPv6 UDP/TCP checksum on the transmit packet.
Verify that the same number of packet are correctly received on the
traffic generator side.
- Use VLAN label.
"""
dmac = self.dut.get_mac_address(self.dut_ports[1])
- pktsChkErr = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=1)/IP(chksum=0x0)/UDP(chksum=0x1)/("X"*46)' % dmac,
- 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=2)/IP(chksum=0x0)/TCP(chksum=0x0)/("X"*46)' % dmac,
- 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=3)/IP(chksum=0x0)/SCTP(chksum=0x0)/("X"*48)' % dmac,
- 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=4)/IPv6(src="::1")/UDP(chksum=0x1)/("X"*46)' % dmac,
- 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/Dot1Q(vlan=5)/IPv6(src="::1")/TCP(chksum=0x0)/("X"*46)' % dmac}
-
+ pktsChkErr = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/UDP(chksum=0xf)/("X"*46)' % dmac,
+ 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/TCP(chksum=0xf)/("X"*46)' % dmac,
+ 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/SCTP(chksum=0xf)/("X"*48)' % dmac,
+ 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::1")/UDP(chksum=0xf)/("X"*46)' % dmac,
+ 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::1")/TCP(chksum=0xf)/("X"*46)' % dmac}
pkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="127.0.0.2")/UDP()/("X"*46)' % dmac,
'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="127.0.0.2")/TCP()/("X"*46)' % dmac,
'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="127.0.0.2")/SCTP()/("X"*48)' % dmac,
'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::2")/UDP()/("X"*46)' % dmac,
'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::2")/TCP()/("X"*46)' % dmac}
-
self.checksum_enablehw(self.dut_ports[0])
self.checksum_enablehw(self.dut_ports[1])
-
self.dut.send_expect("start", "testpmd>")
-
result = self.checksum_validate(pktsChkErr, pkts)
-
self.dut.send_expect("stop", "testpmd>")
-
self.verify(len(result) == 0, string.join(result.values(), ","))
-
+
def test_checksum_offload_enable(self):
"""
Insert IPv4/IPv6 UDP/TCP/SCTP checksum on the transmit packet.
@@ -202,22 +186,19 @@ class TestChecksumOffload(TestCase):
Verify that the same number of packet are correctly received on the
traffic generator side.
"""
-
dmac = self.dut.get_mac_address(self.dut_ports[1])
- pkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/UDP(chksum=0x1)/("X"*46)' % dmac,
- 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/TCP(chksum=0x0)/("X"*46)' % dmac,
- 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/SCTP(chksum=0x0)/("X"*48)' % dmac,
- 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::1")/UDP(chksum=0x1)/("X"*46)' % dmac,
- 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::1")/TCP(chksum=0x0)/("X"*46)' % dmac
- }
+ pkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/UDP(chksum=0xf)/("X"*46)' % dmac,
+ 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/TCP(chksum=0xf)/("X"*46)' % dmac,
+ 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(chksum=0x0)/SCTP(chksum=0xf)/("X"*48)' % dmac,
+ 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::1")/UDP(chksum=0xf)/("X"*46)' % dmac,
+ 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::1")/TCP(chksum=0xf)/("X"*46)' % dmac}
pkts_ref = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="127.0.0.2")/UDP()/("X"*46)' % dmac,
'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="127.0.0.2")/TCP()/("X"*46)' % dmac,
'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="127.0.0.2")/SCTP()/("X"*48)' % dmac,
'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::2")/UDP()/("X"*46)' % dmac,
- 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::2")/TCP()/("X"*46)' % dmac
- }
+ 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="::2")/TCP()/("X"*46)' % dmac}
self.checksum_enablehw(self.dut_ports[0])
self.checksum_enablehw(self.dut_ports[1])
@@ -237,15 +218,13 @@ class TestChecksumOffload(TestCase):
Verify that the same number of packet are correctly received on
the traffic generator side.
"""
-
dmac = self.dut.get_mac_address(self.dut_ports[1])
-
sndIP = '10.0.0.1'
sndIPv6 = '::1'
- sndPkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s",chksum=0x0)/UDP(chksum=0x1)/("X"*46)' % (dmac, sndIP),
- 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s",chksum=0x0)/TCP(chksum=0x0)/("X"*46)' % (dmac, sndIP),
- 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/UDP(chksum=0x1)/("X"*46)' % (dmac, sndIPv6),
- 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/TCP(chksum=0x0)/("X"*46)' % (dmac, sndIPv6)}
+ sndPkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s",chksum=0x0)/UDP(chksum=0xf)/("X"*46)' % (dmac, sndIP),
+ 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP(src="%s",chksum=0x0)/TCP(chksum=0xf)/("X"*46)' % (dmac, sndIP),
+ 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/UDP(chksum=0xf)/("X"*46)' % (dmac, sndIPv6),
+ 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6(src="%s")/TCP(chksum=0xf)/("X"*46)' % (dmac, sndIPv6)}
expIP = "10.0.0.2"
expIPv6 = '::2'
@@ -265,7 +244,6 @@ class TestChecksumOffload(TestCase):
"""
Test ans report checksum offload performance for given parameters.
"""
-
Bps = dict()
Pps = dict()
Pct = dict()
@@ -273,20 +251,20 @@ class TestChecksumOffload(TestCase):
result = [2, lcore, ptype, mode]
for size in size_list:
-
flow = flow_format % (dmac, size)
self.tester.scapy_append('wrpcap("test.pcap", [%s])' % flow)
-
self.tester.scapy_execute()
-
tgenInput = []
- tgenInput.append((self.tester.get_local_port(self.dut_ports[0]), self.tester.get_local_port(self.dut_ports[1]), "test.pcap"))
- tgenInput.append((self.tester.get_local_port(self.dut_ports[1]), self.tester.get_local_port(self.dut_ports[0]), "test.pcap"))
-
- Bps[str(size)], Pps[str(size)] = self.tester.traffic_generator_throughput(tgenInput)
+ tgenInput.append(
+ (self.tester.get_local_port(self.dut_ports[0]), self.tester.get_local_port(self.dut_ports[1]), "test.pcap"))
+ tgenInput.append(
+ (self.tester.get_local_port(self.dut_ports[1]), self.tester.get_local_port(self.dut_ports[0]), "test.pcap"))
+ Bps[str(size)], Pps[
+ str(size)] = self.tester.traffic_generator_throughput(tgenInput)
self.verify(Pps[str(size)] > 0, "No traffic detected")
Pps[str(size)] /= 1E6
- Pct[str(size)] = (Pps[str(size)] * 100) / self.wirespeed(self.nic, size, 2)
+ Pct[str(size)] = (Pps[str(size)] * 100) / \
+ self.wirespeed(self.nic, size, 2)
result.append(Pps[str(size)])
result.append(Pct[str(size)])
@@ -297,23 +275,16 @@ class TestChecksumOffload(TestCase):
"""
Test checksum offload performance.
"""
- self.dut_ports = self.dut.get_ports_performance()
- # Verify that enough ports are available
- self.verify(len(self.dut_ports) >= 2, "Insufficient ports for testing")
-
# sizes = [64, 128, 256, 512, 1024]
sizes = [64, 128]
- pkts = {
- 'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/UDP()/("X"*(%d-46))',
- 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/TCP()/("X"*(%d-58))',
- 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/SCTP()/("X"*(%d-50+2))',
- 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/UDP()/("X"* (lambda x: x - 66 if x > 66 else 0)(%d))',
- 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/TCP()/("X"* (lambda x: x - 78 if x > 78 else 0)(%d))'
- }
+ pkts = {'IP/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/UDP()/("X"*(%d-46))',
+ 'IP/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/TCP()/("X"*(%d-58))',
+ 'IP/SCTP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IP()/SCTP()/("X"*(%d-50+2))',
+ 'IPv6/UDP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/UDP()/("X"* (lambda x: x - 66 if x > 66 else 0)(%d))',
+ 'IPv6/TCP': 'Ether(dst="%s", src="52:00:00:00:00:00")/IPv6()/TCP()/("X"* (lambda x: x - 78 if x > 78 else 0)(%d))'}
lcore = "1S/2C/1T"
portMask = dts.create_mask([self.dut_ports[0], self.dut_ports[1]])
-
for mode in ["sw", "hw"]:
self.logger.info("%s performance" % mode)
rst.write_text(mode + " Performance" + '\r\n')
@@ -321,14 +292,12 @@ class TestChecksumOffload(TestCase):
for size in sizes:
tblheader.append("%sB mpps" % str(size))
tblheader.append("%sB %% " % str(size))
-
dts.results_table_add_header(tblheader)
-
- self.pmdout.start_testpmd(lcore, "--portmask=%s" % self.portMask, socket=self.ports_socket)
+ self.pmdout.start_testpmd(
+ lcore, "--portmask=%s" % self.portMask, socket=self.ports_socket)
self.dut.send_expect("set verbose 1", "testpmd> ")
self.dut.send_expect("set fwd csum", "testpmd> ")
-
if mode == "hw":
self.checksum_enablehw(self.dut_ports[0])
self.checksum_enablehw(self.dut_ports[1])
@@ -337,9 +306,9 @@ class TestChecksumOffload(TestCase):
self.checksum_enablesw(self.dut_ports[1])
self.dut.send_expect("start", "testpmd> ", 3)
-
for ptype in pkts.keys():
- self.benchmark(lcore, ptype, mode, pkts[ptype], sizes, self.nic)
+ self.benchmark(
+ lcore, ptype, mode, pkts[ptype], sizes, self.nic)
self.dut.send_expect("stop", "testpmd> ")
self.dut.send_expect("quit", "#", 10)
diff --git a/tests/TestSuite_cmdline.py b/tests/TestSuite_cmdline.py
index 7eeed2e..e1496f9 100644
--- a/tests/TestSuite_cmdline.py
+++ b/tests/TestSuite_cmdline.py
@@ -58,7 +58,7 @@ class TestCmdline(TestCase):
# Run cmdline app
cores = self.dut.get_core_list('1S/1C/1T')
coreMask = dts.create_mask(cores)
- self.dut.send_expect("./examples/cmdline/build/app/cmdline -n 1 -c " + coreMask, "> ", 5)
+ self.dut.send_expect("./examples/cmdline/build/app/cmdline -n 1 -c " + coreMask, "> ", 10)
def set_up(self):
"""
diff --git a/tests/TestSuite_dual_vlan.py b/tests/TestSuite_dual_vlan.py
new file mode 100644
index 0000000..f9901c9
--- /dev/null
+++ b/tests/TestSuite_dual_vlan.py
@@ -0,0 +1,408 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""
+DPDK Test suite.
+
+Test the support of Dual VLAN Offload Features by Poll Mode Drivers.
+
+"""
+
+import dts
+import random
+import re
+
+txvlan = 3
+outvlan = 1
+invlan = 2
+
+allResult = {"TX+OUTER+INNER": (txvlan, outvlan, invlan),
+ "TX+INNER": (txvlan, invlan),
+ "TX+OUTER": (txvlan, outvlan),
+ "OUTER+INNER": (outvlan, invlan),
+ "INNER": (invlan,),
+ "OUTER": (outvlan,),
+ "NONE": ("No",)
+ }
+
+stripCase = 0x1
+filterCase = 0x2
+qinqCase = 0x4
+txCase = 0x8
+
+vlanCaseDef = [0, stripCase, filterCase, filterCase | stripCase,
+ qinqCase, qinqCase | stripCase, qinqCase | filterCase, qinqCase | filterCase | stripCase,
+ txCase, txCase | stripCase, txCase | filterCase, txCase | filterCase | stripCase,
+ txCase | qinqCase, txCase | qinqCase | stripCase, txCase | qinqCase | filterCase, txCase | qinqCase | filterCase | stripCase]
+
+vlanCase = ["OUTER+INNER", "INNER", ("OUTER+INNER", "NONE"), ("INNER", "NONE"),
+ "OUTER+INNER", "OUTER", ("NONE", "OUTER+INNER"), ("NONE", "OUTER"),
+ "TX+OUTER+INNER", "TX+INNER", ("TX+OUTER+INNER", "NONE"), ("TX+INNER", "NONE"),
+ "TX+OUTER+INNER", "TX+OUTER", ("NONE", "TX+OUTER+INNER"), ("NONE", "TX+OUTER")]
+
+
+from test_case import TestCase
+from pmd_output import PmdOutput
+
+
+class TestDualVlan(TestCase):
+ def set_up_all(self):
+ """
+ Run at the start of each test suite.
+
+ Vlan Prerequistites
+ """
+ global dutRxPortId
+ global dutTxPortId
+
+ # Based on h/w type, choose how many ports to use
+ ports = self.dut.get_ports(self.nic)
+ self.verify(len(ports) >= 2, "Insufficient ports")
+ self.ports_socket = self.dut.get_numa_id(ports[0])
+
+ cores = self.dut.get_core_list('1S/2C/2T')
+ coreMask = dts.create_mask(cores)
+
+ ports = self.dut.get_ports(self.nic)
+ valports = [_ for _ in ports if self.tester.get_local_port(_) != -1]
+
+ portMask = dts.create_mask(valports[:2])
+
+ dutRxPortId = valports[0]
+ dutTxPortId = valports[1]
+
+ self.pmdout = PmdOutput(self.dut)
+ self.pmdout.start_testpmd("all", "--portmask=%s" % portMask, socket=self.ports_socket)
+
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.dut.send_expect("vlan set filter on all", "testpmd> ")
+ self.dut.send_expect("set promisc all off", "testpmd> ")
+
+ out = self.dut.send_expect("set fwd mac", "testpmd> ")
+ self.verify('Set mac packet forwarding mode' in out, "set fwd mac error")
+ out = self.dut.send_expect("start", "testpmd> ", 120)
+
+ def start_tcpdump(self, rxItf):
+
+ self.tester.send_expect("rm -rf ./getPackageByTcpdump.cap", "#")
+ self.tester.send_expect("tcpdump -i %s -w ./getPackageByTcpdump.cap 2> /dev/null& " % rxItf, "#")
+
+ def get_tcpdump_package(self):
+ self.tester.send_expect("killall tcpdump", "#")
+ return self.tester.send_expect("tcpdump -nn -e -v -r ./getPackageByTcpdump.cap", "#")
+
+ def vlan_send_packet(self, *vid):
+ """
+ Send packet to portid
+ """
+ txPort = self.tester.get_local_port(dutRxPortId)
+ rxPort = self.tester.get_local_port(dutTxPortId)
+
+ txItf = self.tester.get_interface(txPort)
+ rxItf = self.tester.get_interface(rxPort)
+ mac = self.dut.get_mac_address(dutRxPortId)
+
+ self.start_tcpdump(rxItf)
+ vlanString = 'sendp([Ether(dst="%s")/' % mac
+ for i in range(len(vid)):
+ vlanString += "Dot1Q(id=0x8100,vlan=%s)/" % vid[i]
+ vlanString += 'IP(len=46)],iface="%s")' % txItf
+
+ self.tester.scapy_append(vlanString)
+
+ self.tester.scapy_execute()
+
+ def mode_config(self, **modeName):
+ """
+ Set up the VLAN mode.
+ """
+
+ for mode in modeName:
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ # fortville NIC vlan filter can't close, if want close need remove rx_vlan
+ if mode == "filter":
+ if modeName[mode] == "off":
+ self.dut.send_expect("rx_vlan add %s %s" % (outvlan, dutRxPortId), "testpmd> ")
+ continue
+ else:
+ self.dut.send_expect("rx_vlan rm %s %s" % (outvlan, dutRxPortId), "testpmd> ")
+ continue
+
+ if mode == "stripq":
+ self.dut.send_expect("vlan set %s %s %s,0" % (mode, modeName[mode], dutRxPortId), "testpmd> ")
+ else:
+ self.dut.send_expect("vlan set %s %s %s" % (mode, modeName[mode], dutRxPortId), "testpmd> ")
+
+ out = self.dut.send_expect("show port info %s" % dutRxPortId, "testpmd> ")
+ for mode in modeName:
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ # fortville NIC vlan filter can't close, if want close need remove rx_vlan
+ if mode == "filter":
+ if modeName[mode] == "off":
+ self.dut.send_expect("rx_vlan add %s %s" % (outvlan, dutRxPortId), "testpmd> ")
+ continue
+ else:
+ self.dut.send_expect("rx_vlan rm %s %s" % (outvlan, dutRxPortId), "testpmd> ")
+ continue
+
+ if mode == "qinq":
+ self.verify("qinq(extend) %s" % modeName[mode] in out, "%s setting error" % mode)
+ continue
+ elif mode == "stripq":
+ continue
+ else:
+ self.verify("%s %s" % (mode, modeName[mode]) in out, "%s setting error" % mode)
+
+ def multimode_test(self, caseIndex):
+ """
+ Setup Strip/Filter/Extend/Insert enable/disable for synthetic test.
+ """
+ caseDef = vlanCaseDef[caseIndex]
+ temp = []
+
+ temp.append("on") if (caseDef & stripCase) != 0 else temp.append("off")
+ temp.append("on") if (caseDef & filterCase) != 0 else temp.append("off")
+ temp.append("on") if (caseDef & qinqCase) != 0 else temp.append("off")
+ self.mode_config(strip=temp[0], filter=temp[1], qinq=temp[2])
+
+ if (caseDef & txCase) != 0:
+ self.dut.send_expect('tx_vlan set %s %s' % (dutTxPortId, txvlan), "testpmd> ")
+
+ configMode = "Strip %s, filter %s 0x1, extend %s, insert %s" % (temp[0], temp[1], temp[2], "on" if (caseDef & txCase) != 0 else "off")
+
+ if (caseDef & filterCase) != 0:
+ self.dut.send_expect('rx_vlan add %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan, invlan)
+ self.check_result(vlanCase[caseIndex][0], configMode + " result Error")
+ self.dut.send_expect('rx_vlan rm %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+ self.dut.send_expect('rx_vlan add %s %s' % (invlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan, invlan)
+ self.check_result(vlanCase[caseIndex][1], configMode + " result Error")
+ self.dut.send_expect('rx_vlan rm %s %s' % (invlan, dutRxPortId), "testpmd> ")
+ if (caseDef & txCase) != 0:
+ self.dut.send_expect('tx_vlan reset %s' % dutTxPortId, "testpmd> ")
+ else:
+ self.dut.send_expect('rx_vlan add %s %s' % (invlan, dutRxPortId), "testpmd> ")
+ self.dut.send_expect('rx_vlan add %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan, invlan)
+ self.check_result(vlanCase[caseIndex], configMode + " result Error")
+ if (caseDef & txCase) != 0:
+ self.dut.send_expect('tx_vlan reset %s' % dutTxPortId, "testpmd> ")
+ self.dut.send_expect('rx_vlan rm %s %s' % (invlan, dutRxPortId), "testpmd> ")
+ self.dut.send_expect('rx_vlan rm %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+
+ def check_result(self, resultKey, errorString):
+ """
+ Check results of synthetic test.
+ """
+ print "vlan flage config:%s" % errorString
+ out = self.get_tcpdump_package()
+ if allResult[resultKey][0] == "No":
+ self.verify("vlan" not in out, errorString)
+ else:
+ resultList = []
+ for i in range(len(allResult[resultKey]) - 1):
+ resultList.append("vlan %s" % allResult[resultKey][i])
+ resultList.append("vlan %s" % allResult[resultKey][len(allResult[resultKey]) - 1])
+ for line in resultList:
+ self.verify(line in out, "reviceive package is wrong:%s" % out)
+
+ def set_up(self):
+ """
+ Run before each test case.
+ """
+ pass
+
+ def test_vlan_filter_config(self):
+ """
+ Enable/Disable VLAN packets filtering
+ """
+ self.mode_config(filter="on")
+ self.mode_config(strip="off")
+ self.mode_config(qinq="off")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ print out
+ self.verify(out is not None and "vlan %s" % outvlan not in out, "Vlan filter enable error: " + out)
+
+ if self.nic not in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.mode_config(filter="off")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan in out, "Vlan filter disable error: " + out)
+ else:
+ self.dut.send_expect('rx_vlan add %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan in out, "Vlan filter disable error: " + out)
+ self.dut.send_expect('rx_vlan rm %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+
+ def test_vlan_filter_table(self):
+ """
+ Add/Remove VLAN Tag Identifier pass VLAN filtering
+ """
+
+ self.mode_config(filter="on")
+ self.mode_config(strip="off")
+ self.mode_config(qinq="off")
+
+ self.dut.send_expect("rx_vlan add %s %s" % (outvlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan in out, "vlan filter table enable error: " + out)
+
+ self.dut.send_expect("rx_vlan rm %s %s" % (outvlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify(out is not None and "vlan %s" % outvlan not in out, "vlan filter table disable error: " + out)
+
+ def test_vlan_strip_config(self):
+ """
+ Enable/Disable VLAN packets striping
+ """
+
+ self.mode_config(filter="off")
+ self.mode_config(qinq="off")
+ self.mode_config(strip="on")
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.dut.send_expect('rx_vlan add %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan not in out, "Vlan strip enable error: " + out)
+
+ self.mode_config(strip="off")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan in out, "Vlan strip disable error: " + out)
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.dut.send_expect('rx_vlan rm %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+
+ def test_vlan_stripq_config(self):
+ """
+ Enable/Disable VLAN packets strip on queue
+ """
+ self.verify(self.nic not in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"], "%s NIC not support queue vlan strip " % self.nic)
+
+ self.mode_config(filter="off")
+ self.mode_config(qinq="off")
+ self.mode_config(strip="off")
+ self.mode_config(stripq="off")
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.dut.send_expect('rx_vlan add %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan in out, "vlan strip queue disable error : " + out)
+ # if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.mode_config(strip="on")
+ self.mode_config(stripq="on")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan not in out, "vlan strip enable error: " + out)
+
+ self.mode_config(stripq="off")
+ self.vlan_send_packet(outvlan)
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan in out, "vlan strip queue disable error: " + out)
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.dut.send_expect('rx_vlan rm %s %s' % (outvlan, dutRxPortId), "testpmd> ")
+
+ def test_vlan_insert_config(self):
+ """
+ Enable/Disable VLAN packets inserting
+ """
+ self.mode_config(filter="off")
+ self.mode_config(qinq="off")
+
+ # hartwell need to set CTRL.VME for vlan insert
+ if(self.nic == "hartwell"):
+ self.dut.send_expect("vlan set strip on %s" % dutTxPortId, "testpmd> ")
+
+ self.dut.send_expect("tx_vlan set %s %s" % (dutTxPortId, txvlan), "testpmd> ")
+
+ self.vlan_send_packet()
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % txvlan in out, "vlan inset enalber error: " + out)
+
+ self.dut.send_expect("tx_vlan reset %s" % dutTxPortId, "testpmd> ")
+ self.vlan_send_packet()
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % txvlan not in out, "vlan inset disable error: " + out)
+
+ def test_vlan_tpid_config(self):
+ """
+ Configure receive port out vlan TPID
+ """
+ self.verify(self.nic not in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single", "hartwell"], "%s NIC not support tcpid " % self.nic)
+
+ self.mode_config(filter="on", strip="on", qinq="on")
+ self.dut.send_expect("vlan set tpid 1234 %s" % dutRxPortId, "testpmd> ")
+ self.vlan_send_packet(outvlan, invlan)
+
+ out = self.get_tcpdump_package()
+ self.verify("vlan %s" % outvlan in out, "vlan tpid disable error: " + out)
+ self.verify("vlan %s" % invlan in out, "vlan tpid disable error: " + out)
+
+ self.dut.send_expect("vlan set tpid 0x8100 %s" % dutRxPortId, "testpmd> ")
+ self.vlan_send_packet(outvlan, invlan)
+
+ out = self.get_tcpdump_package()
+ self.verify(out is not None and "vlan" not in out, "vlane tpid enable error: " + out)
+
+ def test_vlan_synthetic_test(self):
+ """
+ VLAN synthetic test.
+ """
+ self.verify(self.nic != "hartwell", "sorry, dual vlan cannot support this self.nic")
+ for i in range(len(vlanCase)):
+ self.multimode_test(i)
+
+ def test_vlan_random_test(self):
+ """
+ VLAN random test.
+ """
+ self.verify(self.nic != "hartwell", "sorry, dual vlan cannot support this self.nic")
+ for _ in range(30):
+ rand = random.randint(0, 15)
+ self.multimode_test(rand)
+
+ def tear_down(self):
+ """
+ Run after each test case.
+ """
+ pass
+
+ def tear_down_all(self):
+ """
+ Run after each test suite.
+ """
+ self.dut.kill_all()
+ pass
diff --git a/tests/TestSuite_dynamic_config.py b/tests/TestSuite_dynamic_config.py
new file mode 100644
index 0000000..d1ad49c
--- /dev/null
+++ b/tests/TestSuite_dynamic_config.py
@@ -0,0 +1,262 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+DPDK Test suite.
+
+Test the dynamic driver configuration feature.
+
+"""
+
+import dts
+
+from test_case import TestCase
+
+#
+#
+# Test class.
+#
+
+
+class TestDynamicConfig(TestCase):
+
+ #
+ #
+ #
+ # Test cases.
+ #
+
+ def set_up_all(self):
+ """
+ Run at the start of each test suite.
+
+
+ Dynamic config Prerequistites
+ """
+
+ # Based on h/w type, choose how many ports to use
+ self.dut_ports = self.dut.get_ports(self.nic)
+ print self.dut_ports
+
+ # Verify that enough ports are available
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.verify(len(self.dut_ports) >= 2, "Insufficient ports")
+ else:
+ self.verify(len(self.dut_ports) >= 1, "Insufficient ports")
+
+ # Prepare cores and ports
+ cores = self.dut.get_core_list('1S/2C/2T')
+ coreMask = dts.create_mask(cores)
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ portMask = dts.create_mask(self.dut_ports[:2])
+ else:
+ portMask = dts.create_mask([self.dut_ports[0]])
+
+ # launch app
+ cmd = "./%s/build/app/test-pmd/testpmd -c %s -n 3 -- -i --rxpt=0 \
+ --rxht=0 --rxwt=0 --txpt=39 --txht=0 --txwt=0 --portmask=%s" % (self.target, coreMask, portMask)
+
+ self.dut.send_expect("%s" % cmd, "testpmd> ", 120)
+
+ # get dest address from self.target port
+ out = self.dut.send_expect(
+ "show port info %d" % self.dut_ports[0], "testpmd> ")
+
+ self.dest = self.dut.get_mac_address(self.dut_ports[0])
+ mac_scanner = r"MAC address: (([\dA-F]{2}:){5}[\dA-F]{2})"
+
+ ret = dts.regexp(out, mac_scanner)
+
+ self.verify(ret is not None, "MAC address not found")
+ self.verify(cmp(ret.lower(), self.dest) == 0, "MAC address wrong")
+ self.verify("Promiscuous mode: enabled" in out,
+ "wrong default promiscuous value")
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.dut.send_expect("start", "testpmd> ", 120)
+
+ def dynamic_config_send_packet(self, portid, destMac="00:11:22:33:44:55"):
+ """
+ Send 1 packet to portid
+ """
+
+ itf = self.tester.get_interface(self.tester.get_local_port(portid))
+
+ self.tester.scapy_foreground()
+ self.tester.scapy_append(
+ 'sendp([Ether(dst="%s", src="52:00:00:00:00:00")], iface="%s")' % (destMac, itf))
+
+ self.tester.scapy_execute()
+
+ def set_up(self):
+ """
+ Run before each test case.
+ """
+ pass
+
+ def test_dynamic_config_default_mode(self):
+ """
+ Dynamic config default mode test
+ """
+
+ portid = self.dut_ports[0]
+
+ # get the current rx statistic
+ out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # send one packet with different MAC address than the portid
+ self.dynamic_config_send_packet(portid)
+
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # check the pakcet increasment
+ self.verify(int(cur_rxpkt) == int(pre_rxpkt)
+ + 1, "1st packet increasement check error")
+
+ # send one packet with the portid MAC address
+ self.dynamic_config_send_packet(portid, self.dest)
+
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # check the pakcet increasment
+ self.verify(int(cur_rxpkt) == int(pre_rxpkt)
+ + 1, "2nd packet increasement check error")
+
+ def test_dynamic_config_disable_promiscuous(self):
+ """
+ Dynamic config disable promiscuous test
+ """
+
+ portid = self.dut_ports[0]
+ if self.nic in ["fortville_eagle", "fortville_spirit", "fortville_spirit_single"]:
+ self.dut.send_expect("set promisc all off", "testpmd> ")
+ out = self.dut.send_expect(
+ "show port stats %d" % self.dut_ports[1], "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "TX-packets: ([0-9]+)")
+
+ self.dynamic_config_send_packet(portid)
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect(
+ "show port stats %d" % self.dut_ports[1], "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "TX-packets: ([0-9]+)")
+ self.verify(int(cur_rxpkt) == int(
+ pre_rxpkt), "1st packet increasment error")
+ self.dynamic_config_send_packet(portid, self.dest)
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect(
+ "show port stats %d" % self.dut_ports[1], "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "TX-packets: ([0-9]+)")
+ self.verify(int(cur_rxpkt) == int(
+ pre_rxpkt) + 1, "2nd packet increasment error")
+ else:
+ self.dut.send_expect("set promisc %d off" % portid, "testpmd> ")
+
+ # get the current rx statistic
+ out = self.dut.send_expect(
+ "show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # send one packet with different MAC address than the portid
+ self.dynamic_config_send_packet(portid)
+
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect(
+ "show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # check the pakcet increasment
+ self.verify(int(cur_rxpkt) == int(
+ pre_rxpkt), "1st packet increasment error")
+
+ # send one packet with the portid MAC address
+ self.dynamic_config_send_packet(portid, self.dest)
+
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect(
+ "show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # check the pakcet increasment
+ self.verify(int(cur_rxpkt) == int(
+ pre_rxpkt) + 1, "2nd packet increasment error")
+
+ def test_dynamic_config_enable_promiscuous(self):
+ """
+ Dynamic config enable promiscuous test
+ """
+
+ portid = self.dut_ports[0]
+
+ self.dut.send_expect("set promisc %d on" % portid, "testpmd> ")
+
+ # get the current rx statistic
+ out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # send one packet with different MAC address than the portid
+ self.dynamic_config_send_packet(portid)
+
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # check the pakcet increasment
+ self.verify(int(cur_rxpkt) == int(pre_rxpkt)
+ + 1, "1st packet increasment error")
+
+ # send one packet with the portid MAC address
+ self.dynamic_config_send_packet(portid, self.dest)
+
+ pre_rxpkt = cur_rxpkt
+ out = self.dut.send_expect("show port stats %d" % portid, "testpmd> ")
+ cur_rxpkt = dts.regexp(out, "RX-packets: ([0-9]+)")
+
+ # check the pakcet increasment
+ self.verify(int(cur_rxpkt) == int(pre_rxpkt)
+ + 1, "2nd packet increasment error")
+
+ self.dut.send_expect("quit", "# ", 30)
+
+ def tear_down(self):
+ """
+ Run after each test case.
+ """
+ pass
+
+ def tear_down_all(self):
+ """
+ Run after each test suite.
+ """
+ pass
diff --git a/tests/TestSuite_fdir.py b/tests/TestSuite_fdir.py
index 1c8d8f7..3db41c9 100644
--- a/tests/TestSuite_fdir.py
+++ b/tests/TestSuite_fdir.py
@@ -31,33 +31,62 @@
"""
DPDK Test suite.
-Test 82599 Flow Director Support in DPDK
+
+Test 82599 and fortville Flow Director Support in DPDK
"""
-import dts
+import re
import time
+import string
+from time import sleep
+from scapy.utils import struct, socket, PcapWriter
-
+import dts
+from etgen import IxiaPacketGenerator
from test_case import TestCase
+from plotting import Plotting
+from settings import HEADER_SIZE
from pmd_output import PmdOutput
+import sys
+reload(sys)
+sys.setdefaultencoding('utf8')
+#
+#
+# Test class.
+#
-class TestFdir(TestCase):
- def set_up_all(self):
- """
- Run at the start of each test suite.
- """
- ports = self.dut.get_ports()
- self.verify(len(ports) >= 2, "Not enough ports available")
+class TestFdir(TestCase, IxiaPacketGenerator):
- self.pmdout = PmdOutput(self.dut)
+ #
+ #
+ # Utility methods and other non-test code.
+ #
+ ###########################################################################
+ def plot_results(self, number_ports):
- def set_up(self):
- """
- Run before each test case.
- """
- pass
+ cores_configs = []
+ percent_values = []
+
+ # Append the percentage results for the all the cores configs
+ for test_cycle in self.test_cycles:
+ cores_configs.append(test_cycle['cores'])
+ config_results = []
+ for frame_size in self.frame_sizes:
+ config_results.append(test_cycle['pct'][frame_size])
+
+ percent_values.append(config_results)
+
+ image_path = self.plotting.create_bars_plot(
+ 'test_perf_pmd_%sports' % number_ports,
+ 'PMD, %d ports' % number_ports,
+ self.frame_sizes,
+ percent_values,
+ ylabel='% linerate',
+ legend=cores_configs)
+
+ dts.results_plot_print(image_path)
def send_and_verify(self, condition, packet):
"""
@@ -71,294 +100,893 @@ class TestFdir(TestCase):
self.tester.scapy_execute()
time.sleep(.5)
out = self.dut.send_expect("stop", "testpmd>")
- if condition:
- self.verify("PKT_RX_FDIR" in out, "FDIR hash not displayed when required")
- else:
- self.verify("PKT_RX_FDIR" not in out, "FDIR hash displayed when not required")
- def test_fdir_space(self):
+ if(self.nic in ["kawela", "niantic", "fortville_eagle", "fortville_spirit", "fortville_spirit_single"]):
+ if ("fwd" == self.fdir_type):
+ if condition:
+ self.queue = 2
+ else:
+ self.queue = 0
+ elif("drop" == self.fdir_type):
+ if condition:
+ self.queue = 0
+ else:
+ self.queue = -1
+
+ result_scanner = r"port ([0-9]+)/queue ([0-9]+): received ([0-9]+) packets\s*src=[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2} - dst=[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2}:[A-F\d]{2}"
+ scanner = re.compile(result_scanner, re.DOTALL)
+ m = scanner.search(out)
+
+ print "**************Print sub-case result****************"
+ if m:
+ m.groups()
+ if (self.queue == int(m.group(2))):
+ print dts.GREEN("Pass: queue id is " + m.group(2))
+ self.verify(1, "Pass")
+ else:
+ print dts.RED("Fail: queue id is " + m.group(2))
+ self.verify(0, "Fail")
+ print out
+ else:
+ print "not match"
+ if (-1 == self.queue):
+ print dts.GREEN("Pass: fdir should not match ")
+ self.verify(1, "Pass")
+ else:
+ print dts.RED("Fail")
+ self.verify(0, "Fail")
+ print out
+ print "**************Print sub-case result****************"
+
+ #
+ #
+ #
+ # Test cases.
+ #
+ def set_up_all(self):
"""
- Setting memory reserved for FD