aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Wojciechowicz <robertx.wojciechowicz@intel.com>2015-12-09 10:07:38 +0000
committerMaryam Tahhan <maryam.tahhan@intel.com>2016-01-21 09:41:05 +0000
commit9a054248197bdaed71b32e9d9c0ac621bf89c1cd (patch)
treec186250f91e658845cd8f3a985517c33a9ba0220
parent7caf7a6be0fae6b341181b3e6286372e2e93b4b8 (diff)
Add testpmd as vswitch class
The purpose of using testpmd instead of OVS is to get the baseline of the DUT when performing hardware offloading operations. There are supported different checksum calculation and txq flags settings. Change-Id: I93c9b45dcb31eaa1f610b7e061f3dd5936b0e6ec JIRA: VSPERF-193 Signed-off-by: Robert Wojciechowicz <robertx.wojciechowicz@intel.com> Reviewed-by: Dino Simeon Madarang <dino.simeonx.madarang@intel.com> Reviewed-by: Maryam Tahhan <maryam.tahhan@intel.com> Reviewed-by: Brian Castelli <brian.castelli@spirent.com>
-rw-r--r--conf/06_pktfwd.conf36
-rw-r--r--core/component_factory.py10
-rwxr-xr-xcore/loader/loader.py40
-rw-r--r--core/pktfwd_controller.py68
-rwxr-xr-xdocs/design/vswitchperf_design.rst25
-rwxr-xr-xdocs/userguides/quickstart.rst46
-rw-r--r--src/dpdk/__init__.py2
-rw-r--r--src/dpdk/testpmd_proc.py113
-rw-r--r--testcases/testcase.py193
-rw-r--r--tools/pkt_fwd/__init__.py19
-rw-r--r--tools/pkt_fwd/pkt_fwd.py53
-rw-r--r--tools/pkt_fwd/testpmd.py87
-rwxr-xr-xvsperf39
13 files changed, 631 insertions, 100 deletions
diff --git a/conf/06_pktfwd.conf b/conf/06_pktfwd.conf
new file mode 100644
index 00000000..d6a83d07
--- /dev/null
+++ b/conf/06_pktfwd.conf
@@ -0,0 +1,36 @@
+# Copyright 2016 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# ####################################################
+# General packet forwarding configuration
+# ####################################################
+
+PKTFWD_DIR = os.path.join(ROOT_DIR, 'tools/pkt_fwd')
+PKTFWD = 'TestPMD'
+
+# ############################
+# TestPMD configuration: http://dpdk.org/doc/guides/testpmd_app_ug/index.html
+# ############################
+
+TESTPMD_ARGS = []
+# packet forwarding mode: io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho
+TESTPMD_FWD_MODE = 'csum'
+# checksum calculation layer: ip|udp|tcp|sctp|outer-ip
+TESTPMD_CSUM_LAYER = 'ip'
+# checksum calculation place: hw (hardware) | sw (software)
+TESTPMD_CSUM_CALC = 'sw'
+# recognize tunnel headers: on|off
+TESTPMD_CSUM_PARSE_TUNNEL = 'off'
+
+PIDSTAT_MONITOR = ['ovs-vswitchd', 'ovsdb-server', 'qemu-system-x86_64', 'testpmd']
diff --git a/core/component_factory.py b/core/component_factory.py
index 21cdd61d..af237e50 100644
--- a/core/component_factory.py
+++ b/core/component_factory.py
@@ -20,6 +20,7 @@ from core.vswitch_controller_p2p import VswitchControllerP2P
from core.vswitch_controller_pvp import VswitchControllerPVP
from core.vswitch_controller_pvvp import VswitchControllerPVVP
from core.vnf_controller import VnfController
+from core.pktfwd_controller import PktFwdController
from tools.load_gen.stress.stress import Stress
from tools.load_gen.stress_ng.stress_ng import StressNg
from tools.load_gen.dummy.dummy import DummyLoadGen
@@ -108,4 +109,13 @@ def create_loadgen(loadgen_type, loadgen_cfg):
elif loadgen_type.find("stress") >= 0:
return Stress(loadgen_cfg)
+def create_pktfwd(pktfwd_class):
+ """Return a new packet forwarder controller
+ The returned controller is configured with the given
+ packet forwarder class.
+
+ :param pktfwd_class: Reference to packet forwarder class to be used.
+ :return: packet forwarder controller
+ """
+ return PktFwdController(pktfwd_class)
diff --git a/core/loader/loader.py b/core/loader/loader.py
index 39b50f09..0d9c83a6 100755
--- a/core/loader/loader.py
+++ b/core/loader/loader.py
@@ -21,6 +21,7 @@ from tools.pkt_gen.trafficgen import ITrafficGenerator
from tools.collectors.collector import ICollector
from vswitches.vswitch import IVSwitch
from vnfs.vnf.vnf import IVnf
+from tools.pkt_fwd.pkt_fwd import IPktFwd
class Loader(object):
"""Loader class - main object context holder.
@@ -57,6 +58,11 @@ class Loader(object):
settings.getValue('VNF'),
IVnf)
+ self._pktfwd_loader = LoaderServant(
+ settings.getValue('PKTFWD_DIR'),
+ settings.getValue('PKTFWD'),
+ IPktFwd)
+
def get_trafficgen(self):
"""Returns a new instance configured traffic generator.
@@ -109,7 +115,7 @@ class Loader(object):
:return: Dictionary of collectors.
- key: name of the class which implements ICollector,
- - value: Type of traffic generator which implements ICollector.
+ - value: Type of collector which implements ICollector.
"""
return self._metrics_loader.get_classes()
@@ -140,7 +146,7 @@ class Loader(object):
:return: Dictionary of vswitches.
- key: name of the class which implements IVSwitch,
- - value: Type of traffic generator which implements IVSwitch.
+ - value: Type of vswitch which implements IVSwitch.
"""
return self._vswitch_loader.get_classes()
@@ -182,3 +188,33 @@ class Loader(object):
"""
return self._vnf_loader.get_classes_printable()
+ def get_pktfwd(self):
+ """Returns instance of currently configured packet forwarder implementation.
+
+ :return: IPktFwd implementation if available, None otherwise.
+ """
+ return self._pktfwd_loader.get_class()()
+
+ def get_pktfwd_class(self):
+ """Returns type of currently configured packet forwarder implementation.
+
+ :return: Type of IPktFwd implementation if available.
+ None otherwise.
+ """
+ return self._pktfwd_loader.get_class()
+
+ def get_pktfwds(self):
+ """Returns dictionary of all available packet forwarders.
+
+ :return: Dictionary of packet forwarders.
+ - key: name of the class which implements IPktFwd,
+ - value: Type of packet forwarder which implements IPktFwd.
+ """
+ return self._pktfwd_loader.get_classes()
+
+ def get_pktfwds_printable(self):
+ """Returns all available packet forwarders in printable format.
+
+ :return: String containing printable list of packet forwarders.
+ """
+ return self._pktfwd_loader.get_classes_printable()
diff --git a/core/pktfwd_controller.py b/core/pktfwd_controller.py
new file mode 100644
index 00000000..4f300ce8
--- /dev/null
+++ b/core/pktfwd_controller.py
@@ -0,0 +1,68 @@
+# Copyright 2016 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Packet forwarder controller for Physical to Physical deployment
+"""
+
+import logging
+
+from conf import settings
+
+
+class PktFwdController(object):
+ """Packet forwarder controller for P2P deployment scenario.
+
+ Attributes:
+ _pktfwd_class: The packet forwarder class to be used.
+ _pktfwd: The packet forwarder object controlled by this controller
+ """
+ def __init__(self, pktfwd_class):
+ """Initializes up the prerequisites for the P2P deployment scenario.
+
+ :vswitch_class: the vSwitch class to be used.
+ """
+ self._logger = logging.getLogger(__name__)
+ self._pktfwd_class = pktfwd_class
+ self._pktfwd = pktfwd_class()
+ self._logger.debug('Creation using ' + str(self._pktfwd_class))
+
+ def setup(self):
+ """Sets up the packet forwarder for p2p.
+ """
+ self._logger.debug('Setup using ' + str(self._pktfwd_class))
+
+ try:
+ self._pktfwd.start()
+ except:
+ self._pktfwd.stop()
+ raise
+
+ def stop(self):
+ """Tears down the packet forwarder created in setup().
+ """
+ self._logger.debug('Stop using ' + str(self._pktfwd_class))
+ self._pktfwd.stop()
+
+ def __enter__(self):
+ self.setup()
+
+ def __exit__(self, type_, value, traceback):
+ self.stop()
+
+ def get_pktfwd(self):
+ """Get the controlled packet forwarder
+
+ :return: The controlled IPktFwd
+ """
+ return self._pktfwd
diff --git a/docs/design/vswitchperf_design.rst b/docs/design/vswitchperf_design.rst
index b8988458..e139a025 100755
--- a/docs/design/vswitchperf_design.rst
+++ b/docs/design/vswitchperf_design.rst
@@ -96,16 +96,19 @@ Other Configuration
VM, vSwitch, Traffic Generator Independence
===========================================
-VSPERF supports different vSwithes, Traffic Generators and VNFs by using
-standard object-oriented polymorphism:
+VSPERF supports different vSwithes, Traffic Generators, VNFs
+and Forwarding Applications by using standard object-oriented polymorphism:
* Support for vSwitches is implemented by a class inheriting from IVSwitch.
* Support for Traffic Generators is implemented by a class inheriting from
ITrafficGenerator.
* Support for VNF is implemented by a class inheriting from IVNF.
+ * Support for Forwarding Applications is implemented by a class inheriting
+ from IPktFwd.
By dealing only with the abstract interfaces the core framework can support
-many implementations of different vSwitches, Traffic Generators and VNFs.
+many implementations of different vSwitches, Traffic Generators, VNFs
+and Forwarding Applications.
IVSwitch
--------
@@ -163,12 +166,22 @@ IVnf
wait(guest_prompt)
execute_and_wait (command)
+IPktFwd
+--------
+
+ .. code-block:: python
+
+ class IPktFwd:
+ start()
+ stop()
+
+
Controllers
-----------
-Controllers are used in conjunction with abstract interfaces as way of
-decoupling the control of vSwtiches, VNFs and TrafficGenerators from other
-components.
+Controllers are used in conjunction with abstract interfaces as way
+of decoupling the control of vSwtiches, VNFs, TrafficGenerators
+and Forwarding Applications from other components.
The controlled classes provide basic primitive operations. The Controllers
sequence and co-ordinate these primitive operation in to useful actions. For
diff --git a/docs/userguides/quickstart.rst b/docs/userguides/quickstart.rst
index e93a040f..caf3be04 100755
--- a/docs/userguides/quickstart.rst
+++ b/docs/userguides/quickstart.rst
@@ -343,6 +343,52 @@ Guest loopback application must be configured, otherwise traffic
will not be forwarded by VM and testcases with PVP and PVVP deployments
will fail. Guest loopback application is set to 'testpmd' by default.
+Executing Packet Forwarding tests
+-----------------------------------
+
+To select application, which will perform packet forwarding,
+following configuration parameter should be configured:
+
+ .. code-block:: console
+
+ VSWITCH = 'none'
+ PKTFWD = 'TestPMD'
+
+ or use --vswitch and --fwdapp
+
+ ./vsperf --conf-file user_settings.py
+ --vswitch none
+ --fwdapp TestPMD
+
+Supported Packet Forwarding applications are:
+
+ .. code-block:: console
+
+ 'testpmd' - testpmd from dpdk
+
+
+1. Update your ''10_custom.conf'' file to use the appropriate variables
+for selected Packet Forwarder:
+ .. code-block:: console
+
+ # testpmd configuration
+ TESTPMD_ARGS = []
+ # packet forwarding mode: io|mac|mac_retry|macswap|flowgen|rxonly|txonly|csum|icmpecho
+ TESTPMD_FWD_MODE = 'csum'
+ # checksum calculation layer: ip|udp|tcp|sctp|outer-ip
+ TESTPMD_CSUM_LAYER = 'ip'
+ # checksum calculation place: hw (hardware) | sw (software)
+ TESTPMD_CSUM_CALC = 'sw'
+ # recognize tunnel headers: on|off
+ TESTPMD_CSUM_PARSE_TUNNEL = 'off'
+
+2. Run test:
+
+ .. code-block:: console
+
+ ./vsperf --conf-file <path_to_settings_py>
+
+
Code change verification by pylint
----------------------------------
Every developer participating in VSPERF project should run
diff --git a/src/dpdk/__init__.py b/src/dpdk/__init__.py
index 4be1e215..fdbc5414 100644
--- a/src/dpdk/__init__.py
+++ b/src/dpdk/__init__.py
@@ -19,3 +19,5 @@ and removing drivers and binding/unbinding NICs.
"""
from src.dpdk.dpdk import *
+from src.dpdk.testpmd_proc import TestPMDProcess
+
diff --git a/src/dpdk/testpmd_proc.py b/src/dpdk/testpmd_proc.py
new file mode 100644
index 00000000..990ef8da
--- /dev/null
+++ b/src/dpdk/testpmd_proc.py
@@ -0,0 +1,113 @@
+# Copyright 2015 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Class wrapper for controlling a TestPMD instance.
+
+Wraps ``testpmd`` process.
+"""
+
+import os
+import logging
+import time
+import pexpect
+
+from conf import settings
+from tools import tasks
+
+_TESTPMD_PROMPT = 'Done'
+
+_TESTPMD_BIN = os.path.join(
+ settings.getValue('RTE_SDK'), settings.getValue('RTE_TARGET'),
+ 'app', 'testpmd')
+
+_LOG_FILE_VSWITCHD = os.path.join(
+ settings.getValue('LOG_DIR'), settings.getValue('LOG_FILE_VSWITCHD'))
+
+class TestPMDProcess(tasks.Process):
+ """Class wrapper for controlling a TestPMD instance.
+
+ Wraps ``testpmd`` process.
+ """
+ _logfile = _LOG_FILE_VSWITCHD
+ _proc_name = 'testpmd'
+
+ def __init__(self, timeout=30, testpmd_args=None, expected_cmd=None):
+ """Initialise the wrapper with a specific start timeout and extra
+ parameters.
+
+ :param timeout: Timeout to wait for application to start.
+ :param testpmd_args: Command line parameters for testpmd.
+
+ :returns: None
+ """
+ self._logger = logging.getLogger(__name__)
+ self._timeout = timeout
+ self._expect = expected_cmd
+ if not self._expect:
+ self._expect = _TESTPMD_PROMPT
+ testpmd_args = testpmd_args or []
+ self._cmd = ['sudo', '-E', _TESTPMD_BIN] + testpmd_args
+
+ # startup/shutdown
+
+ def start(self):
+ """ Start ``testpmd`` instance.
+
+ :returns: None
+ :raises: pexpect.EOF, pexpect.TIMEOUT
+ """
+
+ try:
+ super(TestPMDProcess, self).start()
+ self.relinquish()
+ except (pexpect.EOF, pexpect.TIMEOUT) as exc:
+ logging.error("TestPMD start failed.")
+ raise exc
+
+ def kill(self, signal='-15', sleep=2):
+ """Kill ``testpmd`` instance if it is alive.
+
+ :returns: None
+ """
+ self._logger.info('Killing testpmd...')
+
+ super(TestPMDProcess, self).kill(signal, sleep)
+
+ # helper functions
+
+ def send(self, cmd, delay=0):
+ """
+ Send ``cmd`` with no wait.
+
+ Useful for asynchronous commands.
+
+ :param cmd: Command to send to guest.
+ :param timeout: Delay to wait after sending command before returning.
+
+ :returns: None
+ """
+ self._logger.debug(cmd)
+ self._child.sendline(cmd)
+ time.sleep(delay)
+
+ def wait(self, msg=_TESTPMD_PROMPT, timeout=30):
+ """
+ Wait for ``msg``.
+
+ :param msg: Message to wait for from guest.
+ :param timeout: Time to wait for message.
+
+ :returns: None
+ """
+ self._child.expect(msg, timeout=timeout)
diff --git a/testcases/testcase.py b/testcases/testcase.py
index a152f91e..4b2751b5 100644
--- a/testcases/testcase.py
+++ b/testcases/testcase.py
@@ -103,6 +103,9 @@ class TestCase(object):
self._traffic['l3'].update({'srcip': S.getValue('VANILLA_TGEN_PORT1_IP'),
'dstip': S.getValue('VANILLA_TGEN_PORT2_IP')})
+ # Packet Forwarding mode
+ self._vswitch_none = 'none' == S.getValue('VSWITCH').strip().lower()
+
def run(self):
"""Run the test
@@ -121,10 +124,16 @@ class TestCase(object):
vnf_ctl = component_factory.create_vnf(
self.deployment,
loader.get_vnf_class())
- vswitch_ctl = component_factory.create_vswitch(
- self.deployment,
- loader.get_vswitch_class(),
- self._traffic)
+
+ if self._vswitch_none:
+ vswitch_ctl = component_factory.create_pktfwd(
+ loader.get_pktfwd_class())
+ else:
+ vswitch_ctl = component_factory.create_vswitch(
+ self.deployment,
+ loader.get_vswitch_class(),
+ self._traffic)
+
collector = component_factory.create_collector(
loader.get_collector_class(),
self._results_dir, self.name)
@@ -135,94 +144,15 @@ class TestCase(object):
self._logger.debug("Setup:")
with vswitch_ctl, loadgen:
with vnf_ctl, collector:
- vswitch = vswitch_ctl.get_vswitch()
- # TODO BOM 15-08-07 the frame mod code assumes that the
- # physical ports are ports 1 & 2. The actual numbers
- # need to be retrived from the vSwitch and the metadata value
- # updated accordingly.
- bridge = S.getValue('VSWITCH_BRIDGE_NAME')
- if self._frame_mod == "vlan":
- # 0x8100 => VLAN ethertype
- self._logger.debug(" **** VLAN ***** ")
- flow = {'table':'2', 'priority':'1000', 'metadata':'2',
- 'actions': ['push_vlan:0x8100', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- flow = {'table':'2', 'priority':'1000', 'metadata':'1',
- 'actions': ['push_vlan:0x8100', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- elif self._frame_mod == "mpls":
- # 0x8847 => MPLS unicast ethertype
- self._logger.debug(" **** MPLS ***** ")
- flow = {'table':'2', 'priority':'1000', 'metadata':'2',
- 'actions': ['push_mpls:0x8847', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- flow = {'table':'2', 'priority':'1000', 'metadata':'1',
- 'actions': ['push_mpls:0x8847', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- elif self._frame_mod == "mac":
- flow = {'table':'2', 'priority':'1000', 'metadata':'2',
- 'actions': ['mod_dl_src:22:22:22:22:22:22',
- 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- flow = {'table':'2', 'priority':'1000', 'metadata':'1',
- 'actions': ['mod_dl_src:11:11:11:11:11:11',
- 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- elif self._frame_mod == "dscp":
- # DSCP 184d == 0x4E<<2 => 'Expedited Forwarding'
- flow = {'table':'2', 'priority':'1000', 'metadata':'2',
- 'dl_type':'0x0800',
- 'actions': ['mod_nw_tos:184', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- flow = {'table':'2', 'priority':'1000', 'metadata':'1',
- 'dl_type':'0x0800',
- 'actions': ['mod_nw_tos:184', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- elif self._frame_mod == "ttl":
- # 251 and 241 are the highest prime numbers < 255
- flow = {'table':'2', 'priority':'1000', 'metadata':'2',
- 'dl_type':'0x0800',
- 'actions': ['mod_nw_ttl:251', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- flow = {'table':'2', 'priority':'1000', 'metadata':'1',
- 'dl_type':'0x0800',
- 'actions': ['mod_nw_ttl:241', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- elif self._frame_mod == "ip_addr":
- flow = {'table':'2', 'priority':'1000', 'metadata':'2',
- 'dl_type':'0x0800',
- 'actions': ['mod_nw_src:10.10.10.10',
- 'mod_nw_dst:20.20.20.20',
- 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- flow = {'table':'2', 'priority':'1000', 'metadata':'1',
- 'dl_type':'0x0800',
- 'actions': ['mod_nw_src:20.20.20.20',
- 'mod_nw_dst:10.10.10.10',
- 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- elif self._frame_mod == "ip_port":
- # TODO BOM 15-08-27 The traffic generated is assumed
- # to be UDP (nw_proto 17d) which is the default case but
- # we will need to pick up the actual traffic params in use.
- flow = {'table':'2', 'priority':'1000', 'metadata':'2',
- 'dl_type':'0x0800', 'nw_proto':'17',
- 'actions': ['mod_tp_src:44444',
- 'mod_tp_dst:44444', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- flow = {'table':'2', 'priority':'1000', 'metadata':'1',
- 'dl_type':'0x0800', 'nw_proto':'17',
- 'actions': ['mod_tp_src:44444',
- 'mod_tp_dst:44444', 'goto_table:3']}
- vswitch.add_flow(bridge, flow)
- else:
- pass
+ if not self._vswitch_none:
+ self._add_flows(vswitch_ctl)
with traffic_ctl:
traffic_ctl.send_traffic(self._traffic)
# dump vswitch flows before they are affected by VNF termination
- vswitch_ctl.dump_vswitch_flows()
+ if not self._vswitch_none:
+ vswitch_ctl.dump_vswitch_flows()
self._logger.debug("Traffic Results:")
traffic_ctl.print_results()
@@ -332,3 +262,92 @@ class TestCase(object):
result[key] = ''
return list(result.keys())
+
+
+ def _add_flows(vswitch_ctl):
+ """Add flows to the vswitch
+
+ :param vswitch_ctl vswitch controller
+ """
+ vswitch = vswitch_ctl.get_vswitch()
+ # TODO BOM 15-08-07 the frame mod code assumes that the
+ # physical ports are ports 1 & 2. The actual numbers
+ # need to be retrived from the vSwitch and the metadata value
+ # updated accordingly.
+ bridge = S.getValue('VSWITCH_BRIDGE_NAME')
+ if self._frame_mod == "vlan":
+ # 0x8100 => VLAN ethertype
+ self._logger.debug(" **** VLAN ***** ")
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'actions': ['push_vlan:0x8100', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'actions': ['push_vlan:0x8100', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "mpls":
+ # 0x8847 => MPLS unicast ethertype
+ self._logger.debug(" **** MPLS ***** ")
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'actions': ['push_mpls:0x8847', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'actions': ['push_mpls:0x8847', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "mac":
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'actions': ['mod_dl_src:22:22:22:22:22:22',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'actions': ['mod_dl_src:11:11:11:11:11:11',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "dscp":
+ # DSCP 184d == 0x4E<<2 => 'Expedited Forwarding'
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_tos:184', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_tos:184', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "ttl":
+ # 251 and 241 are the highest prime numbers < 255
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_ttl:251', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_ttl:241', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "ip_addr":
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_src:10.10.10.10',
+ 'mod_nw_dst:20.20.20.20',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800',
+ 'actions': ['mod_nw_src:20.20.20.20',
+ 'mod_nw_dst:10.10.10.10',
+ 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ elif self._frame_mod == "ip_port":
+ # TODO BOM 15-08-27 The traffic generated is assumed
+ # to be UDP (nw_proto 17d) which is the default case but
+ # we will need to pick up the actual traffic params in use.
+ flow = {'table':'2', 'priority':'1000', 'metadata':'2',
+ 'dl_type':'0x0800', 'nw_proto':'17',
+ 'actions': ['mod_tp_src:44444',
+ 'mod_tp_dst:44444', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ flow = {'table':'2', 'priority':'1000', 'metadata':'1',
+ 'dl_type':'0x0800', 'nw_proto':'17',
+ 'actions': ['mod_tp_src:44444',
+ 'mod_tp_dst:44444', 'goto_table:3']}
+ vswitch.add_flow(bridge, flow)
+ else:
+ pass
diff --git a/tools/pkt_fwd/__init__.py b/tools/pkt_fwd/__init__.py
new file mode 100644
index 00000000..91247e72
--- /dev/null
+++ b/tools/pkt_fwd/__init__.py
@@ -0,0 +1,19 @@
+# Copyright 2016 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Packet forwarders package which contain:
+- All relevant implementations of packet forwarders.
+- Interface definition stored in "pkt_fwd"
+"""
diff --git a/tools/pkt_fwd/pkt_fwd.py b/tools/pkt_fwd/pkt_fwd.py
new file mode 100644
index 00000000..2580ee1f
--- /dev/null
+++ b/tools/pkt_fwd/pkt_fwd.py
@@ -0,0 +1,53 @@
+# Copyright 2016 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Abstract "packet forwarding" model.
+
+This is an abstract class for packet forwarders.
+"""
+
+class IPktFwd(object):
+ """Interface class that is implemented by specific classes
+ of packet forwarders
+ """
+
+ def __enter__(self):
+ """Start the packet forwarder.
+
+ Provide a context manager interface to the packet forwarders.
+ This simply calls the :func:`start` function.
+ """
+ return self.start()
+
+ def __exit__(self, type_, value, traceback):
+ """Stop the packet forwarder.
+
+ Provide a context manager interface to the packet forwarders.
+ This simply calls the :func:`stop` function.
+ """
+ self.stop()
+
+ def start(self):
+ """Start the packet forwarder.
+
+ :returns: None
+ """
+ raise NotImplementedError('Please call an implementation.')
+
+ def stop(self):
+ """Stop the packet forwarder.
+
+ :returns: None
+ """
+ raise NotImplementedError('Please call an implementation.')
+
diff --git a/tools/pkt_fwd/testpmd.py b/tools/pkt_fwd/testpmd.py
new file mode 100644
index 00000000..d8ed8905
--- /dev/null
+++ b/tools/pkt_fwd/testpmd.py
@@ -0,0 +1,87 @@
+# Copyright 2016 Intel Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""VSPERF TestPMD implementation
+"""
+
+import logging
+import pexpect
+from conf import settings
+from src.dpdk import dpdk
+from src.dpdk import TestPMDProcess
+from tools.pkt_fwd.pkt_fwd import IPktFwd
+
+_LOGGER = logging.getLogger(__name__)
+_VSWITCHD_CONST_ARGS = ['--', '-i']
+
+class TestPMD(IPktFwd):
+ """TestPMD implementation (only phy2phy deployment is supported)
+
+ This is wrapper for functionality implemented in ${DPDK}/app/test-pmd.
+
+ The method docstrings document only considerations specific to this
+ implementation. For generic information of the nature of the methods,
+ see the interface definition.
+ """
+
+ _logger = logging.getLogger()
+
+ def __init__(self):
+ vswitchd_args = settings.getValue('VSWITCHD_DPDK_ARGS')
+ vswitchd_args += _VSWITCHD_CONST_ARGS
+ vswitchd_args += settings.getValue('TESTPMD_ARGS')
+
+ self._nports = len(settings.getValue('WHITELIST_NICS'))
+ self._fwdmode = settings.getValue('TESTPMD_FWD_MODE')
+ self._csum_layer = settings.getValue('TESTPMD_CSUM_LAYER')
+ self._csum_calc = settings.getValue('TESTPMD_CSUM_CALC')
+ self._csum_tunnel = settings.getValue('TESTPMD_CSUM_PARSE_TUNNEL')
+
+ self._testpmd = TestPMDProcess(testpmd_args=vswitchd_args)
+
+ def start(self):
+ """See IPktFwd for general description
+
+ Activates testpmd.
+ """
+ self._logger.info("Starting TestPMD...")
+ dpdk.init()
+ self._testpmd.start()
+ self._logger.info("TestPMD...Started.")
+
+ self._testpmd.send('set fwd {}'.format(self._fwdmode), 1)
+
+ for port in range(self._nports):
+ self._testpmd.send('csum set {} {} {}'.format(
+ self._csum_layer, self._csum_calc, port), 1)
+ self._testpmd.send('csum parse_tunnel {} {}'.format(
+ self._csum_tunnel, port), 1)
+
+ self._testpmd.send('start', 1)
+
+ def stop(self):
+ """See IPktFwd for general description
+
+ Kills testpmd.
+ """
+ try:
+ self._testpmd.send('stop')
+ self._testpmd.wait('Done.', 5)
+ self._testpmd.send('quit', 2)
+ self._testpmd.kill()
+ except pexpect.EOF:
+ pass
+ dpdk.cleanup()
+
+
diff --git a/vsperf b/vsperf
index 53699104..50f0996a 100755
--- a/vsperf
+++ b/vsperf
@@ -121,6 +121,8 @@ def parse_arguments():
help='list all system metrics loggers and exit')
parser.add_argument('--list-vswitches', action='store_true',
help='list all system vswitches and exit')
+ parser.add_argument('--list-fwdapps', action='store_true',
+ help='list all system forwarding applications and exit')
parser.add_argument('--list-vnfs', action='store_true',
help='list all system vnfs and exit')
parser.add_argument('--list-settings', action='store_true',
@@ -140,6 +142,7 @@ def parse_arguments():
help='debug level')
group.add_argument('--trafficgen', help='traffic generator to use')
group.add_argument('--vswitch', help='vswitch implementation to use')
+ group.add_argument('--fwdapp', help='packet forwarding application to use')
group.add_argument('--vnf', help='vnf to use')
group.add_argument('--duration', help='traffic transmit duration')
group.add_argument('--sysmetrics', help='system metrics logger to use')
@@ -301,6 +304,7 @@ def main():
# than both a settings file and environment variables
settings.load_from_dict(args)
+ vswitch_none = False
# set dpdk and ovs paths accorfing to VNF and VSWITCH
if settings.getValue('VSWITCH').endswith('Vanilla'):
# settings paths for Vanilla
@@ -318,6 +322,8 @@ def main():
# default - set to VHOST USER but can be changed during enhancement
settings.setValue('RTE_SDK', (settings.getValue('RTE_SDK_USER')))
settings.setValue('OVS_DIR', (settings.getValue('OVS_DIR_USER')))
+ if 'none' == settings.getValue('VSWITCH').strip().lower():
+ vswitch_none = True
configure_logging(settings.getValue('VERBOSITY'))
logger = logging.getLogger()
@@ -337,11 +343,25 @@ def main():
# configure vswitch
if args['vswitch']:
- vswitches = Loader().get_vswitches()
- if args['vswitch'] not in vswitches:
- logging.error('There are no vswitches matching \'%s\' found in'
- ' \'%s\'. Exiting...', args['vswitch'],
- settings.getValue('VSWITCH_DIR'))
+ vswitch_none = 'none' == args['vswitch'].strip().lower()
+ if vswitch_none:
+ settings.setValue('VSWITCH', 'none')
+ else:
+ vswitches = Loader().get_vswitches()
+ if args['vswitch'] not in vswitches:
+ logging.error('There are no vswitches matching \'%s\' found in'
+ ' \'%s\'. Exiting...', args['vswitch'],
+ settings.getValue('VSWITCH_DIR'))
+ sys.exit(1)
+
+ if args['fwdapp']:
+ settings.setValue('PKTFWD', args['fwdapp'])
+ fwdapps = Loader().get_pktfwds()
+ if args['fwdapp'] not in fwdapps:
+ logging.error('There are no forwarding application'
+ ' matching \'%s\' found in'
+ ' \'%s\'. Exiting...', args['fwdapp'],
+ settings.getValue('PKTFWD_DIR'))
sys.exit(1)
if args['vnf']:
@@ -404,6 +424,10 @@ def main():
print(Loader().get_vswitches_printable())
exit()
+ if args['list_fwdapps']:
+ print(Loader().get_pktfwds_printable())
+ exit()
+
if args['list_vnfs']:
print(Loader().get_vnfs_printable())
exit()
@@ -441,6 +465,11 @@ def main():
suite = unittest.TestSuite()
for test in selected_tests:
try:
+ if vswitch_none:
+ if test.deployment.lower() != 'p2p':
+ logging.error('\'none\' vswitch option supported only'
+ ' for p2p deployment.')
+ sys.exit(1)
test.run()
suite.addTest(MockTestCase('', True, test.name))
#pylint: disable=broad-except