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

LLT-5878: Xray tests on CI #16

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
32 changes: 32 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,35 @@ jobs:
fetch-depth: 0
- run: docker build -t neptun-runner:0.0.1 .
- run: cargo xtask perf --base main

xray-tests:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29
- name: Setup
working-directory: xray
run: |
sudo apt update
sudo apt install -y wireguard wireguard-go
python -m pip install --upgrade pip
pip install pipenv
pipenv install
- name: Execute xray
working-directory: xray
run: |
pipenv run python run.py --wg native --ascii --save-output
pipenv run python run.py --wg neptun --ascii --save-output --disable-drop-privileges
mathiaspeters marked this conversation as resolved.
Show resolved Hide resolved
- name: Upload graph results
uses: actions/upload-artifact@v4
with:
name: xray-results
path: xray/results/*.png
- name: Results
working-directory: xray/results
run: |
for file in *.txt; do
echo "----- $file -----"
cat "$file"
echo ""
done
1 change: 1 addition & 0 deletions xray/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
results/
mathiaspeters marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions xray/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ name = "pypi"
ruff = "==0.8"
matplotlib = "==3.9"
scapy = "==2.6"
mpl_ascii = "==0.10"

[dev-packages]

Expand Down
263 changes: 152 additions & 111 deletions xray/Pipfile.lock

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions xray/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ The application is executed with the `run.py` script. I takes some arguments, al

- **--nobuild-xray**: whether or not to build `xray` before running. Default is to build `xray`

- **--save-output**: save the analysis charts in `results` folder.

- **--ascii**: output the analysis chart as text graph.

- **--disable-drop-privileges**: pass the `disable-drop-privileges` flag to `neptun-cli` and `boringtun-cli`.
mathiaspeters marked this conversation as resolved.
Show resolved Hide resolved

## Known issues

- The analysis of pcaps is quite limited right now because it doesn't decrypt the packets (this is being worked on)
Expand Down
36 changes: 31 additions & 5 deletions xray/analyze.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import csv
import math
import matplotlib.pyplot as plt # type: ignore
import matplotlib as mpl
from functools import reduce
from scapy.all import PcapReader # type: ignore
from scapy.layers.inet import UDP # type: ignore
import mpl_ascii


def analyze(csv_path, pcap_path, count, test_type):
Analyzer(csv_path, pcap_path, count, test_type)
def analyze(csv_path, test_path, count, test_type, ascii, save_output):
Analyzer(csv_path, test_path, count, test_type, ascii, save_output)


class CsvData:
Expand Down Expand Up @@ -61,10 +63,10 @@ def __init__(self, pcap_path, test_type):


class Analyzer:
def __init__(self, csv_name, pcap_name, count, test_type):
def __init__(self, csv_name, test_path, count, test_type, ascii, save_output):
self.count = count
self.csv_data = CsvData(csv_name)
self.pcap_data = PcapData(pcap_name, test_type)
self.pcap_data = PcapData(test_path + ".pcap", test_type)

graphs = [
self.ordering_pie_chart,
Expand All @@ -84,6 +86,30 @@ def __init__(self, csv_name, pcap_name, count, test_type):
fn(ax[i, 1])

plt.show()
if save_output:
plt.savefig(test_path + ".png")
mathiaspeters marked this conversation as resolved.
Show resolved Hide resolved

if ascii:
mathiaspeters marked this conversation as resolved.
Show resolved Hide resolved
mpl_ascii.AXES_WIDTH = 70
mpl_ascii.AXES_HEIGHT = 25
mpl.use("module://mpl_ascii")
graphs = [
self.packet_ordering,
self.dropped_packets,
self.packet_latency,
self.packet_funnel,
]
rows = len(graphs)

fig, ax = plt.subplots(nrows=rows)
fig.tight_layout()

for i, fn in enumerate(graphs):
fn(ax[i])

plt.show()
if save_output:
plt.savefig(test_path + ".txt")

def ordering_pie_chart(self, ax):
in_order = count_ordered(self.csv_data.indices, self.count)
Expand Down Expand Up @@ -187,7 +213,7 @@ def packet_funnel(self, ax):
f"Recv ({recv})",
]
values = [self.count, before_wg, after_wg, recv]
plt.bar(categories, values, color="blue", width=0.4)
ax.bar(categories, values, color="blue", width=0.4)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!



# This counts in-order packets by looking at series of successive packets
Expand Down
47 changes: 30 additions & 17 deletions xray/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@

def run_command(cmd, capture_output=False):
args = shlex.split(cmd)
run = subprocess.run(args, capture_output=capture_output,check=True)
run = subprocess.run(args, capture_output=capture_output, check=True)
return (run.stdout, run.stderr)


def get_csv_name(wg, test_type, count):
return f"results/xray_metrics_{wg.lower()}_{test_type}_{count}.csv"


def get_pcap_name(wg, test_type, count):
return f"results/{WG_IFC_NAME}_{wg.lower()}_{test_type}_{count}.pcap"
def get_test_path(wg, test_type, count):
mathiaspeters marked this conversation as resolved.
Show resolved Hide resolved
return f"results/{WG_IFC_NAME}_{wg.lower()}_{test_type}_{count}"


class Wireguard(Enum):
Expand All @@ -44,22 +44,28 @@ def from_str(s):
raise Exception(f"{s} is not a valid wireguard type")


def setup_wireguard(wg, build_neptun):
def setup_wireguard(wg, build_neptun, disable_drop_privileges):
if wg == Wireguard.Native:
run_command(f"sudo ip link add dev {WG_IFC_NAME} type wireguard")
elif wg == Wireguard.WgGo:
wggo = (
run_command("which wireguard", capture_output=True)[0]
run_command("which wireguard-go", capture_output=True)[0]
.strip()
.decode("utf-8")
)
run_command(f"sudo {wggo} {WG_IFC_NAME}")
elif wg == Wireguard.BoringTun:
run_command(f"sudo ../target/release/boringtun-cli {WG_IFC_NAME}")
run_command(
f"sudo ../target/release/boringtun-cli {WG_IFC_NAME}"
+ (" --disable-drop-privileges" if disable_drop_privileges else "")
)
else:
if build_neptun:
run_command(f"cargo build --release -p neptun-cli")
run_command(f"sudo ../target/release/neptun-cli {WG_IFC_NAME}")
run_command(
f"sudo ../target/release/neptun-cli {WG_IFC_NAME}"
+ (" --disable-drop-privileges" if disable_drop_privileges else "")
)
run_command(f"sudo ip link set dev {WG_IFC_NAME} mtu 1420")
run_command(f"sudo ip link set dev {WG_IFC_NAME} up")
run_command(
Expand All @@ -78,10 +84,10 @@ def start_tcpdump(pcap_name):

def run_xray(wg, test_type, count, build_xray):
if build_xray:
run_command(
f"cargo build --release"
)
run_command(f"sudo ../target/release/xray --wg {wg.lower()} --test-type {test_type} --packet-count {count} --csv-name {get_csv_name(wg, test_type, count)}")
run_command(f"cargo build --release")
run_command(
f"sudo ../target/release/xray --wg {wg.lower()} --test-type {test_type} --packet-count {count} --csv-name {get_csv_name(wg, test_type, count)}"
)


def stop_tcpdump(tcpdump):
Expand All @@ -90,9 +96,9 @@ def stop_tcpdump(tcpdump):

def destroy_wireguard(wg):
if wg == Wireguard.NepTUN:
run_command("killall -9 neptun-cli")
run_command("sudo killall -9 neptun-cli")
elif wg == Wireguard.BoringTun:
run_command("killall -9 boringtun-cli")
run_command("sudo killall -9 boringtun-cli")
else:
run_command(f"sudo ip link delete {WG_IFC_NAME}")

Expand All @@ -104,6 +110,9 @@ def main():
parser.add_argument("--count")
parser.add_argument("--nobuild-neptun", action="store_true")
parser.add_argument("--nobuild-xray", action="store_true")
parser.add_argument("--save-output", action="store_true")
parser.add_argument("--disable-drop-privileges", action="store_true")
parser.add_argument("--ascii", action="store_true")
mathiaspeters marked this conversation as resolved.
Show resolved Hide resolved
args = parser.parse_args()

wg = Wireguard.from_str(args.wg)
Expand All @@ -120,12 +129,14 @@ def main():
Path("results/").mkdir(parents=True, exist_ok=True)
try:
os.remove(get_csv_name(wg.name, test_type, count))
os.remove(get_pcap_name(wg.name, test_type, count))
os.remove(get_test_path(wg.name, test_type, count) + ".pcap")
os.remove(get_test_path(wg.name, test_type, count) + ".png")
os.remove(get_test_path(wg.name, test_type, count) + ".txt")
except: # noqa: E722
pass

setup_wireguard(wg, build_neptun)
tcpdump = start_tcpdump(get_pcap_name(wg.name, test_type, count))
setup_wireguard(wg, build_neptun, args.disable_drop_privileges)
tcpdump = start_tcpdump(get_test_path(wg.name, test_type, count) + ".pcap")

succeeded = True
try:
Expand All @@ -140,9 +151,11 @@ def main():
if succeeded:
analyze(
get_csv_name(wg.name, test_type, count),
get_pcap_name(wg.name, test_type, count),
get_test_path(wg.name, test_type, count),
count,
test_type,
args.ascii,
args.save_output,
)


Expand Down
Loading