From 9fb4cf6f17e3e028d4e01514a947ccb2828738ac Mon Sep 17 00:00:00 2001 From: Yaroslav Brustinov Date: Mon, 2 Jan 2017 19:10:25 +0200 Subject: add warning about lack of read permissions for user "nobody" to run scapy server. add flag to disable scapy server run. Change-Id: I65ccfb24ed4a5461fe2a13d8be0f07fad8a50bae Signed-off-by: Yaroslav Brustinov --- scripts/dpdk_setup_ports.py | 4 +- scripts/scapy_daemon_server | 93 ++++++++++++++++++++++++++++++++------------- src/main_dpdk.cpp | 8 ++-- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/scripts/dpdk_setup_ports.py b/scripts/dpdk_setup_ports.py index 66af699f..97484f21 100755 --- a/scripts/dpdk_setup_ports.py +++ b/scripts/dpdk_setup_ports.py @@ -542,13 +542,14 @@ 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: + if map_driver.parent_args.stl and not map_driver.parent_args.no_scapy_server: try: master_core = self.m_cfg_dict[0]['platform']['master_thread_id'] except: master_core = 0 ret = os.system('%s scapy_daemon_server restart -c %s' % (sys.executable, master_core)) if ret: + print("Could not start scapy_daemon_server, which is needed by GUI to create packets.\nIf you don't need it, use --no-scapy-server flag.") sys.exit(1) @@ -861,6 +862,7 @@ def parse_parent_cfg (parent_cfg): parent_parser.add_argument('--cfg', default='') parent_parser.add_argument('--dump-interfaces', nargs='*', default=None) parent_parser.add_argument('--no-ofed-check', action = 'store_true') + parent_parser.add_argument('--no-scapy-server', action = 'store_true') parent_parser.add_argument('--no-watchdog', action = 'store_true') 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)) diff --git a/scripts/scapy_daemon_server b/scripts/scapy_daemon_server index a5e4df06..e19c8b3c 100755 --- a/scripts/scapy_daemon_server +++ b/scripts/scapy_daemon_server @@ -6,6 +6,7 @@ import time import subprocess, shlex from argparse import ArgumentParser, RawTextHelpFormatter import errno +import pwd def fail(msg): print(msg) @@ -14,8 +15,8 @@ def fail(msg): if os.getuid() != 0: 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') +cur_dir = os.path.abspath(os.path.dirname(__file__)) +ext_libs_path = os.path.join(cur_dir, 'external_libs') if ext_libs_path not in sys.path: sys.path.append(ext_libs_path) @@ -30,34 +31,46 @@ 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): +def progress(success_check, start_msg, success_msg, fail_msg, timeout = 35, poll_rate = 0.5, fail_check = None): 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 + if fail_check and fail_check(): + print(termstyle.red(' ' + fail_msg)) + return 1 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)) + print(termstyle.red(' Timeout')) 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' +def demote_func(): + pw_record = pwd.getpwnam('nobody') + os.setgid(pw_record.pw_gid) + os.setuid(pw_record.pw_uid) + + +def run_command(command, timeout = 30, poll_rate = 0.1, cwd = None, demote = False, is_daemon = False): + if not is_daemon: + assert timeout > 0, 'Timeout should be positive' + assert poll_rate > 0, 'Poll rate should be positive' + + preexec_fn = demote_func if demote else None + + try: # P2 + stdout_file = tempfile.TemporaryFile(bufsize = 0) + except: # P3 + stdout_file = tempfile.TemporaryFile(buffering = 0) + 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) + proc = subprocess.Popen(shlex.split(command), stdout = stdout_file, stderr = subprocess.STDOUT, cwd = cwd, + close_fds = True, universal_newlines = True, preexec_fn = preexec_fn) + if is_daemon: + return proc, stdout_file for i in range(int(timeout/poll_rate)): time.sleep(poll_rate) if proc.poll() is not None: # process stopped @@ -68,6 +81,9 @@ def run_command(command, timeout = 15, poll_rate = 0.1, cwd = None): 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()) + finally: + if not is_daemon: + stdout_file.close() def get_daemon_pid(): @@ -100,15 +116,37 @@ 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("taskset -c %s su -s /bin/bash -c '%s scapy_zmq_server.py -s %s' nobody" % (args.core, sys.executable, args.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') + check_path = cur_dir + last_err_path = None + ret = -1 + while ret and check_path != '/': + ret, out = run_command("ls %s" % check_path, demote = True) if ret: - stdout_file.seek(0) - print('Output: %s' % stdout_file.read()) - sys.exit(1) + last_err_path = check_path + check_path = os.path.abspath(os.path.join(check_path, '..')) + if last_err_path: + msg = ''' +Error: current path is not readable by user "nobody" (starting at {path}). +Two possible solutions: + + 1. (Recommended) + Copy TRex to some public location (/tmp or /scratch, assuming it has proper permissions (chmod 777 etc.)) + + 2. (Not recommended) + Change permissions of current path. (Starting from directory {path}). + chmod 777 {path} -R +'''.format(path = last_err_path) + fail(msg) + + server_path = os.path.join(cur_dir, 'automation', 'trex_control_plane', 'stl', 'services', 'scapy_server') + cmd = 'taskset -c {core} {python} ./scapy_zmq_server.py -s {port}'.format(core = args.core, python = sys.executable, port = args.port) + proc, stdout_file = run_command(cmd, demote = True, is_daemon = True, cwd = server_path) + ret = progress(is_running, 'Starting Scapy server', 'Scapy server is started', 'Scapy server failed to run', fail_check = proc.poll) + if proc.poll(): + stdout_file.seek(0) + print('Output: %s' % stdout_file.read()) + stdout_file.close() + sys.exit(1) def restart_daemon(): @@ -124,14 +162,15 @@ def kill_daemon(): 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') + ret = progress(inv(is_running), 'Killing Scapy server', 'Scapy server is killed', 'failed', timeout = 15) 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') + ret = progress(inv(is_running), 'Killing Scapy server with -9', 'Scapy server is killed', 'failed', timeout = 15) if ret: fail('Failed to kill Scapy server, even with -9. Please review manually.\nOutput: %s' % out) + ### Main ### if __name__ == '__main__': diff --git a/src/main_dpdk.cpp b/src/main_dpdk.cpp index 1f0f993f..82ebdddd 100644 --- a/src/main_dpdk.cpp +++ b/src/main_dpdk.cpp @@ -693,6 +693,7 @@ enum { OPT_HELP, OPT_CLOSE, OPT_ARP_REF_PER, OPT_NO_OFED_CHECK, + OPT_NO_SCAPY_SERVER, OPT_ACTIVE_FLOW }; @@ -749,11 +750,11 @@ static CSimpleOpt::SOption parser_options[] = { OPT_NO_WATCHDOG, "--no-watchdog", SO_NONE }, { OPT_ALLOW_COREDUMP, "--allow-coredump", SO_NONE }, { OPT_CHECKSUM_OFFLOAD, "--checksum-offload", SO_NONE }, - { OPT_ACTIVE_FLOW, "--active-flows", SO_REQ_SEP }, + { OPT_ACTIVE_FLOW, "--active-flows", SO_REQ_SEP }, { OPT_CLOSE, "--close-at-end", SO_NONE }, { OPT_ARP_REF_PER, "--arp-refresh-period", SO_REQ_SEP }, { OPT_NO_OFED_CHECK, "--no-ofed-check", SO_NONE }, - + { OPT_NO_SCAPY_SERVER, "--no-scapy-server", SO_NONE }, SO_END_OF_OPTIONS }; @@ -1090,10 +1091,11 @@ static int parse_options(int argc, char *argv[], CParserOption* po, bool first_t break; case OPT_NO_OFED_CHECK: break; + case OPT_NO_SCAPY_SERVER: + break; default: printf("Error: option %s is not handled.\n\n", args.OptionText()); - usage(); return -1; break; } // End of switch -- cgit 1.2.3-korg