many capture modes in Python console 60/5260/1
authorimarom <[email protected]>
Wed, 18 Jan 2017 11:08:41 +0000 (13:08 +0200)
committerimarom <[email protected]>
Wed, 18 Jan 2017 11:08:41 +0000 (13:08 +0200)
Signed-off-by: imarom <[email protected]>
scripts/automation/trex_control_plane/stl/console/trex_capture.py
scripts/automation/trex_control_plane/stl/console/trex_console.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/trex_stl_client.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/parsing_opts.py
scripts/automation/trex_control_plane/stl/trex_stl_lib/utils/text_opts.py
src/rpc-server/commands/trex_rpc_cmd_general.cpp
src/rpc-server/commands/trex_rpc_cmds.h
src/stateless/messaging/trex_stateless_messaging.cpp
src/stateless/messaging/trex_stateless_messaging.h
src/stateless/rx/trex_stateless_capture.cpp
src/stateless/rx/trex_stateless_capture.h

index 922497d..e5708e9 100644 (file)
@@ -1,7 +1,7 @@
 from trex_stl_lib.api import *
 from trex_stl_lib.utils import parsing_opts, text_tables
 import threading
-
+import tempfile
 
 class CaptureMonitorWriter(object):
     def init (self):
@@ -27,7 +27,7 @@ class CaptureMonitorWriterStdout(CaptureMonitorWriter):
     def init (self):
         self.logger.log(format_text("\nStarting capture monitor on selected ports", 'bold'))
         self.logger.log(format_text("*** any captured packet will be displayed on screen ***\n"))
-        self.logger.log(format_text("('capture monitor --stop' to abort capturing...)\n", 'bold')) 
+        self.logger.log(format_text("('capture monitor stop' to abort capturing...)\n", 'bold')) 
         
         
     def deinit (self):
@@ -81,18 +81,42 @@ class CaptureMonitorWriterPipe(CaptureMonitorWriter):
         self.logger   = logger
         
     def init (self):
-        self.fifo_name = '/tmp/out.fif'
-        if os.path.exists(self.fifo_name):
-            os.unlink(self.fifo_name)
+        self.fifo_name = tempfile.mktemp()
+        
+        try:
+            os.mkfifo(self.fifo_name)
+
+            self.logger.log(format_text("\nPlease run 'wireshark -k -i {0}'".format(self.fifo_name), 'bold'))
+            self.logger.log('\nWaiting for Wireshark connection...')
+            
+            self.fifo = os.open(self.fifo_name, os.O_WRONLY)
+            self.logger.log('Successfuly connected to Wireshark...')
+            self.logger.log(format_text('\n*** Capture monitoring started ***\n', 'bold'))
             
-        os.mkfifo(self.fifo_name)
-        self.fifo = os.open(self.fifo_name, os.O_WRONLY)
+            self.writer = RawPcapWriter(self.fifo_name, linktype = 1, sync = True)
+            self.writer._write_header(None)
+
+        except KeyboardInterrupt as e:
+            os.unlink(self.fifo_name)
+            raise STLError("*** pipe monitor aborted...cleaning up")
+
+        except OSError as e:
+            os.unlink(self.fifo_name)
+            raise STLError("failed to create pipe {0}\n{1}".format(self.fifo_name, str(e)))
+        
+        
+    def deinit (self):
+        os.unlink(self.fifo_name)
+
         
-        self.writer = RawPcapWriter(self.fifo_name, linktype = 1, sync = True)
-        self.writer._write_header(None)
-    
     def handle_pkts (self, pkts):
-        pass
+        for pkt in pkts:
+            pkt_bin = base64.b64decode(pkt['binary'])
+            try:
+                self.writer._write_packet(pkt_bin, sec = 0, usec = 0)
+            except IOError:
+                klgjdf
+
         
         
 class CaptureMonitor(object):
@@ -127,14 +151,14 @@ class CaptureMonitor(object):
             raise STLError('unknown writer type')
             
         
-        self.writer.init()
-    
         with self.logger.supress():
                 self.capture_id = self.client.start_capture(tx_port_list, rx_port_list, limit = rate_pps)
 
         self.tx_port_list = tx_port_list
         self.rx_port_list = rx_port_list
         
+        self.writer.init()
+
         self.t = threading.Thread(target = self.__thread_cb)
         self.t.setDaemon(True)
         
