LF testbed2 topology, T-REX upgrade, vpe->vpp rename 96/296/21
authorMiroslav Miklus <mmiklus@cisco.com>
Thu, 11 Feb 2016 14:18:12 +0000 (15:18 +0100)
committerGerrit Code Review <gerrit@fd.io>
Wed, 17 Feb 2016 14:46:28 +0000 (14:46 +0000)
Testing testbed2 infrastructure
T-REX upgrade 1.88 -> 1.91
Rename "vpe" to "vpp"

Change-Id: Ia03c363e2b3c77a4e469509460b25028e5e1814f
Signed-off-by: Miroslav Miklus <mmiklus@cisco.com>
resources/libraries/bash/dut_setup.sh
resources/libraries/python/TrafficGenerator.py
resources/libraries/python/VatExecutor.py
resources/libraries/python/constants.py
resources/libraries/python/ssh.py
resources/libraries/python/topology.py
resources/tools/t-rex-installer.sh
resources/tools/t-rex-stateless-1.88.py [new file with mode: 0755]
resources/tools/t-rex-stateless.py
topologies/available/lf_testbed2-710-520.yaml [new file with mode: 0644]
topologies/available/lf_testbed2.yaml [new file with mode: 0644]

index dc36a08..0309228 100644 (file)
@@ -28,9 +28,9 @@ echo
 cat /proc/meminfo
 
 echo
 cat /proc/meminfo
 
 echo
-echo See vpe process
+echo See vpp process
 echo
 echo
-ps aux | grep vpe
+ps aux | grep vpp
 
 echo
 echo See free memory
 
 echo
 echo See free memory
