def prune_files(p4_prune_dir, p4_passes): util.check_dir(p4_prune_dir) for p4_file in p4_passes: sed_cmd = "sed -r " sed_cmd += "\':a; s%(.*)/\\*.*\\*/%\\1%; ta; /\\/\\*/ !b; N; ba\' " sed_cmd += f"{p4_file} " sed_cmd += " | sed -r \'/^\\s*$/d\' " sed_cmd += f"> {p4_prune_dir}/{p4_file.name}" log.debug("Removing comments and whitespace") log.debug("Command: %s", sed_cmd) util.exec_process(sed_cmd) return p4_prune_dir
def compile_p4_prog(p4c_bin, p4_file, p4_dump_dir): p4_cmd = f"{p4c_bin} " # p4_cmd += f"-vvvv " p4_cmd += f"{p4_file} " p4_cmd += f"-o {p4_dump_dir}" log.debug("Checking compilation with command %s ", p4_cmd) return util.exec_process(p4_cmd)
def generate_p4_prog(p4c_bin, p4_file, config): arch = config["arch"] p4_cmd = f"{p4c_bin} " p4_cmd += f"--output {p4_file} " p4_cmd += f"--arch {arch} " log.debug("Generating random p4 code with command %s ", p4_cmd) return util.exec_process(p4_cmd), p4_file
def generate_p4_dump(p4c_bin, p4_file, p4_dmp_dir): p4_cmd = f"{p4c_bin} " p4_cmd += f"{PASSES} " # p4_cmd += f"-o {p4_dmp_dir} " p4_cmd += f"--dump {p4_dmp_dir} {p4_file} " log.debug("Running dumps with command %s ", p4_cmd) return util.exec_process(p4_cmd)
def validate_p4(p4_file, target_dir, p4c_bin, log_file): p4z3_cmd = "python3 check_p4_whitebox.py " p4z3_cmd += f"-i {p4_file} " p4z3_cmd += f"-o {target_dir} " p4z3_cmd += f"-p {p4c_bin} " p4z3_cmd += f"-l {log_file} " result = util.exec_process(p4z3_cmd) return result.returncode
def generate_p4_dump(p4c_bin, p4_file, config): p4_cmd = f"{p4c_bin} " p4_cmd += f"{p4_file} " if config["use_tofino"]: p4_cmd += f"1 " else: p4_cmd += f"0 " log.debug("Generating random p4 code with command %s ", p4_cmd) return util.exec_process(p4_cmd), p4_file
def run_p4_to_py(p4_file, py_file, config, option_str=""): cmd = f"{P4Z3_BIN} " cmd += f"{p4_file} " cmd += f"--output {py_file} " cmd += option_str if config["use_tofino"]: include_dir = TOFINO_DIR.joinpath(f"install/share/p4c/p4include/ ") cmd += f"-I {include_dir}" log.info("Converting p4 to z3 python with command %s ", cmd) return util.exec_process(cmd)
def validate_p4_blackbox(p4_file, target_dir, log_file, config): p4z3_cmd = "python3 check_p4_blackbox.py " p4z3_cmd += f"-i {p4_file} " p4z3_cmd += f"-o {target_dir} " p4z3_cmd += f"-l {log_file} " if config["use_tofino"]: p4z3_cmd += f"-t " if config["randomize_input"]: p4z3_cmd += f"-r " result = util.exec_process(p4z3_cmd) time.sleep(3) return result.returncode
def validate_p4_blackbox(p4_file, target_dir, log_file, config): p4z3_cmd = "python3 " p4z3_cmd += f"{FILE_DIR.joinpath('generate_p4_test.py')} " p4z3_cmd += f"-i {p4_file} " p4z3_cmd += f"-o {target_dir} " p4z3_cmd += f"-l {log_file} " p4z3_cmd += f"-a {config['arch']} " if config["randomize_input"]: p4z3_cmd += "-r " result = util.exec_process(p4z3_cmd, silent=True) time.sleep(3) return result.returncode
def validate_p4(p4_file, target_dir, p4c_bin, log_file): p4z3_cmd = "python3 " p4z3_cmd += f"{FILE_DIR.joinpath('validate_p4_translation.py')} " p4z3_cmd += f"-i {p4_file} " p4z3_cmd += f"-o {target_dir} " p4z3_cmd += f"-p {p4c_bin} " p4z3_cmd += f"-l {log_file} " # distinguish between well-defined and undefined validation errors p4z3_cmd += "-u " # also dump info which we can reuse for various purposes p4z3_cmd += "-d " result = util.exec_process(p4z3_cmd, silent=True) return result.returncode
def compile_p4_prog(p4c_bin, p4_file, p4_dump_dir): p4_cmd = f"{p4c_bin} " # p4_cmd += f"-vvvv " # the Tofino compiler is not great with warnings if p4c_bin != TNA_BIN: p4_cmd += "--Wdisable " p4_cmd += f"{p4_file} " # p4test does not have the -o flag if p4c_bin != P4TEST_BIN: out_file = p4_file.with_suffix(".out").name p4_cmd += f"-o {p4_dump_dir}/{out_file}" log.debug("Checking compilation with command %s ", p4_cmd) return util.exec_process(p4_cmd, silent=True)
def diff_files(passes, pass_dir, p4_file): p4_name = p4_file.name.stem for index, p4_pass in enumerate(passes[1:]): pass_before = passes[index - 1] pass_after = passes[index] diff_dir = f"{pass_dir}/{p4_name}" util.check_dir(diff_dir) diff_file = f"{diff_dir}/{p4_name}_{p4_pass}.diff" diff_cmd = "diff -rupP " diff_cmd += "--label=\"before_pass\" --label=\"after_pass\" " diff_cmd += f"{pass_before} {pass_after}" diff_cmd += f"> {diff_file}" log.debug("Creating a diff of the file") log.debug("Command: %s", diff_cmd) util.exec_process(diff_cmd) if os.stat(diff_file).st_size == 0: os.remove(diff_file) else: after_name = f"{diff_dir}/{p4_name}_{p4_pass}{p4_file.suffix}" util.copy_file(pass_after, after_name) og_name = f"{diff_dir}/{p4_name}_original{p4_file.suffix}" util.copy_file(p4_file, og_name) return util.EXIT_SUCCESS
def run_p4_to_py(p4_file, py_file): cmd = f"{P4Z3_BIN} " cmd += f"{p4_file} " cmd += f"--output {py_file} " return util.exec_process(cmd)
def run_tofino_test(out_dir, p4_input, stf_file_name): # we need to change the working directory # tofino scripts make some assumptions where to dump files prog_name = p4_input.stem # we need to create a specific test dir in which we can run tests test_dir = out_dir.joinpath("test_dir") util.check_dir(test_dir) util.copy_file(stf_file_name, test_dir) template_name = test_dir.joinpath(f"{prog_name}.py") # use a test template that runs stf tests util.copy_file(f"{FILE_DIR}/tofino_test_template.py", template_name) # initialize the target install log.info("Building the tofino target...") config_cmd = f"{TOFINO_DIR}/pkgsrc/p4-build/configure " config_cmd += f"--with-tofino --with-p4c=bf-p4c " config_cmd += f"--prefix={TOFINO_DIR}/install " config_cmd += f"--bindir={TOFINO_DIR}/install/bin " config_cmd += f"P4_NAME={prog_name} " config_cmd += f"P4_PATH={p4_input.resolve()} " config_cmd += f"P4_VERSION=p4-16 " config_cmd += f"P4_ARCHITECTURE=tna " result = util.exec_process(config_cmd, cwd=out_dir) if result.returncode != util.EXIT_SUCCESS: return result, result.stdout, result.stderr # create the target make_cmd = f"make -C {out_dir} " result = util.exec_process(make_cmd) if result.returncode != util.EXIT_SUCCESS: return result, result.stdout, result.stderr # install the target in the tofino folder make_cmd = f"make install -C {out_dir} " result = util.exec_process(make_cmd) if result.returncode != util.EXIT_SUCCESS: return result, result.stdout, result.stderr procs = [] test_proc = None # start the target in the background log.info("Starting the tofino model...") os_env = os.environ.copy() os_env["SDE"] = f"{TOFINO_DIR}" os_env["SDE_INSTALL"] = f"{TOFINO_DIR}/install" model_cmd = f"{TOFINO_DIR}/run_tofino_model.sh " model_cmd += f"-p {prog_name} " proc = util.start_process(model_cmd, preexec_fn=os.setsid, env=os_env, cwd=out_dir) procs.append(proc) # start the binary for the target in the background log.info("Launching switchd...") os_env = os.environ.copy() os_env["SDE"] = f"{TOFINO_DIR}" os_env["SDE_INSTALL"] = f"{TOFINO_DIR}/install" switch_cmd = f"{TOFINO_DIR}/run_switchd.sh " switch_cmd += f"--arch tofino " switch_cmd += f"-p {prog_name} " proc = util.start_process(switch_cmd, preexec_fn=os.setsid, env=os_env, cwd=out_dir) procs.append(proc) # wait for a bit time.sleep(2) # finally we can run the test log.info("Running the actual test...") test_cmd = f"{TOFINO_DIR}/run_p4_tests.sh " test_cmd += f"-t {test_dir} " os_env = os.environ.copy() os_env["SDE"] = f"{TOFINO_DIR}" os_env["SDE_INSTALL"] = f"{TOFINO_DIR}/install" os_env["PYTHONPATH"] = f"${{PYTHONPATH}}:{FILE_DIR}" test_proc = util.start_process(test_cmd, env=os_env, cwd=out_dir) def signal_handler(sig, frame): log.warning("run_tofino_test: Caught Interrupt, exiting...") cleanup(procs) os.kill(test_proc.pid, signal.SIGINT) os.kill(test_proc.pid, signal.SIGTERM) sys.exit(1) signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler) stdout, stderr = test_proc.communicate() cleanup(procs) return test_proc, stdout, stderr