@@ -154,6 +178,7 @@ class CaptureMonitor(object):
             self.client.stop_capture(self.capture_id, None)
             self.capture_id = -1
             self.writer.deinit()
+
             
     def get_mon_row (self):
         if not self.is_active():
@@ -215,7 +240,7 @@ class CaptureMonitor(object):
             pkts = rc.data()['pkts']
             if not pkts:
                 continue
-                
+            
             self.writer.handle_pkts(pkts)
                 
 
@@ -232,33 +257,50 @@ class CaptureManager(object):
         # install parsers
         
         self.parser = parsing_opts.gen_parser(self, "capture", self.parse_line_internal.__doc__)
-        subparsers = self.parser.add_subparsers(title = "commands", dest="commands")
+        self.subparsers = self.parser.add_subparsers(title = "commands", dest="commands")
+
+        self.install_record_parser()
+        self.install_monitor_parser()
+        
+        # show
+        self.show_parser = self.subparsers.add_parser('show', help = "show all active captures")
+     
+        # reset
+        self.clear_parser = self.subparsers.add_parser('clear', help = "remove all active captures")
+       
+        # register handlers
+        self.cmds = {'record': self.parse_record, 'monitor' : self.parse_monitor, 'clear': self.parse_clear, 'show' : self.parse_show} 
+        
+        
+    def install_record_parser (self):
+        # recording
+        self.record_parser = self.subparsers.add_parser('record', help = "PCAP recording")
+        record_sub = self.record_parser.add_subparsers(title = 'commands', dest = 'record_cmd')
+        self.record_start_parser = record_sub.add_parser('start', help = "starts a new buffered capture")
+        self.record_stop_parser  = record_sub.add_parser('stop', help = "stops an active buffered capture")
 
         # start
-        self.start_parser = subparsers.add_parser('start', help = "starts a new buffered capture")
-        self.start_parser.add_arg_list(parsing_opts.TX_PORT_LIST,
-                                       parsing_opts.RX_PORT_LIST,
-                                       parsing_opts.LIMIT)
+        self.record_start_parser.add_arg_list(parsing_opts.TX_PORT_LIST,
+                                              parsing_opts.RX_PORT_LIST,
+                                              parsing_opts.LIMIT)
 
         # stop
-        self.stop_parser = subparsers.add_parser('stop', help = "stops an active capture")
-        self.stop_parser.add_arg_list(parsing_opts.CAPTURE_ID,
-                                      parsing_opts.OUTPUT_FILENAME)
-
-        # show
-        self.show_parser = subparsers.add_parser('show', help = "show all active captures")
+        self.record_stop_parser.add_arg_list(parsing_opts.CAPTURE_ID,
+                                             parsing_opts.OUTPUT_FILENAME)
 
+        
+        
+    def install_monitor_parser (self):
         # monitor
-        self.monitor_parser = subparsers.add_parser('monitor', help = "attach a constant monitor to port(s)")
-        self.monitor_parser.add_arg_list(parsing_opts.TX_PORT_LIST,
-                                         parsing_opts.RX_PORT_LIST,
-                                         parsing_opts.MONITOR_TYPE)
+        self.monitor_parser = self.subparsers.add_parser('monitor', help = 'live monitoring')
+        monitor_sub = self.monitor_parser.add_subparsers(title = 'commands', dest = 'mon_cmd')
+        self.monitor_start_parser = monitor_sub.add_parser('start', help = 'starts a monitor')
+        self.monitor_stop_parser  = monitor_sub.add_parser('stop', help = 'stops an active monitor')
+
+        self.monitor_start_parser.add_arg_list(parsing_opts.TX_PORT_LIST,
+                                               parsing_opts.RX_PORT_LIST,
+                                               parsing_opts.MONITOR_TYPE)
 
-        # reset
-        self.clear_parser = subparsers.add_parser('clear', help = "remove all active captures")
-       
-        # register handlers
-        self.cmds = {'start': self.parse_start, 'stop' : self.parse_stop, 'clear': self.parse_clear, 'monitor': self.parse_monitor, 'show' : self.parse_show} 
         
         
     def stop (self):
@@ -289,22 +331,48 @@ class CaptureManager(object):
         self.cmds[opts.commands](opts)
 
 
