From 48f947e94e36e877aa6889e10cda0bbdcd573ef4 Mon Sep 17 00:00:00 2001
From: "Sridhar K. N. Rao" <sridhar.rao@spirent.com>
Date: Wed, 4 Aug 2021 17:10:27 +0530
Subject: Integrating DPPD-Prox with Vineperf

This patch adds Integration of DPPD-Prox with Vineperf
Added:
1. Results analysis - bug-fix
2. Restrict to baremetal for this patch.
3. Fix Pylint errors.
4. Copy Rapid private key too.
5. Remove SSH key.

Signed-off-by: Sridhar K. N. Rao <sridhar.rao@spirent.com>
Change-Id: I3ea7e6261e3fab06ef829f22153fe247372fc34b
---
 tools/pkt_gen/prox/__init__.py                     |  18 ++
 tools/pkt_gen/prox/files/format.yaml               | 105 +++++++++++
 tools/pkt_gen/prox/files/helper.lua                |  77 ++++++++
 tools/pkt_gen/prox/files/machine.map               |  14 ++
 tools/pkt_gen/prox/files/vineperf-baremetal.cfg    |  68 +++++++
 tools/pkt_gen/prox/prox.py                         | 203 +++++++++++++++++++++
 tools/pkt_gen/prox/render.py                       |  75 ++++++++
 .../pkt_gen/prox/templates/params-vineperf.lua.j2  |  79 ++++++++
 .../prox/templates/rapid-vineperf-baremetal.env.j2 |  24 +++
 tools/pkt_gen/prox/templates/tst009.test.j2        |  34 ++++
 10 files changed, 697 insertions(+)
 create mode 100644 tools/pkt_gen/prox/__init__.py
 create mode 100644 tools/pkt_gen/prox/files/format.yaml
 create mode 100644 tools/pkt_gen/prox/files/helper.lua
 create mode 100644 tools/pkt_gen/prox/files/machine.map
 create mode 100644 tools/pkt_gen/prox/files/vineperf-baremetal.cfg
 create mode 100644 tools/pkt_gen/prox/prox.py
 create mode 100644 tools/pkt_gen/prox/render.py
 create mode 100644 tools/pkt_gen/prox/templates/params-vineperf.lua.j2
 create mode 100644 tools/pkt_gen/prox/templates/rapid-vineperf-baremetal.env.j2
 create mode 100644 tools/pkt_gen/prox/templates/tst009.test.j2

(limited to 'tools')

