From dbd6b98dd14f1ca7d63b72f05b41ab2ff6acc544 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 28 Jan 2025 10:32:56 +0100 Subject: [PATCH] Add XDP integration test (#1078) --- .ci/xdp/cluster-config.yaml | 15 ++++ .ci/xdp/integration-test.sh | 82 ++++++++++++++++++++++ .ci/xdp/proxy.dockerfile | 3 + .ci/xdp/proxy.dockerfile.dockerignore | 2 + .ci/xdp/server.yaml | 13 ++++ .ci/xdp/spinup-cluster-with-registry.sh | 47 +++++++++++++ .ci/xdp/veth-integ-test.sh | 63 +++++++++++++++++ .github/workflows/xdp-integration-test.yml | 46 ++++++++++++ .gitignore | 1 + 9 files changed, 272 insertions(+) create mode 100644 .ci/xdp/cluster-config.yaml create mode 100755 .ci/xdp/integration-test.sh create mode 100644 .ci/xdp/proxy.dockerfile create mode 100644 .ci/xdp/proxy.dockerfile.dockerignore create mode 100644 .ci/xdp/server.yaml create mode 100755 .ci/xdp/spinup-cluster-with-registry.sh create mode 100755 .ci/xdp/veth-integ-test.sh create mode 100644 .github/workflows/xdp-integration-test.yml diff --git a/.ci/xdp/cluster-config.yaml b/.ci/xdp/cluster-config.yaml new file mode 100644 index 000000000..58ff3b24b --- /dev/null +++ b/.ci/xdp/cluster-config.yaml @@ -0,0 +1,15 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: + - role: control-plane + # Proxy + - role: worker + # Client + - role: worker + # Server + - role: worker +# https://github.com/helm/kind-action?tab=readme-ov-file#configuring-local-registry +containerdConfigPatches: +- |- + [plugins."io.containerd.grpc.v1.cri".registry] + config_path = "/etc/containerd/certs.d" \ No newline at end of file diff --git a/.ci/xdp/integration-test.sh b/.ci/xdp/integration-test.sh new file mode 100755 index 000000000..5868958c5 --- /dev/null +++ b/.ci/xdp/integration-test.sh @@ -0,0 +1,82 @@ +#!/bin/bash +set -eu + +source="${BASH_SOURCE[0]}" + +proxy_image="localhost:$REGISTRY_PORT/quilkin:ci" + +echo "::notice file=$source,line=$LINENO::Building quilkin proxy" +cargo build -p quilkin --bin quilkin +# strip the binary to reduce copy times into the dockerfile +strip ./target/debug/quilkin + +echo "::notice file=$source,line=$LINENO::Building quilkin image" +docker build -f .ci/xdp/proxy.dockerfile -t "${proxy_image}" . +echo "::notice file=$source,line=$LINENO::Pushing quilkin image" +docker push "${proxy_image}" + +echo "::notice file=$source,line=$LINENO::Starting UDP echo server" +kubectl apply --context "$CLUSTER" -f .ci/xdp/server.yaml +kubectl wait --context "$CLUSTER" --for=condition=ready pod/echo-server + +server_ip=$(kubectl get --context "$CLUSTER" pod echo-server --template '{{.status.podIP}}') + +echo "::notice file=$source,line=$LINENO::Starting quilkin proxy" +kubectl apply --context "$CLUSTER" -f - </dev/null || true)" != 'true' ]; then + docker run \ + -d --restart=always -p "127.0.0.1:${REGISTRY_PORT}:5000" --network bridge --name "${REGISTRY_NAME}" \ + registry:2 +fi + +kind create cluster --name "${CLUSTER_DESIRED}" --config=.ci/xdp/cluster-config.yaml + +# 3. Add the registry config to the nodes +# +# This is necessary because localhost resolves to loopback addresses that are +# network-namespace local. +# In other words: localhost in the container is not localhost on the host. +# +# We want a consistent name that works from both ends, so we tell containerd to +# alias localhost:${reg_port} to the registry container when pulling images +REGISTRY_DIR="/etc/containerd/certs.d/localhost:${REGISTRY_PORT}" +for node in $(kind get nodes); do + docker exec "${node}" mkdir -p "${REGISTRY_DIR}" + cat < proxy <-> server links" +ip link add veth-cs type veth peer name veth-proxy + +ip link set veth-cs netns cs +ip link set veth-proxy netns proxy + +echo "::notice file=$source,line=$LINENO::Adding IPs" +ip -n cs addr add 10.0.0.1/24 dev veth-cs +ip -n proxy addr add 10.0.0.2/24 dev veth-proxy + +echo "::notice file=$source,line=$LINENO::Creating network namespaces" +ip -n cs link set veth-cs up +ip -n proxy link set veth-proxy up + +ip netns exec cs fortio udp-echo& +ip netns exec proxy ./target/debug/quilkin proxy --to 10.0.0.1:8078 --publish.udp.xdp& + +echo "::notice file=$source,line=$LINENO::Launching client" +ip netns exec cs fortio load -n 10 udp://10.0.0.2:7777 2> ./target/logs.txt +logs=$(cat ./target/logs.txt) +echo "$logs" + +regex="Total Bytes sent: ([0-9]+), received: ([0-9]+)" + +if [[ $logs =~ $regex ]]; then + send=${BASH_REMATCH[1]} + recv=${BASH_REMATCH[2]} + # We could be more strict here and require they are exactly equal, but I can't + # even consistently get that on my local machine so I doubt CI will fair better + if [[ $recv -ne "0" ]]; then + echo "::notice file=$source,line=$LINENO::Successfully sent ${send}B and received ${recv}B" + exit 0 + fi + + echo "::error file=$source,line=$LINENO::sent ${send}B but only received ${recv}B" + exit 1 +fi + +echo "::error file=$source,line=$LINENO::Failed to find expected log line from UDP client" +exit 2 diff --git a/.github/workflows/xdp-integration-test.yml b/.github/workflows/xdp-integration-test.yml new file mode 100644 index 000000000..99f788fe2 --- /dev/null +++ b/.github/workflows/xdp-integration-test.yml @@ -0,0 +1,46 @@ +name: xdp-integration-test + +on: + push: + branches: + - "main" + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + +jobs: + xdp-integration: + runs-on: ubuntu-24.04 + # env: + # CLUSTER_DESIRED: xdp-integ + # CLUSTER: kind-xdp-integ + # SERVER_PORT: "8078" + # REGISTRY_PORT: "5001" + # REGISTRY_NAME: registry + steps: + - uses: actions/checkout@v4 + # - name: Create cluster + # id: kind + # uses: helm/kind-action@v1 + # with: + # config: .ci/xdp/cluster-config.yaml + # cluster_name: ${{ env.CLUSTER_DESIRED }} + # registry: true + # registry_name: ${{ env.REGISTRY_NAME }} + # registry_port: ${{ env.REGISTRY_PORT }} + - uses: dtolnay/rust-toolchain@stable + - name: Fetch quilkin + run: cargo fetch --target x86_64-unknown-linux-gnu + - name: Build quilkin + run: cargo build -p quilkin --bin quilkin + - name: Install fortio + run: | + curl -L -o fortio.deb https://github.com/fortio/fortio/releases/download/v1.68.0/fortio_1.68.0_amd64.deb + sudo dpkg -i fortio.deb + - name: Run XDP integration test + run: sudo .ci/xdp/veth-integ-test.sh diff --git a/.gitignore b/.gitignore index d4bfdd3e3..d9815e46c 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ !.gcloudignore !.dockerignore !.github +!.ci !xds/ci/.golangci.yaml *.iml