diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml new file mode 100644 index 00000000..6a0cdc71 --- /dev/null +++ b/.github/workflows/dockerhub.yml @@ -0,0 +1,49 @@ +name: dockerhub + +on: + push: + branches: + - 'main' + paths: + - 'docker/**' + - '.github/workflows/dockerhub.yml' + pull_request: + paths: + - 'docker/**' + - '.github/workflows/dockerhub.yml' + +jobs: + docker: + name: Build and push Docker images + runs-on: ubuntu-latest + permissions: + packages: write + contents: read + attestations: write + id-token: write + + steps: + - + name: Set up QEMU + uses: docker/setup-qemu-action@v4 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + - + name: Login to GHCR + if: ${{ github.event_name == 'push' }} + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Checkout + uses: actions/checkout@v6 + - + name: Build and push docker images + run: | + INPUT_PUSH=${{ github.event_name == 'push' && '1' || '0' }} \ + INPUT_PREFIX="ghcr.io/${{ github.repository_owner }}" \ + INPUT_TAG="latest" \ + ./docker/build.sh diff --git a/docker/.gitignore b/docker/.gitignore index 120c3cea..ca284b70 100644 --- a/docker/.gitignore +++ b/docker/.gitignore @@ -1,3 +1 @@ -/nipa-run -/config -/ccache +.ccache/ diff --git a/docker/base/Dockerfile b/docker/base/Dockerfile new file mode 100644 index 00000000..710fa162 --- /dev/null +++ b/docker/base/Dockerfile @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0 +FROM fedora:44 + +LABEL name=nipa-base + +RUN echo "install_weak_deps=False" >> /etc/dnf/dnf.conf +RUN dnf install -y \ + bison ccache flex gcc make rsync \ + bc cpio curl diffutils gawk git perl openssl patch which \ + elfutils-libelf-devel ncurses-devel openssl-devel && \ + sudo dnf clean all + +# nipa user with "root" rights +RUN useradd -m nipa +RUN usermod -aG wheel nipa +RUN echo 'nipa ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +# workaround https://github.com/apptainer/apptainer/issues/2756 +RUN chmod 0400 /etc/shadow +USER nipa +WORKDIR /home/nipa + +RUN git config --global user.name "Nipa Container" && \ + git config --global user.email "nipa@container" + +# CCache +ENV PATH=/usr/lib64/ccache:${PATH} +ENV CCACHE_COMPRESS=true +ENV KBUILD_BUILD_TIMESTAMP="0" diff --git a/docker/base/build.sh b/docker/base/build.sh new file mode 120000 index 00000000..f84531b1 --- /dev/null +++ b/docker/base/build.sh @@ -0,0 +1 @@ +../common/build.sh \ No newline at end of file diff --git a/docker/base/run.sh b/docker/base/run.sh new file mode 120000 index 00000000..aee911b2 --- /dev/null +++ b/docker/base/run.sh @@ -0,0 +1 @@ +../common/run.sh \ No newline at end of file diff --git a/docker/build.sh b/docker/build.sh new file mode 100755 index 00000000..9aaf9c46 --- /dev/null +++ b/docker/build.sh @@ -0,0 +1,5 @@ +#! /bin/bash -e +cd "$(dirname "${0}")" +./base/build.sh +./build/build.sh +./selftests/build.sh diff --git a/docker/build/.dockerignore b/docker/build/.dockerignore new file mode 100644 index 00000000..55686717 --- /dev/null +++ b/docker/build/.dockerignore @@ -0,0 +1 @@ +/.ccache diff --git a/docker/build/Dockerfile b/docker/build/Dockerfile new file mode 100644 index 00000000..20a0a58b --- /dev/null +++ b/docker/build/Dockerfile @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0 +ARG BASE_PREFIX="ghcr.io/linux-netdev" +ARG BASE_TAG="latest" +FROM ${BASE_PREFIX}/nipa-base:${BASE_TAG} + +LABEL name=nipa-build + +RUN sudo dnf install -y \ + clang llvm lld \ + ruff pylint yamllint jsonschema shellcheck \ + dwarves libasan libasan-static glibc-devel.i686 \ + rustc \ + perl-Git lei \ + python-lxml python-yaml python-jsonschema python-GitPython \ + python-pyroute2 python-sphinx python-psutil \ + libcap-devel numactl-devel libmnl-devel \ + coccinelle && \ + sudo dnf clean all + +# Sparse +ARG SPARSE_GIT_URL="https://kernel.googlesource.com/pub/scm/devel/sparse/sparse.git" +ARG SPARSE_GIT_SHA="37156835e3d725b6d750f000be33ba3814bb2310" # include a fix for __builtin_strlen +RUN git clone "${SPARSE_GIT_URL}" sparse && \ + cd "sparse" && \ + git checkout "${SPARSE_GIT_SHA}" && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo make PREFIX=/usr install && \ + cd .. && \ + rm -rf "sparse" diff --git a/docker/build/build.sh b/docker/build/build.sh new file mode 120000 index 00000000..f84531b1 --- /dev/null +++ b/docker/build/build.sh @@ -0,0 +1 @@ +../common/build.sh \ No newline at end of file diff --git a/docker/build/run.sh b/docker/build/run.sh new file mode 120000 index 00000000..aee911b2 --- /dev/null +++ b/docker/build/run.sh @@ -0,0 +1 @@ +../common/run.sh \ No newline at end of file diff --git a/docker/common/build.sh b/docker/common/build.sh new file mode 100755 index 00000000..2250b47a --- /dev/null +++ b/docker/common/build.sh @@ -0,0 +1,26 @@ +#!/bin/bash -e +# SPDX-License-Identifier: GPL-2.0 + +: "${INPUT_PUSH:=0}" +: "${INPUT_PREFIX:="ghcr.io/linux-netdev"}" +: "${INPUT_TAG:="latest"}" + +cd "$(dirname "${0}")" + +DIR_NAME="$(basename "${PWD}")" +ARGS=() +IMG="nipa-${DIR_NAME}" +PUB_IMG="${INPUT_PREFIX}/${IMG}:${INPUT_TAG}" + +if [[ ${-} =~ "x" ]]; then + ARGS+=(--progress plain) +fi + +if [ "${INPUT_PUSH}" = 1 ]; then + ARGS+=(--push) +fi + +docker buildx build --build-arg=BASE_PREFIX="${INPUT_PREFIX}" \ + --build-arg=BASE_TAG="${INPUT_TAG}" -f "Dockerfile" --load \ + -t "${PUB_IMG}" "${ARGS[@]}" "${@}" . +docker system prune --filter "label=name=${IMG}" -f >&2 diff --git a/docker/common/run.sh b/docker/common/run.sh new file mode 100755 index 00000000..8723c04e --- /dev/null +++ b/docker/common/run.sh @@ -0,0 +1,45 @@ +#!/bin/bash -e +# SPDX-License-Identifier: GPL-2.0 + +: "${INPUT_PREFIX:="ghcr.io/linux-netdev"}" +: "${INPUT_TAG:="latest"}" + +SCRIPT_DIR=$(cd "$(dirname "${0}")" && pwd) +DIR_NAME="$(basename "${SCRIPT_DIR}")" +CCACHE_DIR="${SCRIPT_DIR}/.ccache" +mkdir -p "${CCACHE_DIR}" +ARGS=( + -v "${CCACHE_DIR}:/home/nipa/.ccache:rw" + -v "${PWD}:${PWD}:rw" + -w "${PWD}" + -u "${RUID:-$(id -u)}:${RGID:-$(id -g)}" + --group-add "$(grep "^kvm:" /etc/group | cut -d: -f3)" + --rm + -i + --privileged +) +test -t 1 && ARGS+=("-t") + +DOCKER_IMG="${INPUT_PREFIX}/nipa-${DIR_NAME}:${INPUT_TAG}" +echo "Using ${DOCKER_IMG} image" >&2 + +# $1: basedir +add_git_worktree() { + local wt + if [ -f "${1}/.git" ]; then + wt="$(realpath "$(git -C "${1}" rev-parse --git-common-dir)")" + ARGS+=(-v "${wt}:${wt}:rw") + fi +} + +add_git_worktree . +# trying to be smart: mounting directories passed in argument +for arg in "${@}"; do + if [ -d "${arg}" ]; then + d="$(realpath "${arg}")" + ARGS+=(-v "${d}:${d}:rw") + add_git_worktree "${arg}" + fi +done + +docker run "${ARGS[@]}" "${DOCKER_IMG}" "${@:-bash}" diff --git a/docker/.dockerignore b/docker/debian/.dockerignore similarity index 100% rename from docker/.dockerignore rename to docker/debian/.dockerignore diff --git a/docker/debian/.gitignore b/docker/debian/.gitignore new file mode 100644 index 00000000..120c3cea --- /dev/null +++ b/docker/debian/.gitignore @@ -0,0 +1,3 @@ +/nipa-run +/config +/ccache diff --git a/docker/Dockerfile b/docker/debian/Dockerfile similarity index 100% rename from docker/Dockerfile rename to docker/debian/Dockerfile diff --git a/docker/README.rst b/docker/debian/README.rst similarity index 100% rename from docker/README.rst rename to docker/debian/README.rst diff --git a/docker/config.dist b/docker/debian/config.dist similarity index 100% rename from docker/config.dist rename to docker/debian/config.dist diff --git a/docker/nipa.config b/docker/debian/nipa.config similarity index 100% rename from docker/nipa.config rename to docker/debian/nipa.config diff --git a/docker/results.sh b/docker/debian/results.sh similarity index 100% rename from docker/results.sh rename to docker/debian/results.sh diff --git a/docker/run.sh b/docker/debian/run.sh similarity index 98% rename from docker/run.sh rename to docker/debian/run.sh index 98b7f356..a9068e4b 100755 --- a/docker/run.sh +++ b/docker/debian/run.sh @@ -39,7 +39,7 @@ echo >&2 Running nipa in Docker... docker run $DOCKER_FLAGS --rm --user=nipa \ --read-only \ -v $PWD/nipa-run/tmp:/tmp \ - -v $PWD/..:/nipa:ro \ + -v $PWD/../..:/nipa:ro \ -v $PWD/nipa-run/patatt:/home/nipa/.local/share/patatt \ -v $PWD/nipa-run/patatt:/root/.local/share/patatt \ -v $PWD/nipa.config:/nipa.config:ro \ diff --git a/docker/selftests/.dockerignore b/docker/selftests/.dockerignore new file mode 100644 index 00000000..55686717 --- /dev/null +++ b/docker/selftests/.dockerignore @@ -0,0 +1 @@ +/.ccache diff --git a/docker/selftests/Dockerfile b/docker/selftests/Dockerfile new file mode 100644 index 00000000..b6b50f64 --- /dev/null +++ b/docker/selftests/Dockerfile @@ -0,0 +1,129 @@ +# SPDX-License-Identifier: GPL-2.0 +ARG BASE_PREFIX="ghcr.io/linux-netdev" +ARG BASE_TAG="latest" +FROM ${BASE_PREFIX}/nipa-base:${BASE_TAG} + +LABEL name=nipa-selftests-base + +# a common base to run net selftests +RUN sudo dnf install -y \ + busybox kmod qemu-system-x86 systemd virtiofsd \ + clang cmake \ + python3-argcomplete python3-jsonschema python3-pip \ + python3-pyroute2 python3-requests python3-scapy \ + python3-yaml \ + iptables-devel libbpf-devel libcap-devel libdb-devel \ + libmnl-devel libnl3-devel libpcap-devel libselinux-devel \ + libtirpc-devel mbedtls-devel \ + bpftool bpftrace bridge-utils conntrack dropwatch dwarves \ + ebtables-legacy ethtool iperf iperf3 iptables-nft \ + iptables-legacy iptables-utils iputils ipvsadm jq mtools \ + ndisc6 ngrep netperf netsniff-ng net-tools nftables \ + nmap-ncat numactl-devel perf pppoe-server procps-ng psmisc \ + smcrouted socat strace tcpdump teamd traceroute tshark \ + udevadm \ + && \ + sudo dnf clean all + +# systemd changing the MAC address is racy: it does it too slowly and some tests +# start doing their thing, then systemd comes in and flips the address. +# Disable that by setting MACAddressPolicy=none +COPY systemd-network-macaddresspolicy-none /etc/systemd/network/99-default.link + +# use nft by default +RUN sudo alternatives --set iptables /usr/bin/iptables-nft + +# net/netfilter/bridge_brouter.sh requires ebtables-legacy +RUN sudo alternatives --set ebtables /usr/bin/ebtables-legacy + +# Not worth it to build in isolated containers: build deps still needed for slft + +# Needed for net and drivers/net/hw targets +ARG LIBURING_GIT_URL="https://github.com/axboe/liburing.git" +ARG LIBURING_GIT_SHA="liburing-2.14" +RUN git clone "${LIBURING_GIT_URL}" liburing && \ + cd liburing && \ + git checkout "${LIBURING_GIT_SHA}" && \ + ./configure && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo make install && \ + cd .. && \ + rm -rf liburing + +# Needed for drivers/net/netdevsim target +ARG LIBPSAMPLE_GIT_URL="https://github.com/Mellanox/libpsample.git" +ARG LIBPSAMPLE_GIT_SHA="62bb27d9a49424e45191eee81df7ce0d8c74e774" +RUN git clone "${LIBPSAMPLE_GIT_URL}" libpsample && \ + cd libpsample && \ + cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_INSTALL_PREFIX=/usr . && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo make install && \ + cd .. && \ + rm -rf libpsample + +# Needed for net/ppp target +ARG XL2TPD_GIT_URL="https://github.com/xelerance/xl2tpd.git" +ARG XL2TPD_GIT_SHA="v1.3.20" +RUN git clone "${XL2TPD_GIT_URL}" xl2tpd && \ + cd xl2tpd && \ + git checkout "${XL2TPD_GIT_SHA}" && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo make install && \ + cd .. && \ + rm -rf xl2tpd + +# Needed for net target +ARG IPV6TOOLKIT_GIT_URL="https://github.com/fgont/ipv6toolkit.git" +# v2.2 has bad csum: https://github.com/fgont/ipv6toolkit/issues/104 +ARG IPV6TOOLKIT_GIT_SHA="367bbe60489a6ae68898b9c81e672b48ad81df43" +RUN git clone "${IPV6TOOLKIT_GIT_URL}" ipv6toolkit && \ + cd ipv6toolkit && \ + git checkout "${IPV6TOOLKIT_GIT_SHA}" && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo make install && \ + cd .. && \ + rm -rf ipv6toolkit + +# Needed for net/forwarding target +ARG MTOOLS_GIT_URL="https://github.com/troglobit/mtools.git" +ARG MTOOLS_GIT_SHA="v3.2" +RUN git clone "${MTOOLS_GIT_URL}" mtools && \ + cd mtools && \ + git checkout "${MTOOLS_GIT_SHA}" && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo make install && \ + cd .. && \ + rm -rf mtools + +# Needed for net/packetdrill and net/netfilter targets +ARG PACKETDRILL_GIT_URL="https://github.com/google/packetdrill.git" +ARG PACKETDRILL_GIT_SHA="2c4001c4d6fc04a3bbd01d4b92be62717a37648a" +RUN git clone "${PACKETDRILL_GIT_URL}" packetdrill && \ + cd packetdrill/gtests/net/packetdrill && \ + git checkout "${PACKETDRILL_GIT_SHA}" && \ + ./configure && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo cp packetdrill /usr/local/bin/ && \ + cd .. && \ + rm -rf packetdrill + +# Needed for most targets +# Multiple remotes are possible, likely we want next + in-review patches +ARG IPROUTE2_GIT_URL="https://github.com/linux-netdev/iproute2.git" +# ARG IPROUTE2_GIT_URL="https://kernel.googlesource.com/pub/scm/network/iproute2/iproute2-next.git" +# ARG IPROUTE2_GIT_URL="https://kernel.googlesource.com/pub/scm/network/iproute2/iproute2.git" +ARG IPROUTE2_GIT_SHA="fce739fa4f2ec83206d8d9435aa94ce22f09cdb1" +RUN git clone "${IPROUTE2_GIT_URL}" iproute2 && \ + cd iproute2 && \ + git checkout "${IPROUTE2_GIT_SHA}" && \ + ./configure --color=auto && \ + make -j"$(nproc)" -l"$(nproc)" && \ + sudo make install && \ + cd .. && \ + rm -rf iproute2 + +ARG VIRTME_NG_VERSION="1.41" +RUN sudo pip3 install --no-cache-dir \ + virtme-ng=="${VIRTME_NG_VERSION}" + +CMD ["bash"] diff --git a/docker/selftests/build.sh b/docker/selftests/build.sh new file mode 120000 index 00000000..f84531b1 --- /dev/null +++ b/docker/selftests/build.sh @@ -0,0 +1 @@ +../common/build.sh \ No newline at end of file diff --git a/docker/selftests/run.sh b/docker/selftests/run.sh new file mode 120000 index 00000000..aee911b2 --- /dev/null +++ b/docker/selftests/run.sh @@ -0,0 +1 @@ +../common/run.sh \ No newline at end of file diff --git a/docker/selftests/systemd-network-macaddresspolicy-none b/docker/selftests/systemd-network-macaddresspolicy-none new file mode 100644 index 00000000..a1c70fa2 --- /dev/null +++ b/docker/selftests/systemd-network-macaddresspolicy-none @@ -0,0 +1,7 @@ +[Match] +OriginalName=* + +[Link] +NamePolicy=keep kernel database onboard slot path +AlternativeNamesPolicy=database onboard slot path mac +MACAddressPolicy=none