Merge changes from topics 'YARDSTICK-1346', 'YARDSTICK-1345', 'YARDSTICK-1344'
authorRodolfo Alonso Hernandez <rodolfo.alonso.hernandez@intel.com>
Tue, 24 Jul 2018 11:00:01 +0000 (11:00 +0000)
committerGerrit Code Review <gerrit@opnfv.org>
Tue, 24 Jul 2018 11:00:01 +0000 (11:00 +0000)
* changes:
  Add pktgen test case base files
  Add pktgen traffic profile
  Add DPDK pktgen traffic generator

samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml [new file with mode: 0644]
samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml [new file with mode: 0644]
samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml [new file with mode: 0644]
samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml [new file with mode: 0644]
yardstick/common/constants.py
yardstick/common/exceptions.py
yardstick/network_services/traffic_profile/__init__.py
yardstick/network_services/traffic_profile/pktgen.py [new file with mode: 0644]
yardstick/network_services/vnf_generic/vnf/tg_pktgen.py [new file with mode: 0644]
yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py [new file with mode: 0644]
yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py [new file with mode: 0644]

diff --git a/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml b/samples/vnf_samples/nsut/cmts/cmts-tg-topology.yaml
new file mode 100644 (file)
index 0000000..81323e7
--- /dev/null
@@ -0,0 +1,39 @@
+# Copyright (c) 2018 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.
+---
+nsd:nsd-catalog:
+    nsd:
+    -   id: cmts-tg-topology
+        name: cmts-tg-topology
+        short-name: cmts-tg-topology
+        description: cmts-tg-topology
+        constituent-vnfd:
+        -   member-vnf-index: '1'
+            vnfd-id-ref: tg__0
+            VNF model: ../../vnf_descriptors/tg_pktgen.yaml
+        -   member-vnf-index: '2'
+            vnfd-id-ref: vnf__0
+            VNF model: ../../vnf_descriptors/tg_pktgen.yaml
+
+        vld: []
+#        -   id: uplink
+#            name: tg__0 to vnf__0 link 1
+#            type: ELAN
+#            vnfd-connection-point-ref:
+#            -   member-vnf-index-ref: '1'
+#                vnfd-connection-point-ref: sriov01
+#                vnfd-id-ref: tg__0
+#            -   member-vnf-index-ref: '2'
+#                vnfd-connection-point-ref: sriov01
+#                vnfd-id-ref: vnf__0
diff --git a/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml b/samples/vnf_samples/nsut/cmts/tc_k8s_pktgen_01.yaml
new file mode 100644 (file)
index 0000000..cab8bb8
--- /dev/null
@@ -0,0 +1,171 @@
+# Copyright (c) 2018 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.
+---
+schema: yardstick:task:0.1
+scenarios:
+- type: NSPerf
+  traffic_profile: ../../traffic_profiles/pktgen_throughput.yaml
+  topology: cmts-tg-topology.yaml
+  nodes:
+    tg__0: trafficgen-k8syardstick
+    vnf__0: vnf-k8syardstick
+  options: {}
+  runner:
+    type: IterationIPC
+    iterations: 10
+    interval: 15
+    timeout: 10000
+context:
+  name: k8syardstick
+  type: Kubernetes
+
+  servers:
+    vnf:
+      containers:
+        - image: si-docker.ir.intel.com/vcmts-ubuntu/vcmts-pktgen-uepi
+          args: ["/opt/bin/cmk isolate --conf-dir=/etc/cmk --socket-id=0 --pool=dataplane /vcmts/setup.sh anga_mac_1_ds.pcap ds"]
+          env:
+            - name: LUA_PATH
+              value: "/vcmts/Pktgen.lua"
+            - name: CMK_PROC_FS
+              value: "/host/proc"
+          resources:
+            requests:
+              pod.alpha.kubernetes.io/opaque-int-resource-cmk: "1"
+          ports:
+            - containerPort: 22022
+          volumeMounts:
+            - name: hugepages
+              mountPath: /dev/hugepages
+            - name: sysfs
+              mountPath: /sys
+            - name: sriov
+              mountPath: /sriov-cni
+            - name: host-proc
+              mountPath: /host/proc
+              readOnly: true
+            - name: cmk-install-dir
+              mountPath: /opt/bin
+            - name: cmk-conf-dir
+              mountPath: /etc/cmk
+          securityContext:
+            allowPrivilegeEscalation: true
+            privileged: true
+
+      node_ports:
+        - name: lua  # Lower case alphanumeric characters or '-'
+          port: 22022
+      networks:
+        - flannel
+        - sriov01
+      volumes:
+        - name: hugepages
+          hostPath:
+            path: /dev/hugepages
+        - name: sysfs
+          hostPath:
+            path: /sys
+        - name: sriov
+          hostPath:
+            path: /var/lib/cni/sriov
+        - name: cmk-install-dir
+          hostPath:
+            path: /opt/bin
+        - name: host-proc
+          hostPath:
+            path: /proc
+        - name: cmk-conf-dir
+          hostPath:
+            path: /etc/cmk
+
+    trafficgen:
+      containers:
+        - image: si-docker.ir.intel.com/vcmts-ubuntu/vcmts-pktgen-uepi
+          args: ["/opt/bin/cmk isolate --conf-dir=/etc/cmk --socket-id=0 --pool=dataplane /vcmts/setup.sh anga_mac_1_ds.pcap ds"]
+          env:
+            - name: LUA_PATH
+              value: "/vcmts/Pktgen.lua"
+            - name: CMK_PROC_FS
+              value: "/host/proc"
+          resources:
+            requests:
+              pod.alpha.kubernetes.io/opaque-int-resource-cmk: "1"
+          ports:
+            - containerPort: 22022
+          volumeMounts:
+            - name: hugepages
+              mountPath: /dev/hugepages
+            - name: sysfs
+              mountPath: /sys
+            - name: sriov
+              mountPath: /sriov-cni
+            - name: host-proc
+              mountPath: /host/proc
+              readOnly: true
+            - name: cmk-install-dir
+              mountPath: /opt/bin
+            - name: cmk-conf-dir
+              mountPath: /etc/cmk
+          securityContext:
+            allowPrivilegeEscalation: true
+            privileged: true
+
+      node_ports:
+        - name: lua  # Lower case alphanumeric characters or '-'
+          port: 22022
+      networks:
+        - flannel
+        - sriov01
+      volumes:
+        - name: hugepages
+          hostPath:
+            path: /dev/hugepages
+        - name: sysfs
+          hostPath:
+            path: /sys
+        - name: sriov
+          hostPath:
+            path: /var/lib/cni/sriov
+        - name: cmk-install-dir
+          hostPath:
+            path: /opt/bin
+        - name: host-proc
+          hostPath:
+            path: /proc
+        - name: cmk-conf-dir
+          hostPath:
+            path: /etc/cmk
+
+  networks:
+    flannel:
+      args: '[{ "delegate": { "isDefaultGateway": true }}]'
+      plugin: flannel
+    sriov01:
+      plugin: sriov
+      args: '[{"if0": "ens802f0",
+               "if0name": "net0",
+               "dpdk": {
+                   "kernel_driver": "i40evf",
+                   "dpdk_driver": "igb_uio",
+                   "dpdk_tool": "/opt/nsb_bin/dpdk-devbind.py"}
+             }]'
+    sriov02:
+      plugin: sriov
+      args: '[{"if0": "ens802f0",
+               "if0name": "net0",
+               "dpdk": {
+                   "kernel_driver": "i40evf",
+                   "dpdk_driver": "igb_uio",
+                   "dpdk_tool": "/opt/nsb_bin/dpdk-devbind.py"}
+             }]'
diff --git a/samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml b/samples/vnf_samples/traffic_profiles/pktgen_throughput.yaml
new file mode 100644 (file)
index 0000000..e222e1d
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright (c) 2018 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.
+---
+schema: "nsb:traffic_profile:0.1"
+
+name: pktgen
+description: Traffic profile to run throughput tests
+traffic_profile:
+  traffic_type: PktgenTrafficProfile
+  duration: 15
diff --git a/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml b/samples/vnf_samples/vnf_descriptors/tg_pktgen.yaml
new file mode 100644 (file)
index 0000000..17e6316
--- /dev/null
@@ -0,0 +1,47 @@
+# Copyright (c) 2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+---
+vnfd:vnfd-catalog:
+    vnfd:
+    -   id: PktgenTrafficGen  # NSB class mapping
+        name: pktgen_tg
+        short-name: pktgen_tg
+        description: Pktgen DPDK traffic generator
+        mgmt-interface:
+            vdu-id: pktgen
+            {% if ip is defined %}
+            ip: '{{ ip }}'
+            {% endif %}
+            {% if service_ports is defined and service_ports %}
+            service_ports:
+                {% for port in service_ports %}
+                - port: "{{ port['port']|int }}"
+                  node_port: "{{ port['node_port']|int }}"
+                  target_port: "{{ port['target_port']|int }}"
+                {% endfor %}
+            {% endif %}
+
+        vdu:
+        -   id: pktgen_tg
+            name: pktgen_tg
+            description: Pktgen DPDK traffic generator
+
+        benchmark:
+            kpi:
+                - rx_throughput_fps
+                - tx_throughput_fps
+                - tx_throughput_mbps
+                - rx_throughput_mbps
+                - in_packets
+                - out_packets
index 4ed40f8..3d775d4 100644 (file)
@@ -175,3 +175,4 @@ SCOPE_CLUSTER = 'Cluster'
 
 # VNF definition
 SSH_PORT = 22
