trex_stl_client.py revision e8ba50a8
1#!/router/bin/python
2
3# for API usage the path name must be full
4from trex_stl_lib.trex_stl_exceptions import *
5from trex_stl_lib.trex_stl_streams import *
6
7from trex_stl_jsonrpc_client import JsonRpcClient, BatchMessage
8import trex_stl_stats
9
10from trex_stl_port import Port
11from trex_stl_types import *
12from trex_stl_async_client import CTRexAsyncClient
13
14from utils import parsing_opts, text_tables, common
15from utils.text_opts import *
16
17
18from collections import namedtuple
19from yaml import YAMLError
20import time
21import datetime
22import re
23import random
24import json
25import traceback
26
27############################     logger     #############################
28############################                #############################
29############################                #############################
30
31# logger API for the client
32class LoggerApi(object):
33    # verbose levels
34    VERBOSE_QUIET   = 0
35    VERBOSE_REGULAR = 1
36    VERBOSE_HIGH    = 2
37
38    def __init__(self):
39        self.level = LoggerApi.VERBOSE_REGULAR
40
41    # implemented by specific logger
42    def write(self, msg, newline = True):
43        raise Exception("implement this")
44
45    # implemented by specific logger
46    def flush(self):
47        raise Exception("implement this")
48
49    def set_verbose (self, level):
50        if not level in xrange(self.VERBOSE_QUIET, self.VERBOSE_HIGH + 1):
51            raise ValueError("bad value provided for logger")
52
53        self.level = level
54
55    def get_verbose (self):
56        return self.level
57
58
59    def check_verbose (self, level):
60        return (self.level >= level)
61
62
63    # simple log message with verbose
64    def log (self, msg, level = VERBOSE_REGULAR, newline = True):
65        if not self.check_verbose(level):
66            return
67
68        self.write(msg, newline)
69
70    # logging that comes from async event
71    def async_log (self, msg, level = VERBOSE_REGULAR, newline = True):
72        self.log(msg, level, newline)
73
74
75    def pre_cmd (self, desc):
76        self.log(format_text('\n{:<60}'.format(desc), 'bold'), newline = False)
77        self.flush()
78
79    def post_cmd (self, rc):
80        if rc:
81            self.log(format_text("[SUCCESS]\n", 'green', 'bold'))
82        else:
83            self.log(format_text("[FAILED]\n", 'red', 'bold'))
84
85
86    def log_cmd (self, desc):
87        self.pre_cmd(desc)
88        self.post_cmd(True)
89
90
91    # supress object getter
92    def supress (self):
93        class Supress(object):
94            def __init__ (self, logger):
95                self.logger = logger
96
97            def __enter__ (self):
98                self.saved_level = self.logger.get_verbose()
99                self.logger.set_verbose(LoggerApi.VERBOSE_QUIET)
100
101            def __exit__ (self, type, value, traceback):
102                self.logger.set_verbose(self.saved_level)
103
104        return Supress(self)
105
106
107
108# default logger - to stdout
109class DefaultLogger(LoggerApi):
110
111    def __init__ (self):
112        super(DefaultLogger, self).__init__()
113
114    def write (self, msg, newline = True):
115        if newline:
116            print msg
117        else:
118            print msg,
119
120    def flush (self):
121        sys.stdout.flush()
122
123
124############################     async event hander     #############################
125############################                            #############################
126############################                            #############################
127
128# handles different async events given to the client
129class AsyncEventHandler(object):
130
131    def __init__ (self, client):
132        self.client = client
133        self.logger = self.client.logger
134
135        self.events = []
136
137    # public functions
138
139    def get_events (self):
140        return self.events
141
142
143    def clear_events (self):
144        self.events = []
145
146
147    def on_async_dead (self):
148        if self.client.connected:
149            msg = 'lost connection to server'
150            self.__add_event_log(msg, 'local', True)
151            self.client.connected = False
152
153
154    def on_async_alive (self):
155        pass
156
157
158    # handles an async stats update from the subscriber
159    def handle_async_stats_update(self, dump_data):
160        global_stats = {}
161        port_stats = {}
162
163        # filter the values per port and general
164        for key, value in dump_data.iteritems():
165            # match a pattern of ports
166            m = re.search('(.*)\-([0-8])', key)
167            if m:
168                port_id = int(m.group(2))
169                field_name = m.group(1)
170                if self.client.ports.has_key(port_id):
171                    if not port_id in port_stats:
172                        port_stats[port_id] = {}
173                    port_stats[port_id][field_name] = value
174                else:
175                    continue
176            else:
177                # no port match - general stats
178                global_stats[key] = value
179
180        # update the general object with the snapshot
181        self.client.global_stats.update(global_stats)
182
183        # update all ports
184        for port_id, data in port_stats.iteritems():
185            self.client.ports[port_id].port_stats.update(data)
186
187
188    # dispatcher for server async events (port started, port stopped and etc.)
189    def handle_async_event (self, type, data):
190        # DP stopped
191        show_event = False
192
193        # port started
194        if (type == 0):
195            port_id = int(data['port_id'])
196            ev = "Port {0} has started".format(port_id)
197            self.__async_event_port_started(port_id)
198
199        # port stopped
200        elif (type == 1):
201            port_id = int(data['port_id'])
202            ev = "Port {0} has stopped".format(port_id)
203
204            # call the handler
205            self.__async_event_port_stopped(port_id)
206
207
208        # port paused
209        elif (type == 2):
210            port_id = int(data['port_id'])
211            ev = "Port {0} has paused".format(port_id)
212
213            # call the handler
214            self.__async_event_port_paused(port_id)
215
216        # port resumed
217        elif (type == 3):
218            port_id = int(data['port_id'])
219            ev = "Port {0} has resumed".format(port_id)
220
221            # call the handler
222            self.__async_event_port_resumed(port_id)
223
224        # port finished traffic
225        elif (type == 4):
226            port_id = int(data['port_id'])
227            ev = "Port {0} job done".format(port_id)
228
229            # call the handler
230            self.__async_event_port_stopped(port_id)
231            show_event = True
232
233        # port was stolen...
234        elif (type == 5):
235            session_id = data['session_id']
236
237            # false alarm, its us
238            if session_id == self.client.session_id:
239                return
240
241            port_id = int(data['port_id'])
242            who = data['who']
243
244            ev = "Port {0} was forcely taken by '{1}'".format(port_id, who)
245
246            # call the handler
247            self.__async_event_port_forced_acquired(port_id)
248            show_event = True
249
250        # server stopped
251        elif (type == 100):
252            ev = "Server has stopped"
253            self.__async_event_server_stopped()
254            show_event = True
255
256
257        else:
258            # unknown event - ignore
259            return
260
261
262        self.__add_event_log(ev, 'server', show_event)
263
264
265    # private functions
266
267    def __async_event_port_stopped (self, port_id):
268        self.client.ports[port_id].async_event_port_stopped()
269
270
271    def __async_event_port_started (self, port_id):
272        self.client.ports[port_id].async_event_port_started()
273
274
275    def __async_event_port_paused (self, port_id):
276        self.client.ports[port_id].async_event_port_paused()
277
278
279    def __async_event_port_resumed (self, port_id):
280        self.client.ports[port_id].async_event_port_resumed()
281
282
283    def __async_event_port_forced_acquired (self, port_id):
284        self.client.ports[port_id].async_event_forced_acquired()
285
286
287    def __async_event_server_stopped (self):
288        self.client.connected = False
289
290
291    # add event to log
292    def __add_event_log (self, msg, ev_type, show = False):
293
294        if ev_type == "server":
295            prefix = "[server]"
296        elif ev_type == "local":
297            prefix = "[local]"
298
299        ts = time.time()
300        st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
301        self.events.append("{:<10} - {:^8} - {:}".format(st, prefix, format_text(msg, 'bold')))
302
303        if show:
304            self.logger.async_log(format_text("\n\n{:^8} - {:}".format(prefix, format_text(msg, 'bold'))))
305
306
307
308
309
310############################     RPC layer     #############################
311############################                   #############################
312############################                   #############################
313
314class CCommLink(object):
315    """describes the connectivity of the stateless client method"""
316    def __init__(self, server="localhost", port=5050, virtual=False, prn_func = None):
317        self.virtual = virtual
318        self.server = server
319        self.port = port
320        self.rpc_link = JsonRpcClient(self.server, self.port, prn_func)
321
322    @property
323    def is_connected(self):
324        if not self.virtual:
325            return self.rpc_link.connected
326        else:
327            return True
328
329    def get_server (self):
330        return self.server
331
332    def get_port (self):
333        return self.port
334
335    def connect(self):
336        if not self.virtual:
337            return self.rpc_link.connect()
338
339    def disconnect(self):
340        if not self.virtual:
341            return self.rpc_link.disconnect()
342
343    def transmit(self, method_name, params={}):
344        if self.virtual:
345            self._prompt_virtual_tx_msg()
346            _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params)
347            print msg
348            return
349        else:
350            return self.rpc_link.invoke_rpc_method(method_name, params)
351
352    def transmit_batch(self, batch_list):
353        if self.virtual:
354            self._prompt_virtual_tx_msg()
355            print [msg
356                   for _, msg in [self.rpc_link.create_jsonrpc_v2(command.method, command.params)
357                                  for command in batch_list]]
358        else:
359            batch = self.rpc_link.create_batch()
360            for command in batch_list:
361                batch.add(command.method, command.params)
362            # invoke the batch
363            return batch.invoke()
364
365    def _prompt_virtual_tx_msg(self):
366        print "Transmitting virtually over tcp://{server}:{port}".format(server=self.server,
367                                                                         port=self.port)
368
369
370
371############################     client     #############################
372############################                #############################
373############################                #############################
374
375class STLClient(object):
376    """docstring for STLClient"""
377
378    def __init__(self,
379                 username = common.get_current_user(),
380                 server = "localhost",
381                 sync_port = 4501,
382                 async_port = 4500,
383                 verbose_level = LoggerApi.VERBOSE_QUIET,
384                 logger = None,
385                 virtual = False):
386
387
388        self.username   = username
389
390        # init objects
391        self.ports = {}
392        self.server_version = {}
393        self.system_info = {}
394        self.session_id = random.getrandbits(32)
395        self.connected = False
396
397        # logger
398        self.logger = DefaultLogger() if not logger else logger
399
400        # initial verbose
401        self.logger.set_verbose(verbose_level)
402
403        # low level RPC layer
404        self.comm_link = CCommLink(server,
405                                   sync_port,
406                                   virtual,
407                                   self.logger)
408
409        # async event handler manager
410        self.event_handler = AsyncEventHandler(self)
411
412        # async subscriber level
413        self.async_client = CTRexAsyncClient(server,
414                                             async_port,
415                                             self)
416
417
418
419
420        # stats
421        self.connection_info = {"username":   username,
422                                "server":     server,
423                                "sync_port":  sync_port,
424                                "async_port": async_port,
425                                "virtual":    virtual}
426
427
428        self.global_stats = trex_stl_stats.CGlobalStats(self.connection_info,
429                                                    self.server_version,
430                                                    self.ports)
431
432        self.stats_generator = trex_stl_stats.CTRexInfoGenerator(self.global_stats,
433                                                              self.ports)
434
435
436
437    ############# private functions - used by the class itself ###########
438
439    # some preprocessing for port argument
440    def __ports (self, port_id_list):
441
442        # none means all
443        if port_id_list == None:
444            return range(0, self.get_port_count())
445
446        # always list
447        if isinstance(port_id_list, int):
448            port_id_list = [port_id_list]
449
450        if not isinstance(port_id_list, list):
451             raise ValueError("bad port id list: {0}".format(port_id_list))
452
453        for port_id in port_id_list:
454            if not isinstance(port_id, int) or (port_id < 0) or (port_id > self.get_port_count()):
455                raise ValueError("bad port id {0}".format(port_id))
456
457        return port_id_list
458
459
460    # sync ports
461    def __sync_ports (self, port_id_list = None, force = False):
462        port_id_list = self.__ports(port_id_list)
463
464        rc = RC()
465
466        for port_id in port_id_list:
467            rc.add(self.ports[port_id].sync())
468
469        return rc
470
471    # acquire ports, if port_list is none - get all
472    def __acquire (self, port_id_list = None, force = False):
473        port_id_list = self.__ports(port_id_list)
474
475        rc = RC()
476
477        for port_id in port_id_list:
478            rc.add(self.ports[port_id].acquire(force))
479
480        return rc
481
482    # release ports
483    def __release (self, port_id_list = None):
484        port_id_list = self.__ports(port_id_list)
485
486        rc = RC()
487
488        for port_id in port_id_list:
489            rc.add(self.ports[port_id].release())
490
491        return rc
492
493
494    def __add_streams(self, stream_list, port_id_list = None):
495
496        port_id_list = self.__ports(port_id_list)
497
498        rc = RC()
499
500        for port_id in port_id_list:
501            rc.add(self.ports[port_id].add_streams(stream_list))
502
503        return rc
504
505
506
507    def __remove_streams(self, stream_id_list, port_id_list = None):
508
509        port_id_list = self.__ports(port_id_list)
510
511        rc = RC()
512
513        for port_id in port_id_list:
514            rc.add(self.ports[port_id].remove_streams(stream_id_list))
515
516        return rc
517
518
519
520    def __remove_all_streams(self, port_id_list = None):
521        port_id_list = self.__ports(port_id_list)
522
523        rc = RC()
524
525        for port_id in port_id_list:
526            rc.add(self.ports[port_id].remove_all_streams())
527
528        return rc
529
530
531    def __get_stream(self, stream_id, port_id, get_pkt = False):
532
533        return self.ports[port_id].get_stream(stream_id)
534
535
536    def __get_all_streams(self, port_id, get_pkt = False):
537
538        return self.ports[port_id].get_all_streams()
539
540
541    def __get_stream_id_list(self, port_id):
542
543        return self.ports[port_id].get_stream_id_list()
544
545
546    def __start (self, multiplier, duration, port_id_list = None, force = False):
547
548        port_id_list = self.__ports(port_id_list)
549
550        rc = RC()
551
552        for port_id in port_id_list:
553            rc.add(self.ports[port_id].start(multiplier, duration, force))
554
555        return rc
556
557
558    def __resume (self, port_id_list = None, force = False):
559
560        port_id_list = self.__ports(port_id_list)
561        rc = RC()
562
563        for port_id in port_id_list:
564            rc.add(self.ports[port_id].resume())
565
566        return rc
567
568    def __pause (self, port_id_list = None, force = False):
569
570        port_id_list = self.__ports(port_id_list)
571        rc = RC()
572
573        for port_id in port_id_list:
574            rc.add(self.ports[port_id].pause())
575
576        return rc
577
578
579    def __stop (self, port_id_list = None, force = False):
580
581        port_id_list = self.__ports(port_id_list)
582        rc = RC()
583
584        for port_id in port_id_list:
585            rc.add(self.ports[port_id].stop(force))
586
587        return rc
588
589
590    def __update (self, mult, port_id_list = None, force = False):
591
592        port_id_list = self.__ports(port_id_list)
593        rc = RC()
594
595        for port_id in port_id_list:
596            rc.add(self.ports[port_id].update(mult, force))
597
598        return rc
599
600
601    def __validate (self, port_id_list = None):
602        port_id_list = self.__ports(port_id_list)
603
604        rc = RC()
605
606        for port_id in port_id_list:
607            rc.add(self.ports[port_id].validate())
608
609        return rc
610
611
612
613    # connect to server
614    def __connect(self):
615
616        # first disconnect if already connected
617        if self.is_connected():
618            self.__disconnect()
619
620        # clear this flag
621        self.connected = False
622
623        # connect sync channel
624        self.logger.pre_cmd("Connecting to RPC server on {0}:{1}".format(self.connection_info['server'], self.connection_info['sync_port']))
625        rc = self.comm_link.connect()
626        self.logger.post_cmd(rc)
627
628        if not rc:
629            return rc
630
631        # version
632        rc = self._transmit("get_version")
633        if not rc:
634            return rc
635
636
637        self.server_version = rc.data()
638        self.global_stats.server_version = rc.data()
639
640        # cache system info
641        rc = self._transmit("get_system_info")
642        if not rc:
643            return rc
644
645        self.system_info = rc.data()
646
647        # cache supported commands
648        rc = self._transmit("get_supported_cmds")
649        if not rc:
650            return rc
651
652        self.supported_cmds = rc.data()
653
654        # create ports
655        for port_id in xrange(self.system_info["port_count"]):
656            speed = self.system_info['ports'][port_id]['speed']
657            driver = self.system_info['ports'][port_id]['driver']
658
659            self.ports[port_id] = Port(port_id,
660                                       speed,
661                                       driver,
662                                       self.username,
663                                       self.comm_link,
664                                       self.session_id)
665
666
667        # sync the ports
668        rc = self.__sync_ports()
669        if not rc:
670            return rc
671
672
673        # connect async channel
674        self.logger.pre_cmd("connecting to publisher server on {0}:{1}".format(self.connection_info['server'], self.connection_info['async_port']))
675        rc = self.async_client.connect()
676        self.logger.post_cmd(rc)
677
678        if not rc:
679            return rc
680
681        self.connected = True
682
683        return RC_OK()
684
685
686    # disconenct from server
687    def __disconnect(self, release_ports = True):
688        # release any previous acquired ports
689        if self.is_connected() and release_ports:
690            self.__release(self.get_acquired_ports())
691
692        self.comm_link.disconnect()
693        self.async_client.disconnect()
694
695        self.connected = False
696
697        return RC_OK()
698
699
700    # clear stats
701    def __clear_stats(self, port_id_list, clear_global):
702
703        for port_id in port_id_list:
704            self.ports[port_id].clear_stats()
705
706        if clear_global:
707            self.global_stats.clear_stats()
708
709        self.logger.log_cmd("clearing stats on port(s) {0}:".format(port_id_list))
710
711        return RC
712
713
714    # get stats
715    def __get_stats (self, port_id_list):
716        stats = {}
717
718        stats['global'] = self.global_stats.get_stats()
719
720        total = {}
721        for port_id in port_id_list:
722            port_stats = self.ports[port_id].get_stats()
723            stats[port_id] = port_stats
724
725            for k, v in port_stats.iteritems():
726                if not k in total:
727                    total[k] = v
728                else:
729                    total[k] += v
730
731        stats['total'] = total
732
733        return stats
734
735
736    ############ functions used by other classes but not users ##############
737
738    def _verify_port_id_list (self, port_id_list):
739        # check arguments
740        if not isinstance(port_id_list, list):
741            return RC_ERR("ports should be an instance of 'list' not {0}".format(type(port_id_list)))
742
743        # all ports are valid ports
744        if not port_id_list or not all([port_id in self.get_all_ports() for port_id in port_id_list]):
745            return RC_ERR("")
746
747        return RC_OK()
748
749    def _validate_port_list(self, port_id_list):
750        if not isinstance(port_id_list, list):
751            return False
752
753        # check each item of the sequence
754        return (port_id_list and all([port_id in self.get_all_ports() for port_id in port_id_list]))
755
756
757
758    # transmit request on the RPC link
759    def _transmit(self, method_name, params={}):
760        return self.comm_link.transmit(method_name, params)
761
762    # transmit batch request on the RPC link
763    def _transmit_batch(self, batch_list):
764        return self.comm_link.transmit_batch(batch_list)
765
766    # stats
767    def _get_formatted_stats(self, port_id_list, stats_mask = trex_stl_stats.COMPACT):
768        stats_opts = trex_stl_stats.ALL_STATS_OPTS.intersection(stats_mask)
769
770        stats_obj = {}
771        for stats_type in stats_opts:
772            stats_obj.update(self.stats_generator.generate_single_statistic(port_id_list, stats_type))
773
774        return stats_obj
775
776    def _get_streams(self, port_id_list, streams_mask=set()):
777
778        streams_obj = self.stats_generator.generate_streams_info(port_id_list, streams_mask)
779
780        return streams_obj
781
782
783    def _invalidate_stats (self, port_id_list):
784        for port_id in port_id_list:
785            self.ports[port_id].invalidate_stats()
786
787        self.global_stats.invalidate()
788
789        return RC_OK()
790
791
792
793
794
795    #################################
796    # ------ private methods ------ #
797    @staticmethod
798    def __get_mask_keys(ok_values={True}, **kwargs):
799        masked_keys = set()
800        for key, val in kwargs.iteritems():
801            if val in ok_values:
802                masked_keys.add(key)
803        return masked_keys
804
805    @staticmethod
806    def __filter_namespace_args(namespace, ok_values):
807        return {k: v for k, v in namespace.__dict__.items() if k in ok_values}
808
809
810    # API decorator - double wrap because of argument
811    def __api_check(connected = True):
812
813        def wrap (f):
814            def wrap2(*args, **kwargs):
815                client = args[0]
816
817                func_name = f.__name__
818
819                # check connection
820                if connected and not client.is_connected():
821                    raise STLStateError(func_name, 'disconnected')
822
823                ret = f(*args, **kwargs)
824                return ret
825            return wrap2
826
827        return wrap
828
829
830
831    ############################     API     #############################
832    ############################             #############################
833    ############################             #############################
834    def __enter__ (self):
835        self.connect()
836        self.acquire(force = True)
837        self.reset()
838        return self
839
840    def __exit__ (self, type, value, traceback):
841        if self.get_active_ports():
842            self.stop(self.get_active_ports())
843        self.disconnect()
844
845    ############################   Getters   #############################
846    ############################             #############################
847    ############################             #############################
848
849
850    # return verbose level of the logger
851    def get_verbose (self):
852        return self.logger.get_verbose()
853
854    # is the client on read only mode ?
855    def is_all_ports_acquired (self):
856        return not (self.get_all_ports() == self.get_acquired_ports())
857
858    # is the client connected ?
859    def is_connected (self):
860        return self.connected and self.comm_link.is_connected
861
862
863    # get connection info
864    def get_connection_info (self):
865        return self.connection_info
866
867
868    # get supported commands by the server
869    def get_server_supported_cmds(self):
870        return self.supported_cmds
871
872    # get server version
873    def get_server_version(self):
874        return self.server_version
875
876    # get server system info
877    def get_server_system_info(self):
878        return self.system_info
879
880    # get port count
881    def get_port_count(self):
882        return len(self.ports)
883
884
885    # returns the port object
886    def get_port (self, port_id):
887        port = self.ports.get(port_id, None)
888        if (port != None):
889            return port
890        else:
891            raise STLArgumentError('port id', port_id, valid_values = self.get_all_ports())
892
893
894    # get all ports as IDs
895    def get_all_ports (self):
896        return self.ports.keys()
897
898    # get all acquired ports
899    def get_acquired_ports(self):
900        return [port_id
901                for port_id, port_obj in self.ports.iteritems()
902                if port_obj.is_acquired()]
903
904    # get all active ports (TX or pause)
905    def get_active_ports(self):
906        return [port_id
907                for port_id, port_obj in self.ports.iteritems()
908                if port_obj.is_active()]
909
910    # get paused ports
911    def get_paused_ports (self):
912        return [port_id
913                for port_id, port_obj in self.ports.iteritems()
914                if port_obj.is_paused()]
915
916    # get all TX ports
917    def get_transmitting_ports (self):
918        return [port_id
919                for port_id, port_obj in self.ports.iteritems()
920                if port_obj.is_transmitting()]
921
922
923    # get stats
924    def get_stats (self, ports = None, async_barrier = True):
925        # by default use all ports
926        if ports == None:
927            ports = self.get_acquired_ports()
928        else:
929            ports = self.__ports(ports)
930
931        # verify valid port id list
932        rc = self._validate_port_list(ports)
933        if not rc:
934            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
935
936        # check async barrier
937        if not type(async_barrier) is bool:
938            raise STLArgumentError('async_barrier', async_barrier)
939
940
941        # if the user requested a barrier - use it
942        if async_barrier:
943            rc = self.async_client.barrier()
944            if not rc:
945                raise STLError(rc)
946
947        return self.__get_stats(ports)
948
949    # return all async events
950    def get_events (self):
951        return self.event_handler.get_events()
952
953    ############################   Commands   #############################
954    ############################              #############################
955    ############################              #############################
956
957
958    """
959        Sets verbose level
960
961        :parameters:
962            level : str
963                "high"
964                "low"
965                "normal"
966
967        :raises:
968            None
969
970    """
971    def set_verbose (self, level):
972        modes = {'low' : LoggerApi.VERBOSE_QUIET, 'normal': LoggerApi.VERBOSE_REGULAR, 'high': LoggerApi.VERBOSE_HIGH}
973
974        if not level in modes.keys():
975            raise STLArgumentError('level', level)
976
977        self.logger.set_verbose(modes[level])
978
979
980    """
981        Connects to the TRex server
982
983        :parameters:
984            None
985
986        :raises:
987            + :exc:`STLError`
988
989    """
990    @__api_check(False)
991    def connect (self):
992        rc = self.__connect()
993        if not rc:
994            raise STLError(rc)
995
996
997    """
998        Disconnects from the server
999
1000        :parameters:
1001            stop_traffic : bool
1002                tries to stop traffic before disconnecting
1003            release_ports : bool
1004                tries to release all the acquired ports
1005
1006    """
1007    @__api_check(False)
1008    def disconnect (self, stop_traffic = True, release_ports = True):
1009
1010        # try to stop ports but do nothing if not possible
1011        if stop_traffic:
1012            try:
1013                self.stop()
1014            except STLError:
1015                pass
1016
1017
1018        self.logger.pre_cmd("Disconnecting from server at '{0}':'{1}'".format(self.connection_info['server'],
1019                                                                              self.connection_info['sync_port']))
1020        rc = self.__disconnect(release_ports)
1021        self.logger.post_cmd(rc)
1022
1023
1024
1025    """
1026        Acquires ports for executing commands
1027
1028        :parameters:
1029            ports : list
1030                ports to execute the command
1031            force : bool
1032                force acquire the ports
1033
1034        :raises:
1035            + :exc:`STLError`
1036
1037    """
1038    @__api_check(True)
1039    def acquire (self, ports = None, force = False):
1040        # by default use all ports
1041        if ports == None:
1042            ports = self.get_all_ports()
1043
1044        # verify ports
1045        rc = self._validate_port_list(ports)
1046        if not rc:
1047            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1048
1049        # verify valid port id list
1050        if force:
1051            self.logger.pre_cmd("Force acquiring ports {0}:".format(ports))
1052        else:
1053            self.logger.pre_cmd("Acquiring ports {0}:".format(ports))
1054
1055        rc = self.__acquire(ports, force)
1056
1057        self.logger.post_cmd(rc)
1058
1059        if not rc:
1060            # cleanup
1061            self.__release(ports)
1062            raise STLError(rc)
1063
1064
1065    """
1066        Release ports
1067
1068        :parameters:
1069            ports : list
1070                ports to execute the command
1071
1072        :raises:
1073            + :exc:`STLError`
1074
1075    """
1076    @__api_check(True)
1077    def release (self, ports = None):
1078        # by default use all acquired ports
1079        if ports == None:
1080            ports = self.get_acquired_ports()
1081
1082        # verify ports
1083        rc = self._validate_port_list(ports)
1084        if not rc:
1085            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1086
1087        self.logger.pre_cmd("Releasing ports {0}:".format(ports))
1088        rc = self.__release(ports)
1089        self.logger.post_cmd(rc)
1090
1091        if not rc:
1092            raise STLError(rc)
1093
1094    """
1095        Pings the server
1096
1097        :parameters:
1098            None
1099
1100
1101        :raises:
1102            + :exc:`STLError`
1103
1104    """
1105    @__api_check(True)
1106    def ping(self):
1107        self.logger.pre_cmd( "Pinging the server on '{0}' port '{1}': ".format(self.connection_info['server'],
1108                                                                               self.connection_info['sync_port']))
1109        rc = self._transmit("ping")
1110
1111        self.logger.post_cmd(rc)
1112
1113        if not rc:
1114            raise STLError(rc)
1115
1116
1117
1118    """
1119        force acquire ports, stop the traffic, remove all streams and clear stats
1120
1121        :parameters:
1122            ports : list
1123               ports to execute the command
1124
1125
1126        :raises:
1127            + :exc:`STLError`
1128
1129    """
1130    @__api_check(True)
1131    def reset(self, ports = None):
1132
1133        # by default use all ports
1134        if ports == None:
1135            ports = self.get_all_ports()
1136
1137        # verify ports
1138        rc = self._validate_port_list(ports)
1139        if not rc:
1140            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1141
1142        self.acquire(ports, force = True)
1143        self.stop(ports)
1144        self.remove_all_streams(ports)
1145        self.clear_stats(ports)
1146
1147
1148    """
1149        remove all streams from port(s)
1150
1151        :parameters:
1152            ports : list
1153                ports to execute the command
1154
1155
1156        :raises:
1157            + :exc:`STLError`
1158
1159    """
1160    @__api_check(True)
1161    def remove_all_streams (self, ports = None):
1162
1163        # by default use all ports
1164        if ports == None:
1165            ports = self.get_acquired_ports()
1166
1167        # verify valid port id list
1168        rc = self._validate_port_list(ports)
1169        if not rc:
1170            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1171
1172        self.logger.pre_cmd("Removing all streams from port(s) {0}:".format(ports))
1173        rc = self.__remove_all_streams(ports)
1174        self.logger.post_cmd(rc)
1175
1176        if not rc:
1177            raise STLError(rc)
1178
1179
1180    """
1181        add a list of streams to port(s)
1182
1183        :parameters:
1184            ports : list
1185                ports to execute the command
1186            streams: list
1187                streams to attach
1188
1189        :returns:
1190            list of stream IDs in order of the stream list
1191
1192        :raises:
1193            + :exc:`STLError`
1194
1195    """
1196    @__api_check(True)
1197    def add_streams (self, streams, ports = None):
1198        # by default use all ports
1199        if ports == None:
1200            ports = self.get_acquired_ports()
1201
1202        # verify valid port id list
1203        rc = self._validate_port_list(ports)
1204        if not rc:
1205            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1206
1207        # transform single stream
1208        if not isinstance(streams, list):
1209            streams = [streams]
1210
1211        # check streams
1212        if not all([isinstance(stream, STLStream) for stream in streams]):
1213            raise STLArgumentError('streams', streams)
1214
1215        self.logger.pre_cmd("Attaching {0} streams to port(s) {1}:".format(len(streams), ports))
1216        rc = self.__add_streams(streams, ports)
1217        self.logger.post_cmd(rc)
1218
1219        if not rc:
1220            raise STLError(rc)
1221
1222        return [stream.get_id() for stream in streams]
1223
1224
1225    """
1226        remove a list of streams from ports
1227
1228        :parameters:
1229            ports : list
1230                ports to execute the command
1231            stream_id_list: list
1232                stream id list to remove
1233
1234
1235        :raises:
1236            + :exc:`STLError`
1237
1238    """
1239    @__api_check(True)
1240    def remove_streams (self, stream_id_list, ports = None):
1241        # by default use all ports
1242        if ports == None:
1243            ports = self.get_acquired_ports()
1244
1245        # verify valid port id list
1246        rc = self._validate_port_list(ports)
1247        if not rc:
1248            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1249
1250        # transform single stream
1251        if not isinstance(stream_id_list, list):
1252            stream_id_list = [stream_id_list]
1253
1254        # check streams
1255        if not all([isinstance(stream_id, long) for stream_id in stream_id_list]):
1256            raise STLArgumentError('stream_id_list', stream_id_list)
1257
1258        # remove streams
1259        self.logger.pre_cmd("Removing {0} streams from port(s) {1}:".format(len(stream_id_list), ports))
1260        rc = self.__remove_streams(stream_id_list, ports)
1261        self.logger.post_cmd(rc)
1262
1263        if not rc:
1264            raise STLError(rc)
1265
1266
1267
1268    """
1269        start traffic on port(s)
1270
1271        :parameters:
1272            ports : list
1273                ports to execute command
1274
1275            mult : str
1276                multiplier in a form of pps, bps, or line util in %
1277                examples: "5kpps", "10gbps", "85%", "32mbps"
1278
1279            force : bool
1280                imply stopping the port of active and also
1281                forces a profile that exceeds the L1 BW
1282
1283            duration : int
1284                limit the run for time in seconds
1285                -1 means unlimited
1286
1287            total : bool
1288                should the B/W be divided by the ports
1289                or duplicated for each
1290
1291
1292        :raises:
1293            + :exc:`STLError`
1294
1295    """
1296    @__api_check(True)
1297    def start (self,
1298               ports = None,
1299               mult = "1",
1300               force = False,
1301               duration = -1,
1302               total = False):
1303
1304
1305        # by default use all ports
1306        if ports == None:
1307            ports = self.get_acquired_ports()
1308
1309        # verify valid port id list
1310        rc = self._validate_port_list(ports)
1311        if not rc:
1312            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1313
1314        # verify multiplier
1315        mult_obj = parsing_opts.decode_multiplier(mult,
1316                                                  allow_update = False,
1317                                                  divide_count = len(ports) if total else 1)
1318        if not mult_obj:
1319            raise STLArgumentError('mult', mult)
1320
1321        # some type checkings
1322
1323        if not type(force) is bool:
1324            raise STLArgumentError('force', force)
1325
1326        if not isinstance(duration, (int, float)):
1327            raise STLArgumentError('duration', duration)
1328
1329        if not type(total) is bool:
1330            raise STLArgumentError('total', total)
1331
1332
1333        # verify ports are stopped or force stop them
1334        active_ports = list(set(self.get_active_ports()).intersection(ports))
1335        if active_ports:
1336            if not force:
1337                raise STLError("Port(s) {0} are active - please stop them or specify 'force'".format(active_ports))
1338            else:
1339                rc = self.stop(active_ports)
1340                if not rc:
1341                    raise STLError(rc)
1342
1343
1344        # start traffic
1345        self.logger.pre_cmd("Starting traffic on port(s) {0}:".format(ports))
1346        rc = self.__start(mult_obj, duration, ports, force)
1347        self.logger.post_cmd(rc)
1348
1349        if not rc:
1350            raise STLError(rc)
1351
1352
1353
1354
1355    """
1356        stop port(s)
1357
1358        :parameters:
1359            ports : list
1360                ports to execute the command
1361
1362
1363        :raises:
1364            + :exc:`STLError`
1365
1366    """
1367    @__api_check(True)
1368    def stop (self, ports = None):
1369
1370        # by default the user means all the active ports
1371        if ports == None:
1372            ports = self.get_active_ports()
1373            if not ports:
1374                return
1375
1376        # verify valid port id list
1377        rc = self._validate_port_list(ports)
1378        if not rc:
1379            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1380
1381        self.logger.pre_cmd("Stopping traffic on port(s) {0}:".format(ports))
1382        rc = self.__stop(ports)
1383        self.logger.post_cmd(rc)
1384
1385        if not rc:
1386            raise STLError(rc)
1387
1388
1389
1390    """
1391        update traffic on port(s)
1392
1393        :parameters:
1394            ports : list
1395                ports to execute command
1396
1397            mult : str
1398                multiplier in a form of pps, bps, or line util in %
1399                and also with +/-
1400                examples: "5kpps+", "10gbps-", "85%", "32mbps", "20%+"
1401
1402            force : bool
1403                forces a profile that exceeds the L1 BW
1404
1405            total : bool
1406                should the B/W be divided by the ports
1407                or duplicated for each
1408
1409
1410        :raises:
1411            + :exc:`STLError`
1412
1413    """
1414    @__api_check(True)
1415    def update (self, ports = None, mult = "1", total = False, force = False):
1416
1417        # by default the user means all the active ports
1418        if ports == None:
1419            ports = self.get_active_ports()
1420
1421        # verify valid port id list
1422        rc = self._validate_port_list(ports)
1423        if not rc:
1424            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1425
1426        # verify multiplier
1427        mult_obj = parsing_opts.decode_multiplier(mult,
1428                                                  allow_update = True,
1429                                                  divide_count = len(ports) if total else 1)
1430        if not mult_obj:
1431            raise STLArgumentError('mult', mult)
1432
1433        # verify total
1434        if not type(total) is bool:
1435            raise STLArgumentError('total', total)
1436
1437
1438        # call low level functions
1439        self.logger.pre_cmd("Updating traffic on port(s) {0}:".format(ports))
1440        rc = self.__update(mult, ports, force)
1441        self.logger.post_cmd(rc)
1442
1443        if not rc:
1444            raise STLError(rc)
1445
1446
1447
1448    """
1449        pause traffic on port(s)
1450
1451        :parameters:
1452            ports : list
1453                ports to execute command
1454
1455        :raises:
1456            + :exc:`STLError`
1457
1458    """
1459    @__api_check(True)
1460    def pause (self, ports = None):
1461
1462        # by default the user means all the TX ports
1463        if ports == None:
1464            ports = self.get_transmitting_ports()
1465
1466        # verify valid port id list
1467        rc = self._validate_port_list(ports)
1468        if not rc:
1469            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1470
1471        self.logger.pre_cmd("Pausing traffic on port(s) {0}:".format(ports))
1472        rc = self.__pause(ports)
1473        self.logger.post_cmd(rc)
1474
1475        if not rc:
1476            raise STLError(rc)
1477
1478
1479
1480    """
1481        resume traffic on port(s)
1482
1483        :parameters:
1484            ports : list
1485                ports to execute command
1486
1487        :raises:
1488            + :exc:`STLError`
1489
1490    """
1491    @__api_check(True)
1492    def resume (self, ports = None):
1493
1494        # by default the user means all the paused ports
1495        if ports == None:
1496            ports = self.get_paused_ports()
1497
1498        # verify valid port id list
1499        rc = self._validate_port_list(ports)
1500        if not rc:
1501            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1502
1503        self.logger.pre_cmd("Resume traffic on port(s) {0}:".format(ports))
1504        rc = self.__resume(ports)
1505        self.logger.post_cmd(rc)
1506
1507        if not rc:
1508            raise STLError(rc)
1509
1510
1511    """
1512        validate port(s) configuration
1513
1514        :parameters:
1515            ports : list
1516                ports to execute command
1517
1518         mult : str
1519                multiplier in a form of pps, bps, or line util in %
1520                examples: "5kpps", "10gbps", "85%", "32mbps"
1521
1522        duration : int
1523                limit the run for time in seconds
1524                -1 means unlimited
1525
1526        total : bool
1527                should the B/W be divided by the ports
1528                or duplicated for each
1529
1530        :raises:
1531            + :exc:`STLError`
1532
1533    """
1534    @__api_check(True)
1535    def validate (self, ports = None, mult = "1", duration = "-1", total = False):
1536        if ports == None:
1537            ports = self.get_acquired_ports()
1538
1539        # verify valid port id list
1540        rc = self._validate_port_list(ports)
1541        if not rc:
1542            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1543
1544        # verify multiplier
1545        mult_obj = parsing_opts.decode_multiplier(mult,
1546                                                  allow_update = True,
1547                                                  divide_count = len(ports) if total else 1)
1548        if not mult_obj:
1549            raise STLArgumentError('mult', mult)
1550
1551
1552        if not isinstance(duration, (int, float)):
1553            raise STLArgumentError('duration', duration)
1554
1555
1556        self.logger.pre_cmd("Validating streams on port(s) {0}:".format(ports))
1557        rc = self.__validate(ports)
1558        self.logger.post_cmd(rc)
1559
1560
1561        for port in ports:
1562            self.ports[port].print_profile(mult_obj, duration)
1563
1564
1565    """
1566        clear stats on port(s)
1567
1568        :parameters:
1569            ports : list
1570                ports to execute command
1571
1572            clear_global : bool
1573                clear the global stats
1574
1575        :raises:
1576            + :exc:`STLError`
1577
1578    """
1579    @__api_check(False)
1580    def clear_stats (self, ports = None, clear_global = True):
1581
1582        # by default use all ports
1583        if ports == None:
1584            ports = self.get_all_ports()
1585        else:
1586            ports = self.__ports(ports)
1587
1588        # verify valid port id list
1589        rc = self._validate_port_list(ports)
1590        if not rc:
1591            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1592
1593        # verify clear global
1594        if not type(clear_global) is bool:
1595            raise STLArgumentError('clear_global', clear_global)
1596
1597
1598        rc = self.__clear_stats(ports, clear_global)
1599        if not rc:
1600            raise STLError(rc)
1601
1602
1603
1604
1605
1606    """
1607        block until specify port(s) traffic has ended
1608
1609        :parameters:
1610            ports : list
1611                ports to execute command
1612
1613            timeout : int
1614                timeout in seconds
1615
1616        :raises:
1617            + :exc:`STLTimeoutError` - in case timeout has expired
1618            + :exe:'STLError'
1619
1620    """
1621    @__api_check(True)
1622    def wait_on_traffic (self, ports = None, timeout = 60):
1623
1624        # by default use all acquired ports
1625        if ports == None:
1626            ports = self.get_acquired_ports()
1627
1628        # verify valid port id list
1629        rc = self._validate_port_list(ports)
1630        if not rc:
1631            raise STLArgumentError('ports', ports, valid_values = self.get_all_ports())
1632
1633        expr = time.time() + timeout
1634
1635        # wait while any of the required ports are active
1636        while set(self.get_active_ports()).intersection(ports):
1637            time.sleep(0.01)
1638            if time.time() > expr:
1639                raise STLTimeoutError(timeout)
1640
1641
1642    """
1643        clear all events
1644
1645        :parameters:
1646            None
1647
1648        :raises:
1649            None
1650
1651    """
1652    def clear_events (self):
1653        self.event_handler.clear_events()
1654
1655
1656    ############################   Line       #############################
1657    ############################   Commands   #############################
1658    ############################              #############################
1659
1660    # console decorator
1661    def __console(f):
1662        def wrap(*args):
1663            client = args[0]
1664
1665            time1 = time.time()
1666
1667            try:
1668                rc = f(*args)
1669            except STLError as e:
1670                client.logger.log("Log:\n" + format_text(e.brief() + "\n", 'bold'))
1671                return
1672
1673            # if got true - print time
1674            if rc:
1675                delta = time.time() - time1
1676                client.logger.log(format_time(delta) + "\n")
1677
1678
1679        return wrap
1680
1681
1682    @__console
1683    def connect_line (self, line):
1684        '''Connects to the TRex server'''
1685        # define a parser
1686        parser = parsing_opts.gen_parser(self,
1687                                         "connect",
1688                                         self.connect_line.__doc__,
1689                                         parsing_opts.FORCE)
1690
1691        opts = parser.parse_args(line.split())
1692
1693        if opts is None:
1694            return
1695
1696        # call the API
1697        self.connect()
1698        self.acquire(force = opts.force)
1699
1700        # true means print time
1701        return True
1702
1703    @__console
1704    def disconnect_line (self, line):
1705        self.disconnect()
1706
1707
1708
1709    @__console
1710    def reset_line (self, line):
1711        self.reset()
1712
1713        # true means print time
1714        return True
1715
1716
1717    @__console
1718    def start_line (self, line):
1719        '''Start selected traffic in specified ports on TRex\n'''
1720        # define a parser
1721        parser = parsing_opts.gen_parser(self,
1722                                         "start",
1723                                         self.start_line.__doc__,
1724                                         parsing_opts.PORT_LIST_WITH_ALL,
1725                                         parsing_opts.TOTAL,
1726                                         parsing_opts.FORCE,
1727                                         parsing_opts.STREAM_FROM_PATH_OR_FILE,
1728                                         parsing_opts.DURATION,
1729                                         parsing_opts.MULTIPLIER_STRICT,
1730                                         parsing_opts.DRY_RUN)
1731
1732        opts = parser.parse_args(line.split())
1733
1734
1735        if opts is None:
1736            return
1737
1738
1739        active_ports = list(set(self.get_active_ports()).intersection(opts.ports))
1740
1741        if active_ports:
1742            if not opts.force:
1743                msg = "Port(s) {0} are active - please stop them or add '--force'\n".format(active_ports)
1744                self.logger.log(format_text(msg, 'bold'))
1745                return
1746            else:
1747                self.stop(active_ports)
1748
1749
1750        # remove all streams
1751        self.remove_all_streams(opts.ports)
1752
1753        # pack the profile
1754        try:
1755            profile = STLProfile.load(opts.file[0])
1756        except STLError as e:
1757            print format_text("\nError while loading profile '{0}'\n".format(opts.file[0]), 'bold')
1758            print e.brief() + "\n"
1759            return
1760
1761
1762        self.add_streams(profile.get_streams(), ports = opts.ports)
1763
1764        if opts.dry:
1765            self.validate(opts.ports, opts.mult, opts.duration, opts.total)
1766        else:
1767            self.start(opts.ports,
1768                       opts.mult,
1769                       opts.force,
1770                       opts.duration,
1771                       opts.total)
1772
1773        # true means print time
1774        return True
1775
1776
1777
1778    @__console
1779    def stop_line (self, line):
1780        '''Stop active traffic in specified ports on TRex\n'''
1781        parser = parsing_opts.gen_parser(self,
1782                                         "stop",
1783                                         self.stop_line.__doc__,
1784                                         parsing_opts.PORT_LIST_WITH_ALL)
1785
1786        opts = parser.parse_args(line.split())
1787        if opts is None:
1788            return
1789
1790        # find the relevant ports
1791        ports = list(set(self.get_active_ports()).intersection(opts.ports))
1792
1793        if not ports:
1794            self.logger.log(format_text("No active traffic on provided ports\n", 'bold'))
1795            return
1796
1797        self.stop(ports)
1798
1799        # true means print time
1800        return True
1801
1802
1803    @__console
1804    def update_line (self, line):
1805        '''Update port(s) speed currently active\n'''
1806        parser = parsing_opts.gen_parser(self,
1807                                         "update",
1808                                         self.update_line.__doc__,
1809                                         parsing_opts.PORT_LIST_WITH_ALL,
1810                                         parsing_opts.MULTIPLIER,
1811                                         parsing_opts.TOTAL,
1812                                         parsing_opts.FORCE)
1813
1814        opts = parser.parse_args(line.split())
1815        if opts is None:
1816            return
1817
1818         # find the relevant ports
1819        ports = list(set(self.get_active_ports()).intersection(opts.ports))
1820
1821        if not ports:
1822            self.logger.log(format_text("No ports in valid state to update\n", 'bold'))
1823            return
1824
1825        self.update(ports, opts.mult, opts.total, opts.force)
1826
1827        # true means print time
1828        return True
1829
1830
1831    @__console
1832    def pause_line (self, line):
1833        '''Pause active traffic in specified ports on TRex\n'''
1834        parser = parsing_opts.gen_parser(self,
1835                                         "pause",
1836                                         self.pause_line.__doc__,
1837                                         parsing_opts.PORT_LIST_WITH_ALL)
1838
1839        opts = parser.parse_args(line.split())
1840        if opts is None:
1841            return
1842
1843        # find the relevant ports
1844        ports = list(set(self.get_transmitting_ports()).intersection(opts.ports))
1845
1846        if not ports:
1847            self.logger.log(format_text("No ports in valid state to pause\n", 'bold'))
1848            return
1849
1850        self.pause(ports)
1851
1852        # true means print time
1853        return True
1854
1855
1856    @__console
1857    def resume_line (self, line):
1858        '''Resume active traffic in specified ports on TRex\n'''
1859        parser = parsing_opts.gen_parser(self,
1860                                         "resume",
1861                                         self.resume_line.__doc__,
1862                                         parsing_opts.PORT_LIST_WITH_ALL)
1863
1864        opts = parser.parse_args(line.split())
1865        if opts is None:
1866            return
1867
1868        # find the relevant ports
1869        ports = list(set(self.get_paused_ports()).intersection(opts.ports))
1870
1871        if not ports:
1872            self.logger.log(format_text("No ports in valid state to resume\n", 'bold'))
1873            return
1874
1875        return self.resume(ports)
1876
1877        # true means print time
1878        return True
1879
1880
1881    @__console
1882    def clear_stats_line (self, line):
1883        '''Clear cached local statistics\n'''
1884        # define a parser
1885        parser = parsing_opts.gen_parser(self,
1886                                         "clear",
1887                                         self.clear_stats_line.__doc__,
1888                                         parsing_opts.PORT_LIST_WITH_ALL)
1889
1890        opts = parser.parse_args(line.split())
1891
1892        if opts is None:
1893            return
1894
1895        self.clear_stats(opts.ports)
1896
1897
1898
1899
1900    @__console
1901    def show_stats_line (self, line):
1902        '''Fetch statistics from TRex server by port\n'''
1903        # define a parser
1904        parser = parsing_opts.gen_parser(self,
1905                                         "stats",
1906                                         self.show_stats_line.__doc__,
1907                                         parsing_opts.PORT_LIST_WITH_ALL,
1908                                         parsing_opts.STATS_MASK)
1909
1910        opts = parser.parse_args(line.split())
1911
1912        if opts is None:
1913            return
1914
1915        # determine stats mask
1916        mask = self.__get_mask_keys(**self.__filter_namespace_args(opts, trex_stl_stats.ALL_STATS_OPTS))
1917        if not mask:
1918            # set to show all stats if no filter was given
1919            mask = trex_stl_stats.ALL_STATS_OPTS
1920
1921        stats_opts = trex_stl_stats.ALL_STATS_OPTS.intersection(mask)
1922
1923        stats = self._get_formatted_stats(opts.ports, mask)
1924
1925
1926        # print stats to screen
1927        for stat_type, stat_data in stats.iteritems():
1928            text_tables.print_table_with_header(stat_data.text_table, stat_type)
1929
1930
1931    @__console
1932    def show_streams_line(self, line):
1933        '''Fetch streams statistics from TRex server by port\n'''
1934        # define a parser
1935        parser = parsing_opts.gen_parser(self,
1936                                         "streams",
1937                                         self.show_streams_line.__doc__,
1938                                         parsing_opts.PORT_LIST_WITH_ALL,
1939                                         parsing_opts.STREAMS_MASK)
1940
1941        opts = parser.parse_args(line.split())
1942
1943        if opts is None:
1944            return
1945
1946        streams = self._get_streams(opts.ports, set(opts.streams))
1947        if not streams:
1948            self.logger.log(format_text("No streams found with desired filter.\n", "bold", "magenta"))
1949
1950        else:
1951            # print stats to screen
1952            for stream_hdr, port_streams_data in streams.iteritems():
1953                text_tables.print_table_with_header(port_streams_data.text_table,
1954                                                    header= stream_hdr.split(":")[0] + ":",
1955                                                    untouched_header= stream_hdr.split(":")[1])
1956
1957
1958
1959
1960    @__console
1961    def validate_line (self, line):
1962        '''validates port(s) stream configuration\n'''
1963
1964        parser = parsing_opts.gen_parser(self,
1965                                         "validate",
1966                                         self.validate_line.__doc__,
1967                                         parsing_opts.PORT_LIST_WITH_ALL)
1968
1969        opts = parser.parse_args(line.split())
1970        if opts is None:
1971            return
1972
1973        self.validate(opts.ports)
1974
1975
1976
1977