-    def parse_start (self, opts):
+    # record methods
+    def parse_record (self, opts):
+        if opts.record_cmd == 'start':
+            self.parse_record_start(opts)
+        elif opts.record_cmd == 'stop':
+            self.parse_record_stop(opts)
+        else:
+            assert(0)
+            
+    def parse_record_start (self, opts):
         if not opts.tx_port_list and not opts.rx_port_list:
-            self.start_parser.formatted_error('please provide either --tx or --rx')
+            self.record_start_parser.formatted_error('please provide either --tx or --rx')
             return
 
         self.c.start_capture(opts.tx_port_list, opts.rx_port_list, opts.limit)
             
         
-    def parse_stop (self, opts):
-        if self.monitor.is_active() and self.monitor.get_capture_id() == opts.capture_id:
-            self.monitor.stop()
-        else:
-            self.c.stop_capture(opts.capture_id, opts.output_filename)
+    def parse_record_stop (self, opts):
+        captures = self.c.get_capture_status()
+        ids = [c['id'] for c in captures]
+        
+        if opts.capture_id == self.monitor.get_capture_id():
+            self.record_stop_parser.formatted_error("'{0}' is a monitor, please use 'capture monitor stop'".format(opts.capture_id))
+            return
+            
+        if opts.capture_id not in ids:
+            self.record_stop_parser.formatted_error("'{0}' is not an active capture ID".format(opts.capture_id))
+            return
+            
+        self.c.stop_capture(opts.capture_id, opts.output_filename)
 
             
+    # monitor methods
     def parse_monitor (self, opts):
+        if opts.mon_cmd == 'start':
+            self.parse_monitor_start(opts)
+        elif opts.mon_cmd == 'stop':
+            self.parse_monitor_stop(opts)
+        else:
+            assert(0)
+            
+    def parse_monitor_start (self, opts):
         mon_type = 'compact'
         
         if opts.verbose:
@@ -312,10 +380,15 @@ class CaptureManager(object):
         elif opts.pipe:
             mon_type = 'pipe'
             
-            
+        if not opts.tx_port_list and not opts.rx_port_list:
+            self.monitor_start_parser.formatted_error('please provide either --tx or --rx')
+            return
+        
         self.monitor.stop()
-        self.monitor.start(opts.tx_port_list, opts.rx_port_list, 10, mon_type)
+        self.monitor.start(opts.tx_port_list, opts.rx_port_list, 100, mon_type)
     
+    def parse_monitor_stop (self, opts):
+        self.monitor.stop()
         
     def parse_clear (self, opts):
         self.monitor.stop()
@@ -357,9 +430,9 @@ class CaptureManager(object):
         mon_table.header(['ID', 'Packets Seen', 'Bytes Seen', 'TX Ports', 'RX Ports'])
 
         if cap_table._rows:
-            text_tables.print_table_with_header(cap_table, "Buffers")
+            text_tables.print_table_with_header(cap_table, '\nActive Recorders')
 
         if mon_table._rows:
-            text_tables.print_table_with_header(mon_table, "Monitors")
+            text_tables.print_table_with_header(mon_table, '\nActive Monitor')
 
 
index b0ab70e..bf54304 100755 (executable)
@@ -29,6 +29,8 @@ import string
 import os
 import sys
 import tty, termios
+from threading import Lock
+import threading
 
 try:
     import stl_path
@@ -39,6 +41,7 @@ from trex_stl_lib.api import *
 from trex_stl_lib.utils.text_opts import *
 from trex_stl_lib.utils.common import user_input, get_current_user
 from trex_stl_lib.utils import parsing_opts
+from .trex_capture import CaptureManager
 
 try:
     import trex_tui
@@ -172,6 +175,8 @@ class TRexConsole(TRexGeneralCmd):
 
     def __init__(self, stateless_client, verbose = False):
 
+        self.cmd_lock = Lock()
+        
         self.stateless_client = stateless_client
 
         TRexGeneralCmd.__init__(self)
@@ -184,8 +189,11 @@ class TRexConsole(TRexGeneralCmd):
         self.intro  = "\n-=TRex Console v{ver}=-\n".format(ver=__version__)
         self.intro += "\nType 'help' or '?' for supported actions\n"
 
+        self.cap_mngr = CaptureManager(stateless_client, self.cmd_lock)
+
         self.postcmd(False, "")
 
