Skip to content

Commit 76a8e94

Browse files
ci: add vmtest build testing
Signed-off-by: Mykola Lysenko <[email protected]>
1 parent 106bf6a commit 76a8e94

File tree

2 files changed

+361
-1
lines changed

2 files changed

+361
-1
lines changed

.github/workflows/test.yml

Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
name: test
2+
3+
on:
4+
workflow_call:
5+
pull_request:
6+
7+
concurrency:
8+
group: ci-test-${{ github.ref_name }}
9+
cancel-in-progress: true
10+
11+
jobs:
12+
llvm-toolchain:
13+
runs-on: ubuntu-latest
14+
outputs:
15+
llvm: ${{ steps.llvm-toolchain-impl.outputs.version }}
16+
steps:
17+
- if: ${{ github.repository == 'kernel-patches/vmtest' || github.repository == 'kernel-patches/bpf' }}
18+
uses: actions/checkout@v3
19+
with:
20+
repository: 'libbpf/ci'
21+
- if: ${{ github.repository == 'libbpf/ci' }}
22+
uses: actions/checkout@v3
23+
- id: llvm-version
24+
uses: ./get-llvm-version
25+
- id: llvm-toolchain-impl
26+
shell: bash
27+
run: echo "version=llvm-${{ steps.llvm-version.outputs.version }}" >> $GITHUB_OUTPUT
28+
set-matrix:
29+
needs: llvm-toolchain
30+
runs-on: ubuntu-latest
31+
outputs:
32+
build-matrix: ${{ steps.set-matrix-impl.outputs.build_matrix }}
33+
test-matrix: ${{ steps.set-matrix-impl.outputs.test_matrix }}
34+
steps:
35+
- id: set-matrix-impl
36+
shell: python3 -I {0}
37+
run: |
38+
from json import dumps
39+
from enum import Enum
40+
import os
41+
42+
class Arch(Enum):
43+
"""
44+
CPU architecture supported by CI.
45+
"""
46+
aarch64 = "aarch64"
47+
s390x = "s390x"
48+
x86_64 = "x86_64"
49+
50+
def set_output(name, value):
51+
"""Write an output variable to the GitHub output file."""
52+
with open(os.getenv("GITHUB_OUTPUT"), "a") as f:
53+
f.write(f"{name}={value}\n")
54+
55+
def generate_test_config(test):
56+
"""Create the configuration for the provided test."""
57+
experimental = test.endswith("_parallel")
58+
config = {
59+
"test": test,
60+
"continue_on_error": experimental,
61+
# While in experimental mode, parallel jobs may get stuck
62+
# anywhere, including in user space where the kernel won't detect
63+
# a problem and panic. We add a second layer of (smaller) timeouts
64+
# here such that if we get stuck in a parallel run, we hit this
65+
# timeout and fail without affecting the overall job success (as
66+
# would be the case if we hit the job-wide timeout). For
67+
# non-experimental jobs, 360 is the default which will be
68+
# superseded by the overall workflow timeout (but we need to
69+
# specify something).
70+
"timeout_minutes": 30 if experimental else 360,
71+
}
72+
return config
73+
74+
matrix = [
75+
{"kernel": "LATEST", "runs_on": [], "arch": Arch.x86_64.value, "toolchain": "gcc"},
76+
{"kernel": "LATEST", "runs_on": [], "arch": Arch.x86_64.value, "toolchain": "${{ needs.llvm-toolchain.outputs.llvm }}"},
77+
{"kernel": "LATEST", "runs_on": [], "arch": Arch.aarch64.value, "toolchain": "gcc"},
78+
{"kernel": "LATEST", "runs_on": [], "arch": Arch.aarch64.value, "toolchain": "${{ needs.llvm-toolchain.outputs.llvm }}"},
79+
{"kernel": "LATEST", "runs_on": [], "arch": Arch.s390x.value, "toolchain": "gcc"},
80+
]
81+
self_hosted_repos = [
82+
"kernel-patches/bpf",
83+
"kernel-patches/vmtest",
84+
]
85+
86+
# Only a few repository within "kernel-patches" use self-hosted runners.
87+
if "${{ github.repository_owner }}" != "kernel-patches" or "${{ github.repository }}" not in self_hosted_repos:
88+
# Outside of those repositories, we only run on x86_64 GH hosted runners (ubuntu-latest)
89+
for idx in range(len(matrix) - 1, -1, -1):
90+
if matrix[idx]["arch"] != Arch.x86_64.value:
91+
del matrix[idx]
92+
else:
93+
matrix[idx]["runs_on"] = ["ubuntu-latest"]
94+
else:
95+
# Otherwise, run on (self-hosted, arch) runners
96+
for idx in range(len(matrix) - 1, -1, -1):
97+
matrix[idx]["runs_on"].extend(["self-hosted", matrix[idx]["arch"]])
98+
99+
build_matrix = {"include": matrix}
100+
set_output("build_matrix", dumps(build_matrix))
101+
102+
tests = [
103+
"test_progs",
104+
"test_progs_parallel",
105+
"test_progs_no_alu32",
106+
"test_progs_no_alu32_parallel",
107+
"test_maps",
108+
"test_verifier",
109+
]
110+
test_matrix = {"include": [{**config, **generate_test_config(test)}
111+
for config in matrix
112+
for test in tests]}
113+
set_output("test_matrix", dumps(test_matrix))
114+
build:
115+
name: build for ${{ matrix.arch }} with ${{ matrix.toolchain }}
116+
needs: set-matrix
117+
runs-on: ${{ matrix.runs_on }}
118+
timeout-minutes: 100
119+
strategy:
120+
fail-fast: false
121+
matrix: ${{ fromJSON(needs.set-matrix.outputs.build-matrix) }}
122+
env:
123+
KERNEL: ${{ matrix.kernel }}
124+
REPO_ROOT: ${{ github.workspace }}
125+
REPO_PATH: ""
126+
KBUILD_OUTPUT: kbuild-output/
127+
steps:
128+
- if: ${{ github.repository == 'kernel-patches/vmtest' || github.repository == 'kernel-patches/bpf' }}
129+
uses: actions/checkout@v3
130+
with:
131+
repository: 'libbpf/ci'
132+
- if: ${{ github.repository == 'libbpf/ci' }}
133+
uses: actions/checkout@v3
134+
- if: ${{ github.repository == 'kernel-patches/bpf' }}
135+
uses: actions/checkout@v3
136+
# We fetch an actual bit of history here to facilitate incremental
137+
# builds (which may check out some earlier upstream change).
138+
with:
139+
fetch-depth: 50
140+
- if: ${{ github.repository == 'kernel-patches/vmtest' || github.repository == 'libbpf/ci' }}
141+
name: Download bpf-next tree
142+
uses: ./get-linux-source
143+
with:
144+
dest: '.kernel'
145+
- if: ${{ github.repository == 'kernel-patches/vmtest' || github.repository == 'libbpf/ci' }}
146+
name: Move linux source in place
147+
shell: bash
148+
run: |
149+
rm -rf .kernel/.git
150+
cp -rf .kernel/. .
151+
rm -rf .kernel
152+
- name: Get commit meta-data
153+
id: get-commit-metadata
154+
shell: bash
155+
run: |
156+
if [ ${{ github.event_name }} = 'push' ]; then
157+
branch="${{ github.ref_name }}"
158+
echo "branch=${branch}" >> "${GITHUB_OUTPUT}"
159+
else
160+
branch="${{ github.base_ref }}"
161+
echo "branch=${branch}" >> "${GITHUB_OUTPUT}"
162+
fi
163+
164+
upstream=$(echo "${branch}" | sed 's@_base$@@')
165+
commit="$(
166+
git rev-parse "origin/${upstream}" &> /dev/null \
167+
|| (
168+
git fetch --quiet --prune --no-tags --depth=1 --no-recurse-submodules origin +refs/heads/${upstream}:refs/remotes/origin/${upstream} \
169+
&& git rev-parse "origin/${upstream}"
170+
)
171+
)"
172+
173+
echo "timestamp=$(TZ=utc git show --format='%cd' --no-patch --date=iso-strict-local ${commit})" >> "${GITHUB_OUTPUT}"
174+
echo "commit=${commit}" >> "${GITHUB_OUTPUT}"
175+
echo "Most recent upstream commit is ${commit}"
176+
- name: Pull recent KBUILD_OUTPUT contents
177+
uses: actions/cache@v3
178+
with:
179+
path: ${{ env.KBUILD_OUTPUT }}
180+
key: kbuild-output-${{ matrix.arch }}-${{ matrix.toolchain }}-${{ steps.get-commit-metadata.outputs.branch }}-${{ steps.get-commit-metadata.outputs.timestamp }}-${{ steps.get-commit-metadata.outputs.commit }}
181+
restore-keys: |
182+
kbuild-output-${{ matrix.arch }}-${{ matrix.toolchain }}-${{ steps.get-commit-metadata.outputs.branch }}-${{ steps.get-commit-metadata.outputs.timestamp }}-
183+
kbuild-output-${{ matrix.arch }}-${{ matrix.toolchain }}-${{ steps.get-commit-metadata.outputs.branch }}-
184+
kbuild-output-${{ matrix.arch }}-${{ matrix.toolchain }}-
185+
- name: Prepare incremental build
186+
shell: bash
187+
run: |
188+
set -e -u
189+
190+
# $1 - the SHA-1 to fetch and check out
191+
fetch_and_checkout() {
192+
local build_base_sha="${1}"
193+
194+
# If cached artifacts became stale for one reason or another, we
195+
# may not have the build base SHA available. Fetch it and retry.
196+
git fetch origin "${build_base_sha}" && git checkout --quiet "${build_base_sha}"
197+
}
198+
199+
# $1 - value of KBUILD_OUTPUT
200+
clear_cache_artifacts() {
201+
local kbuild_output="${1}"
202+
echo "Unable to find earlier upstream ref. Discarding KBUILD_OUTPUT contents..."
203+
rm --recursive --force "${kbuild_output}"
204+
mkdir "${kbuild_output}"
205+
false
206+
}
207+
208+
# $1 - value of KBUILD_OUTPUT
209+
# $2 - current time in ISO 8601 format
210+
restore_source_code_times() {
211+
local kbuild_output="${1}"
212+
local current_time="${2}"
213+
local src_time="$(date --iso-8601=ns --date="${current_time} - 2 minutes")"
214+
local obj_time="$(date --iso-8601=ns --date="${current_time} - 1 minute")"
215+
216+
git ls-files | xargs --max-args=10000 touch -m --no-create --date="${src_time}"
217+
find "${kbuild_output}" -type f | xargs --max-args=10000 touch -m --no-create --date="${obj_time}"
218+
git checkout --quiet -
219+
echo "Adjusted src and obj time stamps relative to system time"
220+
}
221+
222+
mkdir --parents "${KBUILD_OUTPUT}"
223+
current_time="$(date --iso-8601=ns)"
224+
225+
if [ -f "${KBUILD_OUTPUT}/.build-base-sha" ]; then
226+
build_base_sha="$(cat "${KBUILD_OUTPUT}/.build-base-sha")"
227+
echo "Setting up base build state for ${build_base_sha}"
228+
229+
(
230+
git checkout --quiet "${build_base_sha}" \
231+
|| fetch_and_checkout "${build_base_sha}" \
232+
|| clear_cache_artifacts "${KBUILD_OUTPUT}"
233+
) && restore_source_code_times "${KBUILD_OUTPUT}" "${current_time}"
234+
else
235+
echo "No previous build data found"
236+
fi
237+
238+
echo -n "${{ steps.get-commit-metadata.outputs.commit }}" > "${KBUILD_OUTPUT}/.build-base-sha"
239+
- uses: ./patch-kernel
240+
with:
241+
patches-root: '${{ github.workspace }}/ci/diffs'
242+
repo-root: '${{ github.workspace }}'
243+
- name: Setup build environment
244+
uses: ./setup-build-env
245+
- name: Build kernel image
246+
uses: ./build-linux
247+
with:
248+
arch: ${{ matrix.arch }}
249+
toolchain: ${{ matrix.toolchain }}
250+
kbuild-output: ${{ env.KBUILD_OUTPUT }}
251+
max-make-jobs: 32
252+
- if: ${{ github.event_name != 'push' }}
253+
name: Build selftests
254+
uses: ./build-selftests
255+
with:
256+
toolchain: ${{ matrix.toolchain }}
257+
kbuild-output: ${{ env.KBUILD_OUTPUT }}
258+
max-make-jobs: 32
259+
- if: ${{ github.event_name != 'push' }}
260+
name: Build samples
261+
uses: ./build-samples
262+
with:
263+
toolchain: ${{ matrix.toolchain }}
264+
kbuild-output: ${{ env.KBUILD_OUTPUT }}
265+
max-make-jobs: 32
266+
- if: ${{ github.event_name != 'push' }}
267+
name: Tar artifacts
268+
run: |
269+
# Remove intermediate object files that we have no use for. Ideally
270+
# we'd just exclude them from tar below, but it does not provide
271+
# options to express the precise constraints.
272+
find selftests/ -name "*.o" -a ! -name "*.bpf.o" -print0 | \
273+
xargs --null --max-args=10000 rm
274+
275+
# Strip debug information, which is excessively large (consuming
276+
# bandwidth) while not actually being used (the kernel does not use
277+
# DWARF to symbolize stacktraces).
278+
strip --strip-debug "${KBUILD_OUTPUT}"/vmlinux
279+
280+
file_list=""
281+
if [ "${{ github.repository }}" == "kernel-patches/vmtest" ]; then
282+
# Package up a bunch of additional infrastructure to support running
283+
# 'make kernelrelease' and bpf tool checks later on.
284+
file_list="$(find . -iname Makefile | xargs) \
285+
scripts/ \
286+
tools/testing/selftests/bpf/ \
287+
tools/include/ \
288+
tools/bpf/bpftool/";
289+
fi
290+
# zstd is installed by default in the runner images.
291+
tar -cf - \
292+
"${KBUILD_OUTPUT}"/.config \
293+
"${KBUILD_OUTPUT}"/$(KBUILD_OUTPUT="${KBUILD_OUTPUT}" make -s image_name) \
294+
"${KBUILD_OUTPUT}"/include/config/auto.conf \
295+
"${KBUILD_OUTPUT}"/include/generated/autoconf.h \
296+
"${KBUILD_OUTPUT}"/vmlinux \
297+
${file_list} \
298+
--exclude '*.cmd' \
299+
--exclude '*.d' \
300+
--exclude '*.h' \
301+
--exclude '*.output' \
302+
selftests/bpf/ | zstd -T0 -19 -o vmlinux-${{ matrix.arch }}-${{ matrix.toolchain }}.tar.zst
303+
- if: ${{ github.event_name != 'push' }}
304+
name: Remove KBUILD_OUTPUT contents
305+
shell: bash
306+
run: |
307+
# Remove $KBUILD_OUTPUT to prevent cache creation for pull requests.
308+
# Only on pushed changes are build artifacts actually cached, because
309+
# of github.com/actions/cache's cache isolation logic.
310+
rm -rf "${KBUILD_OUTPUT}"
311+
- if: ${{ github.event_name != 'push' }}
312+
uses: actions/upload-artifact@v3
313+
with:
314+
name: vmlinux-${{ matrix.arch }}-${{ matrix.toolchain }}
315+
if-no-files-found: error
316+
path: vmlinux-${{ matrix.arch }}-${{ matrix.toolchain }}.tar.zst
317+
test:
318+
if: ${{ github.event_name != 'push' }}
319+
name: ${{ matrix.test }} on ${{ matrix.arch }} with ${{ matrix.toolchain }}
320+
needs: [set-matrix, build]
321+
strategy:
322+
fail-fast: false
323+
matrix: ${{ fromJSON(needs.set-matrix.outputs.test-matrix) }}
324+
runs-on: ${{ matrix.runs_on }}
325+
timeout-minutes: 100
326+
env:
327+
KERNEL: ${{ matrix.kernel }}
328+
REPO_ROOT: ${{ github.workspace }}
329+
REPO_PATH: ""
330+
KBUILD_OUTPUT: kbuild-output/
331+
steps:
332+
- uses: actions/checkout@v3
333+
- uses: actions/download-artifact@v3
334+
with:
335+
name: vmlinux-${{ matrix.arch }}-${{ matrix.toolchain }}
336+
path: .
337+
- name: Untar artifacts
338+
# zstd is installed by default in the runner images.
339+
run: zstd -d -T0 vmlinux-${{ matrix.arch }}-${{ matrix.toolchain }}.tar.zst --stdout | tar -xf -
340+
- name: Prepare rootfs
341+
uses: ./prepare-rootfs
342+
with:
343+
project-name: 'libbpf'
344+
arch: ${{ matrix.arch }}
345+
kernel: ${{ matrix.kernel }}
346+
kernel-root: '.'
347+
kbuild-output: ${{ env.KBUILD_OUTPUT }}
348+
image-output: '/tmp/root.img'
349+
test: ${{ matrix.test }}
350+
- name: Run selftests
351+
uses: ./run-qemu
352+
continue-on-error: ${{ matrix.continue_on_error }}
353+
timeout-minutes: ${{ matrix.timeout_minutes }}
354+
with:
355+
arch: ${{ matrix.arch}}
356+
img: '/tmp/root.img'
357+
vmlinuz: '${{ github.workspace }}/vmlinuz'
358+
kernel-root: '.'
359+
max-cpu: 8

prepare-rootfs/run.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/bin/bash
22

33
set -euo pipefail
4+
set +x
45
trap 'exit 2' ERR
56

67
source $(cd $(dirname $0) && pwd)/../helpers.sh
@@ -292,7 +293,7 @@ fi
292293

293294
# Only go to the network if it's actually a glob pattern.
294295
if [[ -v BUILDDIR ]]; then
295-
KERNELRELEASE="$(KBUILD_OUTPUT="${BUILDDIR}" make -C "${KERNELSRC:-$BUILDDIR}" -s kernelrelease)"
296+
KERNELRELEASE="$(KBUILD_OUTPUT=\"${BUILDDIR}\" make -C \"${KERNELSRC:-$BUILDDIR}\" -s kernelrelease)"
296297
elif [[ ! $KERNELRELEASE =~ ^([^\\*?[]|\\[*?[])*\\?$ ]]; then
297298
# We need to cache the list of URLs outside of the command
298299
# substitution, which happens in a subshell.

0 commit comments

Comments
 (0)