summaryrefslogtreecommitdiffstats
path: root/scripts/automation
diff options
context:
space:
mode:
authorDan Klein <danklein10@gmail.com>2015-11-26 13:15:33 +0200
committerDan Klein <danklein10@gmail.com>2015-11-26 13:15:33 +0200
commit4486f9863e7f541ce5b6b4ff2bce6c6f7c41fcd2 (patch)
tree22415c9c16e198e07c6282780fb0787562329b90 /scripts/automation
parent91f6c24f45cbb0cbf8568a9938059a1a934e6ae6 (diff)
parentd9a11302236095e055247295021bdfce6c988802 (diff)
Merge branch 'master' into dan_stateless
# Conflicts (solved): # scripts/automation/trex_control_plane/client_utils/parsing_opts.py
Diffstat (limited to 'scripts/automation')
-rw-r--r--scripts/automation/trex_control_plane/client/trex_async_client.py11
-rwxr-xr-xscripts/automation/trex_control_plane/client/trex_stateless_client.py157
-rwxr-xr-xscripts/automation/trex_control_plane/client_utils/parsing_opts.py95
-rwxr-xr-xscripts/automation/trex_control_plane/console/trex_console.py103
4 files changed, 326 insertions, 40 deletions
diff --git a/scripts/automation/trex_control_plane/client/trex_async_client.py b/scripts/automation/trex_control_plane/client/trex_async_client.py
index 12c89c1a..0a3afbe8 100644
--- a/scripts/automation/trex_control_plane/client/trex_async_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_async_client.py
@@ -195,7 +195,6 @@ class CTRexAsyncClient():
return self.stats
def get_raw_snapshot (self):
- #return str(self.stats.global_stats.get('m_total_tx_bytes')) + " / " + str(self.stats.global_stats.get_rel('m_total_tx_bytes'))
return self.raw_snapshot
# dispatch the message to the right place
@@ -205,18 +204,10 @@ class CTRexAsyncClient():
self.stats.update(data)
# events
elif name == "trex-event":
- self.__handle_async_event(type, data)
+ self.stateless_client.handle_async_event(type, data)
else:
- # ignore
pass
- def __handle_async_event (self, type, data):
- # DP stopped
- if (type == 0):
- port_id = int(data['port_id'])
- print format_text("\n[Event] - Port {0} Stopped".format(port_id), 'bold')
- # call the handler
- self.stateless_client.async_event_port_stopped(port_id)
def stop (self):
self.active = False
diff --git a/scripts/automation/trex_control_plane/client/trex_stateless_client.py b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
index 4cb70483..2db30daf 100755
--- a/scripts/automation/trex_control_plane/client/trex_stateless_client.py
+++ b/scripts/automation/trex_control_plane/client/trex_stateless_client.py
@@ -18,6 +18,7 @@ from common.text_opts import *
from common import trex_stats
from client_utils import parsing_opts, text_tables
import time
+import datetime
from trex_async_client import CTRexAsyncClient
@@ -148,13 +149,14 @@ class Port(object):
STATE_TX = 3
STATE_PAUSE = 4
- def __init__ (self, port_id, user, transmit):
+ def __init__ (self, port_id, speed, driver, user, transmit):
self.port_id = port_id
self.state = self.STATE_IDLE
self.handler = None
self.transmit = transmit
self.user = user
-
+ self.driver = driver
+ self.speed = speed
self.streams = {}
def err(self, msg):
@@ -163,6 +165,9 @@ class Port(object):
def ok(self):
return RC_OK()
+ def get_speed_bps (self):
+ return (self.speed * 1000 * 1000 * 1000)
+
# take the port
def acquire(self, force = False):
params = {"port_id": self.port_id,
@@ -290,6 +295,13 @@ class Port(object):
return self.streams
+ def process_mul (self, mul):
+ # if percentage - translate
+ if mul['type'] == 'percentage':
+ mul['type'] = 'max_bps'
+ mul['max'] = self.get_speed_bps() * (mul['max'] / 100)
+
+
# start traffic
def start (self, mul, duration):
if self.state == self.STATE_DOWN:
@@ -301,6 +313,8 @@ class Port(object):
if self.state == self.STATE_TX:
return self.err("Unable to start traffic - port is already transmitting")
+ self.process_mul(mul)
+
params = {"handler": self.handler,
"port_id": self.port_id,
"mul": mul,
@@ -350,6 +364,7 @@ class Port(object):
return self.ok()
+
def resume (self):
if (self.state != self.STATE_PAUSE) :
@@ -367,6 +382,23 @@ class Port(object):
return self.ok()
+
+ def update (self, mul):
+ if (self.state != self.STATE_TX) :
+ return self.err("port is not transmitting")
+
+ self.process_mul(mul)
+
+ params = {"handler": self.handler,
+ "port_id": self.port_id,
+ "mul": mul}
+
+ rc, data = self.transmit("update_traffic", params)
+ if not rc:
+ return self.err(data)
+
+ return self.ok()
+
################# events handler ######################
def async_event_port_stopped (self):
self.state = self.STATE_STREAMS
@@ -399,10 +431,70 @@ class CTRexStatelessClient(object):
self.connected = False
+ self.events = []
+
################# events handler ######################
+
+ def handle_async_event (self, type, data):
+ # DP stopped
+
+ ev = "[event] - "
+
+ show_event = False
+
+ # port started
+ if (type == 0):
+ port_id = int(data['port_id'])
+ ev += "Port {0} has started".format(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)
+
+
+ # server stopped
+ elif (type == 2):
+ ev += "Server has stopped"
+ self.async_event_server_stopped()
+ show_event = True
+
+ # port finished traffic
+ elif (type == 3):
+ 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
+
+ else:
+ # unknown event - ignore
+ return
+
+ if show_event:
+ print format_text("\n" + ev, 'bold')
+
+ ts = time.time()
+ st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
+ self.events.append("{0} - ".format(st) + format_text(ev, 'bold'))
+
+
def async_event_port_stopped (self, port_id):
self.ports[port_id].async_event_port_stopped()
+ def async_event_server_stopped (self):
+ self.disconnect()
+
+ def get_events (self):
+ return self.events
+
+ def clear_events (self):
+ self.events = []
+
############# helper functions section ##############
def validate_port_list(self, port_id_list):
@@ -471,7 +563,9 @@ class CTRexStatelessClient(object):
# create ports
for port_id in xrange(self.get_port_count()):
- self.ports.append(Port(port_id, self.user, self.transmit))
+ speed = self.system_info['ports'][port_id]['speed']
+ driver = self.system_info['ports'][port_id]['driver']
+ self.ports.append(Port(port_id, speed, driver, self.user, self.transmit))
# acquire all ports
rc = self.acquire()
@@ -693,6 +787,17 @@ class CTRexStatelessClient(object):
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 get_port_stats(self, port_id=None):
pass
@@ -773,6 +878,25 @@ class CTRexStatelessClient(object):
return RC_OK()
+ # update cmd
+ def cmd_update (self, port_id_list, mult):
+
+ # 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.update_traffic(mult, active_ports)
+ rc.annotate("Updating 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):
@@ -894,6 +1018,7 @@ class CTRexStatelessClient(object):
"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,
@@ -920,6 +1045,11 @@ class CTRexStatelessClient(object):
return RC_ERR("Failed to load stream pack")
+ # total has no meaning with percentage - its linear
+ if opts.total and (mult['type'] != 'percentage'):
+ # if total was set - divide it between the ports
+ opts.mult['max'] = opts.mult['max'] / len(opts.ports)
+
return self.cmd_start(opts.ports, stream_list, opts.mult, opts.force, opts.duration)
def cmd_stop_line (self, line):
@@ -936,6 +1066,27 @@ class CTRexStatelessClient(object):
return self.cmd_stop(opts.ports)
+ 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['max'] = opts.mult['max'] / len(opts.ports)
+
+ return self.cmd_update(opts.ports, opts.mult)
+
+
def cmd_reset_line (self, line):
return self.cmd_reset()
diff --git a/scripts/automation/trex_control_plane/client_utils/parsing_opts.py b/scripts/automation/trex_control_plane/client_utils/parsing_opts.py
index c110983b..6c348467 100755
--- a/scripts/automation/trex_control_plane/client_utils/parsing_opts.py
+++ b/scripts/automation/trex_control_plane/client_utils/parsing_opts.py
@@ -19,14 +19,22 @@ SERVER_IP = 7
STREAM_FROM_PATH_OR_FILE = 8
DURATION = 9
FORCE = 10
-GLOBAL_STATS = 11
-PORT_STATS = 12
-PORT_STATUS = 13
-STATS_MASK = 14
+
+TOTAL = 11
+
+GLOBAL_STATS = 12
+PORT_STATS = 13
+PORT_STATUS = 14
+STATS_MASK = 15
# list of ArgumentGroup types
MUTEX = 1
+def check_negative(value):
+ ivalue = int(value)
+ if ivalue < 0:
+ raise argparse.ArgumentTypeError("non positive value provided: '{0}'".format(value))
+ return ivalue
def match_time_unit(val):
'''match some val against time shortcut inputs '''
@@ -46,24 +54,66 @@ def match_time_unit(val):
"-d 10m : in min \n"
"-d 1h : in hours")
+match_multiplier_help = """Multiplier should be passed in the following format:
+ [number][<empty> | bps | kbps | mbps | gbps | pps | kpps | mpps | %% ].
+ no suffix will provide an absoulute factor and percentage
+ will provide a percentage of the line rate. examples
+ : '-m 10', '-m 10kbps', '-m 10mpps', '-m 23%%' """
+
def match_multiplier(val):
'''match some val against multiplier shortcut inputs '''
- match = re.match("^(\d+)(gb|kpps|%?)$", val)
+
+ match = re.match("^(\d+(\.\d+)?)(bps|kbps|mbps|gbps|pps|kpps|mpps|%?)$", val)
+
+ result = {}
+
if match:
- digit = int(match.group(1))
- unit = match.group(2)
+
+ value = float(match.group(1))
+ unit = match.group(3)
+
+ # raw type (factor)
if not unit:
- return digit
- elif unit == 'gb':
- raise NotImplementedError("gb units are not supported yet")
- else:
- raise NotImplementedError("kpps units are not supported yet")
+ result['type'] = 'raw'
+ result['max'] = value
+
+ elif unit == 'bps':
+ result['type'] = 'max_bps'
+ result['max'] = value
+
+ elif unit == 'kbps':
+ result['type'] = 'max_bps'
+ result['max'] = value * 1000
+
+ elif unit == 'mbps':
+ result['type'] = 'max_bps'
+ result['max'] = value * 1000 * 1000
+
+ elif unit == 'gbps':
+ result['type'] = 'max_bps'
+ result['max'] = value * 1000 * 1000 * 1000
+
+ elif unit == 'pps':
+ result['type'] = 'max_pps'
+ result['max'] = value
+
+ elif unit == "kpps":
+ result['type'] = 'max_pps'
+ result['max'] = value * 1000
+
+ elif unit == "mpps":
+ result['type'] = 'max_pps'
+ result['max'] = value * 1000 * 1000
+
+ elif unit == "%":
+ # will be translated by the port object
+ result['type'] = 'percentage'
+ result['max'] = value
+
+ return result
+
else:
- raise argparse.ArgumentTypeError("Multiplier should be passed in the following format: \n"
- "-m 100 : multiply stream file by this factor \n"
- "-m 10gb : from graph calculate the maximum rate as this bandwidth (for each port)\n"
- "-m 10kpps : from graph calculate the maximum rate as this pps (for each port)\n"
- "-m 40% : from graph calculate the maximum rate as this percent from total port (for each port)")
+ raise argparse.ArgumentTypeError(match_multiplier_help)
@@ -75,11 +125,18 @@ def is_valid_file(filename):
OPTIONS_DB = {MULTIPLIER: ArgumentPack(['-m', '--multiplier'],
- {'help': "Set multiplier for stream",
+ {'help': match_multiplier_help,
'dest': "mult",
- 'default': 1.0,
+ 'default': {'type':'raw', 'max':1},
'type': match_multiplier}),
+
+ TOTAL: ArgumentPack(['-t', '--total'],
+ {'help': "traffic will be divided between all ports specified",
+ 'dest': "total",
+ 'default': False,
+ 'action': "store_true"}),
+
PORT_LIST: ArgumentPack(['--port'],
{"nargs": '+',
'dest':'ports',
diff --git a/scripts/automation/trex_control_plane/console/trex_console.py b/scripts/automation/trex_control_plane/console/trex_console.py
index 7d4f3c27..3ddfd8c6 100755
--- a/scripts/automation/trex_control_plane/console/trex_console.py
+++ b/scripts/automation/trex_control_plane/console/trex_console.py
@@ -71,6 +71,23 @@ class TRexGeneralCmd(cmd.Cmd):
readline.write_history_file(self._history_file)
return
+ def print_history (self):
+
+ length = readline.get_current_history_length()
+
+ for i in xrange(1, length + 1):
+ cmd = readline.get_history_item(i)
+ print "{:<5} {:}".format(i, cmd)
+
+ def get_history_item (self, index):
+ length = readline.get_current_history_length()
+ if index > length:
+ print format_text("please select an index between {0} and {1}".format(0, length))
+ return None
+
+ return readline.get_history_item(index)
+
+
def emptyline(self):
"""Called when an empty line is entered in response to the prompt.
@@ -218,6 +235,39 @@ class TRexConsole(TRexGeneralCmd):
else:
print format_text("\nplease specify 'on' or 'off'\n", 'bold')
+ # show history
+ def help_history (self):
+ self.do_history("-h")
+
+ def do_history (self, line):
+ '''Manage the command history\n'''
+
+ item = parsing_opts.ArgumentPack(['item'],
+ {"nargs": '?',
+ 'metavar': 'item',
+ 'type': parsing_opts.check_negative,
+ 'help': "an history item index",
+ 'default': 0})
+
+ parser = parsing_opts.gen_parser(self,
+ "history",
+ self.do_history.__doc__,
+ item)
+
+ opts = parser.parse_args(line.split())
+ if opts is None:
+ return
+
+ if opts.item == 0:
+ self.print_history()
+ else:
+ cmd = self.get_history_item(opts.item)
+ if cmd == None:
+ return
+
+ self.onecmd(cmd)
+
+
############### connect
def do_connect (self, line):
@@ -264,20 +314,28 @@ class TRexConsole(TRexGeneralCmd):
'''stops port(s) transmitting traffic\n'''
self.stateless_client.cmd_stop_line(line)
- ############# stop
+ def help_stop(self):
+ self.do_stop("-h")
+
+ ############# update
+ def do_update(self, line):
+ '''update speed of port(s)currently transmitting traffic\n'''
+ self.stateless_client.cmd_update_line(line)
+
+ def help_update (self):
+ self.do_update("-h")
+
+ ############# pause
def do_pause(self, line):
'''pause port(s) transmitting traffic\n'''
self.stateless_client.cmd_pause_line(line)
- ############# stop
+ ############# resume
def do_resume(self, line):
'''resume port(s) transmitting traffic\n'''
self.stateless_client.cmd_resume_line(line)
-
-
- def help_stop(self):
- self.do_stop("-h")
+
########## reset
def do_reset (self, line):
@@ -293,6 +351,34 @@ class TRexConsole(TRexGeneralCmd):
self.do_stats("-h")
+ def help_events (self):
+ self.do_events("-h")
+
+ def do_events (self, line):
+ '''shows events recieved from server\n'''
+
+ x = parsing_opts.ArgumentPack(['-c','--clear'],
+ {'action' : "store_true",
+ 'default': False,
+ 'help': "clear the events log"})
+
+ parser = parsing_opts.gen_parser(self,
+ "events",
+ self.do_events.__doc__,
+ x)
+
+ opts = parser.parse_args(line.split())
+ if opts is None:
+ return
+
+ events = self.stateless_client.get_events()
+ for ev in events:
+ print ev
+
+ if opts.clear:
+ self.stateless_client.clear_events()
+ print format_text("\n\nEvent log was cleared\n\n")
+
# tui
def do_tui (self, line):
'''Shows a graphical console\n'''
@@ -333,7 +419,7 @@ class TRexConsole(TRexGeneralCmd):
cmds = [x[3:] for x in self.get_names() if x.startswith("do_")]
for cmd in cmds:
- if ( (cmd == "EOF") or (cmd == "q") or (cmd == "exit")):
+ if ( (cmd == "EOF") or (cmd == "q") or (cmd == "exit") or (cmd == "h")):
continue
try:
@@ -347,8 +433,9 @@ class TRexConsole(TRexGeneralCmd):
print "{:<30} {:<30}".format(cmd + " - ", help)
+ # aliases
do_exit = do_EOF = do_q = do_quit
-
+ do_h = do_history
#
def is_valid_file(filename):