Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set up a basic automated e2e smoke test #102

Merged
merged 14 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
**/.git**
**/Dockerfile
**/README
**/*.md

.github
docker*
e2e-test
examples
tools
!tools/setup
103 changes: 103 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Share args between stages.
# See https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact.
# They should be consistent with tools/setup/p4sde_env_setup.sh.
ARG SDE=/home/sde
ARG SDE_INSTALL=${SDE}/install
ARG LD_LIBRARY_PATH=${SDE_INSTALL}/lib:${SDE_INSTALL}/lib64:${SDE_INSTALL}/lib/x86_64-linux-gnu/
ARG LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64
ARG LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib

#======================================
# Stage 1/3: Reuse upstream p4c image.
#======================================
# FROM p4lang/p4c:latest as p4c
# :latest on 2023-06-23:
FROM p4lang/p4c@sha256:c1cbb66cea83de50b43d7ef78d478dd5e43ce9e1116921d6700cc40bb505e12a as p4c

#==============================================
# Stage 2/3: Build P4 DPDK target from source.
#==============================================
FROM ubuntu:20.04 as p4-dpdk-target
ARG DEBIAN_FRONTEND=noninteractive
ARG SDE
ARG SDE_INSTALL
ARG LD_LIBRARY_PATH

# Install core packages needed for later steps.
RUN apt-get update && apt-get install -y \
python-is-python3 \
python3 \
python3-pip \
sudo \
&& rm -rf /var/lib/apt/lists/*

# Copy repo files in.
ARG REPO_NAME=p4-dpdk-target
COPY . ${SDE}/${REPO_NAME}/

# Install dependent packages.
WORKDIR ${SDE}/${REPO_NAME}/tools/setup
RUN pip3 install distro \
&& apt-get update \
&& python3 install_dep.py \
&& rm -rf /var/lib/apt/lists/*

# Build P4 DPDK target.
WORKDIR ${SDE}/${REPO_NAME}
RUN ./autogen.sh \
&& ./configure --prefix=${SDE_INSTALL} \
&& make -j \
&& make install

#===================================
# Stage 3/3: Construct final image.
#===================================
FROM ubuntu:20.04
LABEL maintainer="P4 Developers <[email protected]>"
ARG DEBIAN_FRONTEND=noninteractive
ARG SDE
ARG SDE_INSTALL
ARG LD_LIBRARY_PATH

# Persist essential environment variables.
ENV SDE=${SDE}
ENV SDE_INSTALL=${SDE_INSTALL}
ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH}

# Install some useful tools.
RUN apt-get update && apt-get install -y \
iproute2 \
python-is-python3 \
python3 \
python3-pip \
sudo \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install --upgrade \
scapy

# [from p4c]
# Just copy minimal p4c bins & libs for dpdk backend.
# Adapted from https://github.com/sonic-net/DASH/blob/main/dash-pipeline/dockerfiles/Dockerfile.p4c-dpdk.
COPY --from=p4c \
/usr/local/bin/p4c \
/usr/local/bin/p4c-dpdk \
/usr/local/bin/
COPY --from=p4c \
/usr/lib/x86_64-linux-gnu/libboost_*so* \
/usr/lib/x86_64-linux-gnu/libgc.so* \
/usr/lib/x86_64-linux-gnu/
COPY --from=p4c \
/usr/local/share/p4c/ \
/usr/local/share/p4c/

# [from p4-dpdk-target]
# Just copy SDE_INSTALL dir & minimal system libs.
COPY --from=p4-dpdk-target \
${SDE_INSTALL} \
${SDE_INSTALL}
COPY --from=p4-dpdk-target \
/usr/lib/x86_64-linux-gnu/libedit.so* \
/usr/lib/x86_64-linux-gnu/

# Set default working directory.
WORKDIR ${SDE}
9 changes: 0 additions & 9 deletions bf_switchd/bf_switchd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1565,15 +1565,6 @@ static int bf_switchd_sys_init(void) {
return ret;
}

/* For performance set defaut log level to error for pipe and pkt modules */
bf_sys_log_level_set(BF_MOD_PIPE, BF_LOG_DEST_FILE, BF_LOG_ERR);
bf_sys_trace_level_set(BF_MOD_PIPE, BF_LOG_ERR);

#ifdef BFRT_ENABLED
bf_sys_log_level_set(BF_MOD_BFRT, BF_LOG_DEST_FILE, BF_LOG_ERR);
bf_sys_trace_level_set(BF_MOD_BFRT, BF_LOG_ERR);
#endif

return 0;
}

Expand Down
129 changes: 129 additions & 0 deletions e2e-test/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# P4 DPDK Target End-to-End Testing

## Directory structure

```
suites/
Collection of test suites.

<p4_arch>/<test_suite_name>/
Individual test suite.

(generated) log/
Log files generated during testing.
(generated) p4c_gen/
P4 compiler outputs generated from main.p4.
cmds_bfshell.py:
Commands to run with bfshell before testing script.
cmds_shell.sh:
Commands to run with normal shell before testing script.
(generated) conf_bf_switchd.json:
Config file needed by the bf_switchd binary.
main.p4:
The P4 pipeline code.
README.md:
A description of the test.
test.py:
The packet testing script.

tools/
Tools used to run the tests.
```

