From f34d418db773ad900a0dfb600d66d4892bb8a341 Mon Sep 17 00:00:00 2001
From: imarom <imarom@cisco.com>
Date: Sun, 26 Feb 2017 14:21:07 +0200
Subject: added 'pkt' console command to help with debugging single packets
 transmit

Signed-off-by: imarom <imarom@cisco.com>
---
 .../stl/trex_stl_lib/trex_stl_client.py            | 46 +++++++++++++
 .../stl/trex_stl_lib/utils/parsing_opts.py         | 80 +++++++++++++++++++++-
 2 files changed, 125 insertions(+), 1 deletion(-)

(limited to 'scripts/automation/trex_control_plane/stl/trex_stl_lib')

diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
index a3e04ab6..6b5183ba 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
@@ -4412,3 +4412,49 @@ class STLClient(object):
         self.set_service_mode(ports = opts.ports, enabled = opts.enabled)
         
 
+    @__console
+    def pkt_line (self, line):
+        '''
+            Sends a Scapy format packet
+        '''
+        
+        parser = parsing_opts.gen_parser(self,
+                                         "pkt",
+                                         self.pkt_line.__doc__,
+                                         parsing_opts.PORT_LIST_WITH_ALL,
+                                         parsing_opts.FORCE,
+                                         parsing_opts.COUNT,
+                                         parsing_opts.DRY_RUN,
+                                         parsing_opts.SCAPY_PKT_CMD)
+
+        opts = parser.parse_args(line.split())
+        if not opts:
+            return opts
+            
+        # show layers option
+        if opts.layers:
+            self.logger.log(format_text('\nRegistered Layers:\n', 'underline'))
+            self.logger.log(parsing_opts.ScapyDecoder.formatted_layers())
+            return
+
+        # dry run option
+        if opts.dry:
+            self.logger.log(format_text('\nPacket (Size: {0}):\n'.format(format_num(len(opts.scapy_pkt), suffix = 'B')), 'bold', 'underline'))
+            opts.scapy_pkt.show2()
+            self.logger.log(format_text('\n*** DRY RUN - no traffic was injected ***\n', 'bold'))
+            return
+            
+            
+        self.logger.pre_cmd("Pushing {0} packet(s) (size: {1}) on port(s) {2}:".format(opts.count if opts.count else 'infinite',
+                                                                                       len(opts.scapy_pkt), opts.ports))
+        
+        try:
+            with self.logger.supress():
+                self.push_packets(pkts = bytes(opts.scapy_pkt), ports = opts.ports, force = opts.force, count = opts.count)
+        except STLError as e:
+            self.logger.post_cmd(False)
+            raise
+        else:
+            self.logger.post_cmd(RC_OK())
+        
+    
\ No newline at end of file
diff --git a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
index cb2c9814..dabc7320 100755
--- a/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
@@ -8,6 +8,8 @@ from .constants import ON_OFF_DICT, UP_DOWN_DICT, FLOW_CTRL_DICT
 import sys
 import re
 import os
+import inspect
+
 
 ArgumentPack = namedtuple('ArgumentPack', ['name_or_flags', 'options'])
 ArgumentGroup = namedtuple('ArgumentGroup', ['type', 'args', 'options'])
@@ -73,6 +75,10 @@ DST_IPV4
 
 CAPTURE_ID
 
+SCAPY_PKT
+SHOW_LAYERS
+SCAPY_PKT_CMD
+
 GLOBAL_STATS
 PORT_STATS
 PORT_STATUS
@@ -91,6 +97,8 @@ MONITOR_TYPE_VERBOSE
 MONITOR_TYPE_PIPE
 MONITOR_TYPE
 
+
+
 # ALL_STREAMS
 # STREAM_LIST_WITH_ALL
 
@@ -259,6 +267,59 @@ def is_valid_file(filename):
 
     return filename
 
+# scapy decoder class for parsing opts
+class ScapyDecoder(object):
+    scapy_layers = None
+    
+    @staticmethod
+    def init ():
+        # one time
+        if ScapyDecoder.scapy_layers:
+            return
+        
+        
+            
+        import scapy.all
+        import scapy.layers.dhcp
+        
+        raw = {}
+        
+        # default layers
+        raw.update(scapy.all.__dict__)
+        
+        # extended layers - add here
+        raw.update(scapy.layers.dhcp.__dict__)
+        
+        ScapyDecoder.scapy_layers = {k: v for k, v in raw.items() if inspect.isclass(v) and issubclass(v, scapy.all.Packet)}
+        
+        
+    @staticmethod
+    def to_scapy(scapy_str):
+        ScapyDecoder.init()
+        
+        try:
+            scapy_obj = eval(scapy_str, {'__builtins__': {}, 'True': True, 'False': False}, ScapyDecoder.scapy_layers)
+            len(scapy_obj)
+            return scapy_obj
+        except Exception as e:
+            raise argparse.ArgumentTypeError("invalid scapy expression: '{0}' - {1}".format(scapy_str, str(e)))
+
+        
+    @staticmethod
+    def formatted_layers ():
+        ScapyDecoder.init()
+        
+        output = ''
+        for k, v in sorted(ScapyDecoder.scapy_layers.items()):
+            name    = format_text("'{}'".format(k), 'bold')
+            descr   = v.name
+            #fields  = ", ".join(["'%s'" % f.name for f in v.fields_desc])
+            #print("{:<50} - {} ({})".format(name ,descr, fields))
+            output += "{:<50} - {}\n".format(name ,descr)
+            
+        return output
+        
+        
 def check_ipv4_addr (ipv4_str):
     if not is_valid_ipv4(ipv4_str):
         raise argparse.ArgumentTypeError("invalid IPv4 address: '{0}'".format(ipv4_str))
@@ -355,7 +416,7 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                     'default':  1.0,
                                     'type': float}),
 
-              COUNT: ArgumentPack(['-n', '--count'],
+              COUNT: ArgumentPack(['-c', '--count'],
                                   {'help': "How many times to perform action [default is 1, 0 means forever]",
                                    'dest': "count",
                                    'default':  1,
@@ -660,6 +721,23 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                    'type': int,
                                    'required': True}),
 
+              
+              SCAPY_PKT: ArgumentPack(['-s'],
+                                      {'dest':'scapy_pkt',
+                                       'metavar': 'PACKET',
+                                       'type': ScapyDecoder.to_scapy,
+                                       'help': 'A scapy notation packet (e.g.: Ether()/IP())'}),
+               
+              SHOW_LAYERS: ArgumentPack(['--layers', '-l'],
+                                        {'action': 'store_true',
+                                         'dest': 'layers',
+                                         'help': "Show all registered layers / inspect a specific layer"}),
+              
+              
+              SCAPY_PKT_CMD: ArgumentGroup(MUTEX, [SCAPY_PKT,
+                                                   SHOW_LAYERS],
+                                           {'required': True}),
+              
               # advanced options
               PORT_LIST_WITH_ALL: ArgumentGroup(MUTEX, [PORT_LIST,
                                                         ALL_PORTS],
-- 
cgit