+        
 
     ################### internal section ########################
 
@@ -231,6 +239,7 @@ class TRexConsole(TRexGeneralCmd):
 
         lines = line.split(';')
         try:
+            self.cmd_lock.acquire()
             for line in lines:
                 stop = self.onecmd(line)
                 stop = self.postcmd(stop, line)
@@ -238,10 +247,15 @@ class TRexConsole(TRexGeneralCmd):
                     return "quit"
     
             return ""
+            
         except STLError as e:
             print(e)
             return ''
 
+        finally:
+            self.cmd_lock.release()
+
+
 
     def postcmd(self, stop, line):
         self.prompt = self.stateless_client.generate_prompt(prefix = 'trex')
@@ -349,7 +363,7 @@ class TRexConsole(TRexGeneralCmd):
     @verify_connected
     def do_capture (self, line):
         '''Manage PCAP captures'''
-        self.stateless_client.capture_line(line)
+        self.cap_mngr.parse_line(line)
 
     def help_capture (self):
         self.do_capture("-h")
@@ -443,7 +457,9 @@ class TRexConsole(TRexGeneralCmd):
 
     def do_disconnect (self, line):
         '''Disconnect from the server\n'''
-
+        
+        # stop any monitors before disconnecting
+        self.cap_mngr.stop()
         self.stateless_client.disconnect_line(line)
 
 
@@ -688,6 +704,7 @@ class TRexConsole(TRexGeneralCmd):
              l=help.splitlines()
              print("{:<30} {:<30}".format(cmd + " - ",l[0] ))
 
+             
     # a custorm cmdloop wrapper
     def start(self):
         while True:
@@ -702,6 +719,9 @@ class TRexConsole(TRexGeneralCmd):
                     self.intro = None
                     continue
 
+            finally:
+                self.cap_mngr.stop()
+
         if self.terminal:
             self.terminal.kill()
 
@@ -934,6 +954,8 @@ def main():
         with stateless_client.logger.supress():
             stateless_client.disconnect(stop_traffic = False)
 
+
+
 if __name__ == '__main__':
     
     main()
index d75c554..c632ad7 100755 (executable)
@@ -17,10 +17,12 @@ from .utils.text_opts import *
 from functools import wraps
 from texttable import ansi_len
 
+
 from collections import namedtuple
 from yaml import YAMLError
 import time
 import datetime
+import threading
 import re
 import random
 import json
@@ -601,7 +603,7 @@ class STLClient(object):
                                                                  self.util_stats,
                                                                  self.xstats,
                                                                  self.async_client.monitor)
-
+        
     ############# private functions - used by the class itself ###########
 
     
@@ -2981,7 +2983,7 @@ class STLClient(object):
         self.logger.post_cmd(rc)
 
         if verbose:
-            for x in filter(bool, rc.data()):
+            for x in filter(bool, listify(rc.data())):
                 self.logger.log(format_text("{0}".format(x), 'bold'))
                 
         if not rc:
@@ -2999,6 +3001,10 @@ class STLClient(object):
                 tx_ports       - on which ports to capture TX
                 rx_ports       - on which ports to capture RX
                 limit          - limit how many packets will be written
+                
+            :returns:
+                the new capture_id
+                
             :raises:
                 + :exe:'STLError'
 
@@ -3018,7 +3024,7 @@ class STLClient(object):
 
         non_service_ports =  list_difference(set(tx_ports + rx_ports), self.get_service_enabled_ports())
         if non_service_ports:
-            raise STLError("Port(s) {0} are not under service mode. PCAP capturing requires all ports to be in service mode")
+            raise STLError("Port(s) {0} are not under service mode. PCAP capturing requires all ports to be in service mode".format(non_service_ports))
         
             
         self.logger.pre_cmd("Starting PCAP capturing up to {0} packets".format(limit))
@@ -3030,8 +3036,39 @@ class STLClient(object):
         if not rc:
             raise STLError(rc)
 