## Testing environement

You can either build P4 DPDK target locally following the README at the root of this repo, or build a Docker image. Below we introduce the Docker approach.

All commands in this section are expected to be executed from the root of this repo.

### Docker image building

```console
./tools/docker_build.sh
```

### Convenient Docker scripts

To run a `bash` in a new container:

```console
./tools/docker_run_bash.sh
```

To run a new `bash` in the same running container:

```console
./tools/docker_exec_bash.sh
```

The last script is useful for providing multiple terminal shells in the same container.

## Simple automated smoke test

To run the smoke test in a container, at the **root of this repo**, do:

```console
./tools/docker_run_smoke_test.sh
```

To run it locally, at **this directory**, do:

```console
./tools/test.py suites/pna/basicfwd
```

## Manual testing workflow

In the previous section, all testing steps are executed with a single script. If for some reason (e.g. debugging) you would like to execute these steps separately, the details are described in this section.

All commands in this section are expected to be executed from this directory.

### Compile P4 code

```console
./tools/compile.py suites/pna/basicfwd
```

The following paths will be generated:

- `suites/pna/basicfwd/p4c_gen/`

### Run `bf_switchd`

In terminal 1, do:

```console
./tools/run_bf_switchd.py suites/pna/basicfwd
```

The following paths will be generated:

- `suites/pna/simple_l2_forwarding/log/bf_switchd/`
- `suites/pna/simple_l2_forwarding/conf_bf_switchd.json`

### Run `bfshell`

In terminal 2, do:

```console
./tools/run_bfshell.py suites/pna/basicfwd
```

The following paths will be generated:

- `suites/pna/simple_l2_forwarding/log/bfshell/`

### Run testing script

In terminal 3, do:

```console
./suites/pna/basicfwd/cmds_shell.sh
./suites/pna/basicfwd/test.py
```

### Clean up (optional)

```console
./tools/clean.py suites/pna/basicfwd
```
3 changes: 3 additions & 0 deletions e2e-test/suites/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
log/
p4c_gen/
conf_bf_switchd.json
3 changes: 3 additions & 0 deletions e2e-test/suites/pna/basicfwd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Basic Forwarding Test

Receive packets on a port and forward them on the paired port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc.
32 changes: 32 additions & 0 deletions e2e-test/suites/pna/basicfwd/cmds_bfshell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
tdi_python

# Add ports
for port_id in range(4):
tdi.port.port.add(
DEV_PORT=port_id,
PORT_TYPE="BF_DPDK_TAP",
PORT_DIR="PM_PORT_DIR_DEFAULT",
PORT_IN_ID=port_id,
PORT_OUT_ID =port_id,
PIPE_IN="pipe",
PIPE_OUT="pipe",
MEMPOOL="MEMPOOL0",
PORT_NAME=f"TAP{port_id}",
MTU=1500
)

# Enable TDI program
tdi.main.enable()

# Add entries
control = tdi.main.pipe.MainControl
table = control.forwarding
table.add_with_forward(input_port=0, output_port=1)
table.add_with_forward(input_port=1, output_port=0)
table.add_with_forward(input_port=2, output_port=3)
table.add_with_forward(input_port=3, output_port=2)

# TODO: Replace the following hack with something better.
foo = "fini"
bar = "shed"
print(foo + bar)
11 changes: 11 additions & 0 deletions e2e-test/suites/pna/basicfwd/cmds_shell.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash

# Set up TAP ports
for port in {0..3}; do
sudo ip link set "TAP$port" up
done

# Disable IPv6 because it can interfere with packet sniffing
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.lo.disable_ipv6=1
83 changes: 83 additions & 0 deletions e2e-test/suites/pna/basicfwd/main.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include <core.p4>
#include <pna.p4>

header eth_h {
bit<48> dst_addr;
bit<48> src_addr;
bit<16> ether_type;
}

struct header_t {
eth_h eth;
}

struct metadata_t {}

parser MainParser(
packet_in pkt,
out header_t hdr,
inout metadata_t meta,
in pna_main_parser_input_metadata_t istd
) {
state start {
pkt.extract(hdr.eth);
transition accept;
}
}

control PreControl(
in header_t hdr,
inout metadata_t meta,
in pna_pre_input_metadata_t istd,
inout pna_pre_output_metadata_t ostd
) {
apply {}
}

control MainControl(
inout header_t hdr,
inout metadata_t meta,
in pna_main_input_metadata_t istd,
inout pna_main_output_metadata_t ostd
) {
action forward(PortId_t output_port) {
send_to_port(output_port);
}

action drop() {
drop_packet();
}

table forwarding {
key = {
istd.input_port: exact;
}
actions = {
forward;
drop;
}
const default_action = drop();
}

apply {
forwarding.apply();
}
}

control MainDeparser(
packet_out pkt,
in header_t hdr,
in metadata_t meta,
in pna_main_output_metadata_t ostd
) {
apply {
pkt.emit(hdr);
}
}

PNA_NIC(
MainParser(),
PreControl(),
MainControl(),
MainDeparser()
) main;
Loading