index 24bec0a..2037d49 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Traffic generator library."""
+"""Performance testing traffic generator library."""
 
 from robot.api import logger
 
 from resources.libraries.python.ssh import SSH
 from resources.libraries.python.topology import NodeType
 from resources.libraries.python.topology import NodeSubTypeTG
 
 from robot.api import logger
 
 from resources.libraries.python.ssh import SSH
 from resources.libraries.python.topology import NodeType
 from resources.libraries.python.topology import NodeSubTypeTG
-from resources.libraries.python.topology import Topology
 
 __all__ = ['TrafficGenerator']
 
 
 __all__ = ['TrafficGenerator']
 
@@ -43,6 +42,8 @@ class TrafficGenerator(object):
         :return: nothing
         """
 
         :return: nothing
         """
 
+        trex_path = "/opt/trex-core-1.91"
+
         if node['type'] != NodeType.TG:
             raise Exception('Node type is not a TG')
         if node['subtype'] == NodeSubTypeTG.TREX:
         if node['type'] != NodeType.TG:
             raise Exception('Node type is not a TG')
         if node['subtype'] == NodeSubTypeTG.TREX:
@@ -50,11 +51,14 @@ class TrafficGenerator(object):
             ssh.connect(node)
 
             (ret, stdout, stderr) = ssh.exec_command(
             ssh.connect(node)
 
             (ret, stdout, stderr) = ssh.exec_command(
-                "sh -c 'cd /opt/trex-core-1.88/scripts/ && "
-                "--bind=igb_uio {0} {1}".format(interface1, interface2))
+                "sh -c 'cd {0}/scripts/ && sudo modprobe uio && "
+                "sudo insmod ./ko/src/igb_uio.ko'"\
+                .format(trex_path))
+
             (ret, stdout, stderr) = ssh.exec_command(
             (ret, stdout, stderr) = ssh.exec_command(
-                "sh -c 'cd /opt/trex-core-1.88/scripts/ && "
-                "sudo nohup ./t-rex-64 -i -c 4 --iom 0 > /dev/null 2>&1 &'")
+                "sh -c 'cd {0}/scripts/ && "
+                "sudo nohup ./t-rex-64 -i -c 4 --iom 0 > /dev/null 2>&1 &'"\
+                .format(trex_path))
 
     @staticmethod
     def teardown_traffic_generator(node):
 
     @staticmethod
     def teardown_traffic_generator(node):
@@ -101,55 +105,30 @@ class TrafficGenerator(object):
         ssh = SSH()
         ssh.connect(node)
 
         ssh = SSH()
         ssh.connect(node)
 
-        tg_port3_src_mac = Topology.get_interface_mac_by_port_key(node, "port3")
-        _, adj_int = Topology.\
-            get_adjacent_node_and_interface_by_key(nodes_info, node, "port3")
-        tg_port3_dst_mac = adj_int['mac_address']
-
-        tg_port5_src_mac = Topology.get_interface_mac_by_port_key(node, "port5")
-        _, adj_int = Topology.\
-            get_adjacent_node_and_interface_by_key(nodes_info, node, "port5")
-        tg_port5_dst_mac = adj_int['mac_address']
-
-
         if node['subtype'] == NodeSubTypeTG.TREX:
             if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
                 (ret, stdout, stderr) = ssh.exec_command(
                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex-stateless.py "
                     "-d {0} -r {1}% -s {2} "
         if node['subtype'] == NodeSubTypeTG.TREX:
             if traffic_type in ["3-node-xconnect", "3-node-bridge"]:
                 (ret, stdout, stderr) = ssh.exec_command(
                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex-stateless.py "
                     "-d {0} -r {1}% -s {2} "
-                    "--p1_src_mac 52:00:00:00:00:01 "
-                    "--p1_dst_mac 52:00:00:00:00:02 "
                     "--p1_src_start_ip 10.10.10.1 "
                     "--p1_src_end_ip 10.10.10.254 "
                     "--p1_dst_start_ip 20.20.20.1 "
                     "--p1_src_start_ip 10.10.10.1 "
                     "--p1_src_end_ip 10.10.10.254 "
                     "--p1_dst_start_ip 20.20.20.1 "
-                    "--p1_dst_end_ip 20.20.20.254 "
-                    "--p2_src_mac 52:00:00:00:00:02 "
-                    "--p2_dst_mac 52:00:00:00:00:01 "
                     "--p2_src_start_ip 20.20.20.1 "
                     "--p2_src_end_ip 20.20.20.254 "
                     "--p2_src_start_ip 20.20.20.1 "
                     "--p2_src_end_ip 20.20.20.254 "
-                    "--p2_dst_start_ip 10.10.10.1 "
-                    "--p2_dst_end_ip 10.10.10.254'".\
+                    "--p2_dst_start_ip 10.10.10.1'".\
                     format(duration, rate, framesize), timeout=int(duration)+60)
             elif traffic_type in ["3-node-IPv4"]:
                 (ret, stdout, stderr) = ssh.exec_command(
                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex-stateless.py "
                     "-d {0} -r {1}% -s {2} "
                     format(duration, rate, framesize), timeout=int(duration)+60)
             elif traffic_type in ["3-node-IPv4"]:
                 (ret, stdout, stderr) = ssh.exec_command(
                     "sh -c '/tmp/openvpp-testing/resources/tools/t-rex-stateless.py "
                     "-d {0} -r {1}% -s {2} "
-                    "--p1_src_mac {3} "
-                    "--p1_dst_mac {4} "
                     "--p1_src_start_ip 10.10.10.2 "
                     "--p1_src_end_ip 10.10.10.254 "
                     "--p1_dst_start_ip 20.20.20.2 "
                     "--p1_src_start_ip 10.10.10.2 "
                     "--p1_src_end_ip 10.10.10.254 "
                     "--p1_dst_start_ip 20.20.20.2 "
-                    "--p1_dst_end_ip 20.20.20.2 "
-                    "--p2_src_mac {5} "
-                    "--p2_dst_mac {6} "
                     "--p2_src_start_ip 20.20.20.2 "
                     "--p2_src_end_ip 20.20.20.254 "
                     "--p2_src_start_ip 20.20.20.2 "
                     "--p2_src_end_ip 20.20.20.254 "
-                    "--p2_dst_start_ip 10.10.10.2 "
-                    "--p2_dst_end_ip 10.10.10.2'".\
-                    format(duration, rate, framesize,\
-                           tg_port3_src_mac, tg_port3_dst_mac,\
-                           tg_port5_src_mac, tg_port5_dst_mac),\
-                           timeout=int(duration)+60)
+                    "--p2_dst_start_ip 10.10.10.2'".\
+                    format(duration, rate, framesize),\
+                    timeout=int(duration)+60)
             else:
                 raise NotImplementedError('Unsupported traffic type')
 
             else:
                 raise NotImplementedError('Unsupported traffic type')
 
index aff8c36..d53e57c 100644 (file)
@@ -74,7 +74,7 @@ class VatExecutor(object):
         logger.trace("stdout: '{0}'".format(self._stdout))
         logger.trace("stderr: '{0}'".format(self._stderr))
 
         logger.trace("stdout: '{0}'".format(self._stdout))
         logger.trace("stderr: '{0}'".format(self._stderr))
 
-        # TODO: download vpe_api_test output file
+        # TODO: download vpp_api_test output file
         # self._delete_files(node, remote_file_path, remote_file_out)
 
     def execute_script_json_out(self, vat_name, node, timeout=10,):
         # self._delete_files(node, remote_file_path, remote_file_out)
 
     def execute_script_json_out(self, vat_name, node, timeout=10,):
index d7134ce..f9bbc46 100644 (file)
@@ -16,4 +16,4 @@ class Constants(object):
     RESOURCES_LIB_SH = 'resources/libraries/bash'
     RESOURCES_TPL_VAT = 'resources/templates/vat'
     #OpenVPP VAT binary name
     RESOURCES_LIB_SH = 'resources/libraries/bash'
     RESOURCES_TPL_VAT = 'resources/templates/vat'
     #OpenVPP VAT binary name
-    VAT_BIN_NAME = 'vpe_api_test'
+    VAT_BIN_NAME = 'vpp_api_test'
index 72e41c7..385619c 100644 (file)
@@ -101,7 +101,7 @@ class SSH(object):
             >>> #Execute command without input (sudo -S cmd)
             >>> ssh.exex_command_sudo("ifconfig eth0 down")
             >>> #Execute command with input (sudo -S cmd <<< "input")
             >>> #Execute command without input (sudo -S cmd)
             >>> ssh.exex_command_sudo("ifconfig eth0 down")
             >>> #Execute command with input (sudo -S cmd <<< "input")
-            >>> ssh.exex_command_sudo("vpe_api_test", "dump_interface_table")
+            >>> ssh.exex_command_sudo("vpp_api_test", "dump_interface_table")
         """
         if cmd_input is None:
             command = 'sudo -S {c}'.format(c=cmd)
         """
         if cmd_input is None:
             command = 'sudo -S {c}'.format(c=cmd)
index 3ced69d..6a7ea79 100644 (file)
@@ -323,7 +323,7 @@ class Topology(object):
         This method updates the topology dictionary by querying interface lists
         of all nodes mentioned in the topology dictionary.
         It does this by dumping interface list to json output from all devices
         This method updates the topology dictionary by querying interface lists
         of all nodes mentioned in the topology dictionary.
         It does this by dumping interface list to json output from all devices
-        using vpe_api_test, and pairing known information from topology
+        using vpp_api_test, and pairing known information from topology
         (mac address/pci address of interface) to state from VPP.
         For TG/linux nodes add interface name only.
         """
         (mac address/pci address of interface) to state from VPP.
         For TG/linux nodes add interface name only.
         """
index 28d4ecb..bc36774 100755 (executable)
@@ -1,10 +1,12 @@
 #!/bin/sh
 
 #!/bin/sh
 
+TREX_VERSION="1.91"
+
 TREX_DOWNLOAD_REPO="https://github.com/cisco-system-traffic-generator/trex-core/archive/"
 TREX_DOWNLOAD_REPO="https://github.com/cisco-system-traffic-generator/trex-core/archive/"
-TREX_DOWNLOAD_PACKAGE="v1.88.zip"
+TREX_DOWNLOAD_PACKAGE="v${TREX_VERSION}.zip"
 TREX_PACKAGE_URL="${TREX_DOWNLOAD_REPO}${TREX_DOWNLOAD_PACKAGE}"
 TARGET_DIR="/opt/"
 TREX_PACKAGE_URL="${TREX_DOWNLOAD_REPO}${TREX_DOWNLOAD_PACKAGE}"
 TARGET_DIR="/opt/"
-TREX_DIR="trex-core-1.88/"
+TREX_DIR="trex-core-${TREX_VERSION}/"
 TREX_INSTALL_DIR="${TARGET_DIR}${TREX_DIR}"
 
 if test "$(id -u)" -ne 0
 TREX_INSTALL_DIR="${TARGET_DIR}${TREX_DIR}"
 
 if test "$(id -u)" -ne 0
diff --git a/resources/tools/t-rex-stateless-1.88.py b/resources/tools/t-rex-stateless-1.88.py
new file mode 100755 (executable)
index 0000000..a04f656
--- /dev/null
@@ -0,0 +1,294 @@
+#!/usr/bin/python
+
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# 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.
+
+"""This script uses T-REX stateless API to drive t-rex process.
+
+!!! OUTDATED 1.88 T-REX STATELESS API, USE WITH CAUTION !!!
+
+Requirements:
+- T-REX: https://github.com/cisco-system-traffic-generator/trex-core 
+ - compiled and running T-REX process (eg. ./t-rex-64 -i -c 4)
+ - trex_stl_lib.api library
+- Script must be executed on a node with T-REX instance
+- 2 interfaces must be configured in configuretion file /etc/trex_cfg.yaml
+
+##################### Example of /etc/trex_cfg.yaml ##########################
+- port_limit      : 2 # numbers of ports to use
+  version         : 2
+  interfaces      : ["84:00.0","84:00.1"] # PCI address of interfaces
+  port_info       :  # set eth mac addr 
+          - dest_mac        :   [0x90,0xe2,0xba,0x1f,0x97,0xd5]  # port 0
+            src_mac         :   [0x90,0xe2,0xba,0x1f,0x97,0xd4]
+          - dest_mac        :   [0x90,0xe2,0xba,0x1f,0x97,0xd4]  # port 1
+            src_mac         :   [0x90,0xe2,0xba,0x1f,0x97,0xd5]
+##############################################################################
+
+Functionality:
+1. Configure traffic on running T-REX instance
+2. Clear statistics on all ports
+3. Ctart traffic with specified duration
+4. Print statistics
+
+"""
+
+
+import sys, getopt
+sys.path.insert(0, "/opt/trex-core-1.88/scripts/api/stl/")
+
+from trex_stl_api import *
+
+import dpkt
+import json
+import string
+
+def generate_payload(length):
+    word = ''
+    alphabet_size = len(string.letters)
+    for i in range(length):
+        word += string.letters[(i % alphabet_size)]
+    return word
+
+def create_packets(traffic_options, frame_size=64):
+
+    if frame_size < 64:
+        print "Packet min. size is 64B"
+        sys.exit(2)
+
+    # build A side packet
+    pkt_a = STLPktBuilder()
+
+    pkt_a.add_pkt_layer("l2", dpkt.ethernet.Ethernet())
+    pkt_a.add_pkt_layer("l3_ip", dpkt.ip.IP())
+    pkt_a.add_pkt_layer("l4_udp", dpkt.udp.UDP())
+    pkt_a.set_pkt_payload(generate_payload(frame_size -
+                                           pkt_a.get_packet_length()))
+    pkt_a.set_layer_attr("l3_ip", "len", len(pkt_a.get_layer('l3_ip')))
+
+    # build B side packet
+    pkt_b = pkt_a.clone()
+
+    p1_src_mac = traffic_options['p1_src_mac']
+    p1_dst_mac = traffic_options['p1_dst_mac']
+    p1_src_start_ip = traffic_options['p1_src_start_ip']
+    p1_src_end_ip = traffic_options['p1_src_end_ip']
+    p1_dst_start_ip = traffic_options['p1_dst_start_ip']
+    p1_dst_end_ip = traffic_options['p1_dst_end_ip']
+    p2_src_mac = traffic_options['p2_src_mac']
+    p2_dst_mac = traffic_options['p2_dst_mac']
+    p2_src_start_ip = traffic_options['p2_src_start_ip']
+    p2_src_end_ip = traffic_options['p2_src_end_ip']
+    p2_dst_start_ip = traffic_options['p2_dst_start_ip']
+    p2_dst_end_ip = traffic_options['p2_dst_end_ip']
+
+    pkt_a.set_eth_layer_addr(layer_name="l2",
+                             attr="src",
+                             mac_addr=p1_src_mac)
+    pkt_a.set_eth_layer_addr(layer_name="l2",
+                             attr="dst",
+                             mac_addr=p1_dst_mac)
+    pkt_b.set_eth_layer_addr(layer_name="l2",
+                             attr="src",
+                             mac_addr=p2_src_mac)
+    pkt_b.set_eth_layer_addr(layer_name="l2",
+                             attr="dst",
+                             mac_addr=p2_dst_mac)
+
+    # set IP range for pkt and split it by multiple cores
+    pkt_a.set_vm_ip_range(ip_layer_name="l3_ip",
+                          ip_field="src",
+                          ip_start=p1_src_start_ip, ip_end=p1_src_end_ip,
+                          operation="inc",
+                          split=True)
+
+    pkt_a.set_vm_ip_range(ip_layer_name="l3_ip",
+                          ip_field="dst",
+                          ip_start=p1_dst_start_ip, ip_end=p1_dst_end_ip,
+                          operation="inc")
+
+
+    # build B side packet
+    pkt_b.set_vm_ip_range(ip_layer_name="l3_ip",
+                          ip_field="src",
+                          ip_start=p2_src_start_ip, ip_end=p2_src_end_ip,
+                          operation="inc",
+                          split=True)
+
+    pkt_b.set_vm_ip_range(ip_layer_name="l3_ip",
+                          ip_field="dst",
+                          ip_start=p2_dst_start_ip, ip_end=p2_dst_end_ip,
+                          operation="inc")
+
+    return(pkt_a, pkt_b)
+
+def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps",
+                 warmup=True, warmup_time=5):
+
+    # create client
+    c = STLClient()
+    passed = True
+
+    try:
+        # turn this on for some information
+        #c.set_verbose("high")
+
+        # create two streams
+        s1 = STLStream(packet=pkt_a,
+                       mode=STLTXCont(pps=100))
+
+        # second stream with a phase of 1ms (inter stream gap)
+        s2 = STLStream(packet=pkt_b,
+                       isg=1000,
+                       mode=STLTXCont(pps=100))
+
+
+        # connect to server
+        c.connect()
+
+        # prepare our ports (my machine has 0 <--> 1 with static route)
+        c.reset(ports=[0, 1])
+
+        # add both streams to ports
+        c.add_streams(s1, ports=[0])
+        c.add_streams(s2, ports=[1])
+
+        #warmup phase
+        if warmup == True:
+            c.clear_stats()
+            c.start(ports=[0, 1], mult=rate, duration=warmup_time)
+            c.wait_on_traffic(ports=[0, 1])
+            stats = c.get_stats()
+            print "#####warmup statistics#####"
+            print json.dumps(stats["port 0"], indent=4,
+                             separators=(',', ': '), sort_keys=True)
+            print json.dumps(stats["port 1"], indent=4,
+                             separators=(',', ': '), sort_keys=True)
+            lost_a = stats["port 0"]["opackets"] - stats["port 1"]["ipackets"]
+            lost_b = stats["port 1"]["opackets"] - stats["port 0"]["ipackets"]
+
+            print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
+            print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
+
+
+        # clear the stats before injecting
+        c.clear_stats()
+
+        # choose rate and start traffic
+        c.start(ports=[0, 1], mult=rate, duration=duration)
+
+        # block until done
+        c.wait_on_traffic(ports=[0, 1])
+
+        # read the stats after the test
+        stats = c.get_stats()
+
+        print "#####statistics#####"
+        print json.dumps(stats["port 0"], indent=4,
+                         separators=(',', ': '), sort_keys=True)
+        print json.dumps(stats["port 1"], indent=4,
+                         separators=(',', ': '), sort_keys=True)
+
+        lost_a = stats["port 0"]["opackets"] - stats["port 1"]["ipackets"]
+        lost_b = stats["port 1"]["opackets"] - stats["port 0"]["ipackets"]
+
+        total_sent = stats["port 0"]["opackets"] + stats["port 1"]["opackets"]
+        total_rcvd = stats["port 0"]["ipackets"] + stats["port 1"]["ipackets"]
+
+        print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
+        print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
+        print "rate={0}, totalReceived={1}, totalSent={2}, frameLoss={3}"\
+              .format(rate, total_rcvd, total_sent, lost_a+lost_b)
+
+        if (lost_a == 0) and (lost_b == 0):
+            passed = True
+        else:
+            passed = False
+
+    except STLError as e:
+        passed = False
+        print e
+
+    finally:
+        c.disconnect()
+
+def print_help():
+
+    print "args: [-h] -d <duration> -s <size of frame in bytes>"+\
+    " [-r] <traffic rate with unit: %, mpps> "+\
+    "--p1_src_mac <port1_src_mac> "+\
+    "--p1_dst_mac <port1_dst_mac> "+\
+    "--p1_src_start_ip <port1_src_start_ip> "+\
+    "--p1_src_end_ip <port1_src_end_ip> "+\
+    "--p1_dst_start_ip <port1_dst_start_ip> "+\
+    "--p1_dst_end_ip <port1_dst_end_ip> "+\
+    "--p2_src_mac <port2_src_mac> "+\
+    "--p2_dst_mac <port2_dst_mac> "+\
+    "--p2_src_start_ip <port2_src_start_ip> "+\
+    "--p2_src_end_ip <port2_src_end_ip> "+\
+    "--p2_dst_start_ip <port2_dst_start_ip> "+\
+    "--p2_dst_end_ip <port2_dst_end_ip>"
+
+
+def main(argv):
+
+    _duration = 10
+    _frame_size = 64
+    _rate = '1mpps'
+    _traffic_options = {}
+
+    try:
+        opts, args = getopt.getopt(argv, "hd:s:r:o:",
+                                   ["help",
+                                    "p1_src_mac=",
+                                    "p1_dst_mac=",
+                                    "p1_src_start_ip=",
+                                    "p1_src_end_ip=",
+                                    "p1_dst_start_ip=",
+                                    "p1_dst_end_ip=",
+                                    "p2_src_mac=",
+                                    "p2_dst_mac=",
+                                    "p2_src_start_ip=",
+                                    "p2_src_end_ip=",
+                                    "p2_dst_start_ip=",
+                                    "p2_dst_end_ip="])
+    except getopt.GetoptError:
+        print_help()
+        sys.exit(2)
+    for opt, arg in opts:
+        if opt in ('-h', "--help"):
+            print_help()
+            sys.exit()
+        elif opt == '-d':
+            _duration = int(arg)
+        elif opt == '-s':
+            _frame_size = int(arg)
+        elif opt == '-r':
+            _rate = arg
+        elif opt.startswith( "--p" ):
+            _traffic_options[opt[2:]] = arg
+
+    print _traffic_options
+    if len(_traffic_options) != 12:
+        print "Expected all 12 traffic options"
+        print_help()
+        sys.exit(2)
+
+    pkt_a, pkt_b = create_packets(_traffic_options,
+                                  frame_size=_frame_size)
+
+    simple_burst(pkt_a, pkt_b, duration=_duration, rate=_rate)
+
+if __name__ == "__main__":
+    main(sys.argv[1:])
+
index dfc4ad4..d93a0ac 100755 (executable)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+"""This script uses T-REX stateless API to drive t-rex instance.
+
+Requirements:
+- T-REX: https://github.com/cisco-system-traffic-generator/trex-core 
+ - compiled and running T-REX process (eg. ./t-rex-64 -i -c 4)
+ - trex_stl_lib.api library
+- Script must be executed on a node with T-REX instance
+- 2 interfaces must be configured in configuretion file /etc/trex_cfg.yaml
+
+##################### Example of /etc/trex_cfg.yaml ##########################
+- port_limit      : 2 # numbers of ports to use
+  version         : 2
+  interfaces      : ["84:00.0","84:00.1"] # PCI address of interfaces
+  port_info       :  # set eth mac addr 
+          - dest_mac        :   [0x90,0xe2,0xba,0x1f,0x97,0xd5]  # port 0
+            src_mac         :   [0x90,0xe2,0xba,0x1f,0x97,0xd4]
+          - dest_mac        :   [0x90,0xe2,0xba,0x1f,0x97,0xd4]  # port 1
+            src_mac         :   [0x90,0xe2,0xba,0x1f,0x97,0xd5]
+##############################################################################
+
+Functionality:
+1. Configure traffic on running T-REX instance
+2. Clear statistics on all ports
+3. Ctart traffic with specified duration
+4. Print statistics to stdout
+
+"""
+
 
 import sys, getopt
 
 import sys, getopt
-sys.path.insert(0, "/opt/trex-core-1.88/scripts/api/stl/")
+sys.path.insert(0, "/opt/trex-core-1.91/scripts/automation/trex_control_plane/stl/")
 
 
-from trex_stl_api import *
+from trex_stl_lib.api import *
 
 import dpkt
 import json
 
 import dpkt
 import json
@@ -36,69 +64,42 @@ def create_packets(traffic_options, frame_size=64):
         print "Packet min. size is 64B"
         sys.exit(2)
 
         print "Packet min. size is 64B"
         sys.exit(2)
 
-    # build A side packet
-    pkt_a = STLPktBuilder()
-
-    pkt_a.add_pkt_layer("l2", dpkt.ethernet.Ethernet())
-    pkt_a.add_pkt_layer("l3_ip", dpkt.ip.IP())
-    pkt_a.add_pkt_layer("l4_udp", dpkt.udp.UDP())
-    pkt_a.set_pkt_payload(generate_payload(frame_size -
-                                           pkt_a.get_packet_length()))
-    pkt_a.set_layer_attr("l3_ip", "len", len(pkt_a.get_layer('l3_ip')))
-
-    # build B side packet
-    pkt_b = pkt_a.clone()
+    fsize_no_fcs = frame_size - 4 # no FCS
 
 
-    p1_src_mac = traffic_options['p1_src_mac']
-    p1_dst_mac = traffic_options['p1_dst_mac']
+    #p1_src_mac = traffic_options['p1_src_mac']
+    #p1_dst_mac = traffic_options['p1_dst_mac']
     p1_src_start_ip = traffic_options['p1_src_start_ip']
     p1_src_end_ip = traffic_options['p1_src_end_ip']
     p1_dst_start_ip = traffic_options['p1_dst_start_ip']
     p1_src_start_ip = traffic_options['p1_src_start_ip']
     p1_src_end_ip = traffic_options['p1_src_end_ip']
     p1_dst_start_ip = traffic_options['p1_dst_start_ip']
-    p1_dst_end_ip = traffic_options['p1_dst_end_ip']
-    p2_src_mac = traffic_options['p2_src_mac']
-    p2_dst_mac = traffic_options['p2_dst_mac']
+    #p1_dst_end_ip = traffic_options['p1_dst_end_ip']
+    #p2_src_mac = traffic_options['p2_src_mac']
+    #p2_dst_mac = traffic_options['p2_dst_mac']
     p2_src_start_ip = traffic_options['p2_src_start_ip']
     p2_src_end_ip = traffic_options['p2_src_end_ip']
     p2_dst_start_ip = traffic_options['p2_dst_start_ip']
     p2_src_start_ip = traffic_options['p2_src_start_ip']
     p2_src_end_ip = traffic_options['p2_src_end_ip']
     p2_dst_start_ip = traffic_options['p2_dst_start_ip']
-    p2_dst_end_ip = traffic_options['p2_dst_end_ip']
-
-    pkt_a.set_eth_layer_addr(layer_name="l2",
-                             attr="src",
-                             mac_addr=p1_src_mac)
-    pkt_a.set_eth_layer_addr(layer_name="l2",
-                             attr="dst",
-                             mac_addr=p1_dst_mac)
-    pkt_b.set_eth_layer_addr(layer_name="l2",
-                             attr="src",
-                             mac_addr=p2_src_mac)
-    pkt_b.set_eth_layer_addr(layer_name="l2",
-                             attr="dst",
-                             mac_addr=p2_dst_mac)
-
-    # set IP range for pkt and split it by multiple cores
-    pkt_a.set_vm_ip_range(ip_layer_name="l3_ip",
-                          ip_field="src",
-                          ip_start=p1_src_start_ip, ip_end=p1_src_end_ip,
-                          operation="inc",
-                          split=True)
-
-    pkt_a.set_vm_ip_range(ip_layer_name="l3_ip",
-                          ip_field="dst",
-                          ip_start=p1_dst_start_ip, ip_end=p1_dst_end_ip,
-                          operation="inc")
-
-
-    # build B side packet
-    pkt_b.set_vm_ip_range(ip_layer_name="l3_ip",
-                          ip_field="src",
-                          ip_start=p2_src_start_ip, ip_end=p2_src_end_ip,
-                          operation="inc",
-                          split=True)
-
-    pkt_b.set_vm_ip_range(ip_layer_name="l3_ip",
-                          ip_field="dst",
-                          ip_start=p2_dst_start_ip, ip_end=p2_dst_end_ip,
-                          operation="inc")
+    #p2_dst_end_ip = traffic_options['p2_dst_end_ip']
+
+    base_pkt_a = Ether()/IP(src=p1_src_start_ip, dst=p1_dst_start_ip)/UDP(dport=12, sport=1025, chksum=0)
+    base_pkt_b = Ether()/IP(src=p2_src_start_ip, dst=p2_dst_start_ip)/UDP(dport=12, sport=1025, chksum=0)
+
+    vm1 = CTRexScRaw([STLVmTupleGen(ip_min=p1_src_start_ip, ip_max=p1_src_end_ip,
+                                    name="tuple"), # define tuple gen
+
+                      STLVmWrFlowVar(fv_name="tuple.ip", pkt_offset="IP.src"), # write ip to packet IP.src
+                      STLVmFixIpv4(offset="IP"),                               # fix checksum
+                     ]
+                     , split_by_field="tuple") # split to cores base on the tuple generator
+    vm2 = CTRexScRaw([STLVmTupleGen(ip_min=p2_src_start_ip, ip_max=p2_src_end_ip,
+                                    name="tuple"), # define tuple gen
+
+                      STLVmWrFlowVar(fv_name="tuple.ip", pkt_offset="IP.src"), # write ip to packet IP.src
+                      STLVmFixIpv4(offset="IP"),                               # fix checksum
+                     ]
+                     , split_by_field="tuple") # split to cores base on the tuple generator
+
+    pkt_a = STLPktBuilder(pkt=base_pkt_a/generate_payload(fsize_no_fcs-len(base_pkt_a)), vm=vm1)
+    pkt_b = STLPktBuilder(pkt=base_pkt_b/generate_payload(fsize_no_fcs-len(base_pkt_b)), vm=vm2)
 
     return(pkt_a, pkt_b)
 
 
     return(pkt_a, pkt_b)
 
@@ -117,9 +118,9 @@ def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps",
         s1 = STLStream(packet=pkt_a,
                        mode=STLTXCont(pps=100))
 
         s1 = STLStream(packet=pkt_a,
                        mode=STLTXCont(pps=100))
 
-        # second stream with a phase of 1ms (inter stream gap)
+        # second stream with a phase of 10ns (inter stream gap)
         s2 = STLStream(packet=pkt_b,
         s2 = STLStream(packet=pkt_b,
-                       isg=1000,
+                       isg=10.0,
                        mode=STLTXCont(pps=100))
 
 
                        mode=STLTXCont(pps=100))
 
 
@@ -139,13 +140,12 @@ def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps",
             c.start(ports=[0, 1], mult=rate, duration=warmup_time)
             c.wait_on_traffic(ports=[0, 1])
             stats = c.get_stats()
             c.start(ports=[0, 1], mult=rate, duration=warmup_time)
             c.wait_on_traffic(ports=[0, 1])
             stats = c.get_stats()
+            print stats
             print "#####warmup statistics#####"
             print "#####warmup statistics#####"
-            print json.dumps(stats["port 0"], indent=4,
+            print json.dumps(stats, indent=4,
                              separators=(',', ': '), sort_keys=True)
                              separators=(',', ': '), sort_keys=True)
-            print json.dumps(stats["port 1"], indent=4,
-                             separators=(',', ': '), sort_keys=True)
-            lost_a = stats["port 0"]["opackets"] - stats["port 1"]["ipackets"]
-            lost_b = stats["port 1"]["opackets"] - stats["port 0"]["ipackets"]
+            lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
+            lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
 
             print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
             print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
 
             print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
             print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
@@ -164,16 +164,14 @@ def simple_burst(pkt_a, pkt_b, duration=10, rate="1mpps",
         stats = c.get_stats()
 
         print "#####statistics#####"
         stats = c.get_stats()
 
         print "#####statistics#####"
-        print json.dumps(stats["port 0"], indent=4,
-                         separators=(',', ': '), sort_keys=True)
-        print json.dumps(stats["port 1"], indent=4,
+        print json.dumps(stats, indent=4,
                          separators=(',', ': '), sort_keys=True)
 
                          separators=(',', ': '), sort_keys=True)
 
-        lost_a = stats["port 0"]["opackets"] - stats["port 1"]["ipackets"]
-        lost_b = stats["port 1"]["opackets"] - stats["port 0"]["ipackets"]
+        lost_a = stats[0]["opackets"] - stats[1]["ipackets"]
+        lost_b = stats[1]["opackets"] - stats[0]["ipackets"]
 
 
-        total_sent = stats["port 0"]["opackets"] + stats["port 1"]["opackets"]
-        total_rcvd = stats["port 0"]["ipackets"] + stats["port 1"]["ipackets"]
+        total_sent = stats[0]["opackets"] + stats[1]["opackets"]
+        total_rcvd = stats[0]["ipackets"] + stats[1]["ipackets"]
 
         print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
         print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
 
         print "\npackets lost from 0 --> 1:   {0} pkts".format(lost_a)
         print "packets lost from 1 --> 0:   {0} pkts".format(lost_b)
@@ -245,12 +243,12 @@ def main(argv):
             _frame_size = int(arg)
         elif opt == '-r':
             _rate = arg
             _frame_size = int(arg)
         elif opt == '-r':
             _rate = arg
-        elif opt.startswith( "--p" ):
+        elif opt.startswith("--p"):
             _traffic_options[opt[2:]] = arg
 
     print _traffic_options
             _traffic_options[opt[2:]] = arg
 
     print _traffic_options
-    if len(_traffic_options) != 12:
-        print "Expected all 12 traffic options"
+    if len(_traffic_options) != 6:
+        print "Supported only: src_start_ip, src_end_ip, dst_start_ip"
         print_help()
         sys.exit(2)
 
         print_help()
         sys.exit(2)
 
diff --git a/topologies/available/lf_testbed2-710-520.yaml b/topologies/available/lf_testbed2-710-520.yaml
new file mode 100644 (file)
index 0000000..b272387
--- /dev/null
@@ -0,0 +1,57 @@
+---
+metadata:
+  version: 0.1
+  schema:
+    - resources/topology_schemas/3_node_topology.sch.yaml
+    - resources/topology_schemas/topology.sch.yaml
+  tags: [hw, 3-node]
+
+nodes:
+  TG:
+    type: TG
+    subtype: TREX
+    host: "10.30.51.20"
+    port: 22
+    username: testuser
+    password: Cisco1234
+    interfaces:
+      port3:
+        mac_address: "3c:fd:fe:9c:ed:5c"
+        pci_address: "0000:05:00.0"
+        link: link1
+        driver: i40e
+      port5:
+        mac_address: "3c:fd:fe:9c:ed:5d"
+        pci_address: "0000:05:00.1"
+        link: link2
+        driver: i40e
+  DUT1:
+    type: DUT
+    host: "10.30.51.21"
+    port: 22
+    username: testuser
+    password: Cisco1234
+    interfaces:
+      port1:
+        mac_address: "90:e2:ba:b5:02:b9"
+        pci_address: "0000:0a:00.1"
+        link: link1
+      port3:
+        mac_address: "90:e2:ba:b5:02:b8"
+        pci_address: "0000:0a:00.0"
+        link: link3
+  DUT2:
+    type: DUT
+    host: "10.30.51.22"
+    port: 22
+    username: testuser
+    password: Cisco1234
+    interfaces:
+      port1:
+        mac_address: "90:e2:ba:b5:01:d8"
+        pci_address: "0000:0a:00.0"
+        link: link2
+      port3:
+        mac_address: "90:e2:ba:b5:01:d9"
+        pci_address: "0000:0a:00.1"
+        link: link3
diff --git a/topologies/available/lf_testbed2.yaml b/topologies/available/lf_testbed2.yaml
new file mode 100644 (file)
index 0000000..0bd8935
--- /dev/null
@@ -0,0 +1,57 @@
+---
+metadata:
+  version: 0.1
+  schema:
+    - resources/topology_schemas/3_node_topology.sch.yaml
+    - resources/topology_schemas/topology.sch.yaml
+  tags: [hw, 3-node]
+
+nodes:
+  TG:
+    type: TG
+    subtype: TREX
+    host: "10.30.51.20"
+    port: 22
+    username: testuser
+    password: Cisco1234
+    interfaces:
+      port3:
+        mac_address: "3c:fd:fe:9c:ed:7c"
+        pci_address: "0000:88:00.0"
+        link: link1
+        driver: i40e
+      port5:
+        mac_address: "3c:fd:fe:9c:ed:7d"
+        pci_address: "0000:88:00.1"
+        link: link2
+        driver: i40e
+  DUT1:
+    type: DUT
+    host: "10.30.51.21"
+    port: 22
+    username: testuser
+    password: Cisco1234
+    interfaces:
+      port1:
+        mac_address: "3c:fd:fe:9c:ee:ed"
+        pci_address: "0000:87:00.1"
+        link: link1
+      port3:
+        mac_address: "3c:fd:fe:9c:ee:ec"
+        pci_address: "0000:87:00.0"
+        link: link3
+  DUT2:
+    type: DUT
+    host: "10.30.51.22"
+    port: 22
+    username: testuser
+    password: Cisco1234
+    interfaces:
+      port1:
+        mac_address: "3c:fd:fe:9c:ee:e4"
+        pci_address: "0000:87:00.0"
+        link: link2
+      port3:
+        mac_address: "3c:fd:fe:9c:ee:e5"
+        pci_address: "0000:87:00.1"
+        link: link3