Skip to content

Commit

Permalink
Use namespace for dpdk PTF tests (#4111)
Browse files Browse the repository at this point in the history
Merge main

Formatted
  • Loading branch information
Hoooao authored Aug 19, 2023
1 parent daa1d6c commit 40ebd7e
Showing 1 changed file with 43 additions and 24 deletions.
67 changes: 43 additions & 24 deletions backends/dpdk/run-dpdk-ptf-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
sys.path.append(str(TOOLS_PATH))
import testutils

BRIDGE_PATH = FILE_DIR.joinpath("../ebpf/targets")
sys.path.append(str(BRIDGE_PATH))
from ebpfenv import Bridge

PARSER = argparse.ArgumentParser()
PARSER.add_argument("p4c_dir", help="The location of the the compiler source directory")
PARSER.add_argument("p4_file", help="the p4 file to process")
Expand Down Expand Up @@ -81,21 +85,12 @@


# Check if target ports are ready to be connected (make sure infrap4d is on)
def is_port_alive(host, port) -> bool:
try:
with socket.create_connection((host, port), timeout=5) as conn:
return True
except (socket.timeout, ConnectionRefusedError):
return False


# We want to disable IPv6 to avoid ICMPv6 spam
def diable_IPv6():
testutils.exec_process("sysctl -w net.ipv6.conf.all.disable_ipv6=1")
testutils.exec_process("sysctl -w net.ipv6.conf.default.disable_ipv6=1")
# Also filter igmp packets, -w is necessary because of a race condition
testutils.exec_process("iptables -w -A OUTPUT -p 2 -j DROP")
return testutils.SUCCESS
def is_port_alive(ns, port) -> bool:
command = f"sudo ip netns exec {ns} netstat -tuln"
out, result = testutils.exec_process(command, timeout=10, capture_output=True)
if str(port) in out:
return 1
return 0


class Options:
Expand Down Expand Up @@ -126,13 +121,34 @@ class PTFTestEnv:

def __init__(self, options):
self.options = options
# Configure IPv6
diable_IPv6()
# Create the virtual environment for the test execution.
self.bridge = self.create_bridge()

def __del__(self):
if self.switch_proc:
# Terminate the switch process and emit its output in case of failure.
testutils.kill_proc_group(self.switch_proc)
if self.bridge:
self.bridge.ns_del()

def create_bridge(self) -> Bridge:
"""Create a network namespace environment with Bridge."""
testutils.log.info(
"---------------------- Creating a namespace ----------------------",
)
random.seed(datetime.now().timestamp())
bridge = Bridge(uuid.uuid4())
result = bridge.create_virtual_env(0)
if result != testutils.SUCCESS:
bridge.ns_del()
testutils.log.error(
"---------------------- Namespace creation failed ----------------------",
)
raise SystemExit("Unable to create the namespace environment.")
testutils.log.info(
"---------------------- Namespace successfully created ----------------------"
)
return bridge

def create_TAPs(self, proc_env_vars: dict, insecure_mode: bool = True) -> int:
"""Create TAPs with gNMI"""
Expand All @@ -146,11 +162,11 @@ def create_TAPs(self, proc_env_vars: dict, insecure_mode: bool = True) -> int:
f"device:virtual-device,name:{tap_name},pipeline-name:pipe,mempool-name:MEMPOOL0,mtu:1500,port-type:TAP "
f"-grpc_use_insecure_mode={insecure_mode}"
)
_, returncode = testutils.exec_process(cmd, env=proc_env_vars)
returncode = self.bridge.ns_exec(cmd, env=proc_env_vars)
if returncode != testutils.SUCCESS:
testutils.log.error("Failed to create TAP")
return returncode
_, returncode = testutils.exec_process(f"ifconfig {tap_name} up")
returncode = self.bridge.ns_exec(f"ifconfig {tap_name} up")
if returncode != testutils.SUCCESS:
testutils.log.error("Failed to activate TAP interface")
return returncode
Expand Down Expand Up @@ -191,12 +207,15 @@ def run_infrap4d(
f"{self.options.ipdk_recipe}/install/sbin/infrap4d "
f"-grpc_open_insecure_mode={insecure_mode}"
)
self.switch_proc = testutils.open_process(run_infrap4d_cmd, env=proc_env_vars)
bridge_cmd = self.bridge.get_ns_prefix() + " " + run_infrap4d_cmd
self.switch_proc = testutils.open_process(bridge_cmd, env=proc_env_vars)
cnt = 1
while not is_port_alive(PTF_ADDR, GRPC_PORT) and cnt != 5:
while not is_port_alive(self.bridge.ns_name, GRPC_PORT) and cnt != 5:
time.sleep(2)
cnt += 1
testutils.log.info("Cannot connect to Infrap4d: " + str(cnt) + " try")
if not is_port_alive(self.bridge.ns_name, GRPC_PORT):
return testutils.FAILURE
return self.switch_proc

def build_and_load_pipeline(
Expand All @@ -221,7 +240,7 @@ def build_and_load_pipeline(
f"{conf_bin} "
f"{info_name} "
)
_, returncode = testutils.exec_process(command, timeout=30)
returncode = self.bridge.ns_exec(command, timeout=30)
if returncode != testutils.SUCCESS:
testutils.log.error("Failed to load pipeline")
return returncode
Expand All @@ -234,7 +253,7 @@ def run_ptf(self, grpc_port: int) -> int:
pypath = FILE_DIR
# Show list of the tests
testListCmd = f"ptf --pypath {pypath} --test-dir {self.options.testdir} --list"
_, returncode = testutils.exec_process(testListCmd)
returncode = self.bridge.ns_exec(testListCmd)
if returncode != testutils.SUCCESS:
return returncode
taps: str = ""
Expand All @@ -245,7 +264,7 @@ def run_ptf(self, grpc_port: int) -> int:
f"ptf --pypath {pypath} {taps} --log-file {self.options.testdir.joinpath('ptf.log')} "
f"--test-params={test_params} --test-dir {self.options.testdir}"
)
_, returncode = testutils.exec_process(run_ptf_cmd)
returncode = self.bridge.ns_exec(run_ptf_cmd)
return returncode


Expand Down

0 comments on commit 40ebd7e

Please sign in to comment.