From f34d418db773ad900a0dfb600d66d4892bb8a341 Mon Sep 17 00:00:00 2001 From: imarom 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 --- .../trex_control_plane/stl/console/trex_console.py | 8 +++ .../stl/trex_stl_lib/trex_stl_client.py | 46 +++++++++++++ .../stl/trex_stl_lib/utils/parsing_opts.py | 80 +++++++++++++++++++++- 3 files changed, 133 insertions(+), 1 deletion(-) 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], -- cgit 1.2.3-korg