+        return rc.data()['capture_id']
 
 
+        
+                
+    def __fetch_capture_packets (self, capture_id, output_filename, pkt_count):
+        self.logger.pre_cmd("Writing {0} packets to '{1}'".format(pkt_count, output_filename))
+
+        # create a PCAP file
+        writer = RawPcapWriter(output_filename, linktype = 1)
+        writer._write_header(None)
+        
+        # fetch
+        pending = pkt_count
+        rc = RC_OK()
+        while pending > 0:
+            rc = self._transmit("capture", params = {'command': 'fetch', 'capture_id': capture_id, 'pkt_limit': 50})
+            if not rc:
+                self.logger.post_cmd(rc)
+                raise STLError(rc)
+        
+            pkts = rc.data()['pkts']
+            for pkt in pkts:
+                ts = pkt['ts']
+                pkt_bin = base64.b64decode(pkt['binary'])
+                writer._write_packet(pkt_bin, sec = 0, usec = 0)
+                
+            pending = rc.data()['pending']
+            
+        
+        self.logger.post_cmd(rc)
+        
+        
     @__api_check(True)
     def stop_capture (self, capture_id, output_filename):
         """
@@ -3045,8 +3082,6 @@ class STLClient(object):
                 + :exe:'STLError'
 
         """
-
-        
         
         # stopping a capture requires:
         # 1. stopping
@@ -3063,36 +3098,19 @@ class STLClient(object):
         
         # pkt count
         pkt_count = rc.data()['pkt_count']
-            
-        if not output_filename or pkt_count == 0:
-            return
         
-        self.logger.pre_cmd("Writing {0} packets to '{1}'".format(pkt_count, output_filename))
-
-        # create a PCAP file
-        writer = RawPcapWriter(output_filename, linktype = 1)
-        writer._write_header(None)
-        
-        # fetch
-        while True:
-            rc = self._transmit("capture", params = {'command': 'fetch', 'capture_id': capture_id, 'pkt_limit': 50})
-            if not rc:
-                self.logger.post_cmd(rc)
-                raise STLError(rc)
-        
-            pkts = rc.data()['pkts']
-            for pkt in pkts:
-                ts = pkt['ts']
-                pkt_bin = base64.b64decode(pkt['binary'])
-                writer._write_packet(pkt_bin, sec = 0, usec = 0)
-                
-            if rc.data()['pending'] == 0:
-                break
+        # fetch packets    
+        if output_filename:
+            self.__fetch_capture_packets(capture_id, output_filename, pkt_count)
         
+        # remove
+        self.logger.pre_cmd("Removing PCAP capture {0} from server".format(capture_id))
+        rc = self._transmit("capture", params = {'command': 'remove', 'capture_id': capture_id})
         self.logger.post_cmd(rc)
+        if not rc:
+            raise STLError(rc)
         
 
-    # get capture status
     @__api_check(True)
     def get_capture_status (self):
         """
@@ -3109,7 +3127,25 @@ class STLClient(object):
 
         return rc.data()
 
-    
+    @__api_check(True)
+    def remove_all_captures (self):
+        """
+            Removes any existing captures
+        """
+        captures = self.get_capture_status()
+        
+        self.logger.pre_cmd("Removing all PCAP captures from server")
+        
+        for c in captures:
+            # remove
+            rc = self._transmit("capture", params = {'command': 'remove', 'capture_id': c['id']})
+            if not rc:
+                raise STLError(rc)
+
+        self.logger.post_cmd(RC_OK())
+                
+
+        
     @__api_check(True)
     def set_rx_queue (self, ports = None, size = 1000):
         """
@@ -3230,6 +3266,7 @@ class STLClient(object):
 
         return wrap
 
+
     @__console
     def ping_line (self, line):
         '''pings the server / specific IP'''
@@ -3820,77 +3857,9 @@ class STLClient(object):
                                 opts.link,
                                 opts.led,
                                 opts.flow_ctrl)
+                         
+               
              
