Add fixes for heat deployed UDP_Replay and TRex
[yardstick.git] / yardstick / network_services / vnf_generic / vnf / sample_vnf.py
index 60979eb..1b2533a 100644 (file)
@@ -37,9 +37,9 @@ from yardstick.network_services.vnf_generic.vnf.base import QueueFileWrapper
 from yardstick.network_services.vnf_generic.vnf.base import GenericTrafficGen
 from yardstick.network_services.utils import get_nsb_option
 
-from stl.trex_stl_lib.trex_stl_client import STLClient
-from stl.trex_stl_lib.trex_stl_client import LoggerApi
-from stl.trex_stl_lib.trex_stl_exceptions import STLError, STLStateError
+from trex_stl_lib.trex_stl_client import STLClient
+from trex_stl_lib.trex_stl_client import LoggerApi
+from trex_stl_lib.trex_stl_exceptions import STLError
 
 from yardstick.ssh import AutoConnectSSH
 
@@ -115,7 +115,9 @@ class SetupEnvHelper(object):
 
     def setup_vnf_environment(self):
         pass
-        # raise NotImplementedError
+
+    def kill_vnf(self):
+        pass
 
     def tear_down(self):
         raise NotImplementedError
@@ -182,7 +184,7 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper):
         self.ssh_helper.execute("awk -F: '{ print $1 }' < %s" % memory_path)
 
         if hugepages == "2048kB":
-            pages = 16384
+            pages = 8192
         else:
             pages = 16
 
@@ -297,12 +299,13 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper):
     def setup_vnf_environment(self):
         self._setup_dpdk()
         resource = self._setup_resources()
-        self._kill_vnf()
-        self._detect_drivers()
+        self.kill_vnf()
+        self._detect_and_bind_drivers()
         return resource
 
-    def _kill_vnf(self):
-        self.ssh_helper.execute("sudo pkill %s" % self.APP_NAME)
+    def kill_vnf(self):
+        # have to use exact match
+        self.ssh_helper.execute("sudo pkill -x %s" % self.APP_NAME)
 
     def _setup_dpdk(self):
         """ setup dpdk environment needed for vnf to run """
@@ -335,7 +338,7 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper):
         return ResourceProfile(self.vnfd_helper.mgmt_interface,
                                interfaces=self.vnfd_helper.interfaces, cores=cores)
 
-    def _detect_drivers(self):
+    def _detect_and_bind_drivers(self):
         interfaces = self.vnfd_helper.interfaces
 
         self._find_used_drivers()
@@ -351,6 +354,15 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper):
             self._bind_dpdk('igb_uio', vpci)
             time.sleep(2)
 
+        # debug dump after binding
+        self.ssh_helper.execute("sudo {} -s".format(self.dpdk_nic_bind))
+
+    def rebind_drivers(self, force=True):
+        if not self.used_drivers:
+            self._find_used_drivers()
+        for vpci, (_, driver) in self.used_drivers.items():
+            self._bind_dpdk(driver, vpci, force)
+
     def _bind_dpdk(self, driver, vpci, force=True):
         if force:
             force = '--force '
@@ -376,6 +388,7 @@ class DpdkVnfSetupEnvHelper(SetupEnvHelper):
         return stdout
 
     def _bind_kernel_devices(self):
+        # only used by PingSetupEnvHelper?
         for intf in self.vnfd_helper.interfaces:
             vi = intf["virtual-interface"]
             stdout = self._detect_and_bind_dpdk(vi["vpci"], vi["driver"])
@@ -457,7 +470,7 @@ class ClientResourceHelper(ResourceHelper):
     def get_stats(self, *args, **kwargs):
         try:
             return self.client.get_stats(*args, **kwargs)
-        except STLStateError:
+        except STLError:
             LOG.exception("TRex client not connected")
             return {}
 
@@ -497,18 +510,24 @@ class ClientResourceHelper(ResourceHelper):
     def run_traffic(self, traffic_profile):
         # fixme: fix passing correct trex config file,
         # instead of searching the default path