diff --git a/tools/pkt_gen/prox/__init__.py b/tools/pkt_gen/prox/__init__.py
new file mode 100644
index 00000000..e0e55121
--- /dev/null
+++ b/tools/pkt_gen/prox/__init__.py
@@ -0,0 +1,18 @@
+# Copyright 2021 Spirent Communications.
+#
+# 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.
+
+"""Implementation of prox-based tests
+"""
+
+from .prox import *
diff --git a/tools/pkt_gen/prox/files/format.yaml b/tools/pkt_gen/prox/files/format.yaml
new file mode 100644
index 00000000..6b501040
--- /dev/null
+++ b/tools/pkt_gen/prox/files/format.yaml
@@ -0,0 +1,105 @@
+;Format: PushGateway
+;Format: Xtesting
+;URL:
+  part1: http://testresults.opnfv.org/test/api/v1/results
+;URL:
+  part1: http://192.168.36.61:9091/metrics/job/
+  part2: test
+  part3: /instance/
+  part4: environment_file
+;FlowsizeTest:
+  Flows: Flows 
+  Size: Size
+  RequestedSpeed: RequestedSpeed
+  CoreGenerated: pps_req_tx
+  SentByNIC: pps_tx
+  FwdBySUT: pps_sut_tx
+  RevByCore: pps_rx
+  AvgLatency: lat_avg
+  PCTLatency: lat_perc
+  MinLatency: lat_min
+  MaxLatency: lat_max
+  Sent: abs_tx
+  Received: abs_rx
+  Lost: abs_dropped
+  Misordered: mis_ordered
+  Extent: extent
+  Duplicated: duplicate
+FlowSizeTest:
+  Environment: environment_file
+  Test: test
+  Flows: Flows
+  Size: Size
+  Speed (Mpps):
+    RequestedSpeed: RequestedSpeed
+    CoreGenerated: pps_req_tx
+    SentByNIC: pps_tx
+    FwdBySUT: pps_sut_tx
+    RevByCore: pps_rx
+  Latency (usec):
+    AvgLatency: lat_avg
+    PCTLatency: lat_perc
+    MinLatency: lat_min
+    MaxLatency: lat_max
+    Distribution:
+      bucket_size: bucket_size
+      buckets: buckets
+  Absolute Packet Count:
+    Sent: abs_tx
+    Received: abs_rx
+    Lost: abs_dropped
+  Re-ordering:
+    Misordered: mis_ordered
+    Extent: extent
+    Duplicated: duplicate
+IrqTest:
+  Environment: environment_file
+  Test: test
+  Buckets: buckets
+  Machine_data: machine_data
+ImpairTest:
+  Environment: environment_file
+  Test: test
+  Flows: Flows
+  Size: Size
+  Speed (Mpps):
+    RequestedSpeed: RequestedSpeed
+    CoreGenerated: pps_req_tx
+    SentByNIC: pps_tx
+    FwdBySUT: pps_sut_tx
+    RevByCore: pps_rx
+  Latency (usec):
+    AvgLatency: lat_avg
+    PCTLatency: lat_perc
+    MinLatency: lat_min
+    MaxLatency: lat_max
+    Distribution:
+      bucket_size: bucket_size
+      buckets: buckets
+  Absolute Packet Count:
+    Sent: abs_tx
+    Received: abs_rx
+    Lost: abs_dropped
+  Re-ordering:
+    Misordered: mis_ordered
+    Extent: extent
+    Duplicated: duplicate
+CoreStatsTest:
+  Environment: environment_file
+  Test: test
+  PROXID: PROXID
+  StepSize: StepSize
+  Received: Received
+  Sent: Sent
+  NonDPReceived: NonDPReceived
+  NonDPSent: NonDPSent
+  Dropped: Dropped
+PortStatsTest:
+  Environment: environment_file
+  Test: test
+  PROXID: PROXID
+  StepSize: StepSize
+  Received: Received
+  Sent: Sent
+  NoMbufs: NoMbufs
+  iErrMiss: iErrMiss
diff --git a/tools/pkt_gen/prox/files/helper.lua b/tools/pkt_gen/prox/files/helper.lua
new file mode 100644
index 00000000..1b4c657b
--- /dev/null
+++ b/tools/pkt_gen/prox/files/helper.lua
@@ -0,0 +1,77 @@
+--
+-- Copyright (c) 2020 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.
+--
+
+function convertIPToHex(ip)
+  local address_chunks = {}
+  if type(ip) ~= "string" then
+    print ("IP ADDRESS ERROR: ", ip)
+    return "IP ADDRESS ERROR"
+  end
+
+  local chunks = {ip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)(\/%d+)$")}
+  if #chunks == 5 then
+    for i,v in ipairs(chunks) do
+      if i < 5 then
+        if tonumber(v) > 255 then
+          print ("IPV4 ADDRESS ERROR: ", ip)
+          return "IPV4 ADDRESS ERROR"
+        end
+        address_chunks[#address_chunks + 1] = string.format ("%02x", v)
+      end
+    end
+    result = table.concat(address_chunks, " ")
+    print ("Hex IPV4: ", result)
+    return result
+  end
+
+  local chunks = {ip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")}
+  if #chunks == 4 then
+    for i,v in ipairs(chunks) do
+      if tonumber(v) > 255 then
+        print ("IPV4 ADDRESS ERROR: ", ip)
+        return "IPV4 ADDRESS ERROR"
+      end
+      address_chunks[#address_chunks + 1] = string.format ("%02x", v)
+    end
+    result = table.concat(address_chunks, " ")
+    print ("Hex IPV4: ", result)
+    return result
+  end
+
+  delimiter = ":"
+  for match in (ip..delimiter):gmatch("(.-)"..delimiter) do
+    if match ~= "" then
+      number = tonumber(match, 16)
+      if number <= 65535 then
+        table.insert(address_chunks, string.format("%02x %02x",number/256,number % 256))
+      end
+    else
+      table.insert(address_chunks, "")
+    end
+  end
+  for i, chunk in ipairs(address_chunks) do
+    if chunk =="" then
+      table.remove(address_chunks, i)
+      for j = 1,(8-#address_chunks) do
+        table.insert(address_chunks, i, "00 00")
+      end
+      break
+    end
+  end
+  result = table.concat(address_chunks, " ")
+  print ("Hex IPV6: ", result)
+  return result
+end
diff --git a/tools/pkt_gen/prox/files/machine.map b/tools/pkt_gen/prox/files/machine.map
new file mode 100644
index 00000000..2992884e
--- /dev/null
+++ b/tools/pkt_gen/prox/files/machine.map
@@ -0,0 +1,14 @@
+[DEFAULT]
+machine_index=0
+
+[TestM1]
+machine_index=1
+
+[TestM2]
+machine_index=2
+
+[TestM3]
+machine_index=3
+
+[TestM4]
+machine_index=4
\ No newline at end of file
diff --git a/tools/pkt_gen/prox/files/vineperf-baremetal.cfg b/tools/pkt_gen/prox/files/vineperf-baremetal.cfg
new file mode 100644
index 00000000..03299538
--- /dev/null
+++ b/tools/pkt_gen/prox/files/vineperf-baremetal.cfg
@@ -0,0 +1,68 @@
+[lua]
+dofile("params-vineperf.lua")
+
+[eal options]
+-n=4 ; force number of memory channels
+no-output=no ; disable DPDK debug output
+eal=--proc-type auto ${eal}
+
+[port 0]
+name=p0
+rx desc=2048
+tx desc=2048
+vlan=yes
+vdev=gen_tap
+local ipv4= ${local_ip1}
+lsc=no
+
+[port 1]
+name=p1
+rx desc=2048
+tx desc=2048
+vlan=yes
+vdev=rec_tap
+local ipv4=${local_ip2}
+lsc=no
+
+[variables]
+$mbs=8
+
+[defaults]
+mempool size=8K
+
+[global]
+name=${name}
+heartbeat timeout=${heartbeat}
+
+[core $mcore]
+mode=master
+
+[core $gencores]
+name=p0
+task=0
+mode=gen
+tx port=p0
+bps=1250000000
+pkt inline=00 00 00 00 00 00 00 00 00 00 00 00 08 00 45 00 00 2e 00 01 00 00 40 11 f7 7d ${local_hex_ip1} ${local_hex_ip2} 0b b8 0b b9 00 1a 55 7b
+pkt size=60
+min bulk size=$mbs
+max bulk size=16
+drop=yes
+lat pos=42
+accuracy pos=46
+packet id pos=50
+signature=0x98765432
+signature pos=56
+
+[core $latcores]
+name=lat
+task=0
+mode=lat
+rx port=p1
+lat pos=42
+accuracy pos=46
+packet id pos=50
+signature=0x98765432
+signature pos=56
+accuracy limit nsec=1000000
+latency bucket size=${bucket_size_exp}
diff --git a/tools/pkt_gen/prox/prox.py b/tools/pkt_gen/prox/prox.py
new file mode 100644
index 00000000..2b4ff9ce
--- /dev/null
+++ b/tools/pkt_gen/prox/prox.py
@@ -0,0 +1,203 @@
+# Copyright 2021 Spirent Communications.
+#
+# 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.
+
+"""
+Code to integrate Prox Traffic generator with vineperf test framework.
+
+"""
+
+#import csv
+import logging
+import os
+#import subprocess
+
+from conf import settings
+from core.results.results_constants import ResultsConstants
+#from runrapid import RapidTestManager
+from tools import tasks
+from tools.pkt_gen.prox import render
+
+class Prox():
+    """
+    Prox Traffic Generator
+    """
+    _logger = logging.getLogger(__name__)
+
+    def connect(self):
+        """
+        Do nothing.
+        """
+        return self
+
+    def disconnect(self):
+        """
+        Do nothing.
+        """
+        return self
+
+    def send_burst_traffic(self, traffic=None, duration=20):
+        """
+        Do nothing.
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def send_rfc2889_forwarding(self, traffic=None, tests=1, _duration=20):
+        """
+        Send traffic per RFC2889 Forwarding test specifications.
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def send_rfc2889_caching(self, traffic=None, tests=1, _duration=20):
+        """
+        Send as per RFC2889 Addr-Caching test specifications.
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def send_rfc2889_learning(self, traffic=None, tests=1, _duration=20):
+        """
+        Send traffic per RFC2889 Addr-Learning test specifications.
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def send_cont_traffic(self, traffic=None, duration=30):
+        """
+        Send Custom - Continuous Test traffic
+        Reuse RFC2544 throughput test specifications along with
+        'custom' configuration
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def get_rfc2544_results(self, output):
+        """
+        Reads the output and return the results
+        """
+        result = {}
+        values = None
+        for line in output.splitlines():
+            if line.startswith('|') and 'different number' in line:
+                pktsize = line.split(',')[1]
+                try:
+                    int(pktsize)
+                except ValueError:
+                    self._logger.info("Pkt Size is not an Int\n")
+                    return result
+            if line.startswith('|') and '%' in line:
+                values = line.split('|')
+                if values and len(values) > 12:
+                    tx_pps = float(values[4].strip().split(' ')[0]) * 1000000
+                    rx_pps = float(values[7].strip().split(' ')[0]) * 1000000
+                    rx_mbps = float(values[6].strip().split(' ')[0]) * 1000
+                    max_lat = float(values[10].strip().split(' ')[0]) * 1000
+                    avg_lat = float(values[8].strip().split(' ')[0]) * 1000
+                    loss_percentage = ((float(values[11].strip()) -
+                        float(values[12].strip()))/float(values[11].strip())) * 100
+                    result[ResultsConstants.TX_RATE_FPS] = tx_pps
+                    result[ResultsConstants.THROUGHPUT_RX_FPS] = rx_pps
+                    result[ResultsConstants.TX_RATE_MBPS] = 0
+                    result[ResultsConstants.THROUGHPUT_RX_MBPS] = rx_mbps
+                    result[ResultsConstants.TX_RATE_PERCENT] = 0
+                    result[ResultsConstants.THROUGHPUT_RX_PERCENT] = 0
+                    result[ResultsConstants.MIN_LATENCY_NS] = 0
+                    result[ResultsConstants.MAX_LATENCY_NS] = max_lat
+                    result[ResultsConstants.AVG_LATENCY_NS] = avg_lat
+                    result[ResultsConstants.FRAME_LOSS_PERCENT] = loss_percentage
+        return result
+
+    def send_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
+                                lossrate=0.0):
+        """
+        Send traffic per RFC2544 throughput test specifications.
+        """
+        print("Run with Duration: {}, Tests: {} & Lossrate: {}".format(
+            duration, tests, lossrate))
+        pkt_size = None
+        if traffic and 'l2' in traffic:
+            if 'framesize' in traffic['l2']:
+                framesize = traffic['l2']['framesize']
+                pkt_size = '['+str(framesize)+']'
+        if not settings.getValue('K8S'):
+            # First render all the configurations and place it
+            filesdir = settings.getValue('TRAFFICGEN_PROX_FILES_DIR')
+            confdir = settings.getValue('TRAFFICGEN_PROX_CONF_DIR')
+            render.render_content_jinja(pkt_size)
+            # copy some static files to config folder.
+            for stfile in settings.getValue('TRAFFICGEN_PROX_STATIC_CONF_FILES'):
+                srcfile = os.path.join(filesdir, stfile)
+                if os.path.exists(srcfile):
+                    cmd = ['cp', srcfile, confdir ]
+                    tasks.run_task(cmd, self._logger, 'Copying Static Conf. Files')
+            # in appropriate folder: pick /tmp or /opt or $HOME
+            envfile = os.path.join(confdir, settings.getValue('TRAFFICGEN_PROX_ENV_FILE'))
+            tstfile = os.path.join(confdir, settings.getValue('TRAFFICGEN_PROX_TEST_FILE'))
+            mmapfile = os.path.join(confdir, 'machine.map')
+            cmd = ['python', '-m', 'runrapid',
+                   '--env', envfile,
+                   '--test', tstfile,
+                   '--map', mmapfile,
+                   '--runtime', settings.getValue('TRAFFICGEN_PROX_RUNTIME')]
+            output, error = tasks.run_task(cmd, self._logger, 'Running RUN-RAPID command')
+            if output:
+                return self.get_rfc2544_results(output)
+            else:
+                self._logger.info(error)
+                return None
+        else:
+            self._logger.info("Only Baremetal Support is included.")
+            print("Only Baremetal Support is included")
+            return None
+
+
+    def send_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
+                               lossrate=0.0):
+        """
+        Send traffic per RFC2544 BacktoBack test specifications.
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def start_cont_traffic(self, traffic=None, duration=30):
+        """Non-blocking version of 'send_cont_traffic'.
+
+        See ITrafficGenerator for description
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def stop_cont_traffic(self):
+        """Stop continuous transmission and return results.
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def start_rfc2544_back2back(self, traffic=None, tests=1, duration=20,
+                                lossrate=0.0):
+        """Send traffic per RFC2544 back2back test specifications.
+
+        See ITrafficGenerator for description
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def wait_rfc2544_back2back(self):
+        """Wait and set results of RFC2544 test.
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def start_rfc2544_throughput(self, traffic=None, tests=1, duration=20,
+                                 lossrate=0.0):
+        """Non-blocking version of 'send_rfc2544_throughput'.
+        See ITrafficGenerator for description
+        """
+        raise NotImplementedError('Not implemented by PROX')
+
+    def wait_rfc2544_throughput(self):
+        """Wait and set results of RFC2544 test.
+        """
+        raise NotImplementedError('Not implemented by PROX')
diff --git a/tools/pkt_gen/prox/render.py b/tools/pkt_gen/prox/render.py
new file mode 100644
index 00000000..05b49502
--- /dev/null
+++ b/tools/pkt_gen/prox/render.py
@@ -0,0 +1,75 @@
+# Copyright 2021 Spirent Communications.
+#
+# 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.
+
+"""
+Render Jinja templates to corresponding files
+"""
+
+import os
+
+#from conf import merge_spec
+from conf import settings
+from jinja2 import Environment, FileSystemLoader
+
+def listdir_nohidden(path):
+    """
+    Exclude hidden directories
+    """
+    for fname in os.listdir(path):
+        if not fname.startswith('.'):
+            yield fname
+
+def render_content_jinja_baremetal(pkt_size):
+    """
+    Render Templates
+    """
+    templates_dir_path = settings.getValue('TRAFFICGEN_PROX_TEMPLATES_DIR')
+    values_from_vineperf = {
+        'm1_admin_ip' : settings.getValue('TRAFFICGEN_PROX_EAST_MGMT_IP'),
+        'm2_admin_ip' : settings.getValue('TRAFFICGEN_PROX_WEST_MGMT_IP'),
+        'local_ip1' : settings.getValue('TRAFFICGEN_PROX_EAST_IP'),
+        'local_ip2' : settings.getValue('TRAFFICGEN_PROX_WEST_IP'),
+        'local_eip1' : settings.getValue('TRAFFICGEN_PROX_EAST_ENV_IP'),
+        'local_eip2' : settings.getValue('TRAFFICGEN_PROX_WEST_ENV_IP'),
+        'mac1' : settings.getValue('TRAFFICGEN_PROX_EAST_MAC'),
+        'mac2' : settings.getValue('TRAFFICGEN_PROX_WEST_MAC'),
+        'emac1' : settings.getValue('TRAFFICGEN_PROX_EAST_ENV_MAC'),
+        'emac2' : settings.getValue('TRAFFICGEN_PROX_WEST_ENV_MAC'),
+        'pci1': settings.getValue('TRAFFICGEN_PROX_EAST_PCI_ID'),
+        'pci2': settings.getValue('TRAFFICGEN_PROX_WEST_PCI_ID'),
+        'mcore' : settings.getValue('TRAFFICGEN_PROX_MASTER_CORES'),
+        'gencores' : settings.getValue('TRAFFICGEN_PROX_GENERATOR_CORES'),
+        'latcores' : settings.getValue('TRAFFICGEN_PROX_LATENCY_CORES'),
+        'config_file' : os.path.join(settings.getValue('TRAFFICGEN_PROX_CONF_DIR'),
+            settings.getValue('TRAFFICGEN_PROX_GENERATOR_CONFIG_FILENAME')),
+        'user' : settings.getValue('TRAFFICGEN_PROX_GENERATOR_USER'),
+        'key' : os.path.join(settings.getValue('TRAFFICGEN_PROX_CONF_DIR'),
+            settings.getValue('TRAFFICGEN_PROX_GENERATOR_KEYFILE')),
+        'latency_buckets': settings.getValue('TRAFFICGEN_PROX_LATENCY_BUCKETS'),
+    }
+    if pkt_size:
+        values_from_vineperf['pktsizes'] = pkt_size
+    else:
+        values_from_vineperf['pktsizes'] = settings.getValue('TRAFFICGEN_PROX_PKTSIZES')
+
+    file_loader = FileSystemLoader(templates_dir_path)
+    env = Environment(loader = file_loader)
+    destination_dir = settings.getValue("TRAFFICGEN_PROX_CONF_DIR")
+
+    for filename in listdir_nohidden(templates_dir_path):
+        file = env.get_template(filename)
+        rendered_content = file.render(data = values_from_vineperf)
+        filename = os.path.splitext(filename)[0]
+        with open(os.path.join(destination_dir, filename), "w+") as fileh:
+            fileh.write(rendered_content)
diff --git a/tools/pkt_gen/prox/templates/params-vineperf.lua.j2 b/tools/pkt_gen/prox/templates/params-vineperf.lua.j2
new file mode 100644
index 00000000..b389a51a
--- /dev/null
+++ b/tools/pkt_gen/prox/templates/params-vineperf.lua.j2
@@ -0,0 +1,79 @@
+function convertIPToHex(ip)
+  local address_chunks = {}
+  if type(ip) ~= "string" then
+    print ("IP ADDRESS ERROR: ", ip)
+    return "IP ADDRESS ERROR"
+  end
+
+  local chunks = {ip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)(\/%d+)$")}
+  if #chunks == 5 then
+    for i,v in ipairs(chunks) do
+      if i < 5 then
+        if tonumber(v) > 255 then
+          print ("IPV4 ADDRESS ERROR: ", ip)
+          return "IPV4 ADDRESS ERROR"
+        end
+        address_chunks[#address_chunks + 1] = string.format ("%02x", v)
+      end
+    end
+    result = table.concat(address_chunks, " ")
+    print ("Hex IPV4: ", result)
+    return result
+  end
+
+  local chunks = {ip:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")}
+  if #chunks == 4 then
+    for i,v in ipairs(chunks) do
+      if tonumber(v) > 255 then
+        print ("IPV4 ADDRESS ERROR: ", ip)
+        return "IPV4 ADDRESS ERROR"
+      end
+      address_chunks[#address_chunks + 1] = string.format ("%02x", v)
+    end
+    result = table.concat(address_chunks, " ")
+    print ("Hex IPV4: ", result)
+    return result
+  end
+
+  delimiter = ":"
+  for match in (ip..delimiter):gmatch("(.-)"..delimiter) do
+    if match ~= "" then
+      number = tonumber(match, 16)
+      if number <= 65535 then
+        table.insert(address_chunks, string.format("%02x %02x",number/256,number % 256))
+      end
+    else
+      table.insert(address_chunks, "")
+    end
+  end
+  for i, chunk in ipairs(address_chunks) do
+    if chunk =="" then
+      table.remove(address_chunks, i)
+      for j = 1,(8-#address_chunks) do
+        table.insert(address_chunks, i, "00 00")
+      end
+      break
+    end
+  end
+  result = table.concat(address_chunks, " ")
+  print ("Hex IPV6: ", result)
+  return result
+end
+
+eal="--socket-mem=256,0 --file-prefix Generator -w {{data.pci1}} -w {{data.pci2}}"
+name="Generator"
+local_ip1={{data.local_ip1|tojson}}
+local_hex_ip1=convertIPToHex(local_ip1)
+local_ip2={{data.local_ip2|tojson}}
+local_hex_ip2=convertIPToHex(local_ip2)
+mcore={{data.mcore|tojson}}
+dest_ip1={{data.local_ip2|tojson}}
+dest_hex_ip1=convertIPToHex(dest_ip1)
+dest_hex_mac2={{data.mac1|tojson}}
+dest_ip2={{data.local_ip1|tojson}}
+dest_hex_ip2=convertIPToHex(dest_ip2)
+dest_hex_mac1={{data.mac2|tojson}}
+gencores={{data.gencores|tojson}}
+latcores={{data.latcores|tojson}}
+bucket_size_exp={{data.latency_buckets|tojson}}
+heartbeat="60"
diff --git a/tools/pkt_gen/prox/templates/rapid-vineperf-baremetal.env.j2 b/tools/pkt_gen/prox/templates/rapid-vineperf-baremetal.env.j2
new file mode 100644
index 00000000..8823fe2a
--- /dev/null
+++ b/tools/pkt_gen/prox/templates/rapid-vineperf-baremetal.env.j2
@@ -0,0 +1,24 @@
+[rapid]
+loglevel = DEBUG
+version = 19.6.30
+total_number_of_machines = 2
+
+[M1]
+name = rapid-east
+admin_ip = {{data.m1_admin_ip}}
+dp_ip1 = {{data.local_eip1}}
+dp_mac1 = {{data.emac1}}
+
+[M2]
+name = rapid-west
+admin_ip = {{data.m2_admin_ip}}
+dp_ip1 = {{data.local_eip2}}
+dp_mac1 = {{data.emac2}}
+
+[ssh]
+key = {{data.key}}
+user = {{data.user}}
+
+[Varia]
+vim = Openstack
+stack = rapid
diff --git a/tools/pkt_gen/prox/templates/tst009.test.j2 b/tools/pkt_gen/prox/templates/tst009.test.j2
new file mode 100644
index 00000000..86e7cc8d
--- /dev/null
+++ b/tools/pkt_gen/prox/templates/tst009.test.j2
@@ -0,0 +1,34 @@
+[TestParameters]
+name = Rapid_ETSINFV_TST009
+number_of_tests = 1
+total_number_of_test_machines = 2
+lat_percentile = 99
+
+[TestM1]
+name = Generator
+prox_launch_exit = false
+config_file = {{data.config_file}}
+dest_vm = 2
+mcore = [{{data.mcore}}]
+gencores = [{{data.gencores}}]
+latcores = [{{data.latcores}}]
+
+[TestM2]
+name = Dummy
+prox_launch_exit = false
+prox_socket = false
+
+[test1]
+test=TST009test
+warmupflowsize=128
+warmupimix=[64]
+warmupspeed=1
+warmuptime=2
+#imixs=[[64],[128],[256],[512],[1024],[1280],[1512]]
+imixs=[{{data.pktsizes}}]
+flows=[1]
+drop_rate_threshold = 0
+MAXr = 3
+MAXz = 5000
+MAXFramesPerSecondAllIngress = 12000000
+StepSize = 10000
-- 
cgit