+LUA_PORT = 22022
index 2e6cbdd..56b11b7 100644 (file)
@@ -212,6 +212,10 @@ class WaitTimeout(YardstickException):
     message = 'Wait timeout while waiting for condition'
 
 
+class PktgenActionError(YardstickException):
+    message = 'Error in "%(action)s" action'
+
+
 class KubernetesApiException(YardstickException):
     message = ('Kubernetes API errors. Action: %(action)s, '
                'resource: %(resource)s')
index 356b36b..a1b26a2 100644 (file)
@@ -27,6 +27,7 @@ def register_modules():
         'yardstick.network_services.traffic_profile.prox_profile',
         'yardstick.network_services.traffic_profile.prox_ramp',
         'yardstick.network_services.traffic_profile.rfc2544',
+        'yardstick.network_services.traffic_profile.pktgen',
     ]
 
     for module in modules:
diff --git a/yardstick/network_services/traffic_profile/pktgen.py b/yardstick/network_services/traffic_profile/pktgen.py
new file mode 100644 (file)
index 0000000..30f81b7
--- /dev/null
@@ -0,0 +1,61 @@
+# Copyright (c) 2018 Intel Corporation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from yardstick.common import exceptions
+from yardstick.common import utils
+from yardstick.network_services.traffic_profile import base as tp_base
+
+
+class PktgenTrafficProfile(tp_base.TrafficProfile):
+    """This class handles Pktgen Trex Traffic profile execution"""
+
+    def __init__(self, tp_config):  # pragma: no cover
+        super(PktgenTrafficProfile, self).__init__(tp_config)
+        self._host = None
+        self._port = None
+
+    def init(self, host, port):  # pragma: no cover
+        """Initialize control parameters
+
+        :param host: (str) ip or host name
+        :param port: (int) TCP socket port number for Lua commands
+        """
+        self._host = host
+        self._port = port
+
+    def start(self):
+        if utils.send_socket_command(self._host, self._port,
+                                     'pktgen.start("0")') != 0:
+            raise exceptions.PktgenActionError(action='start')
+
+    def stop(self):
+        if utils.send_socket_command(self._host, self._port,
+                                     'pktgen.stop("0")') != 0:
+            raise exceptions.PktgenActionError(action='stop')
+
+    def rate(self, rate):
+        command = 'pktgen.set("0", "rate", ' + str(rate) + ')'
+        if utils.send_socket_command(self._host, self._port, command) != 0:
+            raise exceptions.PktgenActionError(action='rate')
+
+    def clear_all_stats(self):
+        if utils.send_socket_command(self._host, self._port, 'clr') != 0:
+            raise exceptions.PktgenActionError(action='clear all stats')
+
+    def help(self):
+        if utils.send_socket_command(self._host, self._port, 'help') != 0:
+            raise exceptions.PktgenActionError(action='help')
+
+    def execute_traffic(self, *args, **kwargs):  # pragma: no cover
+        pass
diff --git a/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py b/yardstick/network_services/vnf_generic/vnf/tg_pktgen.py
new file mode 100644 (file)
index 0000000..9d45221
--- /dev/null
@@ -0,0 +1,103 @@
+# Copyright (c) 2018 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.
+
+import logging
+import multiprocessing
+import time
+import uuid
+
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.common import utils
+from yardstick.network_services.vnf_generic.vnf import base as vnf_base
+
+
+LOG = logging.getLogger(__name__)
+
+
+class PktgenTrafficGen(vnf_base.GenericTrafficGen,
+                       vnf_base.GenericVNFEndpoint):
+    """DPDK Pktgen traffic generator
+
+    Website: http://pktgen-dpdk.readthedocs.io/en/latest/index.html
+    """
+
+    TIMEOUT = 30
+
+    def __init__(self, name, vnfd, task_id):
+        vnf_base.GenericTrafficGen.__init__(self, name, vnfd, task_id)
+        self.queue = multiprocessing.Queue()
+        self._id = uuid.uuid1().int
+        self._mq_producer = self._setup_mq_producer(self._id)
+        vnf_base.GenericVNFEndpoint.__init__(self, self._id, [task_id],
+                                             self.queue)
+        self._consumer = vnf_base.GenericVNFConsumer([task_id], self)
+        self._consumer.start_rpc_server()
+        self._traffic_profile = None
+        self._node_ip = vnfd['mgmt-interface'].get('ip')
+        self._lua_node_port = self._get_lua_node_port(
+            vnfd['mgmt-interface'].get('service_ports', []))
+        self._rate = 1
+
+    def instantiate(self, scenario_cfg, context_cfg):  # pragma: no cover
+        pass
+
+    def run_traffic(self, traffic_profile):
+        self._traffic_profile = traffic_profile
+        self._traffic_profile.init(self._node_ip, self._lua_node_port)
+        utils.wait_until_true(self._is_running, timeout=self.TIMEOUT,
+                              sleep=2)
+
+    def terminate(self):  # pragma: no cover
+        pass
+
+    def collect_kpi(self):  # pragma: no cover
+        pass
+
+    def scale(self, flavor=''):  # pragma: no cover
+        pass
+
+    def wait_for_instantiate(self):  # pragma: no cover
+        pass
+
+    def runner_method_start_iteration(self, ctxt, **kwargs):
+        # pragma: no cover
+        LOG.debug('Start method')
+        # NOTE(ralonsoh): 'rate' should be modified between iterations. The
+        # current implementation is just for testing.
+        self._rate += 1
+        self._traffic_profile.start()
+        self._traffic_profile.rate(self._rate)
+        time.sleep(4)
+        self._traffic_profile.stop()
+        self._mq_producer.tg_method_iteration(1, 1, {})
+
+    def runner_method_stop_iteration(self, ctxt, **kwargs):  # pragma: no cover
+        # pragma: no cover
+        LOG.debug('Stop method')
+
+    @staticmethod
+    def _get_lua_node_port(service_ports):
+        for port in (port for port in service_ports if
+                     int(port['port']) == constants.LUA_PORT):
+            return int(port['node_port'])
+        # NOTE(ralonsoh): in case LUA port is not present, an exception should
+        # be raised.
+
+    def _is_running(self):
+        try:
+            self._traffic_profile.help()
+            return True
+        except exceptions.PktgenActionError:
+            return False
diff --git a/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py b/yardstick/tests/unit/network_services/traffic_profile/test_pktgen.py
new file mode 100644 (file)
index 0000000..08542b4
--- /dev/null
@@ -0,0 +1,63 @@
+# Copyright (c) 2018 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.
+
+import mock
+
+from yardstick.common import utils
+from yardstick.network_services.traffic_profile import pktgen
+from yardstick.tests.unit import base as ut_base
+
+
+class TestIXIARFC2544Profile(ut_base.BaseUnitTestCase):
+
+    def setUp(self):
+        self._tp_config = {'traffic_profile': {}}
+        self._host = 'localhost'
+        self._port = '12345'
+        self.tp = pktgen.PktgenTrafficProfile(self._tp_config)
+        self.tp.init(self._host, self._port)
+        self._mock_send_socket_command = mock.patch.object(
+            utils, 'send_socket_command', return_value=0)
+        self.mock_send_socket_command = self._mock_send_socket_command.start()
+        self.addCleanup(self._stop_mock)
+
+    def _stop_mock(self):
+        self._mock_send_socket_command.stop()
+
+    def test_start(self):
+        self.tp.start()
+        self.mock_send_socket_command.assert_called_once_with(
+            self._host, self._port, 'pktgen.start("0")')
+
+    def test_stop(self):
+        self.tp.stop()
+        self.mock_send_socket_command.assert_called_once_with(
+            self._host, self._port, 'pktgen.stop("0")')
+
+    def test_rate(self):
+        rate = 75
+        self.tp.rate(rate)
+        command = 'pktgen.set("0", "rate", 75)'
+        self.mock_send_socket_command.assert_called_once_with(
+            self._host, self._port, command)
+
+    def test_clear_all_stats(self):
+        self.tp.clear_all_stats()
+        self.mock_send_socket_command.assert_called_once_with(
+            self._host, self._port, 'clr')
+
+    def test_help(self):
+        self.tp.help()
+        self.mock_send_socket_command.assert_called_once_with(
+            self._host, self._port, 'help')
diff --git a/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py b/yardstick/tests/unit/network_services/vnf_generic/vnf/test_tg_pktgen.py
new file mode 100644 (file)
index 0000000..d341b97
--- /dev/null
@@ -0,0 +1,79 @@
+# Copyright (c) 2018 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.
+
+import uuid
+
+import mock
+
+from yardstick.common import constants
+from yardstick.common import exceptions
+from yardstick.network_services.vnf_generic.vnf import base as vnf_base
+from yardstick.network_services.vnf_generic.vnf import tg_pktgen
+from yardstick.tests.unit import base as ut_base
+
+
+class PktgenTrafficGenTestCase(ut_base.BaseUnitTestCase):
+
+    SERVICE_PORTS = [{'port': constants.LUA_PORT,
+                      'node_port': '34501'}]
+    VNFD = {'mgmt-interface': {'ip': '1.2.3.4',
+                               'service_ports': SERVICE_PORTS},
+            'vdu': [{'external-interface': 'interface'}],
+            'benchmark': {'kpi': 'fake_kpi'}
+            }
+
+    def setUp(self):
+        self._id = uuid.uuid1().int
+        self._mock_vnf_consumer = mock.patch.object(vnf_base,
+                                                    'GenericVNFConsumer')
+        self.mock_vnf_consumer = self._mock_vnf_consumer.start()
+        self.addCleanup(self._stop_mock)
+
+    def _stop_mock(self):
+        self._mock_vnf_consumer.stop()
+
+    def test__init(self):
+        tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+        self.assertTrue(isinstance(tg, (vnf_base.GenericTrafficGen,
+                                        vnf_base.GenericVNFEndpoint)))
+
+    def test_run_traffic(self):
+        tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+        mock_tp = mock.Mock()
+        with mock.patch.object(tg, '_is_running', return_value=True):
+            tg.run_traffic(mock_tp)
+
+        mock_tp.init.assert_called_once_with(tg._node_ip, tg._lua_node_port)
+
+    def test__get_lua_node_port(self):
+        tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+        service_ports = [{'port': constants.LUA_PORT,
+                          'node_port': '12345'}]
+        self.assertEqual(12345, tg._get_lua_node_port(service_ports))
+
+    def test__get_lua_node_port_no_lua_port(self):
+        tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+        service_ports = [{'port': '333'}]
+        self.assertIsNone(tg._get_lua_node_port(service_ports))
+
+    def test__is_running(self):
+        tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+        with mock.patch.object(tg, '_traffic_profile'):
+            self.assertTrue(tg._is_running())
+
+    def test__is_running_exception(self):
+        tg = tg_pktgen.PktgenTrafficGen('name1', self.VNFD, self._id)
+        with mock.patch.object(tg, '_traffic_profile') as mock_tp:
+            mock_tp.help.side_effect = exceptions.PktgenActionError()
+            self.assertFalse(tg._is_running())