-        self._build_ports()
-        self.client = self._connect()
-        self.client.reset(ports=self.my_ports)
-        self.client.remove_all_streams(self.my_ports)  # remove all streams
-        traffic_profile.register_generator(self)
-
-        while self._terminated.value == 0:
-            self._run_traffic_once(traffic_profile)
-
-        self.client.stop(self.my_ports)
-        self.client.disconnect()
-        self._terminated.value = 0
+        try:
+            self._build_ports()
+            self.client = self._connect()
+            self.client.reset(ports=self.my_ports)
+            self.client.remove_all_streams(self.my_ports)  # remove all streams
+            traffic_profile.register_generator(self)
+
+            while self._terminated.value == 0:
+                self._run_traffic_once(traffic_profile)
+
+            self.client.stop(self.my_ports)
+            self.client.disconnect()
+            self._terminated.value = 0
+        except STLError:
+            if self._terminated.value:
+                LOG.debug("traffic generator is stopped")
+                return  # return if trex/tg server is stopped.
+            raise
 
     def terminate(self):
         self._terminated.value = 1  # stop client
@@ -527,7 +546,8 @@ class ClientResourceHelper(ResourceHelper):
         if not self._queue.empty():
             kpi = self._queue.get()
             self._result.update(kpi)
-        LOG.debug("Collect {0} KPIs {1}".format(self.RESOURCE_WORD, self._result))
+            LOG.debug("Got KPIs from _queue for {0} {1}".format(
+                self.scenario_helper.name, self.RESOURCE_WORD))
         return self._result
 
     def _connect(self, client=None):
@@ -660,19 +680,19 @@ class ScenarioHelper(object):
 
     @property
     def task_path(self):
-        return self.scenario_cfg["task_path"]
+        return self.scenario_cfg['task_path']
 
     @property
     def nodes(self):
-        return self.scenario_cfg['nodes']
+        return self.scenario_cfg.get('nodes')
 
     @property
     def all_options(self):
-        return self.scenario_cfg["options"]
+        return self.scenario_cfg.get('options', {})
 
     @property
     def options(self):
-        return self.all_options[self.name]
+        return self.all_options.get(self.name, {})
 
     @property
     def vnf_cfg(self):
@@ -722,7 +742,6 @@ class SampleVNF(GenericVNF):
         self.q_out = Queue()
         self.queue_wrapper = None
         self.run_kwargs = {}
-        self.scenario_cfg = None
         self.tg_port_pairs = None
         self.used_drivers = {}
         self.vnf_port_pairs = None
@@ -823,7 +842,7 @@ class SampleVNF(GenericVNF):
         self.ssh_helper.drop_connection()
         cmd = self._build_config()
         # kill before starting
-        self.ssh_helper.execute("pkill {}".format(self.APP_NAME))
+        self.setup_helper.kill_vnf()
 
         LOG.debug(cmd)
         self._build_run_kwargs()
@@ -847,7 +866,7 @@ class SampleVNF(GenericVNF):
         self.vnf_execute("quit")
         if self._vnf_process:
             self._vnf_process.terminate()
-        self.ssh_helper.execute("sudo pkill %s" % self.APP_NAME)
+        self.setup_helper.kill_vnf()
         self._tear_down()
         self.resource_helper.stop_collect()
 
@@ -917,7 +936,6 @@ class SampleVNFTrafficGen(GenericTrafficGen):
     def instantiate(self, scenario_cfg, context_cfg):
         self.scenario_helper.scenario_cfg = scenario_cfg
         self.resource_helper.generate_cfg()
-        self.setup_helper.setup_vnf_environment()
         self.resource_helper.setup()
 
         LOG.info("Starting %s server...", self.APP_NAME)
@@ -925,6 +943,7 @@ class SampleVNFTrafficGen(GenericTrafficGen):
         self._tg_process.start()
 
     def wait_for_instantiate(self):
+        # overridden by subclasses
         return self._wait_for_process()
 
     def _check_status(self):
@@ -942,6 +961,9 @@ class SampleVNFTrafficGen(GenericTrafficGen):
                 return self._tg_process.exitcode
 
     def _traffic_runner(self, traffic_profile):
+        # always drop connections first thing in new processes
+        # so we don't get paramiko errors
+        self.ssh_helper.drop_connection()
         LOG.info("Starting %s client...", self.APP_NAME)
         self.resource_helper.run_traffic(traffic_profile)
 
@@ -959,6 +981,9 @@ class SampleVNFTrafficGen(GenericTrafficGen):
         # Wait for traffic process to start
         while self.resource_helper.client_started.value == 0:
             time.sleep(self.RUN_WAIT)
+            # what if traffic process takes a few seconds to start?
+            if not self._traffic_process.is_alive():
+                break
 
         return self._traffic_process.is_alive()