Kernel Compatibility Test #211
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Credits: https://github.com/tokio-rs/io-uring/blob/master/.github/workflows/kernel-version-test.yml | |
| # | |
| # Tests kTLS functionality across multiple kernel versions. | |
| # Manual trigger supports custom space-separated version list. | |
| name: Kernel Compatibility Test | |
| on: | |
| push: | |
| branches: ["main"] | |
| paths: | |
| - "crates/**" | |
| - "Cargo.toml" | |
| - "Cargo.lock" | |
| - ".github/workflows/kernel-compatibility-test.yml" | |
| pull_request: | |
| paths: | |
| - "crates/**" | |
| - "Cargo.toml" | |
| - "Cargo.lock" | |
| - ".github/workflows/kernel-compatibility-test.yml" | |
| merge_group: | |
| paths: | |
| - "crates/**" | |
| - "Cargo.toml" | |
| - "Cargo.lock" | |
| - ".github/workflows/kernel-compatibility-test.yml" | |
| schedule: | |
| # Every day at 04:00 UTC | |
| - cron: "0 4 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "The Linux kernel version to test" | |
| required: true | |
| source: | |
| description: "The compressed source code's download URL" | |
| required: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| prepare-kernel-versions: | |
| name: Prepare kernel versions matrix | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y jq curl | |
| - name: Set matrix | |
| id: set-matrix | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| json_array="[{\"version\":\"${{ github.event.inputs.version }}\",\"source\":\"${{ github.event.inputs.source }}\"}]" | |
| else | |
| echo "Fetching latest kernel versions from kernel.org..." | |
| releases_json=$(curl -s https://www.kernel.org/releases.json) | |
| if [ -z "$releases_json" ]; then | |
| echo "Failed to fetch kernel releases data" | |
| exit 1 | |
| fi | |
| latest_releases=$(echo "$releases_json" | jq -c '[.releases[] | select(.source != null) | {version, source}]') | |
| fixed_versions='[ | |
| {"version": "6.12", "source": "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.tar.xz"}, | |
| {"version": "6.6", "source": "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz"}, | |
| {"version": "6.1.28", "source": "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.28.tar.xz"}, | |
| {"version": "5.15.25", "source": "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.25.tar.xz"}, | |
| {"version": "5.10.102", "source": "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.102.tar.xz"}, | |
| {"version": "5.4.181", "source": "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.181.tar.xz"} | |
| ]' | |
| json_array=$(echo "$latest_releases $fixed_versions" | jq -c -s '.[0] + .[1] | unique_by(.version) | sort_by(.version | gsub("-.*"; "") | split(".") | map(tonumber)) | reverse') | |
| fi | |
| echo "matrix=$json_array" >> $GITHUB_OUTPUT | |
| echo "Generated matrix: $json_array" | |
| build-test-binary: | |
| name: Build test binary | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y musl-tools | |
| - name: Install Rust 1.83.0 | |
| uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: 1.83.0 | |
| targets: x86_64-unknown-linux-musl | |
| - name: Build test binary | |
| run: | | |
| cargo build --package ktls-tests --bin ktls-test-echo --release --target x86_64-unknown-linux-musl | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ktls-test-echo | |
| path: target/x86_64-unknown-linux-musl/release/ktls-test-echo | |
| retention-days: 1 | |
| compression-level: 0 | |
| overwrite: true | |
| build-kernel: | |
| name: Build kernel - ${{ matrix.version }} | |
| needs: prepare-kernel-versions | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| include: ${{fromJson(needs.prepare-kernel-versions.outputs.matrix)}} | |
| fail-fast: false | |
| env: | |
| KERNEL_VERSION: ${{ matrix.version }} | |
| KERNEL_SOURCE_URL: ${{ matrix.source }} | |
| steps: | |
| - name: Cache Linux source | |
| id: cache-kernel | |
| uses: actions/cache@v4 | |
| with: | |
| path: linux-${{ env.KERNEL_VERSION }} | |
| key: linux-${{ env.KERNEL_VERSION }}-cache-v1 | |
| - name: Install dependencies | |
| if: steps.cache-kernel.outputs.cache-hit != 'true' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| bison flex libelf-dev \ | |
| xz-utils wget | |
| - name: Build Linux kernel | |
| if: steps.cache-kernel.outputs.cache-hit != 'true' | |
| run: | | |
| # Download kernel source from the provided URL | |
| filename=$(basename "$KERNEL_SOURCE_URL") | |
| wget "$KERNEL_SOURCE_URL" -O "$filename" | |
| # Extract based on file extension | |
| if [[ "$filename" == *.tar.xz ]]; then | |
| tar xf "$filename" | |
| elif [[ "$filename" == *.tar.gz ]]; then | |
| tar xzf "$filename" | |
| else | |
| echo "Unsupported archive format: $filename" | |
| exit 1 | |
| fi | |
| cd linux-${KERNEL_VERSION} | |
| # Generate the default config | |
| make defconfig | |
| # Enable essentials as built-ins | |
| scripts/config --enable CONFIG_DEVTMPFS | |
| scripts/config --enable CONFIG_DEVTMPFS_MOUNT | |
| # Enable virtio drivers | |
| scripts/config --enable CONFIG_VIRTIO | |
| scripts/config --enable CONFIG_VIRTIO_PCI | |
| scripts/config --enable CONFIG_VIRTIO_BLK | |
| # Enable kTLS support | |
| scripts/config --enable CONFIG_TLS | |
| scripts/config --enable CONFIG_TLS_DEVICE | |
| # Generate the updated config | |
| make olddefconfig | |
| make -j$(nproc) | |
| - name: Upload kernel artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-kernel-${{ env.KERNEL_VERSION }} | |
| path: linux-${{ env.KERNEL_VERSION }}/arch/x86/boot/bzImage | |
| retention-days: 1 | |
| compression-level: 6 | |
| overwrite: true | |
| test: | |
| name: Test - ${{ matrix.kernel.version }} @ ${{ matrix.arg-termination }} ${{ matrix.arg-cipher }} | |
| needs: [prepare-kernel-versions, build-test-binary, build-kernel] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| kernel: ${{fromJson(needs.prepare-kernel-versions.outputs.matrix)}} | |
| arg-termination: ["client", "server"] | |
| arg-cipher: | |
| [ | |
| "TLS13_AES_128_GCM_SHA256", | |
| "TLS13_AES_256_GCM_SHA384", | |
| "TLS13_CHACHA20_POLY1305_SHA256", | |
| "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", | |
| "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", | |
| "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", | |
| ] | |
| fail-fast: false | |
| env: | |
| KERNEL_VERSION: ${{ matrix.kernel.version }} | |
| TEST_ARG_TERMINATION: ${{ matrix.arg-termination }} | |
| TEST_ARG_CIPHER: ${{ matrix.arg-cipher }} | |
| steps: | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| qemu-system-x86 busybox-static cpio e2fsprogs | |
| - name: Download test binary artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ktls-test-echo | |
| path: . | |
| - name: Download kernel artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: linux-kernel-${{ env.KERNEL_VERSION }} | |
| path: . | |
| - name: Prepare initramfs + tests binaries | |
| run: | | |
| rm -rf initramfs && mkdir -p initramfs/{bin,sbin,proc,sys,tmp} | |
| # Copy the test binary (downloaded from artifact) | |
| chmod +x ktls-test-echo | |
| cp ktls-test-echo initramfs/bin/ | |
| # Add necessary binaries from busybox | |
| cp /usr/bin/busybox initramfs/bin/ | |
| for cmd in sh mount ip ifconfig cat; do ln -sf busybox initramfs/bin/$cmd; done | |
| ln -sf ../bin/busybox initramfs/sbin/poweroff | |
| # Generate init script | |
| cat > initramfs/init << EOF | |
| #!/bin/sh | |
| set -e | |
| # Activating the loopback interface (it's required for some network tests) | |
| ip link set lo up | |
| mkdir -p /dev | |
| # Enable necessary devices | |
| # https://www.kernel.org/doc/Documentation/admin-guide/devices.txt | |
| mknod /dev/port c 1 4 | |
| mknod /dev/null c 1 3 | |
| mknod /dev/zero c 1 5 | |
| mknod /dev/tty c 5 0 | |
| mkdir -p /tmp && mount -t tmpfs -o mode=1777 tmpfs /tmp | |
| # Bring up ext4 test volume at /mnt | |
| mount -t devtmpfs devtmpfs /dev | |
| exit_code=0 | |
| # Run the test binary | |
| RUST_BACKTRACE=1 /bin/ktls-test-echo -t "${TEST_ARG_TERMINATION}" -c "${TEST_ARG_CIPHER}" || exit_code=1 | |
| # If the test binary exited with a non-zero code, write it to /dev/port. | |
| # This lets QEMU exit with non-zero exit-code, triggering a CI error. | |
| [ \$exit_code -eq 0 ] || printf '\x01' \\ | |
| | dd of=/dev/port bs=1 seek=244 count=1 2>/dev/null | |
| /sbin/poweroff -f | |
| EOF | |
| chmod +x initramfs/init | |
| # Pack into a CPIO archive | |
| (cd initramfs && find . -print0 \ | |
| | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz) | |
| - name: Run tests in QEMU | |
| run: | | |
| qemu-system-x86_64 \ | |
| -device isa-debug-exit,iobase=0xf4,iosize=0x04 \ | |
| -kernel bzImage \ | |
| -initrd initramfs.cpio.gz \ | |
| -netdev user,id=net0 \ | |
| -device e1000,netdev=net0 \ | |
| -append "console=ttyS0 rootfstype=ramfs panic=1" \ | |
| -nographic -no-reboot -m 1024 -action panic=exit-failure | |
| if [ $? -ne 0 ]; then | |
| echo "tests failed (QEMU exited abnormally)" | |
| exit 1 | |
| else | |
| echo "all tests passed" | |
| fi |