-             
-
-             
-    @__console
-    def capture_line (self, line):
-        '''Manage PCAP recorders'''
-
-        # default
-        if not line:
-            line = "show"
-
-        parser = parsing_opts.gen_parser(self, "capture", self.capture_line.__doc__)
-        subparsers = parser.add_subparsers(title = "commands", dest="commands")
-
-        # start
-        start_parser = subparsers.add_parser('start', help = "starts a new capture")
-        start_parser.add_arg_list(parsing_opts.TX_PORT_LIST,
-                                  parsing_opts.RX_PORT_LIST,
-                                  parsing_opts.LIMIT)
-
-        # stop
-        stop_parser = subparsers.add_parser('stop', help = "stops an active capture")
-        stop_parser.add_arg_list(parsing_opts.CAPTURE_ID,
-                                 parsing_opts.OUTPUT_FILENAME)
-
-        # show
-        show_parser = subparsers.add_parser('show', help = "show all active captures")
-
-        opts = parser.parse_args(line.split())
-
-        if not opts:
-            return opts
-
-        # start
-        if opts.commands == 'start':
-            if not opts.tx_port_list and not opts.rx_port_list:
-                start_parser.formatted_error('please provide either --tx or --rx')
-                return
-
-            self.start_capture(opts.tx_port_list, opts.rx_port_list, opts.limit)
-
-        # stop
-        elif opts.commands == 'stop':
-            self.stop_capture(opts.capture_id, opts.output_filename)
-
-        # show
-        else:
-            data = self.get_capture_status()
-
-            stats_table = text_tables.TRexTextTable()
-            stats_table.set_cols_align(["c"] * 6)
-            stats_table.set_cols_width([15] * 6)
-
-            for elem in data:
-                row = [elem['id'],
-                       elem['state'],
-                       '[{0}/{1}]'.format(elem['count'], elem['limit']),
-                       format_num(elem['bytes'], suffix = 'B'),
-                       bitfield_to_str(elem['filter']['tx']),
-                       bitfield_to_str(elem['filter']['rx'])]
-                
-                stats_table.add_rows([row], header=False)
-
-            stats_table.header(['ID', 'Status', 'Count', 'Bytes', 'TX Ports', 'RX Ports'])
-            text_tables.print_table_with_header(stats_table, "Captures")
-            
-
-        return RC_OK()
-
-        
 
     @__console
     def resolve_line (self, line):
@@ -4089,3 +4058,4 @@ class STLClient(object):
             
         self.set_service_mode(ports = opts.ports, enabled = opts.enabled)
         
+
index cb594ef..8d3aedb 100755 (executable)
@@ -85,6 +85,10 @@ STREAMS_MASK
 CORE_MASK_GROUP
 CAPTURE_PORTS_GROUP
 
+MONITOR_TYPE_VERBOSE
+MONITOR_TYPE_PIPE
+MONITOR_TYPE
+
 # ALL_STREAMS
 # STREAM_LIST_WITH_ALL
 
@@ -606,6 +610,7 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                           'help': 'A list of ports to capture on the TX side',
                                           'default': []}),
                
+              
               RX_PORT_LIST: ArgumentPack(['--rx'],
                                          {'nargs': '+',
                                           'dest':'rx_port_list',
@@ -614,7 +619,21 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                           'type': int,
                                           'help': 'A list of ports to capture on the RX side',
                                           'default': []}),
-                
+              
+              
+              MONITOR_TYPE_VERBOSE: ArgumentPack(['-v', '--verbose'],
+                                                 {'action': 'store_true',
+                                                  'dest': 'verbose',
+                                                  'default': False,
+                                                  'help': 'output to screen as verbose'}),
+              
+              MONITOR_TYPE_PIPE: ArgumentPack(['-p', '--pipe'],
+                                              {'action': 'store_true',
+                                               'dest': 'pipe',
+                                               'default': False,
+                                               'help': 'forward packets to a pipe'}),
+
+
               CAPTURE_ID: ArgumentPack(['-i', '--id'],
                                   {'help': "capture ID to remove",
                                    'dest': "capture_id",
@@ -646,6 +665,12 @@ OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
                                               {'required': False}),
 
               CAPTURE_PORTS_GROUP: ArgumentGroup(NON_MUTEX, [TX_PORT_LIST, RX_PORT_LIST], {}),
+              
+              
+              MONITOR_TYPE: ArgumentGroup(MUTEX, [MONITOR_TYPE_VERBOSE,
+                                                  MONITOR_TYPE_PIPE],
+                                          {'required': False}),
+              
               }
 
 class _MergeAction(argparse._AppendAction):
@@ -760,7 +785,7 @@ class CCmdArgParser(argparse.ArgumentParser):
 
     def formatted_error (self, msg):
         self.print_usage()
-        self.stateless_client.logger.log(msg)
+        self._print_message(('%s: error: %s\n') % (self.prog, msg))
 
 
 def get_flags (opt):
