summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorYaroslav Brustinov <ybrustin@cisco.com>2016-12-14 01:19:31 +0200
committerYaroslav Brustinov <ybrustin@cisco.com>2016-12-20 12:08:30 +0200
commit1530b34cabea906fef56f1537cd32aead6103f9d (patch)
treed00746b88c91e68743860a833eb723239a2f8d2c /scripts
parentde2af4eb20e9f77adfb1ee61e6ae3c82bfb86e92 (diff)
scapy launcher
Change-Id: Iafe0365e82c5386e87dbf7abd0f0982c3ff95d80 Signed-off-by: Yaroslav Brustinov <ybrustin@cisco.com>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/dpdk_setup_ports.py36
-rw-r--r--scripts/external_libs/netstat.py97
-rwxr-xr-xscripts/scapy_daemon_server163
3 files changed, 281 insertions, 15 deletions
diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py
index 59b113ba..fce099b5 100755
--- a/scripts/dpdk_setup_ports.py
+++ b/scripts/dpdk_setup_ports.py
@@ -242,9 +242,7 @@ class ConfigCreator(object):
class map_driver(object):
args=None;
cfg_file='/etc/trex_cfg.yaml'
- parent_cfg = None
- dump_interfaces = None
- no_ofed_check = None
+ parent_args = None
class DpdkSetup(Exception):
pass
@@ -409,7 +407,7 @@ Other network devices
self.raise_error ("Configuration file %s is old, should include version field\n" % fcfg )
if int(cfg_dict['version'])<2 :
- self.raise_error ("Configuration file %s is old, should include version field with value greater than 2\n" % fcfg)
+ self.raise_error ("Configuration file %s is old, expected version 2, got: %s\n" % (fcfg, cfg_dict['version']))
if 'interfaces' not in self.m_cfg_dict[0]:
self.raise_error ("Configuration file %s is old, should include interfaces field even number of elemets" % fcfg)
@@ -461,11 +459,13 @@ Other network devices
def do_run (self,only_check_all_mlx=False):
self.run_dpdk_lspci ()
- if map_driver.dump_interfaces is None or (map_driver.dump_interfaces == [] and map_driver.parent_cfg):
+ if (map_driver.parent_args.dump_interfaces is None or
+ (map_driver.parent_args.dump_interfaces == [] and
+ map_driver.parent_args.cfg)):
self.load_config_file()
if_list=self.m_cfg_dict[0]['interfaces']
else:
- if_list = map_driver.dump_interfaces
+ if_list = map_driver.parent_args.dump_interfaces
if not if_list:
for dev in self.m_devices.values():
if dev.get('Driver_str') in dpdk_nic_bind.dpdk_drivers:
@@ -489,18 +489,18 @@ Other network devices
Mellanox_cnt=Mellanox_cnt+1
- if not map_driver.dump_interfaces :
+ if not map_driver.parent_args.dump_interfaces:
if ((Mellanox_cnt>0) and (Mellanox_cnt!= len(if_list))):
err=" All driver should be from one vendor. you have at least one driver from Mellanox but not all ";
raise DpdkSetup(err)
- if not map_driver.dump_interfaces :
+ if not map_driver.parent_args.dump_interfaces:
if Mellanox_cnt>0 :
self.set_only_mellanox_nics()
if self.get_only_mellanox_nics():
- if not map_driver.no_ofed_check:
+ if not map_driver.parent_args.no_ofed_check:
self.verify_ofed_os()
self.check_ofed_version()
@@ -543,6 +543,11 @@ Other network devices
sys.exit(1)
else:
print('WARNING: Some other program is using DPDK driver.\nIf it is TRex and you did not configure it for dual run, current command will fail.')
+ if map_driver.parent_args.stl:
+ ret = os.system('%s scapy_daemon_server restart' % sys.executable)
+ if ret:
+ sys.exit(1)
+
def do_return_to_linux(self):
if not self.m_devices:
@@ -850,10 +855,11 @@ def parse_parent_cfg (parent_cfg):
parent_parser.add_argument('--dump-interfaces', nargs='*', default=None)
parent_parser.add_argument('--no-ofed-check', action = 'store_true')
parent_parser.add_argument('--no-watchdog', action = 'store_true')
- args, _ = parent_parser.parse_known_args(shlex.split(parent_cfg))
- if args.help:
+ parent_parser.add_argument('-i', action = 'store_true', dest = 'stl', default = False)
+ map_driver.parent_args, _ = parent_parser.parse_known_args(shlex.split(parent_cfg))
+ if map_driver.parent_args.help:
sys.exit(0)
- return (args.cfg, args.dump_interfaces, args.no_ofed_check)
+
def process_options ():
parser = argparse.ArgumentParser(usage="""
@@ -970,9 +976,9 @@ To see more detailed info on interfaces (table):
map_driver.args = parser.parse_args();
if map_driver.args.parent :
- map_driver.parent_cfg, map_driver.dump_interfaces, map_driver.no_ofed_check = parse_parent_cfg (map_driver.args.parent)
- if map_driver.parent_cfg != '':
- map_driver.cfg_file = map_driver.parent_cfg;
+ parse_parent_cfg (map_driver.args.parent)
+ if map_driver.parent_args.cfg:
+ map_driver.cfg_file = map_driver.parent_args.cfg;
if map_driver.args.cfg :
map_driver.cfg_file = map_driver.args.cfg;
diff --git a/scripts/external_libs/netstat.py b/scripts/external_libs/netstat.py
new file mode 100644
index 00000000..03598573
--- /dev/null
+++ b/scripts/external_libs/netstat.py
@@ -0,0 +1,97 @@
+#!/usr/bin/python
+
+# based on http://voorloopnul.com/blog/a-python-netstat-in-less-than-100-lines-of-code/
+# added caching of glob for x10 speedup (additional x2 by omitting pid)
+
+import pwd
+import os
+import glob
+
+PROC_TCP = "/proc/net/tcp"
+STATE = {
+ '01':'ESTABLISHED',
+ '02':'SYN_SENT',
+ '03':'SYN_RECV',
+ '04':'FIN_WAIT1',
+ '05':'FIN_WAIT2',
+ '06':'TIME_WAIT',
+ '07':'CLOSE',
+ '08':'CLOSE_WAIT',
+ '09':'LAST_ACK',
+ '0A':'LISTEN',
+ '0B':'CLOSING'
+ }
+
+def _load():
+ ''' Read the table of tcp connections & remove header '''
+ with open(PROC_TCP,'r') as f:
+ content = f.readlines()
+ content.pop(0)
+ return content
+
+def _hex2dec(s):
+ return str(int(s,16))
+
+def _ip(s):
+ ip = [(_hex2dec(s[6:8])),(_hex2dec(s[4:6])),(_hex2dec(s[2:4])),(_hex2dec(s[0:2]))]
+ return '.'.join(ip)
+
+def _remove_empty(array):
+ return [x for x in array if x]
+
+def _convert_ip_port(array):
+ host,port = array.split(':')
+ return _ip(host),_hex2dec(port)
+
+def netstat(with_pid = True):
+ '''
+ Function to return a list with status of tcp connections at linux systems
+ To get pid of all network process running on system, you must run this script
+ as superuser
+ '''
+
+ pid_cache.clear()
+ content=_load()
+ result = []
+ for line in content:
+ line_array = _remove_empty(line.split(' ')) # Split lines and remove empty spaces.
+ l_host,l_port = _convert_ip_port(line_array[1]) # Convert ipaddress and port from hex to decimal.
+ r_host,r_port = _convert_ip_port(line_array[2])
+ tcp_id = line_array[0]
+ state = STATE.get(line_array[3])
+ uid = pwd.getpwuid(int(line_array[7]))[0] # Get user from UID.
+ inode = line_array[9] # Need the inode to get process pid.
+ if with_pid:
+ pid = _get_pid_of_inode(inode) # Get pid prom inode.
+ try: # try read the process name.
+ exe = os.readlink('/proc/' + pid + '/exe')
+ except:
+ exe = None
+ else:
+ pid = exe = None
+ result.append([tcp_id, uid, l_host, l_port, r_host, r_port, state, pid, exe])
+ pid_cache.clear()
+ return result
+
+pid_cache = {}
+def _get_pid_of_inode(inode):
+ '''
+ To retrieve the process pid, check every running process and look for one using
+ the given inode.
+ '''
+ if not pid_cache:
+ for fd in glob.glob('/proc/[0-9]*/fd/[0-9]*'):
+ try:
+ pid_cache[fd] = os.readlink(fd)
+ except:
+ pass
+ inode = '[' + inode + ']'
+ for key, val in pid_cache.items():
+ if inode in val:
+ return key.split('/')[2]
+ return None
+
+if __name__ == '__main__':
+ for conn in netstat():
+ print(conn)
+
diff --git a/scripts/scapy_daemon_server b/scripts/scapy_daemon_server
new file mode 100755
index 00000000..490e8033
--- /dev/null
+++ b/scripts/scapy_daemon_server
@@ -0,0 +1,163 @@
+#!/usr/bin/python
+
+import os, sys, getpass
+import tempfile
+import time
+import subprocess, shlex
+from argparse import ArgumentParser, RawTextHelpFormatter
+import errno
+
+def fail(msg):
+ print(msg)
+ sys.exit(-1)
+
+if getpass.getuser() != 'root':
+ fail('Please run this program as root/with sudo')
+
+pwd = os.path.abspath(os.path.dirname(__file__))
+ext_libs_path = os.path.join(pwd, 'external_libs')
+if ext_libs_path not in sys.path:
+ sys.path.append(ext_libs_path)
+
+import netstat
+try:
+ from termstyle import termstyle
+except ImportError:
+ import termstyle
+
+
+def inv(f):
+ return lambda *a, **k: not f(*a, **k)
+
+
+def progress(success_check, start_msg, success_msg, fail_msg, timeout = 10, poll_rate = 0.5):
+ sys.stdout.write('%s...' % start_msg)
+ sys.stdout.flush()
+ for i in range(int(timeout/poll_rate)):
+ if success_check():
+ print(termstyle.green(' ' + success_msg))
+ return 0
+ time.sleep(poll_rate)
+ sys.stdout.write('.')
+ sys.stdout.flush()
+ if success_check():
+ print(termstyle.green(' ' + success_msg))
+ return 0
+ print(termstyle.red(' ' + fail_msg))
+ return 1
+
+
+def run_command(command, timeout = 15, poll_rate = 0.1, cwd = None):
+ assert timeout > 0, 'Timeout should be positive'
+ assert poll_rate > 0, 'Poll rate should be positive'
+ try:
+ tempfile.TemporaryFile(bufsize=0)
+ temp_params = {'bufsize': 0}
+ except:
+ tempfile.TemporaryFile(buffering=0)
+ temp_params = {'buffering': 0}
+ with tempfile.TemporaryFile(**temp_params) as stdout_file:
+ proc = subprocess.Popen(shlex.split(command), stdout = stdout_file, stderr = subprocess.STDOUT, cwd = cwd, close_fds = True, universal_newlines = True)
+ for i in range(int(timeout/poll_rate)):
+ time.sleep(poll_rate)
+ if proc.poll() is not None: # process stopped
+ break
+ if proc.poll() is None:
+ proc.kill() # timeout
+ stdout_file.seek(0)
+ return (errno.ETIMEDOUT, '%s\n\n...Timeout of %s second(s) is reached!' % (stdout_file.read(), timeout))
+ stdout_file.seek(0)
+ return (proc.returncode, stdout_file.read())
+
+
+def get_daemon_pid():
+ pid = None
+ for conn in netstat.netstat():
+ if conn[2] == '0.0.0.0' and int(conn[3]) == args.daemon_port and conn[6] == 'LISTEN':
+ pid = conn[7]
+ if pid is None:
+ raise Exception('Found the connection, but could not determine pid: %s' % conn)
+ break
+ return pid
+
+
+# faster variant of get_daemon_pid
+def is_running():
+ for conn in netstat.netstat(with_pid = False):
+ if conn[2] == '0.0.0.0' and int(conn[3]) == args.daemon_port and conn[6] == 'LISTEN':
+ return True
+ return False
+
+
+def show_daemon_status():
+ if is_running():
+ print(termstyle.green('Scapy server is running'))
+ else:
+ print(termstyle.red('Scapy server is NOT running'))
+
+
+def start_daemon():
+ if is_running():
+ print(termstyle.red('Scapy server is already running'))
+ return
+ server_path = os.path.join(pwd, 'automation', 'trex_control_plane', 'stl', 'services', 'scapy_server')
+ with tempfile.TemporaryFile() as stdout_file:
+ subprocess.Popen(shlex.split('sudo -u nobody %s scapy_zmq_server.py -s %s' % (sys.executable, args.daemon_port)), stdout = stdout_file,
+ stderr = subprocess.STDOUT, cwd = server_path, close_fds = True, universal_newlines = True)
+ ret = progress(is_running, 'Starting Scapy server', 'Scapy server is started', 'Scapy server failed to run')
+ if ret:
+ stdout_file.seek(0)
+ print('Output: %s' % stdout_file.read())
+ sys.exit(1)
+
+
+def restart_daemon():
+ if is_running():
+ kill_daemon()
+ time.sleep(0.5)
+ start_daemon()
+
+
+def kill_daemon():
+ pid = get_daemon_pid()
+ if not pid:
+ print(termstyle.red('Scapy server is NOT running'))
+ return True
+ run_command('kill %s' % pid) # usual kill
+ ret = progress(inv(is_running), 'Killing Scapy server', 'Scapy server is killed', 'failed')
+ if not ret:
+ return
+ _, out = run_command('kill -9 %s' % pid) # unconditional kill
+ ret = progress(inv(is_running), 'Killing Scapy server with -9', 'Scapy server is killed', 'failed')
+ if ret:
+ fail('Failed to kill Scapy server, even with -9. Please review manually.\nOutput: %s' % out)
+
+### Main ###
+
+if __name__ == '__main__':
+ actions_help = '''Specify action command to be applied on server.
+ (*) start : start the application in as a daemon process.
+ (*) show : prompt an updated status of daemon process (running/ not running).
+ (*) stop : exit Scapy server daemon process.
+ (*) restart : stop, then start again the application as daemon process
+ '''
+ action_funcs = {'start': start_daemon,
+ 'show': show_daemon_status,
+ 'stop': kill_daemon,
+ 'restart': restart_daemon,
+ }
+
+ parser = ArgumentParser(description = 'Runs Scapy server application.',
+ formatter_class = RawTextHelpFormatter,
+ )
+
+ parser.add_argument('-p', '--port', type = int, default = 4507, metavar="PORT", dest="daemon_port",
+ help="Select tcp port on which Scapy server listens.\nDefault port is 4507.", action="store")
+ parser.add_argument('action', choices=action_funcs.keys(),
+ action='store', help=actions_help)
+ parser.usage = None
+ args = parser.parse_args()
+
+ action_funcs[args.action]()
+
+