def __init__(self, username, server="localhost", sync_port = 5050, async_port = 4500, quiet = False, virtual = False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual, self.prn_func) # default verbose level if not quiet: self.verbose = self.VERBOSE_REGULAR else: self.verbose = self.VERBOSE_QUIET self.ports = {} self._connection_info = {"server": server, "sync_port": sync_port, "async_port": async_port} self.system_info = {} self.server_version = {} self.__err_log = None self.async_client = CTRexAsyncClient(server, async_port, self, self.prn_func) self.streams_db = CStreamsDB() self.global_stats = trex_stats.CGlobalStats(self._connection_info, self.server_version, self.ports) self.stats_generator = trex_stats.CTRexStatsGenerator(self.global_stats, self.ports) self.events = [] self.session_id = random.getrandbits(32) self.read_only = False self.connected = False
def __init__(self, username, server="localhost", sync_port=5050, async_port=4500, quiet=False, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink( server, sync_port, virtual, self.prn_func) # default verbose level if not quiet: self.verbose = self.VERBOSE_REGULAR else: self.verbose = self.VERBOSE_QUIET self.ports = {} self._connection_info = { "server": server, "sync_port": sync_port, "async_port": async_port } self.system_info = {} self.server_version = {} self.__err_log = None self.async_client = CTRexAsyncClient(server, async_port, self, self.prn_func) self.streams_db = CStreamsDB() self.global_stats = trex_stats.CGlobalStats(self._connection_info, self.server_version, self.ports) self.stats_generator = trex_stats.CTRexStatsGenerator( self.global_stats, self.ports) self.events = [] self.session_id = random.getrandbits(32) self.read_only = False self.connected = False
def __init__(self, username, server="localhost", sync_port=5050, async_port=4500, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual) self.verbose = False self._conn_handler = {} self._active_ports = set() self._stats = CTRexStatsManager("port", "stream") self._system_info = None self._server_version = None self.__err_log = None self._async_client = CTRexAsyncClient(async_port)
def __init__(self, username, server="localhost", sync_port=5050, async_port=4500, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink( server, sync_port, virtual) self.verbose = False self.ports = [] self._conn_handler = {} self._active_ports = set() self._system_info = None self._server_version = None self.__err_log = None self._async_client = CTRexAsyncClient(server, async_port, self) self.streams_db = CStreamsDB() self.connected = False
class CTRexStatelessClient(object): """docstring for CTRexStatelessClient""" # verbose levels VERBOSE_QUIET = 0 VERBOSE_REGULAR = 1 VERBOSE_HIGH = 2 def __init__(self, username, server="localhost", sync_port = 5050, async_port = 4500, quiet = False, virtual = False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual, self.prn_func) # default verbose level if not quiet: self.verbose = self.VERBOSE_REGULAR else: self.verbose = self.VERBOSE_QUIET self.ports = {} self._connection_info = {"server": server, "sync_port": sync_port, "async_port": async_port} self.system_info = {} self.server_version = {} self.__err_log = None self.async_client = CTRexAsyncClient(server, async_port, self, self.prn_func) self.streams_db = CStreamsDB() self.global_stats = trex_stats.CGlobalStats(self._connection_info, self.server_version, self.ports) self.stats_generator = trex_stats.CTRexStatsGenerator(self.global_stats, self.ports) self.events = [] self.session_id = random.getrandbits(32) self.read_only = False self.connected = False # returns the port object def get_port (self, port_id): return self.ports.get(port_id, None) # connection server ip def get_server_ip (self): return self.comm_link.get_server() # connection server port def get_server_port (self): return self.comm_link.get_port() ################# events handler ###################### def add_event_log (self, msg, ev_type, show = False): if ev_type == "server": prefix = "[server]" elif ev_type == "local": prefix = "[local]" ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') self.events.append("{:<10} - {:^8} - {:}".format(st, prefix, format_text(msg, 'bold'))) if show: self.prn_func(format_text("\n{:^8} - {:}".format(prefix, format_text(msg, 'bold')))) def handle_async_stats_update(self, dump_data): global_stats = {} port_stats = {} # filter the values per port and general for key, value in dump_data.iteritems(): # match a pattern of ports m = re.search('(.*)\-([0-8])', key) if m: port_id = int(m.group(2)) field_name = m.group(1) if self.ports.has_key(port_id): if not port_id in port_stats: port_stats[port_id] = {} port_stats[port_id][field_name] = value else: continue else: # no port match - general stats global_stats[key] = value # update the general object with the snapshot self.global_stats.update(global_stats) # update all ports for port_id, data in port_stats.iteritems(): self.ports[port_id].port_stats.update(data) def handle_async_event (self, type, data): # DP stopped show_event = False # port started if (type == 0): port_id = int(data['port_id']) ev = "Port {0} has started".format(port_id) self.async_event_port_started(port_id) # port stopped elif (type == 1): port_id = int(data['port_id']) ev = "Port {0} has stopped".format(port_id) # call the handler self.async_event_port_stopped(port_id) # port paused elif (type == 2): port_id = int(data['port_id']) ev = "Port {0} has paused".format(port_id) # call the handler self.async_event_port_paused(port_id) # port resumed elif (type == 3): port_id = int(data['port_id']) ev = "Port {0} has resumed".format(port_id) # call the handler self.async_event_port_resumed(port_id) # port finished traffic elif (type == 4): port_id = int(data['port_id']) ev = "Port {0} job done".format(port_id) # call the handler self.async_event_port_stopped(port_id) show_event = True # port was stolen... elif (type == 5): session_id = data['session_id'] # false alarm, its us if session_id == self.session_id: return port_id = int(data['port_id']) who = data['who'] ev = "Port {0} was forcely taken by '{1}'".format(port_id, who) # call the handler self.async_event_port_forced_acquired(port_id) show_event = True # server stopped elif (type == 100): ev = "Server has stopped" self.async_event_server_stopped() show_event = True else: # unknown event - ignore return self.add_event_log(ev, 'server', show_event) def async_event_port_stopped (self, port_id): self.ports[port_id].async_event_port_stopped() def async_event_port_started (self, port_id): self.ports[port_id].async_event_port_started() def async_event_port_paused (self, port_id): self.ports[port_id].async_event_port_paused() def async_event_port_resumed (self, port_id): self.ports[port_id].async_event_port_resumed() def async_event_port_forced_acquired (self, port_id): self.ports[port_id].async_event_forced_acquired() self.read_only = True def async_event_server_stopped (self): self.connected = False def get_events (self): return self.events def clear_events (self): self.events = [] ############# helper functions section ############## # measure time for functions def timing(f): def wrap(*args): time1 = time.time() ret = f(*args) # don't want to print on error if ret.bad(): return ret delta = time.time() - time1 print format_time(delta) + "\n" return ret return wrap def validate_port_list(self, port_id_list): if not isinstance(port_id_list, list): print type(port_id_list) return False # check each item of the sequence return all([ (port_id >= 0) and (port_id < self.get_port_count()) for port_id in port_id_list ]) # some preprocessing for port argument def __ports (self, port_id_list): # none means all if port_id_list == None: return range(0, self.get_port_count()) # always list if isinstance(port_id_list, int): port_id_list = [port_id_list] if not isinstance(port_id_list, list): raise ValueError("bad port id list: {0}".format(port_id_list)) for port_id in port_id_list: if not isinstance(port_id, int) or (port_id < 0) or (port_id > self.get_port_count()): raise ValueError("bad port id {0}".format(port_id)) return port_id_list ############ boot up section ################ # connection sequence # mode can be RW - read / write, RWF - read write with force , RO - read only def connect(self, mode = "RW"): if self.is_connected(): self.disconnect() # clear this flag self.connected = False # connect sync channel rc = self.comm_link.connect() if rc.bad(): return rc # connect async channel rc = self.async_client.connect() if rc.bad(): return rc # version rc = self.transmit("get_version") if rc.bad(): return rc self.server_version = rc.data() self.global_stats.server_version = rc.data() # cache system info rc = self.transmit("get_system_info") if rc.bad(): return rc self.system_info = rc.data() # cache supported commands rc = self.transmit("get_supported_cmds") if rc.bad(): return rc self.supported_cmds = rc.data() # create ports for port_id in xrange(self.get_port_count()): speed = self.system_info['ports'][port_id]['speed'] driver = self.system_info['ports'][port_id]['driver'] self.ports[port_id] = Port(port_id, speed, driver, self.user, self.comm_link, self.session_id) # sync the ports rc = self.sync_ports() if rc.bad(): return rc # acquire all ports if mode == "RW": rc = self.acquire(force = False) # fallback to read only if failed if rc.bad(): rc.annotate(show_status = False) print format_text("Switching to read only mode - only few commands will be available", 'bold') self.release(self.get_acquired_ports()) self.read_only = True else: self.read_only = False elif mode == "RWF": rc = self.acquire(force = True) if rc.bad(): return rc self.read_only = False elif mode == "RO": # no acquire on read only rc = RC_OK() self.read_only = True self.connected = True return RC_OK() def is_read_only (self): return self.read_only def is_connected (self): return self.connected and self.comm_link.is_connected def disconnect(self): # release any previous acquired ports if self.is_connected(): self.release(self.get_acquired_ports()) self.comm_link.disconnect() self.async_client.disconnect() self.connected = False return RC_OK() def on_async_dead (self): if self.connected: msg = 'lost connection to server' self.add_event_log(msg, 'local', True) self.connected = False def on_async_alive (self): pass ########### cached queries (no server traffic) ########### def get_supported_cmds(self): return self.supported_cmds def get_version(self): return self.server_version def get_system_info(self): return self.system_info def get_port_count(self): return self.system_info.get("port_count") def get_port_ids(self, as_str=False): port_ids = range(self.get_port_count()) if as_str: return " ".join(str(p) for p in port_ids) else: return port_ids def get_stats_async (self): return self.async_client.get_stats() def get_connection_port (self): return self.comm_link.port def get_connection_ip (self): return self.comm_link.server def get_all_ports (self): return [port_id for port_id, port_obj in self.ports.iteritems()] def get_acquired_ports(self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_acquired()] def get_active_ports(self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_active()] def get_paused_ports (self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_paused()] def get_transmitting_ports (self): return [port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_transmitting()] def set_verbose(self, mode): # on high - enable link verbose if mode == self.VERBOSE_HIGH: self.comm_link.set_verbose(True) else: self.comm_link.set_verbose(False) self.verbose = mode def check_verbose (self, level): return (self.verbose >= level) def get_verbose (self): return self.verbose def prn_func (self, msg, level = VERBOSE_REGULAR): if self.check_verbose(level): print msg ############# server actions ################ # ping server def ping(self): return self.transmit("ping") def get_global_stats(self): return self.transmit("get_global_stats") ########## port commands ############## def sync_ports (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].sync()) return rc # acquire ports, if port_list is none - get all def acquire (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].acquire(force)) return rc # release ports def release (self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].release()) return rc def add_stream(self, stream_id, stream_obj, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_stream(stream_id, stream_obj)) return rc def add_stream_pack(self, stream_pack_list, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_streams(stream_pack_list)) return rc def remove_stream(self, stream_id, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_stream(stream_id)) return rc def remove_all_streams(self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_all_streams()) return rc def get_stream(self, stream_id, port_id, get_pkt = False): return self.ports[port_id].get_stream(stream_id) def get_all_streams(self, port_id, get_pkt = False): return self.ports[port_id].get_all_streams() def get_stream_id_list(self, port_id): return self.ports[port_id].get_stream_id_list() def start_traffic (self, multiplier, duration, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].start(multiplier, duration)) return rc def resume_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].resume()) return rc def pause_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].pause()) return rc def stop_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].stop(force)) return rc def update_traffic (self, mult, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].update(mult)) return rc def validate (self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].validate()) return rc def get_port_stats(self, port_id=None): pass def get_stream_stats(self, port_id=None): pass def transmit(self, method_name, params={}): return self.comm_link.transmit(method_name, params) def transmit_batch(self, batch_list): return self.comm_link.transmit_batch(batch_list) ######################### Console (high level) API ######################### @timing def cmd_ping(self): rc = self.ping() rc.annotate("Pinging the server on '{0}' port '{1}': ".format(self.get_connection_ip(), self.get_connection_port())) return rc def cmd_connect(self, mode = "RW"): rc = self.connect(mode) rc.annotate() return rc def cmd_disconnect(self): rc = self.disconnect() rc.annotate() return rc # reset def cmd_reset(self): #self.release(self.get_acquired_ports()) rc = self.acquire(force = True) rc.annotate("Force acquiring all ports:") if rc.bad(): return rc # force stop all ports rc = self.stop_traffic(self.get_port_ids(), True) rc.annotate("Stop traffic on all ports:") if rc.bad(): return rc # remove all streams rc = self.remove_all_streams(self.get_port_ids()) rc.annotate("Removing all streams from all ports:") if rc.bad(): return rc # TODO: clear stats return RC_OK() # stop cmd def cmd_stop (self, port_id_list): # find the relveant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.stop_traffic(active_ports) rc.annotate("Stopping traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() # update cmd def cmd_update (self, port_id_list, mult): # find the relevant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.update_traffic(mult, active_ports) rc.annotate("Updating traffic on port(s) {0}:".format(port_id_list)) return rc # clear stats def cmd_clear(self, port_id_list): for port_id in port_id_list: self.ports[port_id].clear_stats() self.global_stats.clear_stats() return RC_OK() def cmd_invalidate (self, port_id_list): for port_id in port_id_list: self.ports[port_id].invalidate_stats() self.global_stats.invalidate() return RC_OK() # pause cmd def cmd_pause (self, port_id_list): # find the relevant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.pause_traffic(active_ports) rc.annotate("Pausing traffic on port(s) {0}:".format(port_id_list)) return rc # resume cmd def cmd_resume (self, port_id_list): # find the relveant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.resume_traffic(active_ports) rc.annotate("Resume traffic on port(s) {0}:".format(port_id_list)) return rc # start cmd def cmd_start (self, port_id_list, stream_list, mult, force, duration, dry): active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if active_ports: if not force: msg = "Port(s) {0} are active - please stop them or add '--force'".format(active_ports) print format_text(msg, 'bold') return RC_ERR(msg) else: rc = self.cmd_stop(active_ports) if not rc: return rc rc = self.remove_all_streams(port_id_list) rc.annotate("Removing all streams from port(s) {0}:".format(port_id_list)) if rc.bad(): return rc rc = self.add_stream_pack(stream_list.compiled, port_id_list) rc.annotate("Attaching {0} streams to port(s) {1}:".format(len(stream_list.compiled), port_id_list)) if rc.bad(): return rc # when not on dry - start the traffic , otherwise validate only if not dry: rc = self.start_traffic(mult, duration, port_id_list) rc.annotate("Starting traffic on port(s) {0}:".format(port_id_list)) return rc else: rc = self.validate(port_id_list) rc.annotate("Validating traffic profile on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc # show a profile on one port for illustration self.ports[port_id_list[0]].print_profile(mult, duration) return rc # validate port(s) profile def cmd_validate (self, port_id_list): rc = self.validate(port_id_list) rc.annotate("Validating streams on port(s) {0}:".format(port_id_list)) return rc # stats def cmd_stats(self, port_id_list, stats_mask=set()): stats_opts = trex_stats.ALL_STATS_OPTS.intersection(stats_mask) stats_obj = {} for stats_type in stats_opts: stats_obj.update(self.stats_generator.generate_single_statistic(port_id_list, stats_type)) return stats_obj ############## High Level API With Parser ################ def cmd_connect_line (self, line): '''Connects to the TRex server''' # define a parser parser = parsing_opts.gen_parser(self, "connect", self.cmd_connect_line.__doc__, parsing_opts.FORCE) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") if opts.force: rc = self.cmd_connect(mode = "RWF") else: rc = self.cmd_connect(mode = "RW") @timing def cmd_start_line (self, line): '''Start selected traffic in specified ports on TRex\n''' # define a parser parser = parsing_opts.gen_parser(self, "start", self.cmd_start_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.TOTAL, parsing_opts.FORCE, parsing_opts.STREAM_FROM_PATH_OR_FILE, parsing_opts.DURATION, parsing_opts.MULTIPLIER_STRICT, parsing_opts.DRY_RUN) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") if opts.dry: print format_text("\n*** DRY RUN ***", 'bold') if opts.db: stream_list = self.streams_db.get_stream_pack(opts.db) rc = RC(stream_list != None) rc.annotate("Load stream pack (from DB):") if rc.bad(): return RC_ERR("Failed to load stream pack") else: # load streams from file stream_list = None; try: stream_list = self.streams_db.load_yaml_file(opts.file[0]) except Exception as e: s = str(e) rc=RC_ERR(s) rc.annotate() return rc rc = RC(stream_list != None) rc.annotate("Load stream pack (from file):") if stream_list == None: return RC_ERR("Failed to load stream pack") # total has no meaning with percentage - its linear if opts.total and (opts.mult['type'] != 'percentage'): # if total was set - divide it between the ports opts.mult['value'] = opts.mult['value'] / len(opts.ports) return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration, opts.dry) @timing def cmd_resume_line (self, line): '''Resume active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "resume", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_resume(opts.ports) @timing def cmd_stop_line (self, line): '''Stop active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "stop", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_stop(opts.ports) @timing def cmd_pause_line (self, line): '''Pause active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "pause", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_pause(opts.ports) @timing def cmd_update_line (self, line): '''Update port(s) speed currently active\n''' parser = parsing_opts.gen_parser(self, "update", self.cmd_update_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.MULTIPLIER, parsing_opts.TOTAL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") # total has no meaning with percentage - its linear if opts.total and (opts.mult['type'] != 'percentage'): # if total was set - divide it between the ports opts.mult['value'] = opts.mult['value'] / len(opts.ports) return self.cmd_update(opts.ports, opts.mult) @timing def cmd_reset_line (self, line): return self.cmd_reset() def cmd_clear_line (self, line): '''Clear cached local statistics\n''' # define a parser parser = parsing_opts.gen_parser(self, "clear", self.cmd_clear_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_clear(opts.ports) def cmd_stats_line (self, line): '''Fetch statistics from TRex server by port\n''' # define a parser parser = parsing_opts.gen_parser(self, "stats", self.cmd_stats_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.STATS_MASK) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") # determine stats mask mask = self._get_mask_keys(**self._filter_namespace_args(opts, trex_stats.ALL_STATS_OPTS)) if not mask: # set to show all stats if no filter was given mask = trex_stats.ALL_STATS_OPTS stats = self.cmd_stats(opts.ports, mask) # print stats to screen for stat_type, stat_data in stats.iteritems(): text_tables.print_table_with_header(stat_data.text_table, stat_type) return RC_OK() @timing def cmd_validate_line (self, line): '''validates port(s) stream configuration\n''' parser = parsing_opts.gen_parser(self, "validate", self.cmd_validate_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") rc = self.cmd_validate(opts.ports) return rc def cmd_exit_line (self, line): print format_text("Exiting\n", 'bold') # a way to exit return RC_ERR("exit") def cmd_wait_line (self, line): '''wait for a period of time\n''' parser = parsing_opts.gen_parser(self, "wait", self.cmd_wait_line.__doc__, parsing_opts.DURATION) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") delay_sec = opts.duration if (opts.duration > 0) else 1 print format_text("Waiting for {0} seconds...\n".format(delay_sec), 'bold') time.sleep(delay_sec) return RC_OK() # run a script of commands def run_script_file (self, filename): print format_text("\nRunning script file '{0}'...".format(filename), 'bold') rc = self.cmd_connect() if rc.bad(): return with open(filename) as f: script_lines = f.readlines() cmd_table = {} # register all the commands cmd_table['start'] = self.cmd_start_line cmd_table['stop'] = self.cmd_stop_line cmd_table['reset'] = self.cmd_reset_line cmd_table['wait'] = self.cmd_wait_line cmd_table['exit'] = self.cmd_exit_line for index, line in enumerate(script_lines, start = 1): line = line.strip() if line == "": continue if line.startswith("#"): continue sp = line.split(' ', 1) cmd = sp[0] if len(sp) == 2: args = sp[1] else: args = "" print format_text("Executing line {0} : '{1}'\n".format(index, line)) if not cmd in cmd_table: print "\n*** Error at line {0} : '{1}'\n".format(index, line) print format_text("unknown command '{0}'\n".format(cmd), 'bold') return False rc = cmd_table[cmd](args) if rc.bad(): return False print format_text("\n[Done]", 'bold') return True ################################# # ------ private methods ------ # @staticmethod def _get_mask_keys(ok_values={True}, **kwargs): masked_keys = set() for key, val in kwargs.iteritems(): if val in ok_values: masked_keys.add(key) return masked_keys @staticmethod def _filter_namespace_args(namespace, ok_values): return {k: v for k, v in namespace.__dict__.items() if k in ok_values} ################################# # ------ private classes ------ # class CCommLink(object): """describes the connectivity of the stateless client method""" def __init__(self, server="localhost", port=5050, virtual=False, prn_func = None): super(CTRexStatelessClient.CCommLink, self).__init__() self.virtual = virtual self.server = server self.port = port self.verbose = False self.rpc_link = JsonRpcClient(self.server, self.port, prn_func) @property def is_connected(self): if not self.virtual: return self.rpc_link.connected else: return True def get_server (self): return self.server def get_port (self): return self.port def set_verbose(self, mode): self.verbose = mode return self.rpc_link.set_verbose(mode) def connect(self): if not self.virtual: return self.rpc_link.connect() def disconnect(self): if not self.virtual: return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: self._prompt_virtual_tx_msg() _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params) print msg return else: return self.rpc_link.invoke_rpc_method(method_name, params) def transmit_batch(self, batch_list): if self.virtual: self._prompt_virtual_tx_msg() print [msg for _, msg in [self.rpc_link.create_jsonrpc_v2(command.method, command.params) for command in batch_list]] else: batch = self.rpc_link.create_batch() for command in batch_list: batch.add(command.method, command.params) # invoke the batch return batch.invoke() def _prompt_virtual_tx_msg(self): print "Transmitting virtually over tcp://{server}:{port}".format(server=self.server, port=self.port)
class CTRexStatelessClient(object): """docstring for CTRexStatelessClient""" def __init__(self, username, server="localhost", sync_port=5050, async_port=4500, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink( server, sync_port, virtual) self.verbose = False self.ports = [] self._conn_handler = {} self._active_ports = set() self._system_info = None self._server_version = None self.__err_log = None self._async_client = CTRexAsyncClient(server, async_port, self) self.streams_db = CStreamsDB() self.connected = False ################# events handler ###################### def async_event_port_stopped(self, port_id): self.ports[port_id].async_event_port_stopped() ############# helper functions section ############## def validate_port_list(self, port_id_list): if not isinstance(port_id_list, list): print type(port_id_list) return False # check each item of the sequence return all([(port_id >= 0) and (port_id < self.get_port_count()) for port_id in port_id_list]) # some preprocessing for port argument def __ports(self, port_id_list): # none means all if port_id_list == None: return range(0, self.get_port_count()) # always list if isinstance(port_id_list, int): port_id_list = [port_id_list] if not isinstance(port_id_list, list): raise ValueError("bad port id list: {0}".format(port_id_list)) for port_id in port_id_list: if not isinstance(port_id, int) or (port_id < 0) or ( port_id > self.get_port_count()): raise ValueError("bad port id {0}".format(port_id)) return port_id_list ############ boot up section ################ # connection sequence def connect(self): self.connected = False # connect rc, data = self.comm_link.connect() if not rc: return RC_ERR(data) # version rc, data = self.transmit("get_version") if not rc: return RC_ERR(data) self.server_version = data # cache system info rc, data = self.transmit("get_system_info") if not rc: return RC_ERR(data) self.system_info = data # cache supported commands rc, data = self.transmit("get_supported_cmds") if not rc: return RC_ERR(data) self.supported_cmds = data # create ports for port_id in xrange(self.get_port_count()): self.ports.append(Port(port_id, self.user, self.transmit)) # acquire all ports rc = self.acquire() if rc.bad(): return rc rc = self.sync_with_server() if rc.bad(): return rc self.connected = True return RC_OK() def is_connected(self): return self.connected and self.comm_link.is_connected def disconnect(self): self.connected = False self.comm_link.disconnect() return RC_OK() ########### cached queries (no server traffic) ########### def get_supported_cmds(self): return self.supported_cmds def get_version(self): return self.server_version def get_system_info(self): return self.system_info def get_port_count(self): return self.system_info.get("port_count") def get_port_ids(self, as_str=False): port_ids = range(self.get_port_count()) if as_str: return " ".join(str(p) for p in port_ids) else: return port_ids def get_stats_async(self): return self._async_client.get_stats() def get_connection_port(self): return self.comm_link.port def get_connection_ip(self): return self.comm_link.server def get_acquired_ports(self): return [port.port_id for port in self.ports if port.is_acquired()] def get_active_ports(self): return [port.port_id for port in self.ports if port.is_active()] def set_verbose(self, mode): self.comm_link.set_verbose(mode) self.verbose = mode ############# server actions ################ # ping server def ping(self): rc, info = self.transmit("ping") return RC(rc, info) def sync_with_server(self, sync_streams=False): rc, data = self.transmit("sync_user", { "user": self.user, "sync_streams": sync_streams }) if not rc: return RC_ERR(data) for port_info in data: rc = self.ports[port_info['port_id']].sync(port_info) if rc.bad(): return rc return RC_OK() ########## port commands ############## # acquire ports, if port_list is none - get all def acquire(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].acquire(force)) return rc # release ports def release(self, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].release(force)) return rc def add_stream(self, stream_id, stream_obj, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_stream(stream_id, stream_obj)) return rc def add_stream_pack(self, stream_pack_list, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for stream_pack in stream_pack_list: rc.add( self.add_stream(stream_pack.stream_id, stream_pack.stream, port_id_list)) return rc def remove_stream(self, stream_id, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_stream(stream_id)) return rc def remove_all_streams(self, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_all_streams()) return rc def get_stream(self, stream_id, port_id, get_pkt=False): return self.ports[port_id].get_stream(stream_id) def get_all_streams(self, port_id, get_pkt=False): return self.ports[port_id].get_all_streams() def get_stream_id_list(self, port_id): return self.ports[port_id].get_stream_id_list() def start_traffic(self, multiplier, duration, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].start(multiplier, duration)) return rc def resume_traffic(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].resume()) return rc def pause_traffic(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].pause()) return rc def stop_traffic(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].stop(force)) return rc def get_port_stats(self, port_id=None): pass def get_stream_stats(self, port_id=None): pass def transmit(self, method_name, params={}): return self.comm_link.transmit(method_name, params) ######################### Console (high level) API ######################### def cmd_ping(self): rc = self.ping() rc.annotate("Pinging the server on '{0}' port '{1}': ".format( self.get_connection_ip(), self.get_connection_port())) return rc def cmd_connect(self): rc = self.connect() rc.annotate() return rc def cmd_disconnect(self): rc = self.disconnect() rc.annotate() return rc # reset def cmd_reset(self): # sync with the server rc = self.sync_with_server() rc.annotate("Syncing with the server:") if rc.bad(): return rc rc = self.acquire(force=True) rc.annotate("Force acquiring all ports:") if rc.bad(): return rc # force stop all ports rc = self.stop_traffic(self.get_port_ids(), True) rc.annotate("Stop traffic on all ports:") if rc.bad(): return rc # remove all streams rc = self.remove_all_streams(self.get_port_ids()) rc.annotate("Removing all streams from all ports:") if rc.bad(): return rc # TODO: clear stats return RC_OK() # stop cmd def cmd_stop(self, port_id_list): # find the relveant ports active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.stop_traffic(active_ports) rc.annotate("Stopping traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() # pause cmd def cmd_pause(self, port_id_list): # find the relveant ports active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.pause_traffic(active_ports) rc.annotate("Pausing traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() def cmd_pause_line(self, line): '''Pause active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "pause", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") return self.cmd_pause(opts.ports) # resume cmd def cmd_resume(self, port_id_list): # find the relveant ports active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.resume_traffic(active_ports) rc.annotate("Resume traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() def cmd_resume_line(self, line): '''Resume active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "resume", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") return self.cmd_resume(opts.ports) # start cmd def cmd_start(self, port_id_list, stream_list, mult, force, duration): active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if active_ports: if not force: msg = "Port(s) {0} are active - please stop them or add '--force'".format( active_ports) print format_text(msg, 'bold') return RC_ERR(msg) else: rc = self.cmd_stop(active_ports) if not rc: return rc rc = self.remove_all_streams(port_id_list) rc.annotate( "Removing all streams from port(s) {0}:".format(port_id_list)) if rc.bad(): return rc rc = self.add_stream_pack(stream_list.compiled, port_id_list) rc.annotate("Attaching streams to port(s) {0}:".format(port_id_list)) if rc.bad(): return rc # finally, start the traffic rc = self.start_traffic(mult, duration, port_id_list) rc.annotate("Starting traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() ############## High Level API With Parser ################ def cmd_start_line(self, line): '''Start selected traffic in specified ports on TRex\n''' # define a parser parser = parsing_opts.gen_parser( self, "start", self.cmd_start_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.FORCE, parsing_opts.STREAM_FROM_PATH_OR_FILE, parsing_opts.DURATION, parsing_opts.MULTIPLIER) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") if opts.db: stream_list = self.stream_db.get_stream_pack(opts.db) rc = RC(stream_list != None) rc.annotate("Load stream pack (from DB):") if rc.bad(): return RC_ERR("Failed to load stream pack") else: # load streams from file stream_list = self.streams_db.load_yaml_file(opts.file[0]) rc = RC(stream_list != None) rc.annotate("Load stream pack (from file):") if stream_list == None: return RC_ERR("Failed to load stream pack") return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration) def cmd_stop_line(self, line): '''Stop active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "stop", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") return self.cmd_stop(opts.ports) def cmd_reset_line(self, line): return self.cmd_reset() def cmd_exit_line(self, line): print format_text("Exiting\n", 'bold') # a way to exit return RC_ERR("exit") def cmd_wait_line(self, line): '''wait for a period of time\n''' parser = parsing_opts.gen_parser(self, "wait", self.cmd_wait_line.__doc__, parsing_opts.DURATION) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") delay_sec = opts.duration if (opts.duration > 0) else 1 print format_text("Waiting for {0} seconds...\n".format(delay_sec), 'bold') time.sleep(delay_sec) return RC_OK() # run a script of commands def run_script_file(self, filename): print format_text("\nRunning script file '{0}'...".format(filename), 'bold') rc = self.cmd_connect() if rc.bad(): return with open(filename) as f: script_lines = f.readlines() cmd_table = {} # register all the commands cmd_table['start'] = self.cmd_start_line cmd_table['stop'] = self.cmd_stop_line cmd_table['reset'] = self.cmd_reset_line cmd_table['wait'] = self.cmd_wait_line cmd_table['exit'] = self.cmd_exit_line for index, line in enumerate(script_lines, start=1): line = line.strip() if line == "": continue if line.startswith("#"): continue sp = line.split(' ', 1) cmd = sp[0] if len(sp) == 2: args = sp[1] else: args = "" print format_text("Executing line {0} : '{1}'\n".format( index, line)) if not cmd in cmd_table: print "\n*** Error at line {0} : '{1}'\n".format(index, line) print format_text("unknown command '{0}'\n".format(cmd), 'bold') return False rc = cmd_table[cmd](args) if rc.bad(): return False print format_text("\n[Done]", 'bold') return True ################################# # ------ private classes ------ # class CCommLink(object): """describes the connectivity of the stateless client method""" def __init__(self, server="localhost", port=5050, virtual=False): super(CTRexStatelessClient.CCommLink, self).__init__() self.virtual = virtual self.server = server self.port = port self.verbose = False self.rpc_link = JsonRpcClient(self.server, self.port) @property def is_connected(self): if not self.virtual: return self.rpc_link.connected else: return True def set_verbose(self, mode): self.verbose = mode return self.rpc_link.set_verbose(mode) def connect(self): if not self.virtual: return self.rpc_link.connect() def disconnect(self): if not self.virtual: return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: self._prompt_virtual_tx_msg() _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params) print msg return else: return self.rpc_link.invoke_rpc_method(method_name, params) def transmit_batch(self, batch_list): if self.virtual: self._prompt_virtual_tx_msg() print[ msg for _, msg in [ self.rpc_link.create_jsonrpc_v2( command.method, command.params) for command in batch_list ] ] else: batch = self.rpc_link.create_batch() for command in batch_list: batch.add(command.method, command.params) # invoke the batch return batch.invoke() def _prompt_virtual_tx_msg(self): print "Transmitting virtually over tcp://{server}:{port}".format( server=self.server, port=self.port)
class CTRexStatelessClient(object): """docstring for CTRexStatelessClient""" def __init__(self, username, server="localhost", sync_port = 5050, async_port = 4500, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual) self.verbose = False self.ports = [] self._conn_handler = {} self._active_ports = set() self._system_info = None self._server_version = None self.__err_log = None self._async_client = CTRexAsyncClient(server, async_port, self) self.streams_db = CStreamsDB() self.connected = False ################# events handler ###################### def async_event_port_stopped (self, port_id): self.ports[port_id].async_event_port_stopped() ############# helper functions section ############## def validate_port_list(self, port_id_list): if not isinstance(port_id_list, list): print type(port_id_list) return False # check each item of the sequence return all([ (port_id >= 0) and (port_id < self.get_port_count()) for port_id in port_id_list ]) # some preprocessing for port argument def __ports (self, port_id_list): # none means all if port_id_list == None: return range(0, self.get_port_count()) # always list if isinstance(port_id_list, int): port_id_list = [port_id_list] if not isinstance(port_id_list, list): raise ValueError("bad port id list: {0}".format(port_id_list)) for port_id in port_id_list: if not isinstance(port_id, int) or (port_id < 0) or (port_id > self.get_port_count()): raise ValueError("bad port id {0}".format(port_id)) return port_id_list ############ boot up section ################ # connection sequence def connect(self): self.connected = False # connect rc, data = self.comm_link.connect() if not rc: return RC_ERR(data) # version rc, data = self.transmit("get_version") if not rc: return RC_ERR(data) self.server_version = data # cache system info rc, data = self.transmit("get_system_info") if not rc: return RC_ERR(data) self.system_info = data # cache supported commands rc, data = self.transmit("get_supported_cmds") if not rc: return RC_ERR(data) self.supported_cmds = data # create ports for port_id in xrange(self.get_port_count()): self.ports.append(Port(port_id, self.user, self.transmit)) # acquire all ports rc = self.acquire() if rc.bad(): return rc rc = self.sync_with_server() if rc.bad(): return rc self.connected = True return RC_OK() def is_connected (self): return self.connected and self.comm_link.is_connected def disconnect(self): self.connected = False self.comm_link.disconnect() return RC_OK() ########### cached queries (no server traffic) ########### def get_supported_cmds(self): return self.supported_cmds def get_version(self): return self.server_version def get_system_info(self): return self.system_info def get_port_count(self): return self.system_info.get("port_count") def get_port_ids(self, as_str=False): port_ids = range(self.get_port_count()) if as_str: return " ".join(str(p) for p in port_ids) else: return port_ids def get_stats_async (self): return self._async_client.get_stats() def get_connection_port (self): return self.comm_link.port def get_connection_ip (self): return self.comm_link.server def get_acquired_ports(self): return [port.port_id for port in self.ports if port.is_acquired()] def get_active_ports(self): return [port.port_id for port in self.ports if port.is_active()] def set_verbose(self, mode): self.comm_link.set_verbose(mode) self.verbose = mode ############# server actions ################ # ping server def ping(self): rc, info = self.transmit("ping") return RC(rc, info) def sync_with_server(self, sync_streams=False): rc, data = self.transmit("sync_user", {"user": self.user, "sync_streams": sync_streams}) if not rc: return RC_ERR(data) for port_info in data: rc = self.ports[port_info['port_id']].sync(port_info) if rc.bad(): return rc return RC_OK() ########## port commands ############## # acquire ports, if port_list is none - get all def acquire (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].acquire(force)) return rc # release ports def release (self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].release(force)) return rc def add_stream(self, stream_id, stream_obj, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_stream(stream_id, stream_obj)) return rc def add_stream_pack(self, stream_pack_list, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for stream_pack in stream_pack_list: rc.add(self.add_stream(stream_pack.stream_id, stream_pack.stream, port_id_list)) return rc def remove_stream(self, stream_id, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_stream(stream_id)) return rc def remove_all_streams(self, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_all_streams()) return rc def get_stream(self, stream_id, port_id, get_pkt = False): return self.ports[port_id].get_stream(stream_id) def get_all_streams(self, port_id, get_pkt = False): return self.ports[port_id].get_all_streams() def get_stream_id_list(self, port_id): return self.ports[port_id].get_stream_id_list() def start_traffic (self, multiplier, duration, port_id_list = None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].start(multiplier, duration)) return rc def resume_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].resume()) return rc def pause_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].pause()) return rc def stop_traffic (self, port_id_list = None, force = False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].stop(force)) return rc def get_port_stats(self, port_id=None): pass def get_stream_stats(self, port_id=None): pass def transmit(self, method_name, params={}): return self.comm_link.transmit(method_name, params) ######################### Console (high level) API ######################### def cmd_ping(self): rc = self.ping() rc.annotate("Pinging the server on '{0}' port '{1}': ".format(self.get_connection_ip(), self.get_connection_port())) return rc def cmd_connect(self): rc = self.connect() rc.annotate() return rc def cmd_disconnect(self): rc = self.disconnect() rc.annotate() return rc # reset def cmd_reset(self): # sync with the server rc = self.sync_with_server() rc.annotate("Syncing with the server:") if rc.bad(): return rc rc = self.acquire(force = True) rc.annotate("Force acquiring all ports:") if rc.bad(): return rc # force stop all ports rc = self.stop_traffic(self.get_port_ids(), True) rc.annotate("Stop traffic on all ports:") if rc.bad(): return rc # remove all streams rc = self.remove_all_streams(self.get_port_ids()) rc.annotate("Removing all streams from all ports:") if rc.bad(): return rc # TODO: clear stats return RC_OK() # stop cmd def cmd_stop (self, port_id_list): # find the relveant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.stop_traffic(active_ports) rc.annotate("Stopping traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() # pause cmd def cmd_pause (self, port_id_list): # find the relveant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.pause_traffic(active_ports) rc.annotate("Pausing traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() def cmd_pause_line (self, line): '''Pause active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "pause", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") return self.cmd_pause(opts.ports) # resume cmd def cmd_resume (self, port_id_list): # find the relveant ports active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.resume_traffic(active_ports) rc.annotate("Resume traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() def cmd_resume_line (self, line): '''Resume active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "resume", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") return self.cmd_resume(opts.ports) # start cmd def cmd_start (self, port_id_list, stream_list, mult, force, duration): active_ports = list(set(self.get_active_ports()).intersection(port_id_list)) if active_ports: if not force: msg = "Port(s) {0} are active - please stop them or add '--force'".format(active_ports) print format_text(msg, 'bold') return RC_ERR(msg) else: rc = self.cmd_stop(active_ports) if not rc: return rc rc = self.remove_all_streams(port_id_list) rc.annotate("Removing all streams from port(s) {0}:".format(port_id_list)) if rc.bad(): return rc rc = self.add_stream_pack(stream_list.compiled, port_id_list) rc.annotate("Attaching streams to port(s) {0}:".format(port_id_list)) if rc.bad(): return rc # finally, start the traffic rc = self.start_traffic(mult, duration, port_id_list) rc.annotate("Starting traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() ############## High Level API With Parser ################ def cmd_start_line (self, line): '''Start selected traffic in specified ports on TRex\n''' # define a parser parser = parsing_opts.gen_parser(self, "start", self.cmd_start_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.FORCE, parsing_opts.STREAM_FROM_PATH_OR_FILE, parsing_opts.DURATION, parsing_opts.MULTIPLIER) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") if opts.db: stream_list = self.stream_db.get_stream_pack(opts.db) rc = RC(stream_list != None) rc.annotate("Load stream pack (from DB):") if rc.bad(): return RC_ERR("Failed to load stream pack") else: # load streams from file stream_list = self.streams_db.load_yaml_file(opts.file[0]) rc = RC(stream_list != None) rc.annotate("Load stream pack (from file):") if stream_list == None: return RC_ERR("Failed to load stream pack") return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration) def cmd_stop_line (self, line): '''Stop active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "stop", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") return self.cmd_stop(opts.ports) def cmd_reset_line (self, line): return self.cmd_reset() def cmd_exit_line (self, line): print format_text("Exiting\n", 'bold') # a way to exit return RC_ERR("exit") def cmd_wait_line (self, line): '''wait for a period of time\n''' parser = parsing_opts.gen_parser(self, "wait", self.cmd_wait_line.__doc__, parsing_opts.DURATION) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") delay_sec = opts.duration if (opts.duration > 0) else 1 print format_text("Waiting for {0} seconds...\n".format(delay_sec), 'bold') time.sleep(delay_sec) return RC_OK() # run a script of commands def run_script_file (self, filename): print format_text("\nRunning script file '{0}'...".format(filename), 'bold') rc = self.cmd_connect() if rc.bad(): return with open(filename) as f: script_lines = f.readlines() cmd_table = {} # register all the commands cmd_table['start'] = self.cmd_start_line cmd_table['stop'] = self.cmd_stop_line cmd_table['reset'] = self.cmd_reset_line cmd_table['wait'] = self.cmd_wait_line cmd_table['exit'] = self.cmd_exit_line for index, line in enumerate(script_lines, start = 1): line = line.strip() if line == "": continue if line.startswith("#"): continue sp = line.split(' ', 1) cmd = sp[0] if len(sp) == 2: args = sp[1] else: args = "" print format_text("Executing line {0} : '{1}'\n".format(index, line)) if not cmd in cmd_table: print "\n*** Error at line {0} : '{1}'\n".format(index, line) print format_text("unknown command '{0}'\n".format(cmd), 'bold') return False rc = cmd_table[cmd](args) if rc.bad(): return False print format_text("\n[Done]", 'bold') return True ################################# # ------ private classes ------ # class CCommLink(object): """describes the connectivity of the stateless client method""" def __init__(self, server="localhost", port=5050, virtual=False): super(CTRexStatelessClient.CCommLink, self).__init__() self.virtual = virtual self.server = server self.port = port self.verbose = False self.rpc_link = JsonRpcClient(self.server, self.port) @property def is_connected(self): if not self.virtual: return self.rpc_link.connected else: return True def set_verbose(self, mode): self.verbose = mode return self.rpc_link.set_verbose(mode) def connect(self): if not self.virtual: return self.rpc_link.connect() def disconnect(self): if not self.virtual: return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: self._prompt_virtual_tx_msg() _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params) print msg return else: return self.rpc_link.invoke_rpc_method(method_name, params) def transmit_batch(self, batch_list): if self.virtual: self._prompt_virtual_tx_msg() print [msg for _, msg in [self.rpc_link.create_jsonrpc_v2(command.method, command.params) for command in batch_list]] else: batch = self.rpc_link.create_batch() for command in batch_list: batch.add(command.method, command.params) # invoke the batch return batch.invoke() def _prompt_virtual_tx_msg(self): print "Transmitting virtually over tcp://{server}:{port}".format(server=self.server, port=self.port)
class CTRexStatelessClient(object): """docstring for CTRexStatelessClient""" # verbose levels VERBOSE_QUIET = 0 VERBOSE_REGULAR = 1 VERBOSE_HIGH = 2 def __init__(self, username, server="localhost", sync_port=5050, async_port=4500, quiet=False, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink( server, sync_port, virtual, self.prn_func) # default verbose level if not quiet: self.verbose = self.VERBOSE_REGULAR else: self.verbose = self.VERBOSE_QUIET self.ports = {} self._connection_info = { "server": server, "sync_port": sync_port, "async_port": async_port } self.system_info = {} self.server_version = {} self.__err_log = None self.async_client = CTRexAsyncClient(server, async_port, self, self.prn_func) self.streams_db = CStreamsDB() self.global_stats = trex_stats.CGlobalStats(self._connection_info, self.server_version, self.ports) self.stats_generator = trex_stats.CTRexStatsGenerator( self.global_stats, self.ports) self.events = [] self.session_id = random.getrandbits(32) self.read_only = False self.connected = False # returns the port object def get_port(self, port_id): return self.ports.get(port_id, None) # connection server ip def get_server_ip(self): return self.comm_link.get_server() # connection server port def get_server_port(self): return self.comm_link.get_port() ################# events handler ###################### def add_event_log(self, msg, ev_type, show=False): if ev_type == "server": prefix = "[server]" elif ev_type == "local": prefix = "[local]" ts = time.time() st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') self.events.append("{:<10} - {:^8} - {:}".format( st, prefix, format_text(msg, 'bold'))) if show: self.prn_func( format_text("\n{:^8} - {:}".format(prefix, format_text(msg, 'bold')))) def handle_async_stats_update(self, dump_data): global_stats = {} port_stats = {} # filter the values per port and general for key, value in dump_data.iteritems(): # match a pattern of ports m = re.search('(.*)\-([0-8])', key) if m: port_id = int(m.group(2)) field_name = m.group(1) if self.ports.has_key(port_id): if not port_id in port_stats: port_stats[port_id] = {} port_stats[port_id][field_name] = value else: continue else: # no port match - general stats global_stats[key] = value # update the general object with the snapshot self.global_stats.update(global_stats) # update all ports for port_id, data in port_stats.iteritems(): self.ports[port_id].port_stats.update(data) def handle_async_event(self, type, data): # DP stopped show_event = False # port started if (type == 0): port_id = int(data['port_id']) ev = "Port {0} has started".format(port_id) self.async_event_port_started(port_id) # port stopped elif (type == 1): port_id = int(data['port_id']) ev = "Port {0} has stopped".format(port_id) # call the handler self.async_event_port_stopped(port_id) # port paused elif (type == 2): port_id = int(data['port_id']) ev = "Port {0} has paused".format(port_id) # call the handler self.async_event_port_paused(port_id) # port resumed elif (type == 3): port_id = int(data['port_id']) ev = "Port {0} has resumed".format(port_id) # call the handler self.async_event_port_resumed(port_id) # port finished traffic elif (type == 4): port_id = int(data['port_id']) ev = "Port {0} job done".format(port_id) # call the handler self.async_event_port_stopped(port_id) show_event = True # port was stolen... elif (type == 5): session_id = data['session_id'] # false alarm, its us if session_id == self.session_id: return port_id = int(data['port_id']) who = data['who'] ev = "Port {0} was forcely taken by '{1}'".format(port_id, who) # call the handler self.async_event_port_forced_acquired(port_id) show_event = True # server stopped elif (type == 100): ev = "Server has stopped" self.async_event_server_stopped() show_event = True else: # unknown event - ignore return self.add_event_log(ev, 'server', show_event) def async_event_port_stopped(self, port_id): self.ports[port_id].async_event_port_stopped() def async_event_port_started(self, port_id): self.ports[port_id].async_event_port_started() def async_event_port_paused(self, port_id): self.ports[port_id].async_event_port_paused() def async_event_port_resumed(self, port_id): self.ports[port_id].async_event_port_resumed() def async_event_port_forced_acquired(self, port_id): self.ports[port_id].async_event_forced_acquired() self.read_only = True def async_event_server_stopped(self): self.connected = False def get_events(self): return self.events def clear_events(self): self.events = [] ############# helper functions section ############## # measure time for functions def timing(f): def wrap(*args): time1 = time.time() ret = f(*args) # don't want to print on error if ret.bad(): return ret delta = time.time() - time1 print format_time(delta) + "\n" return ret return wrap def validate_port_list(self, port_id_list): if not isinstance(port_id_list, list): print type(port_id_list) return False # check each item of the sequence return all([(port_id >= 0) and (port_id < self.get_port_count()) for port_id in port_id_list]) # some preprocessing for port argument def __ports(self, port_id_list): # none means all if port_id_list == None: return range(0, self.get_port_count()) # always list if isinstance(port_id_list, int): port_id_list = [port_id_list] if not isinstance(port_id_list, list): raise ValueError("bad port id list: {0}".format(port_id_list)) for port_id in port_id_list: if not isinstance(port_id, int) or (port_id < 0) or ( port_id > self.get_port_count()): raise ValueError("bad port id {0}".format(port_id)) return port_id_list ############ boot up section ################ # connection sequence # mode can be RW - read / write, RWF - read write with force , RO - read only def connect(self, mode="RW"): if self.is_connected(): self.disconnect() # clear this flag self.connected = False # connect sync channel rc = self.comm_link.connect() if rc.bad(): return rc # connect async channel rc = self.async_client.connect() if rc.bad(): return rc # version rc = self.transmit("get_version") if rc.bad(): return rc self.server_version = rc.data() self.global_stats.server_version = rc.data() # cache system info rc = self.transmit("get_system_info") if rc.bad(): return rc self.system_info = rc.data() # cache supported commands rc = self.transmit("get_supported_cmds") if rc.bad(): return rc self.supported_cmds = rc.data() # create ports for port_id in xrange(self.get_port_count()): speed = self.system_info['ports'][port_id]['speed'] driver = self.system_info['ports'][port_id]['driver'] self.ports[port_id] = Port(port_id, speed, driver, self.user, self.comm_link, self.session_id) # sync the ports rc = self.sync_ports() if rc.bad(): return rc # acquire all ports if mode == "RW": rc = self.acquire(force=False) # fallback to read only if failed if rc.bad(): rc.annotate(show_status=False) print format_text( "Switching to read only mode - only few commands will be available", 'bold') self.release(self.get_acquired_ports()) self.read_only = True else: self.read_only = False elif mode == "RWF": rc = self.acquire(force=True) if rc.bad(): return rc self.read_only = False elif mode == "RO": # no acquire on read only rc = RC_OK() self.read_only = True self.connected = True return RC_OK() def is_read_only(self): return self.read_only def is_connected(self): return self.connected and self.comm_link.is_connected def disconnect(self): # release any previous acquired ports if self.is_connected(): self.release(self.get_acquired_ports()) self.comm_link.disconnect() self.async_client.disconnect() self.connected = False return RC_OK() def on_async_dead(self): if self.connected: msg = 'lost connection to server' self.add_event_log(msg, 'local', True) self.connected = False def on_async_alive(self): pass ########### cached queries (no server traffic) ########### def get_supported_cmds(self): return self.supported_cmds def get_version(self): return self.server_version def get_system_info(self): return self.system_info def get_port_count(self): return self.system_info.get("port_count") def get_port_ids(self, as_str=False): port_ids = range(self.get_port_count()) if as_str: return " ".join(str(p) for p in port_ids) else: return port_ids def get_stats_async(self): return self.async_client.get_stats() def get_connection_port(self): return self.comm_link.port def get_connection_ip(self): return self.comm_link.server def get_all_ports(self): return [port_id for port_id, port_obj in self.ports.iteritems()] def get_acquired_ports(self): return [ port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_acquired() ] def get_active_ports(self): return [ port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_active() ] def get_paused_ports(self): return [ port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_paused() ] def get_transmitting_ports(self): return [ port_id for port_id, port_obj in self.ports.iteritems() if port_obj.is_transmitting() ] def set_verbose(self, mode): # on high - enable link verbose if mode == self.VERBOSE_HIGH: self.comm_link.set_verbose(True) else: self.comm_link.set_verbose(False) self.verbose = mode def check_verbose(self, level): return (self.verbose >= level) def get_verbose(self): return self.verbose def prn_func(self, msg, level=VERBOSE_REGULAR): if self.check_verbose(level): print msg ############# server actions ################ # ping server def ping(self): return self.transmit("ping") def get_global_stats(self): return self.transmit("get_global_stats") ########## port commands ############## def sync_ports(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].sync()) return rc # acquire ports, if port_list is none - get all def acquire(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].acquire(force)) return rc # release ports def release(self, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].release()) return rc def add_stream(self, stream_id, stream_obj, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_stream(stream_id, stream_obj)) return rc def add_stream_pack(self, stream_pack_list, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].add_streams(stream_pack_list)) return rc def remove_stream(self, stream_id, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_stream(stream_id)) return rc def remove_all_streams(self, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].remove_all_streams()) return rc def get_stream(self, stream_id, port_id, get_pkt=False): return self.ports[port_id].get_stream(stream_id) def get_all_streams(self, port_id, get_pkt=False): return self.ports[port_id].get_all_streams() def get_stream_id_list(self, port_id): return self.ports[port_id].get_stream_id_list() def start_traffic(self, multiplier, duration, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].start(multiplier, duration)) return rc def resume_traffic(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].resume()) return rc def pause_traffic(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].pause()) return rc def stop_traffic(self, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].stop(force)) return rc def update_traffic(self, mult, port_id_list=None, force=False): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].update(mult)) return rc def validate(self, port_id_list=None): port_id_list = self.__ports(port_id_list) rc = RC() for port_id in port_id_list: rc.add(self.ports[port_id].validate()) return rc def get_port_stats(self, port_id=None): pass def get_stream_stats(self, port_id=None): pass def transmit(self, method_name, params={}): return self.comm_link.transmit(method_name, params) def transmit_batch(self, batch_list): return self.comm_link.transmit_batch(batch_list) ######################### Console (high level) API ######################### @timing def cmd_ping(self): rc = self.ping() rc.annotate("Pinging the server on '{0}' port '{1}': ".format( self.get_connection_ip(), self.get_connection_port())) return rc def cmd_connect(self, mode="RW"): rc = self.connect(mode) rc.annotate() return rc def cmd_disconnect(self): rc = self.disconnect() rc.annotate() return rc # reset def cmd_reset(self): #self.release(self.get_acquired_ports()) rc = self.acquire(force=True) rc.annotate("Force acquiring all ports:") if rc.bad(): return rc # force stop all ports rc = self.stop_traffic(self.get_port_ids(), True) rc.annotate("Stop traffic on all ports:") if rc.bad(): return rc # remove all streams rc = self.remove_all_streams(self.get_port_ids()) rc.annotate("Removing all streams from all ports:") if rc.bad(): return rc # TODO: clear stats return RC_OK() # stop cmd def cmd_stop(self, port_id_list): # find the relveant ports active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.stop_traffic(active_ports) rc.annotate("Stopping traffic on port(s) {0}:".format(port_id_list)) if rc.bad(): return rc return RC_OK() # update cmd def cmd_update(self, port_id_list, mult): # find the relevant ports active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.update_traffic(mult, active_ports) rc.annotate("Updating traffic on port(s) {0}:".format(port_id_list)) return rc # clear stats def cmd_clear(self, port_id_list): for port_id in port_id_list: self.ports[port_id].clear_stats() self.global_stats.clear_stats() return RC_OK() def cmd_invalidate(self, port_id_list): for port_id in port_id_list: self.ports[port_id].invalidate_stats() self.global_stats.invalidate() return RC_OK() # pause cmd def cmd_pause(self, port_id_list): # find the relevant ports active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on provided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.pause_traffic(active_ports) rc.annotate("Pausing traffic on port(s) {0}:".format(port_id_list)) return rc # resume cmd def cmd_resume(self, port_id_list): # find the relveant ports active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if not active_ports: msg = "No active traffic on porvided ports" print format_text(msg, 'bold') return RC_ERR(msg) rc = self.resume_traffic(active_ports) rc.annotate("Resume traffic on port(s) {0}:".format(port_id_list)) return rc # start cmd def cmd_start(self, port_id_list, stream_list, mult, force, duration, dry): active_ports = list( set(self.get_active_ports()).intersection(port_id_list)) if active_ports: if not force: msg = "Port(s) {0} are active - please stop them or add '--force'".format( active_ports) print format_text(msg, 'bold') return RC_ERR(msg) else: rc = self.cmd_stop(active_ports) if not rc: return rc rc = self.remove_all_streams(port_id_list) rc.annotate( "Removing all streams from port(s) {0}:".format(port_id_list)) if rc.bad(): return rc rc = self.add_stream_pack(stream_list.compiled, port_id_list) rc.annotate("Attaching {0} streams to port(s) {1}:".format( len(stream_list.compiled), port_id_list)) if rc.bad(): return rc # when not on dry - start the traffic , otherwise validate only if not dry: rc = self.start_traffic(mult, duration, port_id_list) rc.annotate( "Starting traffic on port(s) {0}:".format(port_id_list)) return rc else: rc = self.validate(port_id_list) rc.annotate("Validating traffic profile on port(s) {0}:".format( port_id_list)) if rc.bad(): return rc # show a profile on one port for illustration self.ports[port_id_list[0]].print_profile(mult, duration) return rc # validate port(s) profile def cmd_validate(self, port_id_list): rc = self.validate(port_id_list) rc.annotate("Validating streams on port(s) {0}:".format(port_id_list)) return rc # stats def cmd_stats(self, port_id_list, stats_mask=set()): stats_opts = trex_stats.ALL_STATS_OPTS.intersection(stats_mask) stats_obj = {} for stats_type in stats_opts: stats_obj.update( self.stats_generator.generate_single_statistic( port_id_list, stats_type)) return stats_obj ############## High Level API With Parser ################ def cmd_connect_line(self, line): '''Connects to the TRex server''' # define a parser parser = parsing_opts.gen_parser(self, "connect", self.cmd_connect_line.__doc__, parsing_opts.FORCE) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") if opts.force: rc = self.cmd_connect(mode="RWF") else: rc = self.cmd_connect(mode="RW") @timing def cmd_start_line(self, line): '''Start selected traffic in specified ports on TRex\n''' # define a parser parser = parsing_opts.gen_parser( self, "start", self.cmd_start_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.TOTAL, parsing_opts.FORCE, parsing_opts.STREAM_FROM_PATH_OR_FILE, parsing_opts.DURATION, parsing_opts.MULTIPLIER_STRICT, parsing_opts.DRY_RUN) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") if opts.dry: print format_text("\n*** DRY RUN ***", 'bold') if opts.db: stream_list = self.streams_db.get_stream_pack(opts.db) rc = RC(stream_list != None) rc.annotate("Load stream pack (from DB):") if rc.bad(): return RC_ERR("Failed to load stream pack") else: # load streams from file stream_list = None try: stream_list = self.streams_db.load_yaml_file(opts.file[0]) except Exception as e: s = str(e) rc = RC_ERR(s) rc.annotate() return rc rc = RC(stream_list != None) rc.annotate("Load stream pack (from file):") if stream_list == None: return RC_ERR("Failed to load stream pack") # total has no meaning with percentage - its linear if opts.total and (opts.mult['type'] != 'percentage'): # if total was set - divide it between the ports opts.mult['value'] = opts.mult['value'] / len(opts.ports) return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration, opts.dry) @timing def cmd_resume_line(self, line): '''Resume active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "resume", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_resume(opts.ports) @timing def cmd_stop_line(self, line): '''Stop active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "stop", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_stop(opts.ports) @timing def cmd_pause_line(self, line): '''Pause active traffic in specified ports on TRex\n''' parser = parsing_opts.gen_parser(self, "pause", self.cmd_stop_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_pause(opts.ports) @timing def cmd_update_line(self, line): '''Update port(s) speed currently active\n''' parser = parsing_opts.gen_parser(self, "update", self.cmd_update_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.MULTIPLIER, parsing_opts.TOTAL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") # total has no meaning with percentage - its linear if opts.total and (opts.mult['type'] != 'percentage'): # if total was set - divide it between the ports opts.mult['value'] = opts.mult['value'] / len(opts.ports) return self.cmd_update(opts.ports, opts.mult) @timing def cmd_reset_line(self, line): return self.cmd_reset() def cmd_clear_line(self, line): '''Clear cached local statistics\n''' # define a parser parser = parsing_opts.gen_parser(self, "clear", self.cmd_clear_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") return self.cmd_clear(opts.ports) def cmd_stats_line(self, line): '''Fetch statistics from TRex server by port\n''' # define a parser parser = parsing_opts.gen_parser(self, "stats", self.cmd_stats_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL, parsing_opts.STATS_MASK) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") # determine stats mask mask = self._get_mask_keys( **self._filter_namespace_args(opts, trex_stats.ALL_STATS_OPTS)) if not mask: # set to show all stats if no filter was given mask = trex_stats.ALL_STATS_OPTS stats = self.cmd_stats(opts.ports, mask) # print stats to screen for stat_type, stat_data in stats.iteritems(): text_tables.print_table_with_header(stat_data.text_table, stat_type) return RC_OK() @timing def cmd_validate_line(self, line): '''validates port(s) stream configuration\n''' parser = parsing_opts.gen_parser(self, "validate", self.cmd_validate_line.__doc__, parsing_opts.PORT_LIST_WITH_ALL) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line paramters") rc = self.cmd_validate(opts.ports) return rc def cmd_exit_line(self, line): print format_text("Exiting\n", 'bold') # a way to exit return RC_ERR("exit") def cmd_wait_line(self, line): '''wait for a period of time\n''' parser = parsing_opts.gen_parser(self, "wait", self.cmd_wait_line.__doc__, parsing_opts.DURATION) opts = parser.parse_args(line.split()) if opts is None: return RC_ERR("bad command line parameters") delay_sec = opts.duration if (opts.duration > 0) else 1 print format_text("Waiting for {0} seconds...\n".format(delay_sec), 'bold') time.sleep(delay_sec) return RC_OK() # run a script of commands def run_script_file(self, filename): print format_text("\nRunning script file '{0}'...".format(filename), 'bold') rc = self.cmd_connect() if rc.bad(): return with open(filename) as f: script_lines = f.readlines() cmd_table = {} # register all the commands cmd_table['start'] = self.cmd_start_line cmd_table['stop'] = self.cmd_stop_line cmd_table['reset'] = self.cmd_reset_line cmd_table['wait'] = self.cmd_wait_line cmd_table['exit'] = self.cmd_exit_line for index, line in enumerate(script_lines, start=1): line = line.strip() if line == "": continue if line.startswith("#"): continue sp = line.split(' ', 1) cmd = sp[0] if len(sp) == 2: args = sp[1] else: args = "" print format_text("Executing line {0} : '{1}'\n".format( index, line)) if not cmd in cmd_table: print "\n*** Error at line {0} : '{1}'\n".format(index, line) print format_text("unknown command '{0}'\n".format(cmd), 'bold') return False rc = cmd_table[cmd](args) if rc.bad(): return False print format_text("\n[Done]", 'bold') return True ################################# # ------ private methods ------ # @staticmethod def _get_mask_keys(ok_values={True}, **kwargs): masked_keys = set() for key, val in kwargs.iteritems(): if val in ok_values: masked_keys.add(key) return masked_keys @staticmethod def _filter_namespace_args(namespace, ok_values): return {k: v for k, v in namespace.__dict__.items() if k in ok_values} ################################# # ------ private classes ------ # class CCommLink(object): """describes the connectivity of the stateless client method""" def __init__(self, server="localhost", port=5050, virtual=False, prn_func=None): super(CTRexStatelessClient.CCommLink, self).__init__() self.virtual = virtual self.server = server self.port = port self.verbose = False self.rpc_link = JsonRpcClient(self.server, self.port, prn_func) @property def is_connected(self): if not self.virtual: return self.rpc_link.connected else: return True def get_server(self): return self.server def get_port(self): return self.port def set_verbose(self, mode): self.verbose = mode return self.rpc_link.set_verbose(mode) def connect(self): if not self.virtual: return self.rpc_link.connect() def disconnect(self): if not self.virtual: return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: self._prompt_virtual_tx_msg() _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params) print msg return else: return self.rpc_link.invoke_rpc_method(method_name, params) def transmit_batch(self, batch_list): if self.virtual: self._prompt_virtual_tx_msg() print[ msg for _, msg in [ self.rpc_link.create_jsonrpc_v2( command.method, command.params) for command in batch_list ] ] else: batch = self.rpc_link.create_batch() for command in batch_list: batch.add(command.method, command.params) # invoke the batch return batch.invoke() def _prompt_virtual_tx_msg(self): print "Transmitting virtually over tcp://{server}:{port}".format( server=self.server, port=self.port)
class CTRexStatelessClient(object): """docstring for CTRexStatelessClient""" def __init__(self, username, server="localhost", sync_port=5050, async_port=4500, virtual=False): super(CTRexStatelessClient, self).__init__() self.user = username self.comm_link = CTRexStatelessClient.CCommLink(server, sync_port, virtual) self.verbose = False self._conn_handler = {} self._active_ports = set() self._stats = CTRexStatsManager("port", "stream") self._system_info = None self._server_version = None self.__err_log = None self._async_client = CTRexAsyncClient(async_port) # ----- decorator methods ----- # def acquired(func): def wrapper_f(self, *args, **kwargs): # print func.__name__ # print args # print kwargs port_ids = kwargs.get("port_id") if not port_ids: # print "FROM ARGS!" # print args port_ids = args[0] if isinstance(port_ids, int): # make sure port_ids is a list port_ids = [port_ids] bad_ids = set() # print "=============" # print port_ids for port_id in port_ids: port_owned = self._conn_handler.get(port_id) if not port_owned: bad_ids.add(port_id) # elif active_and_owned: # stronger condition than just owned, hence gets precedence # if port_owned and port_id in self._active_ports: # continue # else: # bad_ids.add(port_id) else: continue if bad_ids: # Some port IDs are not according to desires status raise ValueError( "The requested method ('{0}') cannot be invoked since port IDs {1} are not " "at allowed states".format(func.__name__, list(bad_ids)) ) else: return func(self, *args, **kwargs) return wrapper_f def force_status(owned=True, active_and_owned=False): def wrapper(func): def wrapper_f(self, *args, **kwargs): # print args # print kwargs port_ids = kwargs.get("port_id") if not port_ids: # print "FROM ARGS!" # print args port_ids = args[0] if isinstance(port_ids, int): # make sure port_ids is a list port_ids = [port_ids] bad_ids = set() # print "=============" # print port_ids for port_id in port_ids: port_owned = self._conn_handler.get(port_id) if owned and not port_owned: bad_ids.add(port_id) elif active_and_owned: # stronger condition than just owned, hence gets precedence if port_owned and port_id in self._active_ports: continue else: bad_ids.add(port_id) else: continue if bad_ids: # Some port IDs are not according to desires status raise ValueError( "The requested method ('{0}') cannot be invoked since port IDs {1} are not " "at allowed states".format(func.__name__, list(bad_ids)) ) else: return func(self, *args, **kwargs) return wrapper_f return wrapper @property def system_info(self): if not self._system_info: rc, info = self.get_system_info() if rc: self._system_info = info else: self.__err_log = info return self._system_info if self._system_info else "Unknown" @property def server_version(self): if not self._server_version: rc, ver_info = self.get_version() if rc: self._server_version = ver_info else: self.__err_log = ver_info return self._server_version if self._server_version else "Unknown" def is_connected(self): return self.comm_link.is_connected # ----- user-access methods ----- # def connect(self): rc, err = self.comm_link.connect() if not rc: return rc, err return self._init_sync() def get_stats_async(self): return self._async_client.get_stats() def get_connection_port(self): return self.comm_link.port def disconnect(self): return self.comm_link.disconnect() def ping(self): return self.transmit("ping") def get_supported_cmds(self): return self.transmit("get_supported_cmds") def get_version(self): return self.transmit("get_version") def get_system_info(self): return self.transmit("get_system_info") def get_port_count(self): return self.system_info.get("port_count") def get_port_ids(self, as_str=False): port_ids = range(self.get_port_count()) if as_str: return " ".join(str(p) for p in port_ids) else: return port_ids def sync_user(self, sync_streams=False): return self.transmit("sync_user", {"user": self.user, "sync_streams": sync_streams}) def get_acquired_ports(self): return self._conn_handler.keys() def get_active_ports(self): return list(self._active_ports) def set_verbose(self, mode): self.comm_link.set_verbose(mode) self.verbose = mode def acquire(self, port_id, force=False): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [ RpcCmdData("acquire", {"port_id": p_id, "user": self.user, "force": force}) for p_id in port_ids ] rc, resp_list = self.transmit_batch(commands) if rc: return self._process_batch_result(commands, resp_list, self._handle_acquire_response) else: params = {"port_id": port_id, "user": self.user, "force": force} command = RpcCmdData("acquire", params) return self._handle_acquire_response( command, self.transmit(command.method, command.params), self.default_success_test ) @force_status(owned=True) def release(self, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [ RpcCmdData("release", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids ] rc, resp_list = self.transmit_batch(commands) if rc: return self._process_batch_result( commands, resp_list, self._handle_release_response, success_test=self.ack_success_test ) else: self._conn_handler.pop(port_id) params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} command = RpcCmdData("release", params) return self._handle_release_response( command, self.transmit(command.method, command.params), self.ack_success_test ) @force_status(owned=True) def add_stream(self, stream_id, stream_obj, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") assert isinstance(stream_obj, CStream) params = { "handler": self._conn_handler.get(port_id), "port_id": port_id, "stream_id": stream_id, "stream": stream_obj.dump(), } return self.transmit("add_stream", params) @force_status(owned=True) def add_stream_pack(self, port_id=None, *stream_packs): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") # since almost every run contains more than one transaction with server, handle all as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [] for stream_pack in stream_packs: commands.extend( [ RpcCmdData( "add_stream", { "port_id": p_id, "handler": self._conn_handler.get(p_id), "stream_id": stream_pack.stream_id, "stream": stream_pack.stream, }, ) for p_id in port_ids ] ) res_ok, resp_list = self.transmit_batch(commands) if res_ok: return self._process_batch_result( commands, resp_list, self._handle_add_stream_response, success_test=self.ack_success_test ) @force_status(owned=True) def remove_stream(self, stream_id, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") params = {"handler": self._conn_handler.get(port_id), "port_id": port_id, "stream_id": stream_id} return self.transmit("remove_stream", params) @force_status(owned=True) def remove_all_streams(self, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [ RpcCmdData("remove_all_streams", {"port_id": p_id, "handler": self._conn_handler.get(p_id)}) for p_id in port_ids ] rc, resp_list = self.transmit_batch(commands) if rc: return self._process_batch_result( commands, resp_list, self._handle_remove_streams_response, success_test=self.ack_success_test ) else: params = {"port_id": port_id, "handler": self._conn_handler.get(port_id)} command = RpcCmdData("remove_all_streams", params) return self._handle_remove_streams_response( command, self.transmit(command.method, command.params), self.ack_success_test ) pass @force_status(owned=True) # , active_and_owned=True) def get_all_streams(self, port_id, get_pkt=False): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") params = {"handler": self._conn_handler.get(port_id), "port_id": port_id, "get_pkt": get_pkt} return self.transmit("get_all_streams", params) @force_status(owned=True) # , active_and_owned=True) def get_stream_id_list(self, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} return self.transmit("get_stream_list", params) @force_status(owned=True, active_and_owned=True) def get_stream(self, stream_id, port_id, get_pkt=False): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") params = { "handler": self._conn_handler.get(port_id), "port_id": port_id, "stream_id": stream_id, "get_pkt": get_pkt, } return self.transmit("get_stream_list", params) @acquired def start_traffic(self, multiplier, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [ RpcCmdData( "start_traffic", {"handler": self._conn_handler.get(p_id), "port_id": p_id, "mul": multiplier} ) for p_id in port_ids ] rc, resp_list = self.transmit_batch(commands) if rc: return self._process_batch_result( commands, resp_list, self._handle_start_traffic_response, success_test=self.ack_success_test ) else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id, "mul": multiplier} command = RpcCmdData("start_traffic", params) return self._handle_start_traffic_response( command, self.transmit(command.method, command.params), self.ack_success_test ) @force_status(owned=False, active_and_owned=True) def stop_traffic(self, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [ RpcCmdData("stop_traffic", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids ] rc, resp_list = self.transmit_batch(commands) if rc: return self._process_batch_result( commands, resp_list, self._handle_stop_traffic_response, success_test=self.ack_success_test ) else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} command = RpcCmdData("stop_traffic", params) return self._handle_start_traffic_response( command, self.transmit(command.method, command.params), self.ack_success_test ) # def get_global_stats(self): # command = RpcCmdData("get_global_stats", {}) # return self._handle_get_global_stats_response(command, self.transmit(command.method, command.params)) # # return self.transmit("get_global_stats") @force_status(owned=True, active_and_owned=True) def get_port_stats(self, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [ RpcCmdData("get_port_stats", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids ] rc, resp_list = self.transmit_batch(commands) if rc: self._process_batch_result(commands, resp_list, self._handle_get_port_stats_response) else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} command = RpcCmdData("get_port_stats", params) return self._handle_get_port_stats_response(command, self.transmit(command.method, command.params)) @force_status(owned=True, active_and_owned=True) def get_stream_stats(self, port_id=None): if not self._is_ports_valid(port_id): raise ValueError("Provided illegal port id input") if isinstance(port_id, list) or isinstance(port_id, set): # handle as batch mode port_ids = set(port_id) # convert to set to avoid duplications commands = [ RpcCmdData("get_stream_stats", {"handler": self._conn_handler.get(p_id), "port_id": p_id}) for p_id in port_ids ] rc, resp_list = self.transmit_batch(commands) if rc: self._process_batch_result(commands, resp_list, self._handle_get_stream_stats_response) else: params = {"handler": self._conn_handler.get(port_id), "port_id": port_id} command = RpcCmdData("get_stream_stats", params) return self._handle_get_stream_stats_response(command, self.transmit(command.method, command.params)) # ----- internal methods ----- # def _init_sync(self): # get server version and system info err = False if self.server_version == "Unknown" or self.system_info == "Unknown": self.disconnect() return False, self.__err_log # sync with previous session res_ok, port_info = self.sync_user() if not res_ok: self.disconnect() return False, port_info else: # handle sync data for port in port_info: self._conn_handler[port.get("port_id")] = port.get("handler") if port.get("state") == "transmitting": # port is active self._active_ports.add(port.get("port_id")) return True, "" def transmit(self, method_name, params={}): return self.comm_link.transmit(method_name, params) def transmit_batch(self, batch_list): return self.comm_link.transmit_batch(batch_list) @staticmethod def _object_decoder(obj_type, obj_data): if obj_type == "global": return CGlobalStats(**obj_data) elif obj_type == "port": return CPortStats(**obj_data) elif obj_type == "stream": return CStreamStats(**obj_data) else: # Do not serialize the data into class return obj_data @staticmethod def default_success_test(result_obj): if result_obj.success: return True else: return False @staticmethod def ack_success_test(result_obj): if result_obj.success and result_obj.data == "ACK": return True else: return False # ----- handler internal methods ----- # def _handle_general_response(self, request, response, msg, success_test=None): port_id = request.params.get("port_id") if not success_test: success_test = self.default_success_test if success_test(response): self._conn_handler[port_id] = response.data return RpcResponseStatus(True, port_id, msg) else: return RpcResponseStatus(False, port_id, response.data) def _handle_acquire_response(self, request, response, success_test): port_id = request.params.get("port_id") if success_test(response): self._conn_handler[port_id] = response.data return RpcResponseStatus(True, port_id, "Acquired") else: return RpcResponseStatus(False, port_id, response.data) def _handle_add_stream_response(self, request, response, success_test): port_id = request.params.get("port_id") stream_id = request.params.get("stream_id") if success_test(response): return RpcResponseStatus(True, port_id, "Stream {0} added".format(stream_id)) else: return RpcResponseStatus(False, port_id, response.data) def _handle_remove_streams_response(self, request, response, success_test): port_id = request.params.get("port_id") if success_test(response): return RpcResponseStatus(True, port_id, "Removed") else: return RpcResponseStatus(False, port_id, response.data) def _handle_release_response(self, request, response, success_test): port_id = request.params.get("port_id") if success_test(response): del self._conn_handler[port_id] return RpcResponseStatus(True, port_id, "Released") else: return RpcResponseStatus(False, port_id, response.data) def _handle_start_traffic_response(self, request, response, success_test): port_id = request.params.get("port_id") if success_test(response): self._active_ports.add(port_id) return RpcResponseStatus(True, port_id, "Traffic started") else: return RpcResponseStatus(False, port_id, response.data) def _handle_stop_traffic_response(self, request, response, success_test): port_id = request.params.get("port_id") if success_test(response): self._active_ports.remove(port_id) return RpcResponseStatus(True, port_id, "Traffic stopped") else: return RpcResponseStatus(False, port_id, response.data) def _handle_get_global_stats_response(self, request, response, success_test): if response.success: return CGlobalStats(**response.success) else: return False def _handle_get_port_stats_response(self, request, response, success_test): if response.success: return CPortStats(**response.success) else: return False def _handle_get_stream_stats_response(self, request, response, success_test): if response.success: return CStreamStats(**response.success) else: return False def _is_ports_valid(self, port_id): if isinstance(port_id, list) or isinstance(port_id, set): # check each item of the sequence return all([self._is_ports_valid(port) for port in port_id]) elif (isinstance(port_id, int)) and (port_id >= 0) and (port_id <= self.get_port_count()): return True else: return False def _process_batch_result(self, req_list, resp_list, handler_func=None, success_test=default_success_test): res_ok = True responses = [] if isinstance(success_test, staticmethod): success_test = success_test.__func__ for i, response in enumerate(resp_list): # run handler method with its params processed_response = handler_func(req_list[i], response, success_test) responses.append(processed_response) if not processed_response.success: res_ok = False # else: # res_ok = False # TODO: mark in this case somehow the bad result # print res_ok # print responses return res_ok, responses # ------ private classes ------ # class CCommLink(object): """describes the connectivity of the stateless client method""" def __init__(self, server="localhost", port=5050, virtual=False): super(CTRexStatelessClient.CCommLink, self).__init__() self.virtual = virtual self.server = server self.port = port self.verbose = False self.rpc_link = JsonRpcClient(self.server, self.port) @property def is_connected(self): if not self.virtual: return self.rpc_link.connected else: return True def set_verbose(self, mode): self.verbose = mode return self.rpc_link.set_verbose(mode) def connect(self): if not self.virtual: return self.rpc_link.connect() def disconnect(self): if not self.virtual: return self.rpc_link.disconnect() def transmit(self, method_name, params={}): if self.virtual: self._prompt_virtual_tx_msg() _, msg = self.rpc_link.create_jsonrpc_v2(method_name, params) print msg return else: return self.rpc_link.invoke_rpc_method(method_name, params) def transmit_batch(self, batch_list): if self.virtual: self._prompt_virtual_tx_msg() print [ msg for _, msg in [ self.rpc_link.create_jsonrpc_v2(command.method, command.params) for command in batch_list ] ] else: batch = self.rpc_link.create_batch() for command in batch_list: batch.add(command.method, command.params) # invoke the batch return batch.invoke() def _prompt_virtual_tx_msg(self): print "Transmitting virtually over tcp://{server}:{port}".format(server=self.server, port=self.port)