index 63b05bf..3ffd07e 100644 (file)
@@ -133,12 +133,16 @@ def underline(text):
 
 # apply attribute on each non-empty line
 def text_attribute(text, attribute):
-    return '\n'.join(['{start}{txt}{end}'.format(
-            start = TEXT_CODES[attribute]['start'],
-            txt = line,
-            end = TEXT_CODES[attribute]['end'])
-                    if line else '' for line in ('%s' % text).split('\n')])
-
+    if isinstance(text, str):
+        return "{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'],
+                                           txt=text,
+                                           stop=TEXT_CODES[attribute]['end'])
+    elif isinstance(text, unicode):
+        return u"{start}{txt}{stop}".format(start=TEXT_CODES[attribute]['start'],
+                                            txt=text,
+                                            stop=TEXT_CODES[attribute]['end'])
+    else:
+        raise Exception("not a string")
 
 FUNC_DICT = {'blue': blue,
              'bold': bold,
index 80f69fa..8f7431e 100644 (file)
@@ -853,7 +853,7 @@ TrexRpcCmdSetL3::_run(const Json::Value &params, Json::Value &result) {
  */
 trex_rpc_cmd_rc_e
 TrexRpcCmdCapture::_run(const Json::Value &params, Json::Value &result) {
-    const std::string cmd = parse_choice(params, "command", {"start", "stop", "fetch", "status"}, result);
+    const std::string cmd = parse_choice(params, "command", {"start", "stop", "fetch", "status", "remove"}, result);
     
     if (cmd == "start") {
         parse_cmd_start(params, result);
@@ -863,6 +863,8 @@ TrexRpcCmdCapture::_run(const Json::Value &params, Json::Value &result) {
         parse_cmd_fetch(params, result);
     } else if (cmd == "status") {
         parse_cmd_status(params, result);
+    } else if (cmd == "remove") {
+        parse_cmd_remove(params, result);
     } else {
         /* can't happen */
         assert(0);
@@ -878,10 +880,9 @@ TrexRpcCmdCapture::_run(const Json::Value &params, Json::Value &result) {
 void
 TrexRpcCmdCapture::parse_cmd_start(const Json::Value &params, Json::Value &result) {
     
-    uint32_t limit             = parse_uint32(params, "limit", result);
-    const Json::Value &tx_json = parse_array(params, "tx", result);
-    const Json::Value &rx_json = parse_array(params, "rx", result);
-    
+    uint32_t limit              = parse_uint32(params, "limit", result);
+    const Json::Value &tx_json  = parse_array(params, "tx", result);
+    const Json::Value &rx_json  = parse_array(params, "rx", result);
     CaptureFilter filter;
     
     std::set<uint8_t> ports;
@@ -909,7 +910,7 @@ TrexRpcCmdCapture::parse_cmd_start(const Json::Value &params, Json::Value &resul
     
     static MsgReply<TrexCaptureRCStart> reply;
     reply.reset();
-    
+  
     TrexStatelessRxCaptureStart *start_msg = new TrexStatelessRxCaptureStart(filter, limit, reply);
     get_stateless_obj()->send_msg_to_rx(start_msg);
     
@@ -918,7 +919,7 @@ TrexRpcCmdCapture::parse_cmd_start(const Json::Value &params, Json::Value &resul
         generate_execute_err(result, rc.get_err());
     }
     
-    result["result"] = Json::objectValue;
+    result["result"]["capture_id"] = rc.get_new_id();
 }
 
 /**
@@ -990,7 +991,33 @@ TrexRpcCmdCapture::parse_cmd_fetch(const Json::Value &params, Json::Value &resul
         generate_execute_err(result, rc.get_err());
     }
     
-    result["result"]["pkts"]    = rc.get_pkt_buffer()->to_json();
+    const TrexPktBuffer *pkt_buffer = rc.get_pkt_buffer();
+    
     result["result"]["pending"] = rc.get_pending();
+    result["result"]["pkts"]    = pkt_buffer->to_json();
+    
+    /* delete the buffer */
+    delete pkt_buffer;
+}
+
+void
+TrexRpcCmdCapture::parse_cmd_remove(const Json::Value &params, Json::Value &result) {
+    
+    uint32_t capture_id = parse_uint32(params, "capture_id", result);
+    /* generate a remove command */
+    
+    static MsgReply<TrexCaptureRCRemove> reply;
+    reply.reset();
+    
+    TrexStatelessRxCaptureRemove *remove_msg = new TrexStatelessRxCaptureRemove(capture_id, reply);
+    get_stateless_obj()->send_msg_to_rx(remove_msg);
+    
+    TrexCaptureRCRemove rc = reply.wait_for_reply();
+    if (!rc) {
+        generate_execute_err(result, rc.get_err());
+    }
+    
+    result["result"] = Json::objectValue;
 }
 
index bf78ff8..54797bd 100644 (file)
@@ -165,6 +165,7 @@ TREX_RPC_CMD_DEFINE_EXTENDED(TrexRpcCmdCapture,  "capture", 1, false, APIClass::
     void parse_cmd_stop(const Json::Value &msg, Json::Value &result);
     void parse_cmd_status(const Json::Value &msg, Json::Value &result);
     void parse_cmd_fetch(const Json::Value &msg, Json::Value &result);
+    void parse_cmd_remove(const Json::Value &params, Json::Value &result);
 );
 
 
index b9bb1d1..2452487 100644 (file)
@@ -313,6 +313,19 @@ TrexStatelessRxCaptureStatus::handle(CRxCoreStateless *rx_core) {
     return true;
 }
 
+bool
+TrexStatelessRxCaptureRemove::handle(CRxCoreStateless *rx_core) {
+    
+    TrexCaptureRCRemove remove_rc;
+    
+    TrexStatelessCaptureMngr::getInstance().remove(m_capture_id, remove_rc);
+    
+    /* mark as done */
+    m_reply.set_reply(remove_rc);
+    
+    return true;
+}
+
 
 bool
 TrexStatelessRxStartQueue::handle(CRxCoreStateless *rx_core) {
index 4027d07..3535ad4 100644 (file)
@@ -552,6 +552,21 @@ private:
 };
 
 
+
+class TrexStatelessRxCaptureRemove : public TrexStatelessRxCapture {
+public:
+    TrexStatelessRxCaptureRemove(capture_id_t capture_id, MsgReply<TrexCaptureRCRemove> &reply) : m_reply(reply) {
+        m_capture_id = capture_id;
+    }
+
+    virtual bool handle(CRxCoreStateless *rx_core);
+
+private:
+    capture_id_t                   m_capture_id;
+    MsgReply<TrexCaptureRCRemove> &m_reply;
+};
+
+
 class TrexStatelessRxStartQueue : public TrexStatelessCpToRxMsgBase {
 public:
     TrexStatelessRxStartQueue(uint8_t port_id,
index 85be7ae..5d43ced 100644 (file)
@@ -62,7 +62,7 @@ TrexStatelessCapture::handle_pkt_rx(const rte_mbuf_t *m, int port) {
         return;
     }
     
-    m_pkt_buffer->push(m);
+    m_pkt_buffer->push(m, port, TrexPkt::ORIGIN_RX);
 }
 
 
@@ -87,7 +87,6 @@ TrexStatelessCapture::to_json() const {
         
     default:
         assert(0);
-        
     }
     
     return output;
@@ -178,10 +177,6 @@ TrexStatelessCaptureMngr::fetch(capture_id_t capture_id, uint32_t pkt_limit, Tre
         rc.set_err(TrexCaptureRC::RC_CAPTURE_NOT_FOUND);
         return;
     }
-    if (capture->is_active()) {
-        rc.set_err(TrexCaptureRC::RC_CAPTURE_FETCH_UNDER_ACTIVE);
-        return;
-    }
     
     uint32_t pending = 0;
     TrexPktBuffer *pkt_buffer = capture->fetch(pkt_limit, pending);
@@ -214,6 +209,8 @@ TrexStatelessCaptureMngr::remove(capture_id_t capture_id, TrexCaptureRCRemove &r
     
     /* update global filter */
     update_global_filter();
+    
+    rc.set_ok();
 }
 
 void
index 6cd25a9..4a9efea 100644 (file)
@@ -27,7 +27,7 @@ limitations under the License.
 #include "trex_stateless_pkt.h"
 #include "trex_stateless_capture_msg.h"
 
-typedef int64_t capture_id_t;
+typedef int32_t capture_id_t;
 
 class TrexCaptureRC {
 public: