summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimarom <imarom@cisco.com>2017-02-26 14:21:07 +0200
committerimarom <imarom@cisco.com>2017-02-26 14:26:51 +0200
commitf34d418db773ad900a0dfb600d66d4892bb8a341 (patch)
tree2f5c27957340646643079b059d93e1a25a746b03
parentbed055d35b3ce5be1dd68ea7635dcf2e2da81567 (diff)
added 'pkt' console command to help with debugging single packets transmit
Signed-off-by: imarom <imarom@cisco.com>
-rwxr-xr-xscripts/automation/trex_control_plane/stl/console/trex_console.py8
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py46
-rwxr-xr-xscripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py80
3 files changed, 133 insertions, 1 deletions
diff --git a/scripts/automation/trex_control_plane/stl/console/trex_console.py b/scripts/automation/trex_control_plane/stl/console/trex_console.py
index 5d758fba..a0ff472d 100755
--- a/scripts/automation/trex_control_plane/stl/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/stl/console/trex_console.py
@@ -580,6 +580,14 @@ class TRexConsole(TRexGeneralCmd):
def help_service (self, line):
self.do_service("-h")
+ @verify_connected
+ def do_pkt (self, line):
+ '''Sends a scapy notation packet'''
+ self.stateless_client.pkt_line(line)
+
+ def help_pkt (self, line):
+ self.do_pkt("-h")
+
def help_clear(self):
self.do_clear("-h")
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],