diff --git a/Cilium/1.19.4/build_cilium.sh b/Cilium/1.19.4/build_cilium.sh new file mode 100755 index 00000000..3dbf5e5f --- /dev/null +++ b/Cilium/1.19.4/build_cilium.sh @@ -0,0 +1,842 @@ +#!/bin/bash +# © Copyright IBM Corporation 2026 +# LICENSE: Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) +# +# Instructions: +# Download build script: wget https://raw.githubusercontent.com/linux-on-ibm-z/scripts/master/Cilium/1.19.4/build_cilium.sh +# Execute build script: bash build_cilium.sh (provide -h for help) + +# Package: Cilium +# Version: 1.19.4 +# Source repo: https://github.com/cilium/cilium +# Maintainer : LoZ Open Source Ecosystem (https://www.ibm.com/community/z/usergroups/opensource) +# Language: Go, C++, Bazel + +USER_IN_GROUP_DOCKER=$(id -nGz "$USER" | tr '\0' '\n' | grep -c '^docker$' || true) +set -e -o pipefail + +PACKAGE_NAME="cilium" +PACKAGE_VERSION="v1.19.4" +SOURCE_ROOT="$(pwd)" +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PATCH_URL="https://raw.githubusercontent.com/linux-on-ibm-z/scripts/master/Cilium/1.19.4/patch" + +# For local testing, use local patch directory if it exists +if [ -d "$SCRIPT_DIR/patch" ]; then + PATCH_DIR="$SCRIPT_DIR/patch" + msglog() { echo "$@"; } # Define msglog early for this check + msglog "Using local patch directory: $PATCH_DIR" +else + PATCH_DIR="" +fi + +FORCE="false" +TESTS="false" +DEBUG="false" + +# Component versions +GO_VERSION="1.24.2" +CNI_VERSION="1.9.1" +# KIND_VERSION and KUBERNETES_VERSION removed - tests no longer require cluster deployment +CMAKE_VERSION="3.28.3" + +source "/etc/os-release" +DISTRO="$ID-$VERSION_ID" +LOG_FILE="$SOURCE_ROOT/logs/${PACKAGE_NAME}-${PACKAGE_VERSION}-$DISTRO-$(date +"%F-%T").log" + +trap cleanup 0 1 2 ERR + +#Check if directory exists +if [ ! -d "$SOURCE_ROOT/logs/" ]; then + mkdir -p "$SOURCE_ROOT/logs/" +fi + +error() { + echo "Error: ${*}" + exit 1 +} + +msg() { + echo "${*}" +} + +log() { + echo "${*}" >>"$LOG_FILE" +} + +msglog() { + echo "${*}" |& tee -a "$LOG_FILE" +} + +cleanup() { + # Remove temporary artifacts + rm -rf "$SOURCE_ROOT"/go"${GO_VERSION}".linux-s390x.tar.gz + rm -rf "$SOURCE_ROOT"/aws-lc/build-fips-s390x + msglog "Cleaned up temporary artifacts" +} + +printHelp() { + echo "bash build_cilium.sh [-d debug] [-y install-without-confirmation] [-t run-test-cases]" + echo " default: Builds Cilium ${PACKAGE_VERSION} for s390x" +} + +logDetails() { + msglog "**************************** SYSTEM DETAILS ****************************" + cat /etc/os-release >>"$LOG_FILE" + msglog "detected distribution: $DISTRO" + msglog "*************************** END SYSTEM DETAILS *************************" +} + +prepare() { + if command -v "sudo" >/dev/null; then + msglog "sudo : Yes" + else + msglog "sudo : No" + error "sudo is required. Install sudo from repository using apt, yum or zypper based on your distro." + fi + + # Ensure swap is usable — some distros default to swappiness=0 which causes + # the OOM killer to fire instead of swapping during memory-heavy builds (Bazel bootstrap) + local current_swappiness + current_swappiness=$(cat /proc/sys/vm/swappiness) + if [[ "$current_swappiness" -lt 10 ]]; then + msglog "Adjusting vm.swappiness from $current_swappiness to 60" + sudo sysctl -w vm.swappiness=60 |& tee -a "$LOG_FILE" + fi + + if command -v "docker" >/dev/null; then + msglog "Docker : Yes" + docker --version |& tee -a "$LOG_FILE" + + # Configure BuildKit to use host networking for RUN instructions. + # The default BuildKit network sandbox can break on s390x hosts. + if [ ! -f /etc/buildkit/buildkitd.toml ]; then + sudo mkdir -p /etc/buildkit + sudo tee /etc/buildkit/buildkitd.toml > /dev/null <<'BKEOF' +[worker.oci] + networkMode = "host" +BKEOF + msglog "Created BuildKit config for host networking" + sudo systemctl restart docker |& tee -a "$LOG_FILE" || true + fi + else + msglog "Docker : No" + error "Docker is required. Please install Docker or Podman (with podman-docker) based on your distro." + fi + + if [[ "$USER_IN_GROUP_DOCKER" == "1" ]]; then + msglog "User $USER belongs to group docker" + else + msglog "Warning: User $USER does not belong to group docker. You may need to run 'sudo usermod -aG docker $USER' and log out/in." + fi + + if [[ "$FORCE" == "true" ]]; then + msglog "Force attribute provided. Continuing with install without confirmation." + else + # Ask user for prerequisite installation + msg "\nAs part of the installation, dependencies would be installed/upgraded." + msg "This build process will:" + msg " - Install Go ${GO_VERSION}" + msg " - Clone and build multiple components (image-tools, AWS-LC, proxy, cilium)" + msg " - Build Docker images locally (several GB of disk space required)" + msg "\nPrerequisites:" + msg " - Docker with buildx support" + msg " - Several hours of build time on s390x" + while true; do + read -r -p "Do you want to continue (y/n)? : " yn + case $yn in + [Yy]*) + msglog "User responded with Yes." + break + ;; + [Nn]*) exit ;; + *) echo "Please provide confirmation to proceed." ;; + esac + done + fi +} + + +installGo() { + msglog "Installing Go ${GO_VERSION}" + + cd "$SOURCE_ROOT" + wget -q https://golang.org/dl/go"${GO_VERSION}".linux-s390x.tar.gz |& tee -a "$LOG_FILE" + chmod ugo+r go"${GO_VERSION}".linux-s390x.tar.gz + sudo rm -rf /usr/local/go + sudo tar -C /usr/local -xzf go"${GO_VERSION}".linux-s390x.tar.gz |& tee -a "$LOG_FILE" + + export PATH=/usr/local/go/bin:$PATH + export GOPATH=$SOURCE_ROOT/go + + # Add to profile if not already present + if ! grep -q "/usr/local/go/bin" ~/.bashrc 2>/dev/null; then + echo 'export PATH=/usr/local/go/bin:$PATH' >> ~/.bashrc + fi + + go version |& tee -a "$LOG_FILE" + msglog "Go installation completed" +} + +buildImageTools() { + msglog "Building Cilium image-tools" + + cd "$SOURCE_ROOT" + + # Clone image-tools if it doesn't exist + # Using commit from around Cilium v1.19.4 release date (May 13, 2026) + if [ ! -d "image-tools" ]; then + msglog "Cloning image-tools repository (pinned to e8fd5656)" + git clone https://github.com/cilium/image-tools.git |& tee -a "$LOG_FILE" + cd image-tools + git checkout e8fd56563d1738f3cf72190c6ed54080d8215fc4 |& tee -a "$LOG_FILE" + cd .. + else + msglog "image-tools directory already exists, skipping clone" + fi + + cd image-tools + + # Apply s390x patch + if [ -n "$PATCH_DIR" ]; then + if cat "$PATCH_DIR/image-tools-s390x.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied image-tools s390x patch successfully" + else + if grep -q "linux/s390x" Makefile; then + msglog "s390x support already present, patch may have been previously applied" + else + msglog "Warning: Failed to apply image-tools patch, attempting to continue anyway" + fi + fi + else + if curl -sSL "$PATCH_URL/image-tools-s390x.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied image-tools s390x patch successfully" + else + if grep -q "linux/s390x" Makefile; then + msglog "s390x support already present, patch may have been previously applied" + else + msglog "Warning: Failed to apply image-tools patch, attempting to continue anyway" + fi + fi + fi + + # Remove container-based buildx builders and use default docker builder + # Container-based builders cannot access locally-built images + msglog "Configuring buildx to use default docker builder" + for builder in $(docker buildx ls | grep docker-container | awk '{print $1}' | grep -v NAME); do + msglog "Removing container-based builder: $builder" + docker buildx rm "$builder" 2>&1 | tee -a "$LOG_FILE" || true + done + + # Set buildx to use default builder + docker buildx use default |& tee -a "$LOG_FILE" + + # Create .buildx_builder file pointing to default + echo "default" > .buildx_builder + + export MAKER_IMAGE=local/image-maker:$(scripts/make-image-tag.sh images/maker) + export TESTER_IMAGE=local/image-tester:$(scripts/make-image-tag.sh images/tester) + export COMPILERS_IMAGE=local/image-compilers:$(scripts/make-image-tag.sh images/compilers) + export CILIUM_LLVM_IMAGE=local/cilium-llvm:$(scripts/make-image-tag.sh images/llvm) + export CILIUM_BPFTOOL_IMAGE=local/cilium-bpftool:$(scripts/make-image-tag.sh images/bpftool) + export CILIUM_IPTABLES_IMAGE=local/iptables:$(scripts/make-image-tag.sh images/iptables) + + export REGISTRIES=local + export PLATFORMS=linux/s390x + export PUSH=false + + msglog "Building maker-image" + if ! make maker-image |& tee -a "$LOG_FILE"; then + error "maker-image build failed" + fi + + msglog "Building tester-image" + if ! make tester-image |& tee -a "$LOG_FILE"; then + error "tester-image build failed" + fi + + msglog "Building iptables-image" + if ! make iptables-image |& tee -a "$LOG_FILE"; then + error "iptables-image build failed" + fi + + msglog "Building compilers-image (requires maker and tester)" + if ! make compilers-image |& tee -a "$LOG_FILE"; then + error "compilers-image build failed" + fi + + msglog "Building bpftool-image (requires compilers and tester)" + if ! make bpftool-image |& tee -a "$LOG_FILE"; then + error "bpftool-image build failed" + fi + + msglog "Building llvm-image (requires compilers and tester - this will take 30-60 minutes)" + if ! make llvm-image |& tee -a "$LOG_FILE"; then + error "llvm-image build failed" + fi + + # Verify all images were built + msglog "Verifying all image-tools images were built" + for img in "$MAKER_IMAGE" "$TESTER_IMAGE" "$COMPILERS_IMAGE" "$CILIUM_LLVM_IMAGE" "$CILIUM_BPFTOOL_IMAGE" "$CILIUM_IPTABLES_IMAGE"; do + if ! docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^${img}$"; then + error "Image $img was not built successfully" + fi + done + msglog "All image-tools images verified successfully" + + # Export image names for use by Cilium build + echo "export MAKER_IMAGE=$MAKER_IMAGE" >> "$SOURCE_ROOT/cilium_env.sh" + echo "export TESTER_IMAGE=$TESTER_IMAGE" >> "$SOURCE_ROOT/cilium_env.sh" + echo "export COMPILERS_IMAGE=$COMPILERS_IMAGE" >> "$SOURCE_ROOT/cilium_env.sh" + echo "export CILIUM_LLVM_IMAGE=$CILIUM_LLVM_IMAGE" >> "$SOURCE_ROOT/cilium_env.sh" + echo "export CILIUM_BPFTOOL_IMAGE=$CILIUM_BPFTOOL_IMAGE" >> "$SOURCE_ROOT/cilium_env.sh" + echo "export CILIUM_IPTABLES_IMAGE=$CILIUM_IPTABLES_IMAGE" >> "$SOURCE_ROOT/cilium_env.sh" + + msglog "Image-tools build completed" +} + +buildAWSLC() { + msglog "Building AWS-LC cryptographic library with FIPS support" + + cd "$SOURCE_ROOT" + rm -rf aws-lc + # Clone official AWS-LC repo + msglog "Cloning AWS-LC from official repo" + git clone https://github.com/aws/aws-lc.git |& tee -a "$LOG_FILE" + cd aws-lc + + # Checkout commit that patches were created against + git checkout ec37c27edb7b5002955b68a5c834164a43ddcb14 |& tee -a "$LOG_FILE" + msglog "Using AWS-LC commit ec37c27e (base for s390x patches)" + + # Apply s390x FIPS delocate patch + if [ -n "$PATCH_DIR" ]; then + if cat "$PATCH_DIR/aws-lc-s390x.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied AWS-LC s390x FIPS delocate patch successfully" + git add -A + git -c user.name="Build Script" -c user.email="build@localhost" commit -m "Apply s390x patches" |& tee -a "$LOG_FILE" + else + msglog "Warning: AWS-LC s390x patch failed to apply, build may fail" + fi + else + if curl -sSL "$PATCH_URL/aws-lc-s390x.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied AWS-LC s390x FIPS delocate patch successfully" + git add -A + git -c user.name="Build Script" -c user.email="build@localhost" commit -m "Apply s390x patches" |& tee -a "$LOG_FILE" + else + msglog "Warning: AWS-LC s390x patch failed to apply, build may fail" + fi + fi + + export AWS_LC_LOCAL_COMMIT="$(git rev-parse --short=9 HEAD)" + export AWS_LC_LOCAL_SRC="$PWD" + + # Host verification build - non-fatal since the actual FIPS build happens inside Bazel/envoy + if CC=${CC:-gcc} CXX=${CXX:-g++} cmake -S . -B build-fips-s390x \ + -DFIPS=1 \ + -DBUILD_TESTING=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_FLAGS='-fPIC -Wno-error=cast-align -Wno-cast-align' \ + -DCMAKE_CXX_FLAGS='-fPIC -Wno-error=cast-align -Wno-cast-align' |& tee -a "$LOG_FILE"; then + cmake --build build-fips-s390x -j$(nproc) |& tee -a "$LOG_FILE" || \ + msglog "Warning: AWS-LC host verification build failed (non-fatal - FIPS build happens inside envoy)" + else + msglog "Warning: AWS-LC cmake configuration failed (non-fatal - FIPS build happens inside envoy)" + fi + + echo "export AWS_LC_LOCAL_COMMIT=$AWS_LC_LOCAL_COMMIT" >> "$SOURCE_ROOT/cilium_env.sh" + echo "export AWS_LC_LOCAL_SRC=$AWS_LC_LOCAL_SRC" >> "$SOURCE_ROOT/cilium_env.sh" + + msglog "AWS-LC build completed" +} + +buildProxy() { + msglog "Building cilium-envoy (Envoy proxy with Cilium extensions)" + + cd "$SOURCE_ROOT" + rm -rf proxy + git clone https://github.com/cilium/proxy.git |& tee -a "$LOG_FILE" + cd proxy + + # Checkout specific commit that uses apt.llvm.org (compatible with s390x) + # Later commits switched to LLVM binaries which don't support s390x + git checkout ec2c6a48 |& tee -a "$LOG_FILE" + + # Apply s390x AWS-LC patch + if [ -n "$PATCH_DIR" ]; then + if cat "$PATCH_DIR/proxy-s390x-aws-lc.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied proxy s390x patch successfully" + else + msglog "Warning: Proxy s390x patch failed to apply, build may fail" + fi + else + if curl -sSL "$PATCH_URL/proxy-s390x-aws-lc.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied proxy s390x patch successfully" + else + msglog "Warning: Proxy s390x patch failed to apply, build may fail" + fi + fi + + # Source environment from AWS-LC build + source "$SOURCE_ROOT/cilium_env.sh" + + # Do NOT manually copy AWS-LC - let the Makefile's prepare-aws-lc-local target handle it + # Remove any stale .aws-lc-local directory to ensure clean staging + rm -rf "$SOURCE_ROOT/proxy/.aws-lc-local" + + export CILIUM_ENVOY_IMAGE="local/cilium-envoy-dev:$(git rev-parse HEAD)-s390x" + export DOCKER_DEV_ACCOUNT=local + export ARCH=s390x + export AWS_LC_FIPS=1 + + # Remove container-based buildx builders and use default docker builder. + # The default builder uses the Docker daemon's embedded BuildKit which + # respects /etc/buildkit/buildkitd.toml (configured for host networking). + for builder in $(docker buildx ls | grep docker-container | awk '{print $1}' | grep -v NAME); do + docker buildx rm "$builder" 2>/dev/null || true + done + docker buildx use default |& tee -a "$LOG_FILE" + sed -i 's/docker buildx create/echo skip-buildx-create #/' Makefile.docker + + export DOCKER_BUILD_OPTS="--load" + + msglog "Building docker-image-builder for proxy" + make docker-image-builder |& tee -a "$LOG_FILE" + + export IMAGE_PUSH=false + export CARGO_BAZEL_REPIN=true + export ENVOY_IP_TEST_VERSIONS=v4only + + msglog "Building docker-image-envoy with local AWS-LC source (commit: $AWS_LC_LOCAL_COMMIT)" + msglog "Using 3 parallel jobs with 8GB RAM and 3 CPUs (reduced for stability)" + + # Pass AWS-LC and Bazel options to make + # Note: EXTRA_BAZEL_BUILD_OPTS must be quoted to preserve spaces + # Reduced parallelism to avoid Bazel server crashes + make \ + AWS_LC_LOCAL_SRC="${AWS_LC_LOCAL_SRC}" \ + AWS_LC_LOCAL_COMMIT="${AWS_LC_LOCAL_COMMIT}" \ + EXTRA_BAZEL_BUILD_OPTS="--config=aws-lc-fips-http3-exp --jobs=3 --local_ram_resources=8192 --local_cpu_resources=3 --action_env=AWS_LC_FIPS=1 --verbose_failures --sandbox_debug" \ + docker-image-envoy |& tee -a "$LOG_FILE" + + echo "export CILIUM_ENVOY_IMAGE=$CILIUM_ENVOY_IMAGE" >> "$SOURCE_ROOT/cilium_env.sh" + + msglog "Cilium-envoy proxy build completed" + msglog "Cilium-envoy proxy build completed" + msglog "Cilium-envoy proxy build completed" +} + +buildCilium() { + msglog "Building Cilium core components" + + cd "$SOURCE_ROOT" + rm -rf cilium + git clone --depth 1 --branch "$PACKAGE_VERSION" https://github.com/cilium/cilium.git |& tee -a "$LOG_FILE" + cd cilium + + # Apply s390x patch + if [ -n "$PATCH_DIR" ]; then + if cat "$PATCH_DIR/cilium-s390x.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied Cilium s390x patch successfully" + sed -i "s/docker buildx create/echo default #/" images/Makefile + else + msglog "Warning: Cilium s390x patch failed to apply, build may fail" + fi + else + if curl -sSL "$PATCH_URL/cilium-s390x.patch" | git apply - |& tee -a "$LOG_FILE"; then + msglog "Applied Cilium s390x patch successfully" + sed -i "s/docker buildx create/echo default #/" images/Makefile + else + msglog "Warning: Cilium s390x patch failed to apply, build may fail" + fi + fi + + # Update CNI version + images/scripts/update-cni-version.sh "$CNI_VERSION" |& tee -a "$LOG_FILE" + + # Source environment variables + source "$SOURCE_ROOT/cilium_env.sh" + + export CILIUM_RUNTIME_IMAGE="local/cilium-runtime-dev:$(images/scripts/make-image-tag.sh images/runtime)" + export CILIUM_BUILDER_IMAGE="local/cilium-builder-dev:$(images/scripts/make-image-tag.sh images/builder)" + + export PUSH=false + export REGISTRIES=local + export OUTPUT=--load + export PLATFORMS=linux/s390x + export UBUNTU_IMAGE=public.ecr.aws/ubuntu/ubuntu:24.04@sha256:8307fed669bda8e552b5716194d81544760741347dbf3333e7dcd33680a2b986 + + msglog "Building Cilium runtime image" + make -C images runtime-image |& tee -a "$LOG_FILE" + + msglog "Building Cilium builder image" + make -C images builder-image |& tee -a "$LOG_FILE" + + msglog "Building Cilium main image" + make -C images cilium-image |& tee -a "$LOG_FILE" + + msglog "Building Cilium operator image" + OPERATOR_VARIANT=operator-generic make -C images operator-image |& tee -a "$LOG_FILE" + + msglog "Building Hubble relay image" + make -C images hubble-relay-image |& tee -a "$LOG_FILE" + + msglog "Cilium core components build completed" +} + +buildAncillaryServices() { + msglog "Building ancillary services (certgen, hubble-ui, alpine-curl, json-mock)" + + cd "$SOURCE_ROOT" + + # Build certgen + msglog "Building certgen" + rm -rf certgen + git clone -b v0.4.3 https://github.com/cilium/certgen.git |& tee -a "$LOG_FILE" + cd certgen + DOCKER_IMAGE=local/certgen:latest DOCKER_IMAGE_TAG=latest make docker-image |& tee -a "$LOG_FILE" + + # Build hubble-ui + msglog "Building hubble-ui" + cd "$SOURCE_ROOT" + rm -rf hubble-ui + git clone -b v0.13.5 https://github.com/cilium/hubble-ui.git |& tee -a "$LOG_FILE" + cd hubble-ui + + # Fix s390x support in byteorder file + sed -i "s/armbe || arm64be || mips || mips64 || ppc64/armbe || arm64be || mips || mips64 || ppc64 || s390x/" backend/vendor/github.com/cilium/cilium/pkg/byteorder/byteorder_bigendian.go + + # Build frontend + docker buildx build --platform linux/s390x --load -t local/hubble-ui:latest . |& tee -a "$LOG_FILE" + + # Build backend + docker buildx build --platform linux/s390x --load -f backend/Dockerfile -t local/hubble-ui-backend:latest ./backend |& tee -a "$LOG_FILE" + + # Build alpine-curl + msglog "Building alpine-curl" + cd "$SOURCE_ROOT" + rm -rf alpine-curl + git clone -b v1.5.0 https://github.com/cilium/alpine-curl.git |& tee -a "$LOG_FILE" + cd alpine-curl + docker buildx build --platform linux/s390x --load -t local/alpine-curl:v1.5.0 . |& tee -a "$LOG_FILE" + + # Build json-mock + msglog "Building json-mock" + cd "$SOURCE_ROOT" + rm -rf json-mock + git clone -b v1.3.9 https://github.com/cilium/json-mock.git |& tee -a "$LOG_FILE" + cd json-mock + docker buildx build --platform linux/s390x --load -t local/json-mock:v1.3.9 . |& tee -a "$LOG_FILE" + + msglog "Ancillary services build completed" +} + +runTests() { + if [[ "$TESTS" != "true" ]]; then + return 0 + fi + + set +e + export TEST_LOG="$LOGDIR/test-$(date +"%F-%T").log" + touch "$TEST_LOG" + + msglog "Running Cilium image validation tests" + printf -- "\n==== Cilium Image Validation Tests ====\n" | tee -a "$TEST_LOG" + + cd "$SOURCE_ROOT" + + # Verify all expected images are built + msglog "Verifying all required images are built..." + printf -- "\nRequired Docker Images:\n" | tee -a "$TEST_LOG" + + cat < /tmp/docker_images_actual.txt + + local missing_count=0 + local test_failed=0 + + # Check core images + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "local/cilium-dev:${PACKAGE_VERSION}-wip"; then + printf -- "✓ cilium-dev image found\n" | tee -a "$TEST_LOG" + else + printf -- "✗ cilium-dev image MISSING\n" | tee -a "$TEST_LOG" + missing_count=$((missing_count + 1)) + fi + + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "local/operator-dev:${PACKAGE_VERSION}-wip"; then + printf -- "✓ operator-dev image found\n" | tee -a "$TEST_LOG" + else + printf -- "✗ operator-dev image MISSING\n" | tee -a "$TEST_LOG" + missing_count=$((missing_count + 1)) + fi + + if docker images --format '{{.Repository}}' | grep -q "local/cilium-envoy-dev"; then + printf -- "✓ cilium-envoy-dev image found\n" | tee -a "$TEST_LOG" + else + printf -- "✗ cilium-envoy-dev image MISSING\n" | tee -a "$TEST_LOG" + missing_count=$((missing_count + 1)) + fi + + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "local/hubble-relay-dev:${PACKAGE_VERSION}-wip"; then + printf -- "✓ hubble-relay-dev image found\n" | tee -a "$TEST_LOG" + else + printf -- "✗ hubble-relay-dev image MISSING\n" | tee -a "$TEST_LOG" + missing_count=$((missing_count + 1)) + fi + + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "local/hubble-ui:latest"; then + printf -- "✓ hubble-ui image found\n" | tee -a "$TEST_LOG" + else + printf -- "✗ hubble-ui image MISSING\n" | tee -a "$TEST_LOG" + missing_count=$((missing_count + 1)) + fi + + # Test binary execution + printf -- "\n==== Testing Binary Execution ====\n" | tee -a "$TEST_LOG" + + # Test Cilium agent + printf -- "\nTesting Cilium agent binary...\n" | tee -a "$TEST_LOG" + local VERSION_NUM="${PACKAGE_VERSION#v}" + local agent_output + agent_output=$(docker run --rm local/cilium-dev:${PACKAGE_VERSION}-wip cilium version 2>&1 || true) + printf -- "%s\n" "$agent_output" | tee -a "$TEST_LOG" + if echo "$agent_output" | grep -q "${VERSION_NUM}"; then + printf -- "✓ Cilium agent version check PASSED\n" | tee -a "$TEST_LOG" + else + printf -- "✗ Cilium agent version check FAILED\n" | tee -a "$TEST_LOG" + test_failed=1 + fi + + # Test Operator + printf -- "\nTesting Cilium operator binary...\n" | tee -a "$TEST_LOG" + local operator_output + operator_output=$(docker run --rm --entrypoint cilium-operator-generic local/operator-dev:${PACKAGE_VERSION}-wip --version 2>&1 || true) + printf -- "%s\n" "$operator_output" | tee -a "$TEST_LOG" + if echo "$operator_output" | grep -q "${VERSION_NUM}"; then + printf -- "✓ Cilium operator version check PASSED\n" | tee -a "$TEST_LOG" + else + printf -- "✗ Cilium operator version check FAILED\n" | tee -a "$TEST_LOG" + test_failed=1 + fi + + # Test Envoy proxy and verify FIPS + printf -- "\nTesting Envoy proxy and FIPS mode...\n" | tee -a "$TEST_LOG" + local envoy_image=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep "local/cilium-envoy-dev" | grep "s390x" | head -1) + if [[ -n "$envoy_image" ]]; then + local envoy_version=$(docker run --rm "$envoy_image" /usr/bin/cilium-envoy --version 2>&1) + printf -- "$envoy_version\n" | tee -a "$TEST_LOG" + + if echo "$envoy_version" | grep -q "BoringSSL-FIPS"; then + printf -- "✓ Envoy proxy FIPS mode VERIFIED (BoringSSL-FIPS)\n" | tee -a "$TEST_LOG" + else + printf -- "✗ Envoy proxy FIPS mode NOT FOUND\n" | tee -a "$TEST_LOG" + test_failed=1 + fi + else + printf -- "✗ Envoy proxy image not found\n" | tee -a "$TEST_LOG" + test_failed=1 + fi + + # Test Hubble relay + printf -- "\nTesting Hubble relay binary...\n" | tee -a "$TEST_LOG" + local relay_output + relay_output=$(docker run --rm local/hubble-relay-dev:${PACKAGE_VERSION}-wip version 2>&1 || true) + printf -- "%s\n" "$relay_output" | tee -a "$TEST_LOG" + if echo "$relay_output" | grep -qi "hubble-relay"; then + printf -- "✓ Hubble relay version check PASSED\n" | tee -a "$TEST_LOG" + else + printf -- "✗ Hubble relay version check FAILED\n" | tee -a "$TEST_LOG" + test_failed=1 + fi + + # Verify architecture + printf -- "\nVerifying s390x architecture...\n" | tee -a "$TEST_LOG" + local arch_output + arch_output=$(docker run --rm local/cilium-dev:${PACKAGE_VERSION}-wip uname -m 2>&1 || true) + printf -- "%s\n" "$arch_output" | tee -a "$TEST_LOG" + if echo "$arch_output" | grep -q "s390x"; then + printf -- "✓ Architecture verified as s390x\n" | tee -a "$TEST_LOG" + else + printf -- "✗ Architecture verification FAILED\n" | tee -a "$TEST_LOG" + test_failed=1 + fi + + # Summary + printf -- "\n==== Test Summary ====\n" | tee -a "$TEST_LOG" + printf -- "Missing images: $missing_count\n" | tee -a "$TEST_LOG" + + if [[ $missing_count -gt 0 || $test_failed -eq 1 ]]; then + printf -- "\n✗ TESTS FAILED\n" | tee -a "$TEST_LOG" + printf -- "Check logs at $TEST_LOG\n" | tee -a "$TEST_LOG" + msglog "Tests FAILED - Check $TEST_LOG for details" + set -e + return 1 + else + printf -- "\n✓ ALL TESTS PASSED\n" | tee -a "$TEST_LOG" + printf -- "\nAll Cilium images successfully built and validated for s390x!\n" | tee -a "$TEST_LOG" + printf -- "\nTo deploy Cilium to a Kubernetes cluster:\n" | tee -a "$TEST_LOG" + printf -- " 1. Set up a Kubernetes cluster on s390x (kubeadm, k3s, etc.)\n" | tee -a "$TEST_LOG" + printf -- " 2. Load images to cluster nodes\n" | tee -a "$TEST_LOG" + printf -- " 3. Deploy with Helm\n" | tee -a "$TEST_LOG" + msglog "All tests PASSED!" + fi + + set -e +} + +gettingStarted() { + msglog "\n**********************************************************************************************************" + msglog "\n* Cilium ${PACKAGE_VERSION} has been successfully built for s390x architecture" + msglog "* Built Docker images:" + msglog "* - local/cilium-runtime-dev" + msglog "* - local/cilium-builder-dev" + msglog "* - local/cilium-dev" + msglog "* - local/operator-dev" + msglog "* - local/hubble-relay-dev" + msglog "* - local/cilium-envoy-dev" + msglog "* - local/hubble-ui" + msglog "* - local/hubble-ui-backend" + msglog "* - local/certgen" + msglog "* - And supporting images (image-tools, alpine-curl, json-mock)" + msglog "*" + msglog "* To view built images: docker images | grep local/" + msglog "*" + msglog "* To deploy Cilium:" + msglog "* 1. Set up a Kubernetes cluster (Kind, k3s, or full cluster)" + msglog "* 2. Use Helm to install Cilium with the local images" + msglog "* 3. See cilium.sh for a full deployment example with all configuration options" + msglog "*" + msglog "* Log file: $LOG_FILE" + msglog "*" + msglog "**********************************************************************************************************" +} + +configureAndInstall() { + msglog "Configuration and Installation started" + + installGo + + buildImageTools + buildAWSLC + + # Build Envoy proxy with FIPS-enabled AWS-LC + buildProxy + + buildCilium + buildAncillaryServices + + runTests + + msglog "Build completed successfully" +} + +logDetails |& tee -a "$LOG_FILE" + +#Parse command line options. +while getopts "h?ytd" opt; do + case "$opt" in + h | \?) + printHelp + exit 0 + ;; + y) FORCE="true" ;; + t) TESTS="true" ;; + d) DEBUG="true" ; set -x ;; + esac +done + +prepare |& tee -a "$LOG_FILE" + +case "$DISTRO" in +#---------------------------------------------------------- +"rhel-9.4" | "rhel-9.5" | "rhel-9.6" | "rhel-9.7" | "rhel-9.8" | "rhel-10.0" | "rhel-10.1" | "rhel-10.2") + printf -- "\nInstalling %s %s for %s \n" "$PACKAGE_NAME" "$PACKAGE_VERSION" "$DISTRO" |& tee -a "${LOG_FILE}" + + sudo dnf install -y --allowerasing wget curl git cmake clang make rsync file \ + ca-certificates gnupg yum-utils device-mapper-persistent-data lvm2 |& tee -a "${LOG_FILE}" + + configureAndInstall |& tee -a "$LOG_FILE" + ;; + +#---------------------------------------------------------- +"sles-15.6" | "sles-15.7" | "sles-16.0") + printf -- "\nInstalling %s %s for %s \n" "$PACKAGE_NAME" "$PACKAGE_VERSION" "$DISTRO" |& tee -a "${LOG_FILE}" + + sudo zypper install -y wget curl git cmake gcc gcc-c++ make rsync file patch \ + ca-certificates |& tee -a "${LOG_FILE}" + + configureAndInstall |& tee -a "$LOG_FILE" + ;; + +#---------------------------------------------------------- +"ubuntu-22.04" | "ubuntu-24.04") + printf -- "\nInstalling %s %s for %s \n" "$PACKAGE_NAME" "$PACKAGE_VERSION" "$DISTRO" |& tee -a "${LOG_FILE}" + + # Ensure universe repo is enabled (clang requires it) + if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then + sudo sed -i 's/Components: main$/Components: main universe/' /etc/apt/sources.list.d/ubuntu.sources |& tee -a "${LOG_FILE}" + elif [ -f /etc/apt/sources.list ]; then + sudo sed -i 's/^\(deb .* main\)$/\1 universe/' /etc/apt/sources.list |& tee -a "${LOG_FILE}" + fi + + sudo apt-get update |& tee -a "${LOG_FILE}" + sudo apt-get install -y wget curl git cmake clang make rsync file \ + ca-certificates gnupg lsb-release apt-transport-https |& tee -a "${LOG_FILE}" + + configureAndInstall |& tee -a "$LOG_FILE" + ;; + +#---------------------------------------------------------- +*) + error "$DISTRO not supported. Supported distributions: rhel-9.x, rhel-10.x, sles-15.x, sles-16.0, ubuntu-22.04, ubuntu-24.04" + ;; +esac + +gettingStarted |& tee -a "$LOG_FILE" + +# Alternative testing approach if Kind node image build fails +testCiliumWithoutKind() { + msglog "Testing Cilium deployment without Kind (using existing cluster or kubeadm)" + + # Option 1: Deploy to existing Kubernetes cluster on s390x + if kubectl cluster-info &>/dev/null; then + msglog "Found existing Kubernetes cluster, deploying Cilium..." + + # Install Cilium Helm repo + helm repo add cilium https://helm.cilium.io/ || true + helm repo update + + # Deploy Cilium with local images + helm install cilium cilium/cilium --version $PACKAGE_VERSION \ + --namespace kube-system \ + --set image.repository=local/cilium-dev \ + --set image.tag="$PACKAGE_VERSION"-local \ + --set image.pullPolicy=Never \ + --set operator.image.repository=local/operator-dev \ + --set operator.image.tag="$PACKAGE_VERSION"-local \ + --set hubble.relay.image.repository=local/hubble-relay-dev \ + --set hubble.relay.image.tag="$PACKAGE_VERSION"-local + + kubectl wait --for=condition=ready pod -l k8s-app=cilium -n kube-system --timeout=300s + kubectl exec -n kube-system ds/cilium -- cilium status + + msglog "Cilium deployed successfully!" + else + msglog "No Kubernetes cluster found. To test Cilium:" + msglog "1. Set up a Kubernetes cluster on s390x (kubeadm, k3s, etc.)" + msglog "2. Load images: docker save local/cilium-dev | ssh docker load" + msglog "3. Deploy with Helm using the configuration above" + fi +} diff --git a/Cilium/1.19.4/patch/aws-lc-s390x.patch b/Cilium/1.19.4/patch/aws-lc-s390x.patch new file mode 100644 index 00000000..8e6ef833 --- /dev/null +++ b/Cilium/1.19.4/patch/aws-lc-s390x.patch @@ -0,0 +1,3594 @@ +diff --git a/util/fipstools/acvp/modulewrapper/main.cc b/util/fipstools/acvp/modulewrapper/main.cc +index 4b832cd..f1ea342 100644 +--- a/util/fipstools/acvp/modulewrapper/main.cc ++++ b/util/fipstools/acvp/modulewrapper/main.cc +@@ -45,6 +45,8 @@ int main(int argc, char **argv) { + puts("PPC32BE (32-bit)"); + #elif defined(OPENSSL_PPC64BE) + puts("PPC64BE (64-bit)"); ++#elif defined(OPENSSL_S390X) ++ puts("s390x (64-bit)"); + #else + #error "FIPS build not supported on this architecture" + #endif +diff --git a/util/fipstools/delocate/delocate.go b/util/fipstools/delocate/delocate.go +index 9058ad9..984a744 100644 +--- a/util/fipstools/delocate/delocate.go ++++ b/util/fipstools/delocate/delocate.go +@@ -48,6 +48,12 @@ type inputFile struct { + ast *node32 + } + ++type s390xGotHelper struct { ++ symbol string ++ section string ++ instruction string ++} ++ + type stringWriter interface { + WriteString(string) (int, error) + } +@@ -58,6 +64,7 @@ const ( + ppc64le processorType = iota + 1 + x86_64 + aarch64 ++ s390x + ) + + // represents a unique symbol for an occurrence of OPENSSL_ia32cap_P. +@@ -126,6 +133,23 @@ type delocation struct { + gotOffsetsNeeded map[string]struct{} + // gotOffOffsetsNeeded contains the symbols whose @GOTOFF offsets are needed. + gotOffOffsetsNeeded map[string]struct{} ++ // gotValueSymbolsNeeded maps synthetic s390x relative-literal slot symbol ++ // names to their targets. These slots hold PC-relative deltas for local ++ // lgrl/clgrl @GOT rewrites so the code can materialize full addresses without ++ // leaving absolute relocations in the hashed module. ++ gotValueSymbolsNeeded map[string]string ++ // s390xGotHelpersNeeded maps helper symbol names to helper specifications for ++ // external s390x GOT references. These helpers live outside the hashed module ++ // range so final link-time GOT relocations do not invalidate the recorded ++ // FIPS hash. ++ s390xGotHelpersNeeded map[string]s390xGotHelper ++ // s390xLocalGotSlotRegs tracks registers that currently hold the address of a ++ // synthetic local @GOT delta slot. Some later conditional loads must be ++ // rewritten to materialize the full target address from that slot. ++ s390xLocalGotSlotRegs map[string]struct{} ++ // s390xExrlTargets records local labels targeted by EXRL. GNU as requires ++ // these targets to be aligned so the relative offset is encodable. ++ s390xExrlTargets map[string]struct{} + + currentInput inputFile + } +@@ -195,6 +219,8 @@ func (d *delocation) processInput(input inputFile) (err error) { + statement, err = d.processPPCInstruction(statement, node.up) + case aarch64: + statement, err = d.processAarch64Instruction(statement, node.up) ++ case s390x: ++ statement, err = d.processS390xInstruction(statement, node.up) + default: + panic("unknown processor") + } +@@ -421,6 +447,15 @@ func (d *delocation) processLabelContainingDirective(statement, directive *node3 + + func (d *delocation) processLabel(statement, label *node32) (*node32, error) { + symbol := d.contents(label) ++ emittedSymbol := symbol ++ if label.pegRule == ruleLocalSymbol { ++ emittedSymbol = d.mapLocalSymbol(symbol) ++ } ++ if d.processor == s390x { ++ if _, ok := d.s390xExrlTargets[emittedSymbol]; ok { ++ d.output.WriteString("\t.balign 4\n") ++ } ++ } + + switch label.pegRule { + case ruleLocalLabel: +@@ -428,7 +463,7 @@ func (d *delocation) processLabel(statement, label *node32) (*node32, error) { + case ruleLocalSymbol: + // symbols need to be mapped so that local symbols from two + // different .s inputs don't collide. +- d.output.WriteString(d.mapLocalSymbol(symbol) + ":\n") ++ d.output.WriteString(emittedSymbol + ":\n") + case ruleSymbolName: + d.output.WriteString(localTargetName(symbol) + ":\n") + d.writeNode(statement) +@@ -590,12 +625,12 @@ func (d *delocation) processAarch64Instruction(statement, instruction *node32) ( + symbol = d.contents(argNodes[1].up) + case ruleMemoryRef: + assertNodeType(argNodes[1].up, ruleSymbolRef) +- node, empty := d.gatherOffsets(argNodes[1].up.up, "") ++ node, empty, _ := d.gatherOffsets(argNodes[1].up.up, "") + if len(empty) != 0 { + panic("prefix offsets found for adrp") + } + symbol = d.contents(node) +- _, offset = d.gatherOffsets(node.next, "") ++ _, offset, _ = d.gatherOffsets(node.next, "") + default: + panic("Unhandled adrp argument type " + rul3s[argNodes[1].pegRule]) + } +@@ -951,16 +986,37 @@ func (d *delocation) loadFromTOC(w stringWriter, symbol, offset, dest string) wr + } + } + +-func (d *delocation) gatherOffsets(symRef *node32, offsets string) (*node32, string) { +- for symRef != nil && symRef.pegRule == ruleOffset { +- offset := d.contents(symRef) +- if offset[0] != '+' && offset[0] != '-' { +- offset = "+" + offset ++func (d *delocation) gatherOffsets(symRef *node32, offsets string) (*node32, string, bool) { ++ changed := false ++ for symRef != nil { ++ offsetNode := symRef ++ if symRef.pegRule == ruleSymbolOffset { ++ offsetNode = symRef.up + } +- offsets = offsets + offset ++ if offsetNode == nil || (offsetNode.pegRule != ruleOffset && offsetNode.pegRule != ruleSymbolDelta) { ++ break ++ } ++ ++ offset := d.contents(offsetNode) ++ if offsetNode.pegRule == ruleOffset { ++ if offset[0] != '+' && offset[0] != '-' { ++ offset = "+" + offset ++ } ++ } else { ++ sign := offset[:1] ++ symbol := offset[1:] ++ if strings.HasPrefix(symbol, ".L") { ++ mapped := d.mapLocalSymbol(symbol) ++ if mapped != symbol { ++ changed = true ++ } ++ offset = sign + mapped ++ } ++ } ++ offsets += offset + symRef = symRef.next + } +- return symRef, offsets ++ return symRef, offsets, changed + } + + func (d *delocation) parseMemRef(memRef *node32) (symbol, offset, section string, didChange, symbolIsLocal bool, nextRef *node32) { +@@ -972,7 +1028,9 @@ func (d *delocation) parseMemRef(memRef *node32) (symbol, offset, section string + nextRef = memRef.next + + // (Offset* '+')? +- symRef, offset = d.gatherOffsets(symRef, offset) ++ var changed bool ++ symRef, offset, changed = d.gatherOffsets(symRef, offset) ++ didChange = didChange || changed + + // (LocalSymbol / SymbolName) + symbol = d.contents(symRef) +@@ -987,7 +1045,8 @@ func (d *delocation) parseMemRef(memRef *node32) (symbol, offset, section string + symRef = symRef.next + + // Offset* +- symRef, offset = d.gatherOffsets(symRef, offset) ++ symRef, offset, changed = d.gatherOffsets(symRef, offset) ++ didChange = didChange || changed + + // ('@' Section / Offset*)? + if symRef != nil { +@@ -995,7 +1054,8 @@ func (d *delocation) parseMemRef(memRef *node32) (symbol, offset, section string + section = d.contents(symRef) + symRef = symRef.next + +- symRef, offset = d.gatherOffsets(symRef, offset) ++ symRef, offset, changed = d.gatherOffsets(symRef, offset) ++ didChange = didChange || changed + } + + if symRef != nil { +@@ -1214,6 +1274,309 @@ Args: + return statement, nil + } + ++func gotValueSlotName(symbol string) string { ++ replacer := strings.NewReplacer("@", "_", ".", "_", "-", "_", "+", "_") ++ return ".Lboringssl_gotent_" + replacer.Replace(symbol) ++} ++ ++func s390xGotHelperName(symbol, section, instruction string) string { ++ replacer := strings.NewReplacer("@", "_", ".", "_", "-", "_", "+", "_") ++ return ".Lbcm_s390x_" + instruction + "_" + replacer.Replace(symbol) + "_" + section ++} ++ ++func s390xTempRegister(avoid []string) string { ++ candidates := []string{"%r1", "%r2", "%r3", "%r4", "%r5"} ++ ++NextCandidate: ++ for _, candidate := range candidates { ++ for _, avoidReg := range avoid { ++ if candidate == avoidReg { ++ continue NextCandidate ++ } ++ } ++ return candidate ++ } ++ ++ panic("too many excluded s390x registers") ++} ++ ++func s390xIndexRegister(avoid []string) string { ++ candidates := []string{"%r1", "%r2", "%r3", "%r4", "%r5"} ++ ++NextCandidate: ++ for _, candidate := range candidates { ++ for _, avoidReg := range avoid { ++ if candidate == avoidReg { ++ continue NextCandidate ++ } ++ } ++ return candidate ++ } ++ ++ panic("too many excluded s390x index registers") ++} ++ ++func s390xTrackedLocalGotSlotBaseReg(arg string) (string, bool) { ++ if !strings.HasPrefix(arg, "0(") || !strings.HasSuffix(arg, ")") || strings.Contains(arg, ",") { ++ return "", false ++ } ++ ++ reg := strings.TrimSuffix(strings.TrimPrefix(arg, "0("), ")") ++ if !strings.HasPrefix(reg, "%r") { ++ return "", false ++ } ++ ++ return reg, true ++} ++ ++func s390xConditionalLoadRegInstruction(name string) (string, bool) { ++ if !strings.HasPrefix(name, "locg") || strings.HasPrefix(name, "locgr") { ++ return "", false ++ } ++ ++ return "locgr" + strings.TrimPrefix(name, "locg"), true ++} ++ ++func (d *delocation) processS390xInstruction(statement, instruction *node32) (*node32, error) { ++ assertNodeType(instruction, ruleInstructionName) ++ instructionName := d.contents(instruction) ++ ++ argNodes := instructionArgs(instruction.next) ++ ++ var args []string ++ changed := false ++ localGotValueRewrite := false ++ externalGotHelperRewrite := false ++ localGotConditionalLoadRewrite := false ++ trackLocalGotSlotReg := false ++ localGotConditionalLoadBaseReg := "" ++ localGotConditionalLoadRegInstruction := "" ++ ++ for _, arg := range argNodes { ++ fullArg := arg ++ isIndirect := false ++ ++ if arg.pegRule == ruleIndirectionIndicator { ++ arg = arg.next ++ isIndirect = true ++ } ++ ++ switch arg.pegRule { ++ case ruleRegisterOrConstant, ruleLocalLabelRef: ++ args = append(args, d.contents(fullArg)) ++ ++ case ruleMemoryRef: ++ symbol, offset, section, didChange, symbolIsLocal, memRef := d.parseMemRef(arg.up) ++ _, knownSymbol := d.symbols[symbol] ++ changed = changed || didChange ++ if instructionName == "exrl" && symbolIsLocal && section == "" && len(offset) == 0 && memRef == nil { ++ d.s390xExrlTargets[symbol] = struct{}{} ++ } ++ ++ if len(symbol) > 0 { ++ if knownSymbol { ++ symbol = localTargetName(symbol) ++ changed = true ++ } ++ ++ if section == "PLT" { ++ if !knownSymbol && !symbolIsLocal && !isSynthesized(symbol, s390x) { ++ d.redirectors[symbol+"@"+section] = redirectorName(symbol) ++ symbol = redirectorName(symbol) ++ } ++ section = "" ++ changed = true ++ } ++ } ++ ++ if section == "GOT" || section == "GOTENT" { ++ if instructionName != "lgrl" && instructionName != "clgrl" && instructionName != "larl" { ++ return nil, fmt.Errorf("can't process %q instruction with @%s", instructionName, section) ++ } ++ if knownSymbol || symbolIsLocal || isSynthesized(symbol, s390x) { ++ slotName := gotValueSlotName(symbol) ++ d.gotValueSymbolsNeeded[slotName] = symbol ++ symbol = slotName ++ section = "" ++ localGotValueRewrite = true ++ trackLocalGotSlotReg = instructionName == "larl" ++ } else { ++ helperInstruction := "lgrl" ++ if instructionName == "larl" { ++ helperInstruction = "larl" ++ } ++ helperName := s390xGotHelperName(symbol, section, helperInstruction) ++ d.s390xGotHelpersNeeded[helperName] = s390xGotHelper{ ++ symbol: symbol, ++ section: section, ++ instruction: helperInstruction, ++ } ++ symbol = helperName ++ section = "" ++ externalGotHelperRewrite = true ++ } ++ changed = true ++ } ++ ++ if section != "" && section != "tls" { ++ return nil, fmt.Errorf("Unknown section type %q", section) ++ } ++ ++ argStr := "" ++ if isIndirect { ++ argStr += "*" ++ } ++ argStr += symbol ++ if len(offset) > 0 { ++ argStr += offset ++ } ++ if len(section) > 0 { ++ argStr += "@" ++ argStr += section ++ } ++ ++ for ; memRef != nil; memRef = memRef.next { ++ argStr += d.contents(memRef) ++ } ++ args = append(args, argStr) ++ ++ default: ++ panic(fmt.Sprintf("unknown instruction argument type %q", rul3s[arg.pegRule])) ++ } ++ } ++ ++ if !changed && len(args) == 2 { ++ if baseReg, ok := s390xTrackedLocalGotSlotBaseReg(args[1]); ok { ++ if _, tracked := d.s390xLocalGotSlotRegs[baseReg]; tracked { ++ if regInstruction, ok := s390xConditionalLoadRegInstruction(instructionName); ok { ++ localGotConditionalLoadRewrite = true ++ localGotConditionalLoadBaseReg = baseReg ++ localGotConditionalLoadRegInstruction = regInstruction ++ changed = true ++ } ++ } ++ } ++ } ++ ++ if changed { ++ d.writeCommentedNode(statement) ++ if localGotConditionalLoadRewrite { ++ tempReg := s390xTempRegister([]string{args[0], localGotConditionalLoadBaseReg, "%r14", "%r15"}) ++ d.output.WriteString("\tlay %r15, -8(%r15)\n") ++ d.output.WriteString("\tstg\t" + tempReg + ", 0(%r15)\n") ++ d.output.WriteString("\tlg\t" + tempReg + ", 0(" + localGotConditionalLoadBaseReg + ")\n") ++ d.output.WriteString("\tlay\t" + tempReg + ", 0(" + localGotConditionalLoadBaseReg + "," + tempReg + ")\n") ++ d.output.WriteString("\t" + localGotConditionalLoadRegInstruction + "\t" + args[0] + ", " + tempReg + "\n") ++ d.output.WriteString("\tlg\t" + tempReg + ", 0(%r15)\n") ++ d.output.WriteString("\tlay %r15, 8(%r15)\n") ++ } else if localGotValueRewrite { ++ if len(args) != 2 { ++ return nil, fmt.Errorf("expected two arguments when rewriting %q", instructionName) ++ } ++ reg, slot := args[0], args[1] ++ switch instructionName { ++ case "lgrl": ++ baseReg := s390xIndexRegister([]string{reg, "%r14", "%r15"}) ++ tempReg := s390xTempRegister([]string{reg, baseReg, "%r14", "%r15"}) ++ d.output.WriteString("\tlay %r15, -16(%r15)\n") ++ d.output.WriteString("\tstg\t" + baseReg + ", 0(%r15)\n") ++ d.output.WriteString("\tstg\t" + tempReg + ", 8(%r15)\n") ++ d.output.WriteString("\tlarl\t" + baseReg + ", " + slot + "\n") ++ d.output.WriteString("\tlg\t" + tempReg + ", 0(" + baseReg + ")\n") ++ d.output.WriteString("\tlay\t" + reg + ", 0(" + baseReg + "," + tempReg + ")\n") ++ d.output.WriteString("\tlg\t" + tempReg + ", 8(%r15)\n") ++ d.output.WriteString("\tlg\t" + baseReg + ", 0(%r15)\n") ++ d.output.WriteString("\tlay %r15, 16(%r15)\n") ++ case "larl": ++ d.output.WriteString("\tlarl\t" + reg + ", " + slot + "\n") ++ case "clgrl": ++ baseReg := s390xIndexRegister([]string{reg, "%r14", "%r15"}) ++ tempReg := s390xTempRegister([]string{reg, baseReg, "%r14", "%r15"}) ++ d.output.WriteString("\tlay %r15, -16(%r15)\n") ++ d.output.WriteString("\tstg\t" + baseReg + ", 0(%r15)\n") ++ d.output.WriteString("\tstg\t" + tempReg + ", 8(%r15)\n") ++ d.output.WriteString("\tlarl\t" + baseReg + ", " + slot + "\n") ++ d.output.WriteString("\tlg\t" + tempReg + ", 0(" + baseReg + ")\n") ++ d.output.WriteString("\tlay\t" + baseReg + ", 0(" + baseReg + "," + tempReg + ")\n") ++ d.output.WriteString("\tclgr\t" + reg + ", " + baseReg + "\n") ++ d.output.WriteString("\tlg\t" + tempReg + ", 8(%r15)\n") ++ d.output.WriteString("\tlg\t" + baseReg + ", 0(%r15)\n") ++ d.output.WriteString("\tlay %r15, 16(%r15)\n") ++ default: ++ return nil, fmt.Errorf("unexpected s390x GOT rewrite instruction %q", instructionName) ++ } ++ } else if externalGotHelperRewrite { ++ if len(args) != 2 { ++ return nil, fmt.Errorf("expected two arguments when rewriting %q", instructionName) ++ } ++ reg, helper := args[0], args[1] ++ switch instructionName { ++ case "lgrl", "larl": ++ if reg == "%r2" { ++ d.output.WriteString("\tlay %r15, -8(%r15)\n") ++ d.output.WriteString("\tstg\t%r1, 0(%r15)\n") ++ d.output.WriteString("\tbrasl\t%r1, " + helper + "\n") ++ d.output.WriteString("\tlg\t%r1, 0(%r15)\n") ++ d.output.WriteString("\tlay %r15, 8(%r15)\n") ++ } else if reg == "%r1" { ++ d.output.WriteString("\tlay %r15, -8(%r15)\n") ++ d.output.WriteString("\tstg\t%r2, 0(%r15)\n") ++ d.output.WriteString("\tbrasl\t%r1, " + helper + "\n") ++ d.output.WriteString("\tlgr\t%r1, %r2\n") ++ d.output.WriteString("\tlg\t%r2, 0(%r15)\n") ++ d.output.WriteString("\tlay %r15, 8(%r15)\n") ++ } else { ++ d.output.WriteString("\tlay %r15, -16(%r15)\n") ++ d.output.WriteString("\tstg\t%r1, 0(%r15)\n") ++ d.output.WriteString("\tstg\t%r2, 8(%r15)\n") ++ d.output.WriteString("\tbrasl\t%r1, " + helper + "\n") ++ d.output.WriteString("\tlgr\t" + reg + ", %r2\n") ++ d.output.WriteString("\tlg\t%r2, 8(%r15)\n") ++ d.output.WriteString("\tlg\t%r1, 0(%r15)\n") ++ d.output.WriteString("\tlay %r15, 16(%r15)\n") ++ } ++ case "clgrl": ++ d.output.WriteString("\tlay %r15, -16(%r15)\n") ++ d.output.WriteString("\tstg\t%r1, 0(%r15)\n") ++ d.output.WriteString("\tstg\t%r2, 8(%r15)\n") ++ d.output.WriteString("\tbrasl\t%r1, " + helper + "\n") ++ switch reg { ++ case "%r2": ++ d.output.WriteString("\tlgr\t%r1, %r2\n") ++ d.output.WriteString("\tlg\t%r2, 8(%r15)\n") ++ d.output.WriteString("\tclgr\t%r2, %r1\n") ++ d.output.WriteString("\tlg\t%r1, 0(%r15)\n") ++ case "%r1": ++ d.output.WriteString("\tlg\t%r1, 0(%r15)\n") ++ d.output.WriteString("\tclgr\t%r1, %r2\n") ++ d.output.WriteString("\tlg\t%r2, 8(%r15)\n") ++ default: ++ d.output.WriteString("\tclgr\t" + reg + ", %r2\n") ++ d.output.WriteString("\tlg\t%r2, 8(%r15)\n") ++ d.output.WriteString("\tlg\t%r1, 0(%r15)\n") ++ } ++ d.output.WriteString("\tlay %r15, 16(%r15)\n") ++ default: ++ return nil, fmt.Errorf("unexpected s390x GOT helper rewrite instruction %q", instructionName) ++ } ++ } else { ++ replacement := "\t" + instructionName + "\t" + strings.Join(args, ", ") + "\n" ++ d.output.WriteString(replacement) ++ } ++ } else { ++ d.writeNode(statement) ++ } ++ ++ if len(args) > 0 && strings.HasPrefix(args[0], "%r") { ++ delete(d.s390xLocalGotSlotRegs, args[0]) ++ } ++ if trackLocalGotSlotReg && len(args) > 0 && strings.HasPrefix(args[0], "%r") { ++ d.s390xLocalGotSlotRegs[args[0]] = struct{}{} ++ } ++ ++ return statement, nil ++} ++ + /* Intel */ + + type instructionType int +@@ -2213,7 +2576,7 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe + + processor := x86_64 + if len(inputs) > 0 { +- processor = detectProcessor(inputs[0]) ++ processor = detectProcessorInputs(inputs) + } + + for _, input := range inputs { +@@ -2305,6 +2668,10 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe + gotExternalsNeeded: make(map[string]struct{}), + gotOffsetsNeeded: make(map[string]struct{}), + gotOffOffsetsNeeded: make(map[string]struct{}), ++ gotValueSymbolsNeeded: make(map[string]string), ++ s390xGotHelpersNeeded: make(map[string]s390xGotHelper), ++ s390xLocalGotSlotRegs: make(map[string]struct{}), ++ s390xExrlTargets: make(map[string]struct{}), + } + + w.WriteString(".text\n") +@@ -2392,6 +2759,12 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe + w.WriteString(".type " + redirector + ", @function\n") + w.WriteString(redirector + ":\n") + w.WriteString("\tjmp\t" + name + "\n") ++ ++ case s390x: ++ w.WriteString(".balign 2\n") ++ w.WriteString(".type " + redirector + ", @function\n") ++ w.WriteString(redirector + ":\n") ++ w.WriteString("\tjg " + name + "\n") + } + } + +@@ -2425,6 +2798,13 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe + w.WriteString("\tadd x0, x0, :lo12:" + target + "\n") + w.WriteString("\tret\n") + }) ++ ++ case s390x: ++ w.WriteString(".balign 2\n") ++ w.WriteString(".type " + funcName + ", @function\n") ++ w.WriteString(funcName + ":\n") ++ w.WriteString("\tlarl %r2, " + target + "\n") ++ w.WriteString("\tbr %r14\n") + } + } + +@@ -2465,6 +2845,34 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe + w.WriteString("\tret\n") + }) + ++ case s390x: ++ var helperNames []string ++ for helperName := range d.s390xGotHelpersNeeded { ++ helperNames = append(helperNames, helperName) ++ } ++ sort.Strings(helperNames) ++ for _, helperName := range helperNames { ++ helper := d.s390xGotHelpersNeeded[helperName] ++ w.WriteString(".balign 2\n") ++ w.WriteString(".type " + helperName + ", @function\n") ++ w.WriteString(helperName + ":\n") ++ w.WriteString("\t" + helper.instruction + " %r2, " + helper.symbol + "@" + helper.section + "\n") ++ w.WriteString("\tbr %r1\n") ++ } ++ slotNames := sortedSetMap(d.gotValueSymbolsNeeded) ++ for _, slotName := range slotNames { ++ target := d.gotValueSymbolsNeeded[slotName] ++ // Keep the slot in .text so PC-relative references are fully resolved ++ // before inject_hash computes the FIPS module hash. Encode the target as ++ // a PC-relative delta so the slot avoids an absolute R_390_64 relocation ++ // in .text, which ld.lld rejects for PIC consumers. ++ w.WriteString(".balign 8\n") ++ w.WriteString(".type " + slotName + ", @object\n") ++ w.WriteString(".size " + slotName + ", 8\n") ++ w.WriteString(slotName + ":\n") ++ w.WriteString("\t.quad " + target + "-" + slotName + "\n") ++ } ++ + case x86_64: + externalNames := sortedSet(d.gotExternalsNeeded) + for _, name := range externalNames { +@@ -2510,6 +2918,7 @@ func transform(w stringWriter, includes []string, inputs []inputFile, startEndDe + w.WriteString(".Lboringssl_gotoff_" + name + ":\n") + w.WriteString("\t.quad " + name + "@GOTOFF\n") + } ++ + } + + return nil +@@ -2885,7 +3294,7 @@ func (d *delocation) mapLocalSymbol(symbol string) string { + return symbol + "_BCM_" + strconv.Itoa(d.currentInput.index) + } + +-func detectProcessor(input inputFile) processorType { ++func detectProcessor(input inputFile) (processorType, bool) { + for statement := input.ast.up; statement != nil; statement = statement.next { + node := skipNodes(statement.up, ruleWS) + if node == nil || node.pegRule != ruleInstruction { +@@ -2897,15 +3306,40 @@ func detectProcessor(input inputFile) processorType { + + switch instructionName { + case "movq", "call", "leaq": +- return x86_64 ++ return x86_64, true + case "addis", "addi", "mflr": +- return ppc64le ++ return ppc64le, true + case "str", "bl", "ldr", "st1": +- return aarch64 ++ return aarch64, true ++ case "larl", "brasl", "lgrl", "stg", "exrl": ++ return s390x, true ++ } ++ } ++ ++ return x86_64, false ++} ++ ++func detectProcessorInputs(inputs []inputFile) processorType { ++ for _, input := range inputs { ++ if processor, ok := detectProcessor(input); ok { ++ return processor ++ } ++ } ++ ++ paths := make([]string, 0, len(inputs)) ++ for i, input := range inputs { ++ if i == 4 { ++ paths = append(paths, "...") ++ break + } ++ paths = append(paths, input.path) + } + +- panic("processed entire input and didn't recognise any instructions.") ++ panic(fmt.Sprintf( ++ "processed %d inputs and didn't recognise any instructions (sample inputs: %s)", ++ len(inputs), ++ strings.Join(paths, ", "), ++ )) + } + + func sortedSet(m map[string]struct{}) []string { +@@ -2916,3 +3350,12 @@ func sortedSet(m map[string]struct{}) []string { + sort.Strings(ret) + return ret + } ++ ++func sortedSetMap(m map[string]string) []string { ++ ret := make([]string, 0, len(m)) ++ for key := range m { ++ ret = append(ret, key) ++ } ++ sort.Strings(ret) ++ return ret ++} +diff --git a/util/fipstools/delocate/delocate.peg b/util/fipstools/delocate/delocate.peg +index 762f1d2..f2d5381 100644 +--- a/util/fipstools/delocate/delocate.peg ++++ b/util/fipstools/delocate/delocate.peg +@@ -107,7 +107,9 @@ MemoryRef <- (SymbolRef BaseIndexScale / + SegmentRegister Offset / + ARMBaseIndexScale / + BaseIndexScale) +-SymbolRef <- (Offset* '+')? (LocalSymbol / SymbolName) Offset* ('@' Section Offset*)? ++SymbolRef <- (Offset* '+')? (LocalSymbol / SymbolName) SymbolOffset* ('@' Section SymbolOffset*)? ++SymbolOffset <- Offset / SymbolDelta ++SymbolDelta <- [+\-] (LocalSymbol / SymbolName) + Low12BitsSymbolRef <- ":lo12:" (LocalSymbol / SymbolName) Offset? + ARMBaseIndexScale <- '[' ARMRegister (',' WS? (('#'? Offset (('*' [0-9]+) / ('*' '(' [0-9]+ Operator [0-9]+ ')') / (('+' [0-9]+)*))? ) / ('#'? ARMGOTLow12) / ('#'? Low12BitsSymbolRef) / ARMRegister) (',' WS? ARMConstantTweak)?)? ']' ARMPostincrement? + ARMGOTLow12 <- ":got_lo12:" SymbolName +@@ -122,9 +124,10 @@ S2nBignumHelper <- '(' [0-9]+ WS? OffsetOperator WS? [0-9]+ ')' WS? OffsetOperat + Offset <- '+'? '-'? (("0b" [01]+) / + ("0x" [[0-9A-F]]+) / + ([0-9]+ WS OffsetOperator [0-9]+ / +- [0-9]+ ( OffsetOperator '(' [0-9]+ OffsetOperator [0-9]+ ')' )? / +- [0-9]+ ( OffsetOperator [0-9]+ OffsetOperator [0-9]+ )? / +- [0-9]+ ( OffsetOperator [0-9]+ )? / ++ [0-9]+ OffsetOperator '(' [0-9]+ OffsetOperator [0-9]+ ')' / ++ [0-9]+ OffsetOperator [0-9]+ OffsetOperator [0-9]+ / ++ [0-9]+ OffsetOperator [0-9]+ / ++ [0-9]+ / + S2nBignumHelper S2nBignumHelper (S2nBignumHelper ([0-9]+ OffsetOperator)? [0-9]+ OffsetOperator)? [0-9]+ / + S2nBignumHelper [0-9]+ ((WS? OffsetOperator [0-9]+ (WS? OffsetOperator [0-9]+)?) / (!'x')) / + S2nBignumHelper / +diff --git a/util/fipstools/delocate/delocate.peg.go b/util/fipstools/delocate/delocate.peg.go +index d9e804f..eb8c8aa 100644 +--- a/util/fipstools/delocate/delocate.peg.go ++++ b/util/fipstools/delocate/delocate.peg.go +@@ -1,6 +1,6 @@ + package main + +-// Code generated by /Users/justsmth/go/bin/peg delocate.peg DO NOT EDIT. ++// Code generated by /Users/kaitlyndavis/go/bin/peg util/fipstools/delocate/delocate.peg DO NOT EDIT. + + import ( + "fmt" +@@ -68,6 +68,8 @@ const ( + ruleARMRegisterBoundary + ruleMemoryRef + ruleSymbolRef ++ ruleSymbolOffset ++ ruleSymbolDelta + ruleLow12BitsSymbolRef + ruleARMBaseIndexScale + ruleARMGOTLow12 +@@ -133,6 +135,8 @@ var rul3s = [...]string{ + "ARMRegisterBoundary", + "MemoryRef", + "SymbolRef", ++ "SymbolOffset", ++ "SymbolDelta", + "Low12BitsSymbolRef", + "ARMBaseIndexScale", + "ARMGOTLow12", +@@ -258,7 +262,7 @@ func (t *tokens32) Tokens() []token32 { + type Asm struct { + Buffer string + buffer []rune +- rules [62]func() bool ++ rules [64]func() bool + parse func(rule ...int) error + reset func() + Pretty bool +@@ -6568,7 +6572,7 @@ func (p *Asm) Init(options ...func(*Asm) error) error { + position, tokenIndex = position835, tokenIndex835 + return false + }, +- /* 49 SymbolRef <- <((Offset* '+')? (LocalSymbol / SymbolName) Offset* ('@' Section Offset*)?)> */ ++ /* 49 SymbolRef <- <((Offset* '+')? (LocalSymbol / SymbolName) SymbolOffset* ('@' Section SymbolOffset*)?)> */ + func() bool { + position848, tokenIndex848 := position, tokenIndex + { +@@ -6610,7 +6614,7 @@ func (p *Asm) Init(options ...func(*Asm) error) error { + l856: + { + position857, tokenIndex857 := position, tokenIndex +- if !_rules[ruleOffset]() { ++ if !_rules[ruleSymbolOffset]() { + goto l857 + } + goto l856 +@@ -6629,7 +6633,7 @@ func (p *Asm) Init(options ...func(*Asm) error) error { + l860: + { + position861, tokenIndex861 := position, tokenIndex +- if !_rules[ruleOffset]() { ++ if !_rules[ruleSymbolOffset]() { + goto l861 + } + goto l860 +@@ -6648,1532 +6652,1594 @@ func (p *Asm) Init(options ...func(*Asm) error) error { + position, tokenIndex = position848, tokenIndex848 + return false + }, +- /* 50 Low12BitsSymbolRef <- <(':' ('l' / 'L') ('o' / 'O') '1' '2' ':' (LocalSymbol / SymbolName) Offset?)> */ ++ /* 50 SymbolOffset <- <(Offset / SymbolDelta)> */ + func() bool { + position862, tokenIndex862 := position, tokenIndex + { + position863 := position +- if buffer[position] != rune(':') { +- goto l862 +- } +- position++ + { + position864, tokenIndex864 := position, tokenIndex +- if buffer[position] != rune('l') { ++ if !_rules[ruleOffset]() { + goto l865 + } +- position++ + goto l864 + l865: + position, tokenIndex = position864, tokenIndex864 +- if buffer[position] != rune('L') { ++ if !_rules[ruleSymbolDelta]() { + goto l862 + } +- position++ + } + l864: ++ add(ruleSymbolOffset, position863) ++ } ++ return true ++ l862: ++ position, tokenIndex = position862, tokenIndex862 ++ return false ++ }, ++ /* 51 SymbolDelta <- <(('+' / '-') (LocalSymbol / SymbolName))> */ ++ func() bool { ++ position866, tokenIndex866 := position, tokenIndex ++ { ++ position867 := position ++ { ++ position868, tokenIndex868 := position, tokenIndex ++ if buffer[position] != rune('+') { ++ goto l869 ++ } ++ position++ ++ goto l868 ++ l869: ++ position, tokenIndex = position868, tokenIndex868 ++ if buffer[position] != rune('-') { ++ goto l866 ++ } ++ position++ ++ } ++ l868: ++ { ++ position870, tokenIndex870 := position, tokenIndex ++ if !_rules[ruleLocalSymbol]() { ++ goto l871 ++ } ++ goto l870 ++ l871: ++ position, tokenIndex = position870, tokenIndex870 ++ if !_rules[ruleSymbolName]() { ++ goto l866 ++ } ++ } ++ l870: ++ add(ruleSymbolDelta, position867) ++ } ++ return true ++ l866: ++ position, tokenIndex = position866, tokenIndex866 ++ return false ++ }, ++ /* 52 Low12BitsSymbolRef <- <(':' ('l' / 'L') ('o' / 'O') '1' '2' ':' (LocalSymbol / SymbolName) Offset?)> */ ++ func() bool { ++ position872, tokenIndex872 := position, tokenIndex ++ { ++ position873 := position ++ if buffer[position] != rune(':') { ++ goto l872 ++ } ++ position++ ++ { ++ position874, tokenIndex874 := position, tokenIndex ++ if buffer[position] != rune('l') { ++ goto l875 ++ } ++ position++ ++ goto l874 ++ l875: ++ position, tokenIndex = position874, tokenIndex874 ++ if buffer[position] != rune('L') { ++ goto l872 ++ } ++ position++ ++ } ++ l874: + { +- position866, tokenIndex866 := position, tokenIndex ++ position876, tokenIndex876 := position, tokenIndex + if buffer[position] != rune('o') { +- goto l867 ++ goto l877 + } + position++ +- goto l866 +- l867: +- position, tokenIndex = position866, tokenIndex866 ++ goto l876 ++ l877: ++ position, tokenIndex = position876, tokenIndex876 + if buffer[position] != rune('O') { +- goto l862 ++ goto l872 + } + position++ + } +- l866: ++ l876: + if buffer[position] != rune('1') { +- goto l862 ++ goto l872 + } + position++ + if buffer[position] != rune('2') { +- goto l862 ++ goto l872 + } + position++ + if buffer[position] != rune(':') { +- goto l862 ++ goto l872 + } + position++ + { +- position868, tokenIndex868 := position, tokenIndex ++ position878, tokenIndex878 := position, tokenIndex + if !_rules[ruleLocalSymbol]() { +- goto l869 ++ goto l879 + } +- goto l868 +- l869: +- position, tokenIndex = position868, tokenIndex868 ++ goto l878 ++ l879: ++ position, tokenIndex = position878, tokenIndex878 + if !_rules[ruleSymbolName]() { +- goto l862 ++ goto l872 + } + } +- l868: ++ l878: + { +- position870, tokenIndex870 := position, tokenIndex ++ position880, tokenIndex880 := position, tokenIndex + if !_rules[ruleOffset]() { +- goto l870 ++ goto l880 + } +- goto l871 +- l870: +- position, tokenIndex = position870, tokenIndex870 ++ goto l881 ++ l880: ++ position, tokenIndex = position880, tokenIndex880 + } +- l871: +- add(ruleLow12BitsSymbolRef, position863) ++ l881: ++ add(ruleLow12BitsSymbolRef, position873) + } + return true +- l862: +- position, tokenIndex = position862, tokenIndex862 ++ l872: ++ position, tokenIndex = position872, tokenIndex872 + return false + }, +- /* 51 ARMBaseIndexScale <- <('[' ARMRegister (',' WS? (('#'? Offset (('*' [0-9]+) / ('*' '(' [0-9]+ Operator [0-9]+ ')') / ('+' [0-9]+)*)?) / ('#'? ARMGOTLow12) / ('#'? Low12BitsSymbolRef) / ARMRegister) (',' WS? ARMConstantTweak)?)? ']' ARMPostincrement?)> */ ++ /* 53 ARMBaseIndexScale <- <('[' ARMRegister (',' WS? (('#'? Offset (('*' [0-9]+) / ('*' '(' [0-9]+ Operator [0-9]+ ')') / ('+' [0-9]+)*)?) / ('#'? ARMGOTLow12) / ('#'? Low12BitsSymbolRef) / ARMRegister) (',' WS? ARMConstantTweak)?)? ']' ARMPostincrement?)> */ + func() bool { +- position872, tokenIndex872 := position, tokenIndex ++ position882, tokenIndex882 := position, tokenIndex + { +- position873 := position ++ position883 := position + if buffer[position] != rune('[') { +- goto l872 ++ goto l882 + } + position++ + if !_rules[ruleARMRegister]() { +- goto l872 ++ goto l882 + } + { +- position874, tokenIndex874 := position, tokenIndex ++ position884, tokenIndex884 := position, tokenIndex + if buffer[position] != rune(',') { +- goto l874 ++ goto l884 + } + position++ + { +- position876, tokenIndex876 := position, tokenIndex ++ position886, tokenIndex886 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l876 ++ goto l886 + } +- goto l877 +- l876: +- position, tokenIndex = position876, tokenIndex876 ++ goto l887 ++ l886: ++ position, tokenIndex = position886, tokenIndex886 + } +- l877: ++ l887: + { +- position878, tokenIndex878 := position, tokenIndex ++ position888, tokenIndex888 := position, tokenIndex + { +- position880, tokenIndex880 := position, tokenIndex ++ position890, tokenIndex890 := position, tokenIndex + if buffer[position] != rune('#') { +- goto l880 ++ goto l890 + } + position++ +- goto l881 +- l880: +- position, tokenIndex = position880, tokenIndex880 ++ goto l891 ++ l890: ++ position, tokenIndex = position890, tokenIndex890 + } +- l881: ++ l891: + if !_rules[ruleOffset]() { +- goto l879 ++ goto l889 + } + { +- position882, tokenIndex882 := position, tokenIndex ++ position892, tokenIndex892 := position, tokenIndex + { +- position884, tokenIndex884 := position, tokenIndex ++ position894, tokenIndex894 := position, tokenIndex + if buffer[position] != rune('*') { +- goto l885 ++ goto l895 + } + position++ + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l885 ++ goto l895 + } + position++ +- l886: ++ l896: + { +- position887, tokenIndex887 := position, tokenIndex ++ position897, tokenIndex897 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l887 ++ goto l897 + } + position++ +- goto l886 +- l887: +- position, tokenIndex = position887, tokenIndex887 ++ goto l896 ++ l897: ++ position, tokenIndex = position897, tokenIndex897 + } +- goto l884 +- l885: +- position, tokenIndex = position884, tokenIndex884 ++ goto l894 ++ l895: ++ position, tokenIndex = position894, tokenIndex894 + if buffer[position] != rune('*') { +- goto l888 ++ goto l898 + } + position++ + if buffer[position] != rune('(') { +- goto l888 ++ goto l898 + } + position++ + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l888 ++ goto l898 + } + position++ +- l889: ++ l899: + { +- position890, tokenIndex890 := position, tokenIndex ++ position900, tokenIndex900 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l890 ++ goto l900 + } + position++ +- goto l889 +- l890: +- position, tokenIndex = position890, tokenIndex890 ++ goto l899 ++ l900: ++ position, tokenIndex = position900, tokenIndex900 + } + if !_rules[ruleOperator]() { +- goto l888 ++ goto l898 + } + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l888 ++ goto l898 + } + position++ +- l891: ++ l901: + { +- position892, tokenIndex892 := position, tokenIndex ++ position902, tokenIndex902 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l892 ++ goto l902 + } + position++ +- goto l891 +- l892: +- position, tokenIndex = position892, tokenIndex892 ++ goto l901 ++ l902: ++ position, tokenIndex = position902, tokenIndex902 + } + if buffer[position] != rune(')') { +- goto l888 ++ goto l898 + } + position++ +- goto l884 +- l888: +- position, tokenIndex = position884, tokenIndex884 +- l893: ++ goto l894 ++ l898: ++ position, tokenIndex = position894, tokenIndex894 ++ l903: + { +- position894, tokenIndex894 := position, tokenIndex ++ position904, tokenIndex904 := position, tokenIndex + if buffer[position] != rune('+') { +- goto l894 ++ goto l904 + } + position++ + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l894 ++ goto l904 + } + position++ +- l895: ++ l905: + { +- position896, tokenIndex896 := position, tokenIndex ++ position906, tokenIndex906 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l896 ++ goto l906 + } + position++ +- goto l895 +- l896: +- position, tokenIndex = position896, tokenIndex896 ++ goto l905 ++ l906: ++ position, tokenIndex = position906, tokenIndex906 + } +- goto l893 +- l894: +- position, tokenIndex = position894, tokenIndex894 ++ goto l903 ++ l904: ++ position, tokenIndex = position904, tokenIndex904 + } + } +- l884: +- goto l883 ++ l894: ++ goto l893 + +- position, tokenIndex = position882, tokenIndex882 ++ position, tokenIndex = position892, tokenIndex892 + } +- l883: +- goto l878 +- l879: +- position, tokenIndex = position878, tokenIndex878 ++ l893: ++ goto l888 ++ l889: ++ position, tokenIndex = position888, tokenIndex888 + { +- position898, tokenIndex898 := position, tokenIndex ++ position908, tokenIndex908 := position, tokenIndex + if buffer[position] != rune('#') { +- goto l898 ++ goto l908 + } + position++ +- goto l899 +- l898: +- position, tokenIndex = position898, tokenIndex898 ++ goto l909 ++ l908: ++ position, tokenIndex = position908, tokenIndex908 + } +- l899: ++ l909: + if !_rules[ruleARMGOTLow12]() { +- goto l897 ++ goto l907 + } +- goto l878 +- l897: +- position, tokenIndex = position878, tokenIndex878 ++ goto l888 ++ l907: ++ position, tokenIndex = position888, tokenIndex888 + { +- position901, tokenIndex901 := position, tokenIndex ++ position911, tokenIndex911 := position, tokenIndex + if buffer[position] != rune('#') { +- goto l901 ++ goto l911 + } + position++ +- goto l902 +- l901: +- position, tokenIndex = position901, tokenIndex901 ++ goto l912 ++ l911: ++ position, tokenIndex = position911, tokenIndex911 + } +- l902: ++ l912: + if !_rules[ruleLow12BitsSymbolRef]() { +- goto l900 ++ goto l910 + } +- goto l878 +- l900: +- position, tokenIndex = position878, tokenIndex878 ++ goto l888 ++ l910: ++ position, tokenIndex = position888, tokenIndex888 + if !_rules[ruleARMRegister]() { +- goto l874 ++ goto l884 + } + } +- l878: ++ l888: + { +- position903, tokenIndex903 := position, tokenIndex ++ position913, tokenIndex913 := position, tokenIndex + if buffer[position] != rune(',') { +- goto l903 ++ goto l913 + } + position++ + { +- position905, tokenIndex905 := position, tokenIndex ++ position915, tokenIndex915 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l905 ++ goto l915 + } +- goto l906 +- l905: +- position, tokenIndex = position905, tokenIndex905 ++ goto l916 ++ l915: ++ position, tokenIndex = position915, tokenIndex915 + } +- l906: ++ l916: + if !_rules[ruleARMConstantTweak]() { +- goto l903 ++ goto l913 + } +- goto l904 +- l903: +- position, tokenIndex = position903, tokenIndex903 ++ goto l914 ++ l913: ++ position, tokenIndex = position913, tokenIndex913 + } +- l904: +- goto l875 +- l874: +- position, tokenIndex = position874, tokenIndex874 ++ l914: ++ goto l885 ++ l884: ++ position, tokenIndex = position884, tokenIndex884 + } +- l875: ++ l885: + if buffer[position] != rune(']') { +- goto l872 ++ goto l882 + } + position++ + { +- position907, tokenIndex907 := position, tokenIndex ++ position917, tokenIndex917 := position, tokenIndex + if !_rules[ruleARMPostincrement]() { +- goto l907 ++ goto l917 + } +- goto l908 +- l907: +- position, tokenIndex = position907, tokenIndex907 ++ goto l918 ++ l917: ++ position, tokenIndex = position917, tokenIndex917 + } +- l908: +- add(ruleARMBaseIndexScale, position873) ++ l918: ++ add(ruleARMBaseIndexScale, position883) + } + return true +- l872: +- position, tokenIndex = position872, tokenIndex872 ++ l882: ++ position, tokenIndex = position882, tokenIndex882 + return false + }, +- /* 52 ARMGOTLow12 <- <(':' ('g' / 'G') ('o' / 'O') ('t' / 'T') '_' ('l' / 'L') ('o' / 'O') '1' '2' ':' SymbolName)> */ ++ /* 54 ARMGOTLow12 <- <(':' ('g' / 'G') ('o' / 'O') ('t' / 'T') '_' ('l' / 'L') ('o' / 'O') '1' '2' ':' SymbolName)> */ + func() bool { +- position909, tokenIndex909 := position, tokenIndex ++ position919, tokenIndex919 := position, tokenIndex + { +- position910 := position ++ position920 := position + if buffer[position] != rune(':') { +- goto l909 ++ goto l919 + } + position++ + { +- position911, tokenIndex911 := position, tokenIndex ++ position921, tokenIndex921 := position, tokenIndex + if buffer[position] != rune('g') { +- goto l912 ++ goto l922 + } + position++ +- goto l911 +- l912: +- position, tokenIndex = position911, tokenIndex911 ++ goto l921 ++ l922: ++ position, tokenIndex = position921, tokenIndex921 + if buffer[position] != rune('G') { +- goto l909 ++ goto l919 + } + position++ + } +- l911: ++ l921: + { +- position913, tokenIndex913 := position, tokenIndex ++ position923, tokenIndex923 := position, tokenIndex + if buffer[position] != rune('o') { +- goto l914 ++ goto l924 + } + position++ +- goto l913 +- l914: +- position, tokenIndex = position913, tokenIndex913 ++ goto l923 ++ l924: ++ position, tokenIndex = position923, tokenIndex923 + if buffer[position] != rune('O') { +- goto l909 ++ goto l919 + } + position++ + } +- l913: ++ l923: + { +- position915, tokenIndex915 := position, tokenIndex ++ position925, tokenIndex925 := position, tokenIndex + if buffer[position] != rune('t') { +- goto l916 ++ goto l926 + } + position++ +- goto l915 +- l916: +- position, tokenIndex = position915, tokenIndex915 ++ goto l925 ++ l926: ++ position, tokenIndex = position925, tokenIndex925 + if buffer[position] != rune('T') { +- goto l909 ++ goto l919 + } + position++ + } +- l915: ++ l925: + if buffer[position] != rune('_') { +- goto l909 ++ goto l919 + } + position++ + { +- position917, tokenIndex917 := position, tokenIndex ++ position927, tokenIndex927 := position, tokenIndex + if buffer[position] != rune('l') { +- goto l918 ++ goto l928 + } + position++ +- goto l917 +- l918: +- position, tokenIndex = position917, tokenIndex917 ++ goto l927 ++ l928: ++ position, tokenIndex = position927, tokenIndex927 + if buffer[position] != rune('L') { +- goto l909 ++ goto l919 + } + position++ + } +- l917: ++ l927: + { +- position919, tokenIndex919 := position, tokenIndex ++ position929, tokenIndex929 := position, tokenIndex + if buffer[position] != rune('o') { +- goto l920 ++ goto l930 + } + position++ +- goto l919 +- l920: +- position, tokenIndex = position919, tokenIndex919 ++ goto l929 ++ l930: ++ position, tokenIndex = position929, tokenIndex929 + if buffer[position] != rune('O') { +- goto l909 ++ goto l919 + } + position++ + } +- l919: ++ l929: + if buffer[position] != rune('1') { +- goto l909 ++ goto l919 + } + position++ + if buffer[position] != rune('2') { +- goto l909 ++ goto l919 + } + position++ + if buffer[position] != rune(':') { +- goto l909 ++ goto l919 + } + position++ + if !_rules[ruleSymbolName]() { +- goto l909 ++ goto l919 + } +- add(ruleARMGOTLow12, position910) ++ add(ruleARMGOTLow12, position920) + } + return true +- l909: +- position, tokenIndex = position909, tokenIndex909 ++ l919: ++ position, tokenIndex = position919, tokenIndex919 + return false + }, +- /* 53 ARMPostincrement <- <'!'> */ ++ /* 55 ARMPostincrement <- <'!'> */ + func() bool { +- position921, tokenIndex921 := position, tokenIndex ++ position931, tokenIndex931 := position, tokenIndex + { +- position922 := position ++ position932 := position + if buffer[position] != rune('!') { +- goto l921 ++ goto l931 + } + position++ +- add(ruleARMPostincrement, position922) ++ add(ruleARMPostincrement, position932) + } + return true +- l921: +- position, tokenIndex = position921, tokenIndex921 ++ l931: ++ position, tokenIndex = position931, tokenIndex931 + return false + }, +- /* 54 BaseIndexScale <- <('(' RegisterOrConstant? WS? (',' WS? RegisterOrConstant WS? (',' [0-9]+)?)? ')')> */ ++ /* 56 BaseIndexScale <- <('(' RegisterOrConstant? WS? (',' WS? RegisterOrConstant WS? (',' [0-9]+)?)? ')')> */ + func() bool { +- position923, tokenIndex923 := position, tokenIndex ++ position933, tokenIndex933 := position, tokenIndex + { +- position924 := position ++ position934 := position + if buffer[position] != rune('(') { +- goto l923 ++ goto l933 + } + position++ + { +- position925, tokenIndex925 := position, tokenIndex ++ position935, tokenIndex935 := position, tokenIndex + if !_rules[ruleRegisterOrConstant]() { +- goto l925 ++ goto l935 + } +- goto l926 +- l925: +- position, tokenIndex = position925, tokenIndex925 ++ goto l936 ++ l935: ++ position, tokenIndex = position935, tokenIndex935 + } +- l926: ++ l936: + { +- position927, tokenIndex927 := position, tokenIndex ++ position937, tokenIndex937 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l927 ++ goto l937 + } +- goto l928 +- l927: +- position, tokenIndex = position927, tokenIndex927 ++ goto l938 ++ l937: ++ position, tokenIndex = position937, tokenIndex937 + } +- l928: ++ l938: + { +- position929, tokenIndex929 := position, tokenIndex ++ position939, tokenIndex939 := position, tokenIndex + if buffer[position] != rune(',') { +- goto l929 ++ goto l939 + } + position++ + { +- position931, tokenIndex931 := position, tokenIndex ++ position941, tokenIndex941 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l931 ++ goto l941 + } +- goto l932 +- l931: +- position, tokenIndex = position931, tokenIndex931 ++ goto l942 ++ l941: ++ position, tokenIndex = position941, tokenIndex941 + } +- l932: ++ l942: + if !_rules[ruleRegisterOrConstant]() { +- goto l929 ++ goto l939 + } + { +- position933, tokenIndex933 := position, tokenIndex ++ position943, tokenIndex943 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l933 ++ goto l943 + } +- goto l934 +- l933: +- position, tokenIndex = position933, tokenIndex933 ++ goto l944 ++ l943: ++ position, tokenIndex = position943, tokenIndex943 + } +- l934: ++ l944: + { +- position935, tokenIndex935 := position, tokenIndex ++ position945, tokenIndex945 := position, tokenIndex + if buffer[position] != rune(',') { +- goto l935 ++ goto l945 + } + position++ + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l935 ++ goto l945 + } + position++ +- l937: ++ l947: + { +- position938, tokenIndex938 := position, tokenIndex ++ position948, tokenIndex948 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l938 ++ goto l948 + } + position++ +- goto l937 +- l938: +- position, tokenIndex = position938, tokenIndex938 ++ goto l947 ++ l948: ++ position, tokenIndex = position948, tokenIndex948 + } +- goto l936 +- l935: +- position, tokenIndex = position935, tokenIndex935 ++ goto l946 ++ l945: ++ position, tokenIndex = position945, tokenIndex945 + } +- l936: +- goto l930 +- l929: +- position, tokenIndex = position929, tokenIndex929 ++ l946: ++ goto l940 ++ l939: ++ position, tokenIndex = position939, tokenIndex939 + } +- l930: ++ l940: + if buffer[position] != rune(')') { +- goto l923 ++ goto l933 + } + position++ +- add(ruleBaseIndexScale, position924) ++ add(ruleBaseIndexScale, position934) + } + return true +- l923: +- position, tokenIndex = position923, tokenIndex923 ++ l933: ++ position, tokenIndex = position933, tokenIndex933 + return false + }, +- /* 55 Operator <- <('+' / '-')> */ ++ /* 57 Operator <- <('+' / '-')> */ + func() bool { +- position939, tokenIndex939 := position, tokenIndex ++ position949, tokenIndex949 := position, tokenIndex + { +- position940 := position ++ position950 := position + { +- position941, tokenIndex941 := position, tokenIndex ++ position951, tokenIndex951 := position, tokenIndex + if buffer[position] != rune('+') { +- goto l942 ++ goto l952 + } + position++ +- goto l941 +- l942: +- position, tokenIndex = position941, tokenIndex941 ++ goto l951 ++ l952: ++ position, tokenIndex = position951, tokenIndex951 + if buffer[position] != rune('-') { +- goto l939 ++ goto l949 + } + position++ + } +- l941: +- add(ruleOperator, position940) ++ l951: ++ add(ruleOperator, position950) + } + return true +- l939: +- position, tokenIndex = position939, tokenIndex939 ++ l949: ++ position, tokenIndex = position949, tokenIndex949 + return false + }, +- /* 56 OffsetOperator <- <('+' / '-' / '*')> */ ++ /* 58 OffsetOperator <- <('+' / '-' / '*')> */ + func() bool { +- position943, tokenIndex943 := position, tokenIndex ++ position953, tokenIndex953 := position, tokenIndex + { +- position944 := position ++ position954 := position + { +- position945, tokenIndex945 := position, tokenIndex ++ position955, tokenIndex955 := position, tokenIndex + if buffer[position] != rune('+') { +- goto l946 ++ goto l956 + } + position++ +- goto l945 +- l946: +- position, tokenIndex = position945, tokenIndex945 ++ goto l955 ++ l956: ++ position, tokenIndex = position955, tokenIndex955 + if buffer[position] != rune('-') { +- goto l947 ++ goto l957 + } + position++ +- goto l945 +- l947: +- position, tokenIndex = position945, tokenIndex945 ++ goto l955 ++ l957: ++ position, tokenIndex = position955, tokenIndex955 + if buffer[position] != rune('*') { +- goto l943 ++ goto l953 + } + position++ + } +- l945: +- add(ruleOffsetOperator, position944) ++ l955: ++ add(ruleOffsetOperator, position954) + } + return true +- l943: +- position, tokenIndex = position943, tokenIndex943 ++ l953: ++ position, tokenIndex = position953, tokenIndex953 + return false + }, +- /* 57 S2nBignumHelper <- <('(' [0-9]+ WS? OffsetOperator WS? [0-9]+ ')' WS? OffsetOperator? WS?)> */ ++ /* 59 S2nBignumHelper <- <('(' [0-9]+ WS? OffsetOperator WS? [0-9]+ ')' WS? OffsetOperator? WS?)> */ + func() bool { +- position948, tokenIndex948 := position, tokenIndex ++ position958, tokenIndex958 := position, tokenIndex + { +- position949 := position ++ position959 := position + if buffer[position] != rune('(') { +- goto l948 ++ goto l958 + } + position++ + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l948 ++ goto l958 + } + position++ +- l950: ++ l960: + { +- position951, tokenIndex951 := position, tokenIndex ++ position961, tokenIndex961 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l951 ++ goto l961 + } + position++ +- goto l950 +- l951: +- position, tokenIndex = position951, tokenIndex951 ++ goto l960 ++ l961: ++ position, tokenIndex = position961, tokenIndex961 + } + { +- position952, tokenIndex952 := position, tokenIndex ++ position962, tokenIndex962 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l952 ++ goto l962 + } +- goto l953 +- l952: +- position, tokenIndex = position952, tokenIndex952 ++ goto l963 ++ l962: ++ position, tokenIndex = position962, tokenIndex962 + } +- l953: ++ l963: + if !_rules[ruleOffsetOperator]() { +- goto l948 ++ goto l958 + } + { +- position954, tokenIndex954 := position, tokenIndex ++ position964, tokenIndex964 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l954 ++ goto l964 + } +- goto l955 +- l954: +- position, tokenIndex = position954, tokenIndex954 ++ goto l965 ++ l964: ++ position, tokenIndex = position964, tokenIndex964 + } +- l955: ++ l965: + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l948 ++ goto l958 + } + position++ +- l956: ++ l966: + { +- position957, tokenIndex957 := position, tokenIndex ++ position967, tokenIndex967 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l957 ++ goto l967 + } + position++ +- goto l956 +- l957: +- position, tokenIndex = position957, tokenIndex957 ++ goto l966 ++ l967: ++ position, tokenIndex = position967, tokenIndex967 + } + if buffer[position] != rune(')') { +- goto l948 ++ goto l958 + } + position++ + { +- position958, tokenIndex958 := position, tokenIndex ++ position968, tokenIndex968 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l958 ++ goto l968 + } +- goto l959 +- l958: +- position, tokenIndex = position958, tokenIndex958 ++ goto l969 ++ l968: ++ position, tokenIndex = position968, tokenIndex968 + } +- l959: ++ l969: + { +- position960, tokenIndex960 := position, tokenIndex ++ position970, tokenIndex970 := position, tokenIndex + if !_rules[ruleOffsetOperator]() { +- goto l960 ++ goto l970 + } +- goto l961 +- l960: +- position, tokenIndex = position960, tokenIndex960 ++ goto l971 ++ l970: ++ position, tokenIndex = position970, tokenIndex970 + } +- l961: ++ l971: + { +- position962, tokenIndex962 := position, tokenIndex ++ position972, tokenIndex972 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l962 ++ goto l972 + } +- goto l963 +- l962: +- position, tokenIndex = position962, tokenIndex962 ++ goto l973 ++ l972: ++ position, tokenIndex = position972, tokenIndex972 + } +- l963: +- add(ruleS2nBignumHelper, position949) ++ l973: ++ add(ruleS2nBignumHelper, position959) + } + return true +- l948: +- position, tokenIndex = position948, tokenIndex948 ++ l958: ++ position, tokenIndex = position958, tokenIndex958 + return false + }, +- /* 58 Offset <- <('+'? '-'? (('0' ('b' / 'B') ('0' / '1')+) / ('0' ('x' / 'X') ([0-9] / [0-9] / ([a-f] / [A-F]))+) / ((([0-9]+ WS OffsetOperator [0-9]+) / ([0-9]+ (OffsetOperator '(' [0-9]+ OffsetOperator [0-9]+ ')')?) / ([0-9]+ (OffsetOperator [0-9]+ OffsetOperator [0-9]+)?) / ([0-9]+ (OffsetOperator [0-9]+)?) / (S2nBignumHelper S2nBignumHelper (S2nBignumHelper ([0-9]+ OffsetOperator)? [0-9]+ OffsetOperator)? [0-9]+) / (S2nBignumHelper [0-9]+ ((WS? OffsetOperator [0-9]+ (WS? OffsetOperator [0-9]+)?) / !'x')) / S2nBignumHelper / ('(' [0-9]+ WS? OffsetOperator WS? [0-9]+ WS? OffsetOperator WS? [0-9]+ ')')) !([a-z] / [A-Z]))))> */ ++ /* 60 Offset <- <('+'? '-'? (('0' ('b' / 'B') ('0' / '1')+) / ('0' ('x' / 'X') ([0-9] / [0-9] / ([a-f] / [A-F]))+) / ((([0-9]+ WS OffsetOperator [0-9]+) / ([0-9]+ OffsetOperator '(' [0-9]+ OffsetOperator [0-9]+ ')') / ([0-9]+ OffsetOperator [0-9]+ OffsetOperator [0-9]+) / ([0-9]+ OffsetOperator [0-9]+) / [0-9]+ / (S2nBignumHelper S2nBignumHelper (S2nBignumHelper ([0-9]+ OffsetOperator)? [0-9]+ OffsetOperator)? [0-9]+) / (S2nBignumHelper [0-9]+ ((WS? OffsetOperator [0-9]+ (WS? OffsetOperator [0-9]+)?) / !'x')) / S2nBignumHelper / ('(' [0-9]+ WS? OffsetOperator WS? [0-9]+ WS? OffsetOperator WS? [0-9]+ ')')) !([a-z] / [A-Z]))))> */ + func() bool { +- position964, tokenIndex964 := position, tokenIndex ++ position974, tokenIndex974 := position, tokenIndex + { +- position965 := position ++ position975 := position + { +- position966, tokenIndex966 := position, tokenIndex ++ position976, tokenIndex976 := position, tokenIndex + if buffer[position] != rune('+') { +- goto l966 ++ goto l976 + } + position++ +- goto l967 +- l966: +- position, tokenIndex = position966, tokenIndex966 ++ goto l977 ++ l976: ++ position, tokenIndex = position976, tokenIndex976 + } +- l967: ++ l977: + { +- position968, tokenIndex968 := position, tokenIndex ++ position978, tokenIndex978 := position, tokenIndex + if buffer[position] != rune('-') { +- goto l968 ++ goto l978 + } + position++ +- goto l969 +- l968: +- position, tokenIndex = position968, tokenIndex968 ++ goto l979 ++ l978: ++ position, tokenIndex = position978, tokenIndex978 + } +- l969: ++ l979: + { +- position970, tokenIndex970 := position, tokenIndex ++ position980, tokenIndex980 := position, tokenIndex + if buffer[position] != rune('0') { +- goto l971 ++ goto l981 + } + position++ + { +- position972, tokenIndex972 := position, tokenIndex ++ position982, tokenIndex982 := position, tokenIndex + if buffer[position] != rune('b') { +- goto l973 ++ goto l983 + } + position++ +- goto l972 +- l973: +- position, tokenIndex = position972, tokenIndex972 ++ goto l982 ++ l983: ++ position, tokenIndex = position982, tokenIndex982 + if buffer[position] != rune('B') { +- goto l971 ++ goto l981 + } + position++ + } +- l972: ++ l982: + { +- position976, tokenIndex976 := position, tokenIndex ++ position986, tokenIndex986 := position, tokenIndex + if buffer[position] != rune('0') { +- goto l977 ++ goto l987 + } + position++ +- goto l976 +- l977: +- position, tokenIndex = position976, tokenIndex976 ++ goto l986 ++ l987: ++ position, tokenIndex = position986, tokenIndex986 + if buffer[position] != rune('1') { +- goto l971 ++ goto l981 + } + position++ + } +- l976: +- l974: ++ l986: ++ l984: + { +- position975, tokenIndex975 := position, tokenIndex ++ position985, tokenIndex985 := position, tokenIndex + { +- position978, tokenIndex978 := position, tokenIndex ++ position988, tokenIndex988 := position, tokenIndex + if buffer[position] != rune('0') { +- goto l979 ++ goto l989 + } + position++ +- goto l978 +- l979: +- position, tokenIndex = position978, tokenIndex978 ++ goto l988 ++ l989: ++ position, tokenIndex = position988, tokenIndex988 + if buffer[position] != rune('1') { +- goto l975 ++ goto l985 + } + position++ + } +- l978: +- goto l974 +- l975: +- position, tokenIndex = position975, tokenIndex975 ++ l988: ++ goto l984 ++ l985: ++ position, tokenIndex = position985, tokenIndex985 + } +- goto l970 +- l971: +- position, tokenIndex = position970, tokenIndex970 ++ goto l980 ++ l981: ++ position, tokenIndex = position980, tokenIndex980 + if buffer[position] != rune('0') { +- goto l980 ++ goto l990 + } + position++ + { +- position981, tokenIndex981 := position, tokenIndex ++ position991, tokenIndex991 := position, tokenIndex + if buffer[position] != rune('x') { +- goto l982 ++ goto l992 + } + position++ +- goto l981 +- l982: +- position, tokenIndex = position981, tokenIndex981 ++ goto l991 ++ l992: ++ position, tokenIndex = position991, tokenIndex991 + if buffer[position] != rune('X') { +- goto l980 ++ goto l990 + } + position++ + } +- l981: ++ l991: + { +- position985, tokenIndex985 := position, tokenIndex ++ position995, tokenIndex995 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l986 ++ goto l996 + } + position++ +- goto l985 +- l986: +- position, tokenIndex = position985, tokenIndex985 ++ goto l995 ++ l996: ++ position, tokenIndex = position995, tokenIndex995 + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l987 ++ goto l997 + } + position++ +- goto l985 +- l987: +- position, tokenIndex = position985, tokenIndex985 ++ goto l995 ++ l997: ++ position, tokenIndex = position995, tokenIndex995 + { +- position988, tokenIndex988 := position, tokenIndex ++ position998, tokenIndex998 := position, tokenIndex + if c := buffer[position]; c < rune('a') || c > rune('f') { +- goto l989 ++ goto l999 + } + position++ +- goto l988 +- l989: +- position, tokenIndex = position988, tokenIndex988 ++ goto l998 ++ l999: ++ position, tokenIndex = position998, tokenIndex998 + if c := buffer[position]; c < rune('A') || c > rune('F') { +- goto l980 ++ goto l990 + } + position++ + } +- l988: ++ l998: + } +- l985: +- l983: ++ l995: ++ l993: + { +- position984, tokenIndex984 := position, tokenIndex ++ position994, tokenIndex994 := position, tokenIndex + { +- position990, tokenIndex990 := position, tokenIndex ++ position1000, tokenIndex1000 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l991 ++ goto l1001 + } + position++ +- goto l990 +- l991: +- position, tokenIndex = position990, tokenIndex990 ++ goto l1000 ++ l1001: ++ position, tokenIndex = position1000, tokenIndex1000 + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l992 ++ goto l1002 + } + position++ +- goto l990 +- l992: +- position, tokenIndex = position990, tokenIndex990 ++ goto l1000 ++ l1002: ++ position, tokenIndex = position1000, tokenIndex1000 + { +- position993, tokenIndex993 := position, tokenIndex ++ position1003, tokenIndex1003 := position, tokenIndex + if c := buffer[position]; c < rune('a') || c > rune('f') { +- goto l994 ++ goto l1004 + } + position++ +- goto l993 +- l994: +- position, tokenIndex = position993, tokenIndex993 ++ goto l1003 ++ l1004: ++ position, tokenIndex = position1003, tokenIndex1003 + if c := buffer[position]; c < rune('A') || c > rune('F') { +- goto l984 ++ goto l994 + } + position++ + } +- l993: ++ l1003: + } +- l990: +- goto l983 +- l984: +- position, tokenIndex = position984, tokenIndex984 ++ l1000: ++ goto l993 ++ l994: ++ position, tokenIndex = position994, tokenIndex994 + } +- goto l970 +- l980: +- position, tokenIndex = position970, tokenIndex970 ++ goto l980 ++ l990: ++ position, tokenIndex = position980, tokenIndex980 + { +- position995, tokenIndex995 := position, tokenIndex ++ position1005, tokenIndex1005 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l996 ++ goto l1006 + } + position++ +- l997: ++ l1007: + { +- position998, tokenIndex998 := position, tokenIndex ++ position1008, tokenIndex1008 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l998 ++ goto l1008 + } + position++ +- goto l997 +- l998: +- position, tokenIndex = position998, tokenIndex998 ++ goto l1007 ++ l1008: ++ position, tokenIndex = position1008, tokenIndex1008 + } + if !_rules[ruleWS]() { +- goto l996 ++ goto l1006 + } + if !_rules[ruleOffsetOperator]() { +- goto l996 ++ goto l1006 + } + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l996 ++ goto l1006 + } + position++ +- l999: ++ l1009: + { +- position1000, tokenIndex1000 := position, tokenIndex ++ position1010, tokenIndex1010 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1000 ++ goto l1010 + } + position++ +- goto l999 +- l1000: +- position, tokenIndex = position1000, tokenIndex1000 ++ goto l1009 ++ l1010: ++ position, tokenIndex = position1010, tokenIndex1010 + } +- goto l995 +- l996: +- position, tokenIndex = position995, tokenIndex995 ++ goto l1005 ++ l1006: ++ position, tokenIndex = position1005, tokenIndex1005 + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1001 ++ goto l1011 + } + position++ +- l1002: ++ l1012: + { +- position1003, tokenIndex1003 := position, tokenIndex ++ position1013, tokenIndex1013 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1003 ++ goto l1013 + } + position++ +- goto l1002 +- l1003: +- position, tokenIndex = position1003, tokenIndex1003 ++ goto l1012 ++ l1013: ++ position, tokenIndex = position1013, tokenIndex1013 ++ } ++ if !_rules[ruleOffsetOperator]() { ++ goto l1011 ++ } ++ if buffer[position] != rune('(') { ++ goto l1011 ++ } ++ position++ ++ if c := buffer[position]; c < rune('0') || c > rune('9') { ++ goto l1011 + } ++ position++ ++ l1014: + { +- position1004, tokenIndex1004 := position, tokenIndex +- if !_rules[ruleOffsetOperator]() { +- goto l1004 +- } +- if buffer[position] != rune('(') { +- goto l1004 +- } +- position++ ++ position1015, tokenIndex1015 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1004 ++ goto l1015 + } + position++ +- l1006: +- { +- position1007, tokenIndex1007 := position, tokenIndex +- if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1007 +- } +- position++ +- goto l1006 +- l1007: +- position, tokenIndex = position1007, tokenIndex1007 +- } +- if !_rules[ruleOffsetOperator]() { +- goto l1004 +- } ++ goto l1014 ++ l1015: ++ position, tokenIndex = position1015, tokenIndex1015 ++ } ++ if !_rules[ruleOffsetOperator]() { ++ goto l1011 ++ } ++ if c := buffer[position]; c < rune('0') || c > rune('9') { ++ goto l1011 ++ } ++ position++ ++ l1016: ++ { ++ position1017, tokenIndex1017 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1004 ++ goto l1017 + } + position++ +- l1008: +- { +- position1009, tokenIndex1009 := position, tokenIndex +- if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1009 +- } +- position++ +- goto l1008 +- l1009: +- position, tokenIndex = position1009, tokenIndex1009 +- } +- if buffer[position] != rune(')') { +- goto l1004 ++ goto l1016 ++ l1017: ++ position, tokenIndex = position1017, tokenIndex1017 ++ } ++ if buffer[position] != rune(')') { ++ goto l1011 ++ } ++ position++ ++ goto l1005 ++ l1011: ++ position, tokenIndex = position1005, tokenIndex1005 ++ if c := buffer[position]; c < rune('0') || c > rune('9') { ++ goto l1018 ++ } ++ position++ ++ l1019: ++ { ++ position1020, tokenIndex1020 := position, tokenIndex ++ if c := buffer[position]; c < rune('0') || c > rune('9') { ++ goto l1020 + } + position++ +- goto l1005 +- l1004: +- position, tokenIndex = position1004, tokenIndex1004 ++ goto l1019 ++ l1020: ++ position, tokenIndex = position1020, tokenIndex1020 ++ } ++ if !_rules[ruleOffsetOperator]() { ++ goto l1018 + } +- l1005: +- goto l995 +- l1001: +- position, tokenIndex = position995, tokenIndex995 + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1010 ++ goto l1018 + } + position++ +- l1011: ++ l1021: + { +- position1012, tokenIndex1012 := position, tokenIndex ++ position1022, tokenIndex1022 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1012 ++ goto l1022 + } + position++ +- goto l1011 +- l1012: +- position, tokenIndex = position1012, tokenIndex1012 ++ goto l1021 ++ l1022: ++ position, tokenIndex = position1022, tokenIndex1022 ++ } ++ if !_rules[ruleOffsetOperator]() { ++ goto l1018 ++ } ++ if c := buffer[position]; c < rune('0') || c > rune('9') { ++ goto l1018 + } ++ position++ ++ l1023: + { +- position1013, tokenIndex1013 := position, tokenIndex +- if !_rules[ruleOffsetOperator]() { +- goto l1013 +- } ++ position1024, tokenIndex1024 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1013 ++ goto l1024 + } + position++ +- l1015: +- { +- position1016, tokenIndex1016 := position, tokenIndex +- if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1016 +- } +- position++ +- goto l1015 +- l1016: +- position, tokenIndex = position1016, tokenIndex1016 +- } +- if !_rules[ruleOffsetOperator]() { +- goto l1013 +- } ++ goto l1023 ++ l1024: ++ position, tokenIndex = position1024, tokenIndex1024 ++ } ++ goto l1005 ++ l1018: ++ position, tokenIndex = position1005, tokenIndex1005 ++ if c := buffer[position]; c < rune('0') || c > rune('9') { ++ goto l1025 ++ } ++ position++ ++ l1026: ++ { ++ position1027, tokenIndex1027 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1013 ++ goto l1027 + } + position++ +- l1017: +- { +- position1018, tokenIndex1018 := position, tokenIndex +- if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1018 +- } +- position++ +- goto l1017 +- l1018: +- position, tokenIndex = position1018, tokenIndex1018 +- } +- goto l1014 +- l1013: +- position, tokenIndex = position1013, tokenIndex1013 ++ goto l1026 ++ l1027: ++ position, tokenIndex = position1027, tokenIndex1027 ++ } ++ if !_rules[ruleOffsetOperator]() { ++ goto l1025 + } +- l1014: +- goto l995 +- l1010: +- position, tokenIndex = position995, tokenIndex995 + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1019 ++ goto l1025 + } + position++ +- l1020: ++ l1028: + { +- position1021, tokenIndex1021 := position, tokenIndex ++ position1029, tokenIndex1029 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1021 ++ goto l1029 + } + position++ +- goto l1020 +- l1021: +- position, tokenIndex = position1021, tokenIndex1021 ++ goto l1028 ++ l1029: ++ position, tokenIndex = position1029, tokenIndex1029 + } ++ goto l1005 ++ l1025: ++ position, tokenIndex = position1005, tokenIndex1005 ++ if c := buffer[position]; c < rune('0') || c > rune('9') { ++ goto l1030 ++ } ++ position++ ++ l1031: + { +- position1022, tokenIndex1022 := position, tokenIndex +- if !_rules[ruleOffsetOperator]() { +- goto l1022 +- } ++ position1032, tokenIndex1032 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1022 ++ goto l1032 + } + position++ +- l1024: +- { +- position1025, tokenIndex1025 := position, tokenIndex +- if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1025 +- } +- position++ +- goto l1024 +- l1025: +- position, tokenIndex = position1025, tokenIndex1025 +- } +- goto l1023 +- l1022: +- position, tokenIndex = position1022, tokenIndex1022 ++ goto l1031 ++ l1032: ++ position, tokenIndex = position1032, tokenIndex1032 + } +- l1023: +- goto l995 +- l1019: +- position, tokenIndex = position995, tokenIndex995 ++ goto l1005 ++ l1030: ++ position, tokenIndex = position1005, tokenIndex1005 + if !_rules[ruleS2nBignumHelper]() { +- goto l1026 ++ goto l1033 + } + if !_rules[ruleS2nBignumHelper]() { +- goto l1026 ++ goto l1033 + } + { +- position1027, tokenIndex1027 := position, tokenIndex ++ position1034, tokenIndex1034 := position, tokenIndex + if !_rules[ruleS2nBignumHelper]() { +- goto l1027 ++ goto l1034 + } + { +- position1029, tokenIndex1029 := position, tokenIndex ++ position1036, tokenIndex1036 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1029 ++ goto l1036 + } + position++ +- l1031: ++ l1038: + { +- position1032, tokenIndex1032 := position, tokenIndex ++ position1039, tokenIndex1039 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1032 ++ goto l1039 + } + position++ +- goto l1031 +- l1032: +- position, tokenIndex = position1032, tokenIndex1032 ++ goto l1038 ++ l1039: ++ position, tokenIndex = position1039, tokenIndex1039 + } + if !_rules[ruleOffsetOperator]() { +- goto l1029 ++ goto l1036 + } +- goto l1030 +- l1029: +- position, tokenIndex = position1029, tokenIndex1029 ++ goto l1037 ++ l1036: ++ position, tokenIndex = position1036, tokenIndex1036 + } +- l1030: ++ l1037: + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1027 ++ goto l1034 + } + position++ +- l1033: ++ l1040: + { +- position1034, tokenIndex1034 := position, tokenIndex ++ position1041, tokenIndex1041 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1034 ++ goto l1041 + } + position++ +- goto l1033 +- l1034: +- position, tokenIndex = position1034, tokenIndex1034 ++ goto l1040 ++ l1041: ++ position, tokenIndex = position1041, tokenIndex1041 + } + if !_rules[ruleOffsetOperator]() { +- goto l1027 ++ goto l1034 + } +- goto l1028 +- l1027: +- position, tokenIndex = position1027, tokenIndex1027 ++ goto l1035 ++ l1034: ++ position, tokenIndex = position1034, tokenIndex1034 + } +- l1028: ++ l1035: + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1026 ++ goto l1033 + } + position++ +- l1035: ++ l1042: + { +- position1036, tokenIndex1036 := position, tokenIndex ++ position1043, tokenIndex1043 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1036 ++ goto l1043 + } + position++ +- goto l1035 +- l1036: +- position, tokenIndex = position1036, tokenIndex1036 ++ goto l1042 ++ l1043: ++ position, tokenIndex = position1043, tokenIndex1043 + } +- goto l995 +- l1026: +- position, tokenIndex = position995, tokenIndex995 ++ goto l1005 ++ l1033: ++ position, tokenIndex = position1005, tokenIndex1005 + if !_rules[ruleS2nBignumHelper]() { +- goto l1037 ++ goto l1044 + } + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1037 ++ goto l1044 + } + position++ +- l1038: ++ l1045: + { +- position1039, tokenIndex1039 := position, tokenIndex ++ position1046, tokenIndex1046 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1039 ++ goto l1046 + } + position++ +- goto l1038 +- l1039: +- position, tokenIndex = position1039, tokenIndex1039 ++ goto l1045 ++ l1046: ++ position, tokenIndex = position1046, tokenIndex1046 + } + { +- position1040, tokenIndex1040 := position, tokenIndex ++ position1047, tokenIndex1047 := position, tokenIndex + { +- position1042, tokenIndex1042 := position, tokenIndex ++ position1049, tokenIndex1049 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l1042 ++ goto l1049 + } +- goto l1043 +- l1042: +- position, tokenIndex = position1042, tokenIndex1042 ++ goto l1050 ++ l1049: ++ position, tokenIndex = position1049, tokenIndex1049 + } +- l1043: ++ l1050: + if !_rules[ruleOffsetOperator]() { +- goto l1041 ++ goto l1048 + } + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1041 ++ goto l1048 + } + position++ +- l1044: ++ l1051: + { +- position1045, tokenIndex1045 := position, tokenIndex ++ position1052, tokenIndex1052 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1045 ++ goto l1052 + } + position++ +- goto l1044 +- l1045: +- position, tokenIndex = position1045, tokenIndex1045 ++ goto l1051 ++ l1052: ++ position, tokenIndex = position1052, tokenIndex1052 + } + { +- position1046, tokenIndex1046 := position, tokenIndex ++ position1053, tokenIndex1053 := position, tokenIndex + { +- position1048, tokenIndex1048 := position, tokenIndex ++ position1055, tokenIndex1055 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l1048 ++ goto l1055 + } +- goto l1049 +- l1048: +- position, tokenIndex = position1048, tokenIndex1048 ++ goto l1056 ++ l1055: ++ position, tokenIndex = position1055, tokenIndex1055 + } +- l1049: ++ l1056: + if !_rules[ruleOffsetOperator]() { +- goto l1046 ++ goto l1053 + } + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1046 ++ goto l1053 + } + position++ +- l1050: ++ l1057: + { +- position1051, tokenIndex1051 := position, tokenIndex ++ position1058, tokenIndex1058 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1051 ++ goto l1058 + } + position++ +- goto l1050 +- l1051: +- position, tokenIndex = position1051, tokenIndex1051 ++ goto l1057 ++ l1058: ++ position, tokenIndex = position1058, tokenIndex1058 + } +- goto l1047 +- l1046: +- position, tokenIndex = position1046, tokenIndex1046 +- } +- l1047: +- goto l1040 +- l1041: +- position, tokenIndex = position1040, tokenIndex1040 ++ goto l1054 ++ l1053: ++ position, tokenIndex = position1053, tokenIndex1053 ++ } ++ l1054: ++ goto l1047 ++ l1048: ++ position, tokenIndex = position1047, tokenIndex1047 + { +- position1052, tokenIndex1052 := position, tokenIndex ++ position1059, tokenIndex1059 := position, tokenIndex + if buffer[position] != rune('x') { +- goto l1052 ++ goto l1059 + } + position++ +- goto l1037 +- l1052: +- position, tokenIndex = position1052, tokenIndex1052 ++ goto l1044 ++ l1059: ++ position, tokenIndex = position1059, tokenIndex1059 + } + } +- l1040: +- goto l995 +- l1037: +- position, tokenIndex = position995, tokenIndex995 ++ l1047: ++ goto l1005 ++ l1044: ++ position, tokenIndex = position1005, tokenIndex1005 + if !_rules[ruleS2nBignumHelper]() { +- goto l1053 ++ goto l1060 + } +- goto l995 +- l1053: +- position, tokenIndex = position995, tokenIndex995 ++ goto l1005 ++ l1060: ++ position, tokenIndex = position1005, tokenIndex1005 + if buffer[position] != rune('(') { +- goto l964 ++ goto l974 + } + position++ + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l964 ++ goto l974 + } + position++ +- l1054: ++ l1061: + { +- position1055, tokenIndex1055 := position, tokenIndex ++ position1062, tokenIndex1062 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1055 ++ goto l1062 + } + position++ +- goto l1054 +- l1055: +- position, tokenIndex = position1055, tokenIndex1055 ++ goto l1061 ++ l1062: ++ position, tokenIndex = position1062, tokenIndex1062 + } + { +- position1056, tokenIndex1056 := position, tokenIndex ++ position1063, tokenIndex1063 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l1056 ++ goto l1063 + } +- goto l1057 +- l1056: +- position, tokenIndex = position1056, tokenIndex1056 ++ goto l1064 ++ l1063: ++ position, tokenIndex = position1063, tokenIndex1063 + } +- l1057: ++ l1064: + if !_rules[ruleOffsetOperator]() { +- goto l964 ++ goto l974 + } + { +- position1058, tokenIndex1058 := position, tokenIndex ++ position1065, tokenIndex1065 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l1058 ++ goto l1065 + } +- goto l1059 +- l1058: +- position, tokenIndex = position1058, tokenIndex1058 ++ goto l1066 ++ l1065: ++ position, tokenIndex = position1065, tokenIndex1065 + } +- l1059: ++ l1066: + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l964 ++ goto l974 + } + position++ +- l1060: ++ l1067: + { +- position1061, tokenIndex1061 := position, tokenIndex ++ position1068, tokenIndex1068 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1061 ++ goto l1068 + } + position++ +- goto l1060 +- l1061: +- position, tokenIndex = position1061, tokenIndex1061 ++ goto l1067 ++ l1068: ++ position, tokenIndex = position1068, tokenIndex1068 + } + { +- position1062, tokenIndex1062 := position, tokenIndex ++ position1069, tokenIndex1069 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l1062 ++ goto l1069 + } +- goto l1063 +- l1062: +- position, tokenIndex = position1062, tokenIndex1062 ++ goto l1070 ++ l1069: ++ position, tokenIndex = position1069, tokenIndex1069 + } +- l1063: ++ l1070: + if !_rules[ruleOffsetOperator]() { +- goto l964 ++ goto l974 + } + { +- position1064, tokenIndex1064 := position, tokenIndex ++ position1071, tokenIndex1071 := position, tokenIndex + if !_rules[ruleWS]() { +- goto l1064 ++ goto l1071 + } +- goto l1065 +- l1064: +- position, tokenIndex = position1064, tokenIndex1064 ++ goto l1072 ++ l1071: ++ position, tokenIndex = position1071, tokenIndex1071 + } +- l1065: ++ l1072: + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l964 ++ goto l974 + } + position++ +- l1066: ++ l1073: + { +- position1067, tokenIndex1067 := position, tokenIndex ++ position1074, tokenIndex1074 := position, tokenIndex + if c := buffer[position]; c < rune('0') || c > rune('9') { +- goto l1067 ++ goto l1074 + } + position++ +- goto l1066 +- l1067: +- position, tokenIndex = position1067, tokenIndex1067 ++ goto l1073 ++ l1074: ++ position, tokenIndex = position1074, tokenIndex1074 + } + if buffer[position] != rune(')') { +- goto l964 ++ goto l974 + } + position++ + } +- l995: ++ l1005: + { +- position1068, tokenIndex1068 := position, tokenIndex ++ position1075, tokenIndex1075 := position, tokenIndex + { +- position1069, tokenIndex1069 := position, tokenIndex ++ position1076, tokenIndex1076 := position, tokenIndex + if c := buffer[position]; c < rune('a') || c > rune('z') { +- goto l1070 ++ goto l1077 + } + position++ +- goto l1069 +- l1070: +- position, tokenIndex = position1069, tokenIndex1069 ++ goto l1076 ++ l1077: ++ position, tokenIndex = position1076, tokenIndex1076 + if c := buffer[position]; c < rune('A') || c > rune('Z') { +- goto l1068 ++ goto l1075 + } + position++ + } +- l1069: +- goto l964 +- l1068: +- position, tokenIndex = position1068, tokenIndex1068 ++ l1076: ++ goto l974 ++ l1075: ++ position, tokenIndex = position1075, tokenIndex1075 + } + } +- l970: +- add(ruleOffset, position965) ++ l980: ++ add(ruleOffset, position975) + } + return true +- l964: +- position, tokenIndex = position964, tokenIndex964 ++ l974: ++ position, tokenIndex = position974, tokenIndex974 + return false + }, +- /* 59 Section <- <([a-z] / [A-Z] / '@')+> */ ++ /* 61 Section <- <([a-z] / [A-Z] / '@')+> */ + func() bool { +- position1071, tokenIndex1071 := position, tokenIndex ++ position1078, tokenIndex1078 := position, tokenIndex + { +- position1072 := position ++ position1079 := position + { +- position1075, tokenIndex1075 := position, tokenIndex ++ position1082, tokenIndex1082 := position, tokenIndex + if c := buffer[position]; c < rune('a') || c > rune('z') { +- goto l1076 ++ goto l1083 + } + position++ +- goto l1075 +- l1076: +- position, tokenIndex = position1075, tokenIndex1075 ++ goto l1082 ++ l1083: ++ position, tokenIndex = position1082, tokenIndex1082 + if c := buffer[position]; c < rune('A') || c > rune('Z') { +- goto l1077 ++ goto l1084 + } + position++ +- goto l1075 +- l1077: +- position, tokenIndex = position1075, tokenIndex1075 ++ goto l1082 ++ l1084: ++ position, tokenIndex = position1082, tokenIndex1082 + if buffer[position] != rune('@') { +- goto l1071 ++ goto l1078 + } + position++ + } +- l1075: +- l1073: ++ l1082: ++ l1080: + { +- position1074, tokenIndex1074 := position, tokenIndex ++ position1081, tokenIndex1081 := position, tokenIndex + { +- position1078, tokenIndex1078 := position, tokenIndex ++ position1085, tokenIndex1085 := position, tokenIndex + if c := buffer[position]; c < rune('a') || c > rune('z') { +- goto l1079 ++ goto l1086 + } + position++ +- goto l1078 +- l1079: +- position, tokenIndex = position1078, tokenIndex1078 ++ goto l1085 ++ l1086: ++ position, tokenIndex = position1085, tokenIndex1085 + if c := buffer[position]; c < rune('A') || c > rune('Z') { +- goto l1080 ++ goto l1087 + } + position++ +- goto l1078 +- l1080: +- position, tokenIndex = position1078, tokenIndex1078 ++ goto l1085 ++ l1087: ++ position, tokenIndex = position1085, tokenIndex1085 + if buffer[position] != rune('@') { +- goto l1074 ++ goto l1081 + } + position++ + } +- l1078: +- goto l1073 +- l1074: +- position, tokenIndex = position1074, tokenIndex1074 ++ l1085: ++ goto l1080 ++ l1081: ++ position, tokenIndex = position1081, tokenIndex1081 + } +- add(ruleSection, position1072) ++ add(ruleSection, position1079) + } + return true +- l1071: +- position, tokenIndex = position1071, tokenIndex1071 ++ l1078: ++ position, tokenIndex = position1078, tokenIndex1078 + return false + }, +- /* 60 SegmentRegister <- <('%' ([c-g] / 's') ('s' ':'))> */ ++ /* 62 SegmentRegister <- <('%' ([c-g] / 's') ('s' ':'))> */ + func() bool { +- position1081, tokenIndex1081 := position, tokenIndex ++ position1088, tokenIndex1088 := position, tokenIndex + { +- position1082 := position ++ position1089 := position + if buffer[position] != rune('%') { +- goto l1081 ++ goto l1088 + } + position++ + { +- position1083, tokenIndex1083 := position, tokenIndex ++ position1090, tokenIndex1090 := position, tokenIndex + if c := buffer[position]; c < rune('c') || c > rune('g') { +- goto l1084 ++ goto l1091 + } + position++ +- goto l1083 +- l1084: +- position, tokenIndex = position1083, tokenIndex1083 ++ goto l1090 ++ l1091: ++ position, tokenIndex = position1090, tokenIndex1090 + if buffer[position] != rune('s') { +- goto l1081 ++ goto l1088 + } + position++ + } +- l1083: ++ l1090: + if buffer[position] != rune('s') { +- goto l1081 ++ goto l1088 + } + position++ + if buffer[position] != rune(':') { +- goto l1081 ++ goto l1088 + } + position++ +- add(ruleSegmentRegister, position1082) ++ add(ruleSegmentRegister, position1089) + } + return true +- l1081: +- position, tokenIndex = position1081, tokenIndex1081 ++ l1088: ++ position, tokenIndex = position1088, tokenIndex1088 + return false + }, + } +diff --git a/util/fipstools/delocate/delocate_test.go b/util/fipstools/delocate/delocate_test.go +index 940924a..204cea1 100644 +--- a/util/fipstools/delocate/delocate_test.go ++++ b/util/fipstools/delocate/delocate_test.go +@@ -59,6 +59,9 @@ var delocateTests = []delocateTest{ + {"x86_64-FourArg", nil, []string{"in.s"}, "out.s", true}, + {"x86_64-Relro", nil, []string{"in.s"}, "out.s", true}, + {"aarch64-Basic", nil, []string{"in.s"}, "out.s", true}, ++ {"s390x-Basic", nil, []string{"in.s"}, "out.s", true}, ++ {"s390x-BSS", nil, []string{"in.s"}, "out.s", true}, ++ {"s390x-EXRL", nil, []string{"in.s"}, "out.s", true}, + } + + func TestDelocate(t *testing.T) { +@@ -107,3 +110,18 @@ func TestDelocate(t *testing.T) { + }) + } + } ++ ++func TestDetectProcessorInputs(t *testing.T) { ++ inputs := []inputFile{ ++ {index: 0, path: filepath.Join(*testDataDir, "s390x-DetectLaterInput", "in1.s")}, ++ {index: 1, path: filepath.Join(*testDataDir, "s390x-DetectLaterInput", "in2.s")}, ++ } ++ ++ if err := parseInputs(inputs, nil); err != nil { ++ t.Fatalf("parseInputs failed: %s", err) ++ } ++ ++ if got := detectProcessorInputs(inputs); got != s390x { ++ t.Fatalf("detectProcessorInputs() = %v, want %v", got, s390x) ++ } ++} +diff --git a/util/fipstools/delocate/testdata/s390x-BSS/in.s b/util/fipstools/delocate/testdata/s390x-BSS/in.s +new file mode 100644 +index 0000000..a675939 +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-BSS/in.s +@@ -0,0 +1,7 @@ ++.text ++.comm foo_storage,8,8 ++.globl foo ++.type foo, @function ++foo: ++ brasl %r14, foo_storage_bss_get@PLT ++ br %r14 +diff --git a/util/fipstools/delocate/testdata/s390x-BSS/out.s b/util/fipstools/delocate/testdata/s390x-BSS/out.s +new file mode 100644 +index 0000000..3b18cb4 +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-BSS/out.s +@@ -0,0 +1,56 @@ ++.text ++.file 1 "inserted_by_delocate.c" ++.loc 1 1 0 ++.type BORINGSSL_bcm_text_hash, @object ++.size BORINGSSL_bcm_text_hash, 32 ++BORINGSSL_bcm_text_hash: ++.byte 0xae ++.byte 0x2c ++.byte 0xea ++.byte 0x2a ++.byte 0xbd ++.byte 0xa6 ++.byte 0xf3 ++.byte 0xec ++.byte 0x97 ++.byte 0x7f ++.byte 0x9b ++.byte 0xf6 ++.byte 0x94 ++.byte 0x9a ++.byte 0xfc ++.byte 0x83 ++.byte 0x68 ++.byte 0x27 ++.byte 0xcb ++.byte 0xa0 ++.byte 0xa0 ++.byte 0x9f ++.byte 0x6b ++.byte 0x6f ++.byte 0xde ++.byte 0x52 ++.byte 0xcd ++.byte 0xe2 ++.byte 0xcd ++.byte 0xff ++.byte 0x31 ++.byte 0x80 ++BORINGSSL_bcm_text_start: ++.text ++.comm foo_storage,8,8 ++.globl foo ++.type foo, @function ++.Lfoo_local_target: ++foo: ++# WAS brasl %r14, foo_storage_bss_get@PLT ++ brasl %r14, foo_storage_bss_get ++ br %r14 ++.text ++.loc 1 2 0 ++BORINGSSL_bcm_text_end: ++.balign 2 ++.type foo_storage_bss_get, @function ++foo_storage_bss_get: ++ larl %r2, foo_storage ++ br %r14 +diff --git a/util/fipstools/delocate/testdata/s390x-Basic/in.s b/util/fipstools/delocate/testdata/s390x-Basic/in.s +new file mode 100644 +index 0000000..4af29d0 +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-Basic/in.s +@@ -0,0 +1,40 @@ ++.text ++.globl foo ++.type foo, @function ++foo: ++.Ltmp0: ++ larl %r5, .L286 ++ ng %r1, .L287-.L286(%r5) ++ brasl %r14, memcpy@PLT ++ lgrl %r1, OPENSSL_cleanse@GOTENT ++ lgrl %r2, free@GOT ++ clgrl %r2, free@GOT ++ larl %r3, free@GOT ++ lgrl %r4, bar@GOT ++ larl %r5, bar@GOT ++ lgrl %r0, bar@GOT ++ clgrl %r0, bar@GOT ++ br %r14 ++ ++.globl bar ++.type bar, @function ++bar: ++ br %r14 ++ ++.globl chooser ++.type chooser, @function ++chooser: ++ larl %r2, bar@GOT ++ lgrl %r1, baz@GOT ++ locge %r1, 0(%r2) ++ br %r1 ++ ++.globl baz ++.type baz, @function ++baz: ++ br %r14 ++ ++.section .rodata ++.L286: ++.L287: ++ .quad 0xf000f000f000f000 +diff --git a/util/fipstools/delocate/testdata/s390x-Basic/out.s b/util/fipstools/delocate/testdata/s390x-Basic/out.s +new file mode 100644 +index 0000000..40355ca +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-Basic/out.s +@@ -0,0 +1,194 @@ ++.text ++.file 1 "inserted_by_delocate.c" ++.loc 1 1 0 ++.type BORINGSSL_bcm_text_hash, @object ++.size BORINGSSL_bcm_text_hash, 32 ++BORINGSSL_bcm_text_hash: ++.byte 0xae ++.byte 0x2c ++.byte 0xea ++.byte 0x2a ++.byte 0xbd ++.byte 0xa6 ++.byte 0xf3 ++.byte 0xec ++.byte 0x97 ++.byte 0x7f ++.byte 0x9b ++.byte 0xf6 ++.byte 0x94 ++.byte 0x9a ++.byte 0xfc ++.byte 0x83 ++.byte 0x68 ++.byte 0x27 ++.byte 0xcb ++.byte 0xa0 ++.byte 0xa0 ++.byte 0x9f ++.byte 0x6b ++.byte 0x6f ++.byte 0xde ++.byte 0x52 ++.byte 0xcd ++.byte 0xe2 ++.byte 0xcd ++.byte 0xff ++.byte 0x31 ++.byte 0x80 ++BORINGSSL_bcm_text_start: ++.text ++.globl foo ++.type foo, @function ++.Lfoo_local_target: ++foo: ++.Ltmp0: ++ ++ larl %r5, .L286 ++ ng %r1, .L287-.L286(%r5) ++# WAS brasl %r14, memcpy@PLT ++ brasl %r14, .Lbcm_redirector_memcpy ++# WAS lgrl %r1, OPENSSL_cleanse@GOTENT ++ lay %r15, -8(%r15) ++ stg %r2, 0(%r15) ++ brasl %r1, .Lbcm_s390x_lgrl_OPENSSL_cleanse_GOTENT ++ lgr %r1, %r2 ++ lg %r2, 0(%r15) ++ lay %r15, 8(%r15) ++# WAS lgrl %r2, free@GOT ++ lay %r15, -8(%r15) ++ stg %r1, 0(%r15) ++ brasl %r1, .Lbcm_s390x_lgrl_free_GOT ++ lg %r1, 0(%r15) ++ lay %r15, 8(%r15) ++# WAS clgrl %r2, free@GOT ++ lay %r15, -16(%r15) ++ stg %r1, 0(%r15) ++ stg %r2, 8(%r15) ++ brasl %r1, .Lbcm_s390x_lgrl_free_GOT ++ lgr %r1, %r2 ++ lg %r2, 8(%r15) ++ clgr %r2, %r1 ++ lg %r1, 0(%r15) ++ lay %r15, 16(%r15) ++# WAS larl %r3, free@GOT ++ lay %r15, -16(%r15) ++ stg %r1, 0(%r15) ++ stg %r2, 8(%r15) ++ brasl %r1, .Lbcm_s390x_larl_free_GOT ++ lgr %r3, %r2 ++ lg %r2, 8(%r15) ++ lg %r1, 0(%r15) ++ lay %r15, 16(%r15) ++# WAS lgrl %r4, bar@GOT ++ lay %r15, -16(%r15) ++ stg %r1, 0(%r15) ++ stg %r2, 8(%r15) ++ larl %r1, .Lboringssl_gotent__Lbar_local_target ++ lg %r2, 0(%r1) ++ lay %r4, 0(%r1,%r2) ++ lg %r2, 8(%r15) ++ lg %r1, 0(%r15) ++ lay %r15, 16(%r15) ++# WAS larl %r5, bar@GOT ++ larl %r5, .Lboringssl_gotent__Lbar_local_target ++# WAS lgrl %r0, bar@GOT ++ lay %r15, -16(%r15) ++ stg %r1, 0(%r15) ++ stg %r2, 8(%r15) ++ larl %r1, .Lboringssl_gotent__Lbar_local_target ++ lg %r2, 0(%r1) ++ lay %r0, 0(%r1,%r2) ++ lg %r2, 8(%r15) ++ lg %r1, 0(%r15) ++ lay %r15, 16(%r15) ++# WAS clgrl %r0, bar@GOT ++ lay %r15, -16(%r15) ++ stg %r1, 0(%r15) ++ stg %r2, 8(%r15) ++ larl %r1, .Lboringssl_gotent__Lbar_local_target ++ lg %r2, 0(%r1) ++ lay %r1, 0(%r1,%r2) ++ clgr %r0, %r1 ++ lg %r2, 8(%r15) ++ lg %r1, 0(%r15) ++ lay %r15, 16(%r15) ++ br %r14 ++ ++.globl bar ++.type bar, @function ++.Lbar_local_target: ++bar: ++ br %r14 ++ ++.globl chooser ++.type chooser, @function ++.Lchooser_local_target: ++chooser: ++# WAS larl %r2, bar@GOT ++ larl %r2, .Lboringssl_gotent__Lbar_local_target ++# WAS lgrl %r1, baz@GOT ++ lay %r15, -16(%r15) ++ stg %r2, 0(%r15) ++ stg %r3, 8(%r15) ++ larl %r2, .Lboringssl_gotent__Lbaz_local_target ++ lg %r3, 0(%r2) ++ lay %r1, 0(%r2,%r3) ++ lg %r3, 8(%r15) ++ lg %r2, 0(%r15) ++ lay %r15, 16(%r15) ++# WAS locge %r1, 0(%r2) ++ lay %r15, -8(%r15) ++ stg %r3, 0(%r15) ++ lg %r3, 0(%r2) ++ lay %r3, 0(%r2,%r3) ++ locgre %r1, %r3 ++ lg %r3, 0(%r15) ++ lay %r15, 8(%r15) ++ br %r1 ++ ++.globl baz ++.type baz, @function ++.Lbaz_local_target: ++baz: ++ br %r14 ++ ++# WAS .section .rodata ++.text ++.L286: ++ ++.L287: ++ ++ .quad 0xf000f000f000f000 ++.text ++.loc 1 2 0 ++BORINGSSL_bcm_text_end: ++.balign 2 ++.type .Lbcm_redirector_memcpy, @function ++.Lbcm_redirector_memcpy: ++ jg memcpy@PLT ++.balign 2 ++.type .Lbcm_s390x_larl_free_GOT, @function ++.Lbcm_s390x_larl_free_GOT: ++ larl %r2, free@GOT ++ br %r1 ++.balign 2 ++.type .Lbcm_s390x_lgrl_OPENSSL_cleanse_GOTENT, @function ++.Lbcm_s390x_lgrl_OPENSSL_cleanse_GOTENT: ++ lgrl %r2, OPENSSL_cleanse@GOTENT ++ br %r1 ++.balign 2 ++.type .Lbcm_s390x_lgrl_free_GOT, @function ++.Lbcm_s390x_lgrl_free_GOT: ++ lgrl %r2, free@GOT ++ br %r1 ++.balign 8 ++.type .Lboringssl_gotent__Lbar_local_target, @object ++.size .Lboringssl_gotent__Lbar_local_target, 8 ++.Lboringssl_gotent__Lbar_local_target: ++ .quad .Lbar_local_target-.Lboringssl_gotent__Lbar_local_target ++.balign 8 ++.type .Lboringssl_gotent__Lbaz_local_target, @object ++.size .Lboringssl_gotent__Lbaz_local_target, 8 ++.Lboringssl_gotent__Lbaz_local_target: ++ .quad .Lbaz_local_target-.Lboringssl_gotent__Lbaz_local_target +diff --git a/util/fipstools/delocate/testdata/s390x-DetectLaterInput/in1.s b/util/fipstools/delocate/testdata/s390x-DetectLaterInput/in1.s +new file mode 100644 +index 0000000..d73df7c +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-DetectLaterInput/in1.s +@@ -0,0 +1,2 @@ ++.text ++.comm foo_storage,8,8 +diff --git a/util/fipstools/delocate/testdata/s390x-DetectLaterInput/in2.s b/util/fipstools/delocate/testdata/s390x-DetectLaterInput/in2.s +new file mode 100644 +index 0000000..9a98cba +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-DetectLaterInput/in2.s +@@ -0,0 +1,6 @@ ++.text ++.globl foo ++.type foo, @function ++foo: ++ brasl %r14, bar@PLT ++ br %r14 +diff --git a/util/fipstools/delocate/testdata/s390x-EXRL/in.s b/util/fipstools/delocate/testdata/s390x-EXRL/in.s +new file mode 100644 +index 0000000..de62534 +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-EXRL/in.s +@@ -0,0 +1,8 @@ ++.text ++.globl foo ++.type foo, @function ++foo: ++ exrl %r3, .Ltmp0 ++ br %r14 ++.Ltmp0: ++ mvc 0(1,%r4), 0(%r2) +diff --git a/util/fipstools/delocate/testdata/s390x-EXRL/out.s b/util/fipstools/delocate/testdata/s390x-EXRL/out.s +new file mode 100644 +index 0000000..b61499f +--- /dev/null ++++ b/util/fipstools/delocate/testdata/s390x-EXRL/out.s +@@ -0,0 +1,53 @@ ++.text ++.file 1 "inserted_by_delocate.c" ++.loc 1 1 0 ++.type BORINGSSL_bcm_text_hash, @object ++.size BORINGSSL_bcm_text_hash, 32 ++BORINGSSL_bcm_text_hash: ++.byte 0xae ++.byte 0x2c ++.byte 0xea ++.byte 0x2a ++.byte 0xbd ++.byte 0xa6 ++.byte 0xf3 ++.byte 0xec ++.byte 0x97 ++.byte 0x7f ++.byte 0x9b ++.byte 0xf6 ++.byte 0x94 ++.byte 0x9a ++.byte 0xfc ++.byte 0x83 ++.byte 0x68 ++.byte 0x27 ++.byte 0xcb ++.byte 0xa0 ++.byte 0xa0 ++.byte 0x9f ++.byte 0x6b ++.byte 0x6f ++.byte 0xde ++.byte 0x52 ++.byte 0xcd ++.byte 0xe2 ++.byte 0xcd ++.byte 0xff ++.byte 0x31 ++.byte 0x80 ++BORINGSSL_bcm_text_start: ++.text ++.globl foo ++.type foo, @function ++.Lfoo_local_target: ++foo: ++ exrl %r3, .Ltmp0 ++ br %r14 ++ .balign 4 ++.Ltmp0: ++ ++ mvc 0(1,%r4), 0(%r2) ++.text ++.loc 1 2 0 ++BORINGSSL_bcm_text_end: + diff --git a/Cilium/1.19.4/patch/cilium-s390x.patch b/Cilium/1.19.4/patch/cilium-s390x.patch new file mode 100644 index 00000000..fd21fe7f --- /dev/null +++ b/Cilium/1.19.4/patch/cilium-s390x.patch @@ -0,0 +1,2985 @@ +diff --git a/bpf/include/bpf/csum.h b/bpf/include/bpf/csum.h +index 7705174781..adf5497981 100644 +--- a/bpf/include/bpf/csum.h ++++ b/bpf/include/bpf/csum.h +@@ -35,6 +35,7 @@ static __always_inline __wsum csum_diff(const void *from, __u32 size_from, + { + if (__builtin_constant_p(size_from) && + __builtin_constant_p(size_to)) { ++#if __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ + /* Optimizations for frequent hot-path cases that are tiny to just + * inline into the code instead of calling more expensive helper. + */ +@@ -45,6 +46,14 @@ static __always_inline __wsum csum_diff(const void *from, __u32 size_from, + return csum_add(seed, + csum_add(~(*(__u32 *)from), + *(__u32 *)to)); ++#else ++ /* On big-endian targets (bpfeb/s390x), the inline __u32 ++ * optimization produces incorrect ones-complement intermediates ++ * because the carry structure of csum_add on a host-order 32-bit ++ * integer differs from summing two network-order 16-bit words. ++ * Fall through to csum_diff_external which uses csum_partial. ++ */ ++#endif + } + + return csum_diff_external(from, size_from, to, size_to, seed); +diff --git a/bpf/lib/common.h b/bpf/lib/common.h +index 951dd1d68f..c3bdaa2953 100644 +--- a/bpf/lib/common.h ++++ b/bpf/lib/common.h +@@ -62,6 +62,12 @@ enum { + + typedef __u64 mac_t; + ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++#define mac_t_to_bytes(x) __builtin_bswap64(x) ++#else ++#define mac_t_to_bytes(x) (x) ++#endif ++ + union v4addr { + __be32 be32; + __u8 addr[4]; +diff --git a/bpf/lib/eps.h b/bpf/lib/eps.h +index 6f16d6619a..81850548c0 100644 +--- a/bpf/lib/eps.h ++++ b/bpf/lib/eps.h +@@ -106,11 +106,19 @@ struct remote_endpoint_info { + } tunnel_endpoint; + __u16 pad; + __u8 key; ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ __u8 pad2:4, ++ flag_remote_cluster:1, ++ flag_ipv6_tunnel_ep:1, ++ flag_has_tunnel_ep:1, ++ flag_skip_tunnel:1; ++#else + __u8 flag_skip_tunnel:1, + flag_has_tunnel_ep:1, + flag_ipv6_tunnel_ep:1, + flag_remote_cluster:1, + pad2:4; ++#endif + }; + + struct ipcache_key { +diff --git a/bpf/lib/hash.h b/bpf/lib/hash.h +index a43fff08e2..e4e3f9ee57 100644 +--- a/bpf/lib/hash.h ++++ b/bpf/lib/hash.h +@@ -6,13 +6,21 @@ + #include "common.h" + #include "jhash.h" + ++#ifdef __BIG_ENDIAN_BITFIELD ++#define HASH_WORD16_LE(v) ((__u16)__builtin_bswap16((__u16)(v))) ++#define HASH_WORD32_LE(v) ((__u32)__builtin_bswap32((__u32)(v))) ++#else ++#define HASH_WORD16_LE(v) ((__u16)(v)) ++#define HASH_WORD32_LE(v) ((__u32)(v)) ++#endif ++ + /* The daddr is explicitly excluded from the hash here in order to allow for + * backend selection to choose the same backend even on different service VIPs. + */ + static __always_inline __u32 + __hash_from_tuple_v4(const struct ipv4_ct_tuple *tuple, __be16 sport, __be16 dport) + { +- return jhash_3words(tuple->saddr, ((__u32)dport << 16) | sport, ++ return jhash_3words(HASH_WORD32_LE(tuple->saddr), ((__u32)HASH_WORD16_LE(dport) << 16) | HASH_WORD16_LE(sport), + tuple->nexthdr, HASH_INIT4_SEED); + } + +@@ -26,12 +34,12 @@ __hash_from_tuple_v6(const struct ipv6_ct_tuple *tuple, __be16 sport, __be16 dpo + { + __u32 a, b, c; + +- a = tuple->saddr.p1; +- b = tuple->saddr.p2; +- c = tuple->saddr.p3; ++ a = HASH_WORD32_LE(tuple->saddr.p1); ++ b = HASH_WORD32_LE(tuple->saddr.p2); ++ c = HASH_WORD32_LE(tuple->saddr.p3); + __jhash_mix(a, b, c); +- a += tuple->saddr.p4; +- b += ((__u32)dport << 16) | sport; ++ a += HASH_WORD32_LE(tuple->saddr.p4); ++ b += ((__u32)HASH_WORD16_LE(dport) << 16) | HASH_WORD16_LE(sport); + c += tuple->nexthdr; + __jhash_mix(a, b, c); + a += HASH_INIT6_SEED; +@@ -43,3 +51,6 @@ static __always_inline __u32 hash_from_tuple_v6(const struct ipv6_ct_tuple *tupl + { + return __hash_from_tuple_v6(tuple, tuple->sport, tuple->dport); + } ++ ++#undef HASH_WORD16_LE ++#undef HASH_WORD32_LE +diff --git a/bpf/lib/ip_options.h b/bpf/lib/ip_options.h +index 4ee6b5e1a8..a821c022b3 100644 +--- a/bpf/lib/ip_options.h ++++ b/bpf/lib/ip_options.h +@@ -114,7 +114,7 @@ trace_id_from_ip4(struct __ctx_buff *ctx, __s64 *value, + + if (ctx_load_bytes(ctx, offset + 2, &temp, sizeof(temp)) < 0) + return TRACE_ID_ERROR; +- *value = bpf_ntohs(temp); ++ *value = (__u16)bpf_ntohs(temp); + return 0; + } + case OPT32_LEN: { +@@ -122,7 +122,7 @@ trace_id_from_ip4(struct __ctx_buff *ctx, __s64 *value, + + if (ctx_load_bytes(ctx, offset + 2, &temp, sizeof(temp)) < 0) + return TRACE_ID_ERROR; +- *value = bpf_ntohl(temp); ++ *value = (__u32)bpf_ntohl(temp); + return 0; + } + case OPT64_LEN: { +diff --git a/bpf/lib/ipv4.h b/bpf/lib/ipv4.h +index 7eea2caaa2..17950a8130 100644 +--- a/bpf/lib/ipv4.h ++++ b/bpf/lib/ipv4.h +@@ -67,8 +67,13 @@ static __always_inline int ipv4_dec_ttl(struct __ctx_buff *ctx, int off, + new_ttl = ttl - 1; + ip4->ttl = new_ttl; + +- /* l3_csum_replace() takes at min 2 bytes, zero extended. */ +- if (ipv4_csum_update_by_value(ctx, off, ttl, new_ttl, 2) < 0) ++ /* l3_csum_replace() takes at min 2 bytes, zero extended. ++ * TTL is the high byte of the 16-bit [TTL, Protocol] word in ++ * network order. Use bpf_htons() to place it correctly for ++ * the ones-complement checksum on both LE and BE. ++ */ ++ if (ipv4_csum_update_by_value(ctx, off, bpf_htons((__u16)ttl << 8), ++ bpf_htons((__u16)new_ttl << 8), 2) < 0) + return DROP_CSUM_L3; + + return 0; +diff --git a/bpf/lib/lb.h b/bpf/lib/lb.h +index 13e953da12..b39b8b1d4f 100644 +--- a/bpf/lib/lb.h ++++ b/bpf/lib/lb.h +@@ -129,8 +129,7 @@ union lb4_affinity_client_id { + struct lb4_affinity_key { + union lb4_affinity_client_id client_id; + __u16 rev_nat_id; +- __u8 netns_cookie:1, +- reserved:7; ++ __u8 netns_cookie; + __u8 pad1; + __u32 pad2; + } __packed; +@@ -143,8 +142,7 @@ union lb6_affinity_client_id { + struct lb6_affinity_key { + union lb6_affinity_client_id client_id; + __u16 rev_nat_id; +- __u8 netns_cookie:1, +- reserved:7; ++ __u8 netns_cookie; + __u8 pad1; + __u32 pad2; + } __packed; +diff --git a/bpf/lib/local_delivery.h b/bpf/lib/local_delivery.h +index f48235a8ba..59e793e9ec 100644 +--- a/bpf/lib/local_delivery.h ++++ b/bpf/lib/local_delivery.h +@@ -189,8 +189,8 @@ static __always_inline int ipv6_local_delivery(struct __ctx_buff *ctx, int l3_of + __u8 direction, bool from_host, + bool from_tunnel) + { +- mac_t router_mac = ep->node_mac; +- mac_t lxc_mac = ep->mac; ++ mac_t router_mac = mac_t_to_bytes(ep->node_mac); ++ mac_t lxc_mac = mac_t_to_bytes(ep->mac); + int ret; + + cilium_dbg(ctx, DBG_LOCAL_DELIVERY, ep->lxc_id, seclabel); +@@ -216,8 +216,8 @@ static __always_inline int ipv4_local_delivery(struct __ctx_buff *ctx, int l3_of + __u8 direction, bool from_host, + bool from_tunnel, __u32 cluster_id) + { +- mac_t router_mac = ep->node_mac; +- mac_t lxc_mac = ep->mac; ++ mac_t router_mac = mac_t_to_bytes(ep->node_mac); ++ mac_t lxc_mac = mac_t_to_bytes(ep->mac); + int ret; + + cilium_dbg(ctx, DBG_LOCAL_DELIVERY, ep->lxc_id, seclabel); +diff --git a/bpf/lib/policy.h b/bpf/lib/policy.h +index 9c25173590..8320cdb969 100644 +--- a/bpf/lib/policy.h ++++ b/bpf/lib/policy.h +@@ -53,8 +53,7 @@ enum { + struct policy_key { + struct bpf_lpm_trie_key lpm_key; + __u32 sec_label; +- __u8 egress:1, +- pad:7; ++ __u8 egress; + __u8 protocol; /* can be wildcarded if 'dport' is fully wildcarded */ + __be16 dport; /* can be wildcarded with CIDR-like prefix */ + }; +@@ -65,11 +64,19 @@ struct policy_key { + + struct policy_entry { + __be16 proxy_port; ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++ __u8 lpm_prefix_length:5, /* map key protocol and dport prefix length */ ++ reserved:2, /* bits used in Cilium 1.16, keep unused for Cilium 1.17 */ ++ deny:1; ++ __u8 has_explicit_auth_type:1, ++ auth_type:7; ++#else + __u8 deny:1, + reserved:2, /* bits used in Cilium 1.16, keep unused for Cilium 1.17 */ + lpm_prefix_length:5; /* map key protocol and dport prefix length */ + __u8 auth_type:7, + has_explicit_auth_type:1; ++#endif + __u32 precedence; + __u32 cookie; + }; +@@ -92,8 +99,7 @@ struct policy_stats_key { + __u8 pad1; + __u8 prefix_len; + __u32 sec_label; +- __u8 egress:1, +- pad:7; ++ __u8 egress; + __u8 protocol; /* can be wildcarded if 'dport' is fully wildcarded */ + __be16 dport; /* can be wildcarded with CIDR-like prefix */ + }; +@@ -124,7 +130,6 @@ __policy_account(__u32 remote_id, __u8 egress, __u8 proto, __be16 dport, __u8 lp + .prefix_len = lpm_prefix_length, + .sec_label = remote_id, + .egress = egress, +- .pad = 0, + }; + + /* +@@ -225,7 +230,6 @@ __policy_can_access(const void *map, struct __ctx_buff *ctx, __u32 local_id, + .lpm_key = { POLICY_FULL_PREFIX, {} }, /* always look up with unwildcarded data */ + .sec_label = remote_id, + .egress = !dir, +- .pad = 0, + .protocol = proto, + .dport = dport, + }; +diff --git a/bpf/tests/builtin_memcmp.h b/bpf/tests/builtin_memcmp.h +index 07168492c5..def789ae6f 100644 +--- a/bpf/tests/builtin_memcmp.h ++++ b/bpf/tests/builtin_memcmp.h +@@ -64,67 +64,3 @@ + test___builtin_memcmp_single(62); + test___builtin_memcmp_single(63); + test___builtin_memcmp_single(64); +- test___builtin_memcmp_single(65); +- test___builtin_memcmp_single(66); +- test___builtin_memcmp_single(67); +- test___builtin_memcmp_single(68); +- test___builtin_memcmp_single(69); +- test___builtin_memcmp_single(70); +- test___builtin_memcmp_single(71); +- test___builtin_memcmp_single(72); +- test___builtin_memcmp_single(73); +- test___builtin_memcmp_single(74); +- test___builtin_memcmp_single(75); +- test___builtin_memcmp_single(76); +- test___builtin_memcmp_single(77); +- test___builtin_memcmp_single(78); +- test___builtin_memcmp_single(79); +- test___builtin_memcmp_single(80); +- test___builtin_memcmp_single(81); +- test___builtin_memcmp_single(82); +- test___builtin_memcmp_single(83); +- test___builtin_memcmp_single(84); +- test___builtin_memcmp_single(85); +- test___builtin_memcmp_single(86); +- test___builtin_memcmp_single(87); +- test___builtin_memcmp_single(88); +- test___builtin_memcmp_single(89); +- test___builtin_memcmp_single(90); +- test___builtin_memcmp_single(91); +- test___builtin_memcmp_single(92); +- test___builtin_memcmp_single(93); +- test___builtin_memcmp_single(94); +- test___builtin_memcmp_single(95); +- test___builtin_memcmp_single(96); +- test___builtin_memcmp_single(97); +- test___builtin_memcmp_single(98); +- test___builtin_memcmp_single(99); +- test___builtin_memcmp_single(100); +- test___builtin_memcmp_single(101); +- test___builtin_memcmp_single(102); +- test___builtin_memcmp_single(103); +- test___builtin_memcmp_single(104); +- test___builtin_memcmp_single(105); +- test___builtin_memcmp_single(106); +- test___builtin_memcmp_single(107); +- test___builtin_memcmp_single(108); +- test___builtin_memcmp_single(109); +- test___builtin_memcmp_single(110); +- test___builtin_memcmp_single(111); +- test___builtin_memcmp_single(112); +- test___builtin_memcmp_single(113); +- test___builtin_memcmp_single(114); +- test___builtin_memcmp_single(115); +- test___builtin_memcmp_single(116); +- test___builtin_memcmp_single(117); +- test___builtin_memcmp_single(118); +- test___builtin_memcmp_single(119); +- test___builtin_memcmp_single(120); +- test___builtin_memcmp_single(121); +- test___builtin_memcmp_single(122); +- test___builtin_memcmp_single(123); +- test___builtin_memcmp_single(124); +- test___builtin_memcmp_single(125); +- test___builtin_memcmp_single(126); +- test___builtin_memcmp_single(127); +- test___builtin_memcmp_single(128); +diff --git a/bpf/tests/builtin_memcpy.h b/bpf/tests/builtin_memcpy.h +index e14abdd14e..bb78cd96bf 100644 +--- a/bpf/tests/builtin_memcpy.h ++++ b/bpf/tests/builtin_memcpy.h +@@ -64,67 +64,3 @@ + test___builtin_memcpy_single(62); + test___builtin_memcpy_single(63); + test___builtin_memcpy_single(64); +- test___builtin_memcpy_single(65); +- test___builtin_memcpy_single(66); +- test___builtin_memcpy_single(67); +- test___builtin_memcpy_single(68); +- test___builtin_memcpy_single(69); +- test___builtin_memcpy_single(70); +- test___builtin_memcpy_single(71); +- test___builtin_memcpy_single(72); +- test___builtin_memcpy_single(73); +- test___builtin_memcpy_single(74); +- test___builtin_memcpy_single(75); +- test___builtin_memcpy_single(76); +- test___builtin_memcpy_single(77); +- test___builtin_memcpy_single(78); +- test___builtin_memcpy_single(79); +- test___builtin_memcpy_single(80); +- test___builtin_memcpy_single(81); +- test___builtin_memcpy_single(82); +- test___builtin_memcpy_single(83); +- test___builtin_memcpy_single(84); +- test___builtin_memcpy_single(85); +- test___builtin_memcpy_single(86); +- test___builtin_memcpy_single(87); +- test___builtin_memcpy_single(88); +- test___builtin_memcpy_single(89); +- test___builtin_memcpy_single(90); +- test___builtin_memcpy_single(91); +- test___builtin_memcpy_single(92); +- test___builtin_memcpy_single(93); +- test___builtin_memcpy_single(94); +- test___builtin_memcpy_single(95); +- test___builtin_memcpy_single(96); +- test___builtin_memcpy_single(97); +- test___builtin_memcpy_single(98); +- test___builtin_memcpy_single(99); +- test___builtin_memcpy_single(100); +- test___builtin_memcpy_single(101); +- test___builtin_memcpy_single(102); +- test___builtin_memcpy_single(103); +- test___builtin_memcpy_single(104); +- test___builtin_memcpy_single(105); +- test___builtin_memcpy_single(106); +- test___builtin_memcpy_single(107); +- test___builtin_memcpy_single(108); +- test___builtin_memcpy_single(109); +- test___builtin_memcpy_single(110); +- test___builtin_memcpy_single(111); +- test___builtin_memcpy_single(112); +- test___builtin_memcpy_single(113); +- test___builtin_memcpy_single(114); +- test___builtin_memcpy_single(115); +- test___builtin_memcpy_single(116); +- test___builtin_memcpy_single(117); +- test___builtin_memcpy_single(118); +- test___builtin_memcpy_single(119); +- test___builtin_memcpy_single(120); +- test___builtin_memcpy_single(121); +- test___builtin_memcpy_single(122); +- test___builtin_memcpy_single(123); +- test___builtin_memcpy_single(124); +- test___builtin_memcpy_single(125); +- test___builtin_memcpy_single(126); +- test___builtin_memcpy_single(127); +- test___builtin_memcpy_single(128); +diff --git a/bpf/tests/builtin_memmove.h b/bpf/tests/builtin_memmove.h +index b2ad2a6c65..e4fd726867 100644 +--- a/bpf/tests/builtin_memmove.h ++++ b/bpf/tests/builtin_memmove.h +@@ -64,70 +64,6 @@ + test___builtin_memmove1_single(62); + test___builtin_memmove1_single(63); + test___builtin_memmove1_single(64); +- test___builtin_memmove1_single(65); +- test___builtin_memmove1_single(66); +- test___builtin_memmove1_single(67); +- test___builtin_memmove1_single(68); +- test___builtin_memmove1_single(69); +- test___builtin_memmove1_single(70); +- test___builtin_memmove1_single(71); +- test___builtin_memmove1_single(72); +- test___builtin_memmove1_single(73); +- test___builtin_memmove1_single(74); +- test___builtin_memmove1_single(75); +- test___builtin_memmove1_single(76); +- test___builtin_memmove1_single(77); +- test___builtin_memmove1_single(78); +- test___builtin_memmove1_single(79); +- test___builtin_memmove1_single(80); +- test___builtin_memmove1_single(81); +- test___builtin_memmove1_single(82); +- test___builtin_memmove1_single(83); +- test___builtin_memmove1_single(84); +- test___builtin_memmove1_single(85); +- test___builtin_memmove1_single(86); +- test___builtin_memmove1_single(87); +- test___builtin_memmove1_single(88); +- test___builtin_memmove1_single(89); +- test___builtin_memmove1_single(90); +- test___builtin_memmove1_single(91); +- test___builtin_memmove1_single(92); +- test___builtin_memmove1_single(93); +- test___builtin_memmove1_single(94); +- test___builtin_memmove1_single(95); +- test___builtin_memmove1_single(96); +- test___builtin_memmove1_single(97); +- test___builtin_memmove1_single(98); +- test___builtin_memmove1_single(99); +- test___builtin_memmove1_single(100); +- test___builtin_memmove1_single(101); +- test___builtin_memmove1_single(102); +- test___builtin_memmove1_single(103); +- test___builtin_memmove1_single(104); +- test___builtin_memmove1_single(105); +- test___builtin_memmove1_single(106); +- test___builtin_memmove1_single(107); +- test___builtin_memmove1_single(108); +- test___builtin_memmove1_single(109); +- test___builtin_memmove1_single(110); +- test___builtin_memmove1_single(111); +- test___builtin_memmove1_single(112); +- test___builtin_memmove1_single(113); +- test___builtin_memmove1_single(114); +- test___builtin_memmove1_single(115); +- test___builtin_memmove1_single(116); +- test___builtin_memmove1_single(117); +- test___builtin_memmove1_single(118); +- test___builtin_memmove1_single(119); +- test___builtin_memmove1_single(120); +- test___builtin_memmove1_single(121); +- test___builtin_memmove1_single(122); +- test___builtin_memmove1_single(123); +- test___builtin_memmove1_single(124); +- test___builtin_memmove1_single(125); +- test___builtin_memmove1_single(126); +- test___builtin_memmove1_single(127); +- test___builtin_memmove1_single(128); + test___builtin_memmove2_single(1); + test___builtin_memmove2_single(2); + test___builtin_memmove2_single(4); +@@ -161,38 +97,6 @@ + test___builtin_memmove2_single(60); + test___builtin_memmove2_single(62); + test___builtin_memmove2_single(64); +- test___builtin_memmove2_single(66); +- test___builtin_memmove2_single(68); +- test___builtin_memmove2_single(70); +- test___builtin_memmove2_single(72); +- test___builtin_memmove2_single(74); +- test___builtin_memmove2_single(76); +- test___builtin_memmove2_single(78); +- test___builtin_memmove2_single(80); +- test___builtin_memmove2_single(82); +- test___builtin_memmove2_single(84); +- test___builtin_memmove2_single(86); +- test___builtin_memmove2_single(88); +- test___builtin_memmove2_single(90); +- test___builtin_memmove2_single(92); +- test___builtin_memmove2_single(94); +- test___builtin_memmove2_single(96); +- test___builtin_memmove2_single(98); +- test___builtin_memmove2_single(100); +- test___builtin_memmove2_single(102); +- test___builtin_memmove2_single(104); +- test___builtin_memmove2_single(106); +- test___builtin_memmove2_single(108); +- test___builtin_memmove2_single(110); +- test___builtin_memmove2_single(112); +- test___builtin_memmove2_single(114); +- test___builtin_memmove2_single(116); +- test___builtin_memmove2_single(118); +- test___builtin_memmove2_single(120); +- test___builtin_memmove2_single(122); +- test___builtin_memmove2_single(124); +- test___builtin_memmove2_single(126); +- test___builtin_memmove2_single(128); + test___builtin_memmove3_single(1); + test___builtin_memmove3_single(2); + test___builtin_memmove3_single(4); +@@ -226,35 +130,3 @@ + test___builtin_memmove3_single(60); + test___builtin_memmove3_single(62); + test___builtin_memmove3_single(64); +- test___builtin_memmove3_single(66); +- test___builtin_memmove3_single(68); +- test___builtin_memmove3_single(70); +- test___builtin_memmove3_single(72); +- test___builtin_memmove3_single(74); +- test___builtin_memmove3_single(76); +- test___builtin_memmove3_single(78); +- test___builtin_memmove3_single(80); +- test___builtin_memmove3_single(82); +- test___builtin_memmove3_single(84); +- test___builtin_memmove3_single(86); +- test___builtin_memmove3_single(88); +- test___builtin_memmove3_single(90); +- test___builtin_memmove3_single(92); +- test___builtin_memmove3_single(94); +- test___builtin_memmove3_single(96); +- test___builtin_memmove3_single(98); +- test___builtin_memmove3_single(100); +- test___builtin_memmove3_single(102); +- test___builtin_memmove3_single(104); +- test___builtin_memmove3_single(106); +- test___builtin_memmove3_single(108); +- test___builtin_memmove3_single(110); +- test___builtin_memmove3_single(112); +- test___builtin_memmove3_single(114); +- test___builtin_memmove3_single(116); +- test___builtin_memmove3_single(118); +- test___builtin_memmove3_single(120); +- test___builtin_memmove3_single(122); +- test___builtin_memmove3_single(124); +- test___builtin_memmove3_single(126); +- test___builtin_memmove3_single(128); +diff --git a/bpf/tests/builtin_memmove2.h b/bpf/tests/builtin_memmove2.h +index 01d5e4aeb6..163937d780 100644 +--- a/bpf/tests/builtin_memmove2.h ++++ b/bpf/tests/builtin_memmove2.h +@@ -33,38 +33,6 @@ + test___builtin_memmove4_single(60); + test___builtin_memmove4_single(62); + test___builtin_memmove4_single(64); +- test___builtin_memmove4_single(66); +- test___builtin_memmove4_single(68); +- test___builtin_memmove4_single(70); +- test___builtin_memmove4_single(72); +- test___builtin_memmove4_single(74); +- test___builtin_memmove4_single(76); +- test___builtin_memmove4_single(78); +- test___builtin_memmove4_single(80); +- test___builtin_memmove4_single(82); +- test___builtin_memmove4_single(84); +- test___builtin_memmove4_single(86); +- test___builtin_memmove4_single(88); +- test___builtin_memmove4_single(90); +- test___builtin_memmove4_single(92); +- test___builtin_memmove4_single(94); +- test___builtin_memmove4_single(96); +- test___builtin_memmove4_single(98); +- test___builtin_memmove4_single(100); +- test___builtin_memmove4_single(102); +- test___builtin_memmove4_single(104); +- test___builtin_memmove4_single(106); +- test___builtin_memmove4_single(108); +- test___builtin_memmove4_single(110); +- test___builtin_memmove4_single(112); +- test___builtin_memmove4_single(114); +- test___builtin_memmove4_single(116); +- test___builtin_memmove4_single(118); +- test___builtin_memmove4_single(120); +- test___builtin_memmove4_single(122); +- test___builtin_memmove4_single(124); +- test___builtin_memmove4_single(126); +- test___builtin_memmove4_single(128); + test___builtin_memmove5_single(1); + test___builtin_memmove5_single(2); + test___builtin_memmove5_single(4); +@@ -98,35 +66,3 @@ + test___builtin_memmove5_single(60); + test___builtin_memmove5_single(62); + test___builtin_memmove5_single(64); +- test___builtin_memmove5_single(66); +- test___builtin_memmove5_single(68); +- test___builtin_memmove5_single(70); +- test___builtin_memmove5_single(72); +- test___builtin_memmove5_single(74); +- test___builtin_memmove5_single(76); +- test___builtin_memmove5_single(78); +- test___builtin_memmove5_single(80); +- test___builtin_memmove5_single(82); +- test___builtin_memmove5_single(84); +- test___builtin_memmove5_single(86); +- test___builtin_memmove5_single(88); +- test___builtin_memmove5_single(90); +- test___builtin_memmove5_single(92); +- test___builtin_memmove5_single(94); +- test___builtin_memmove5_single(96); +- test___builtin_memmove5_single(98); +- test___builtin_memmove5_single(100); +- test___builtin_memmove5_single(102); +- test___builtin_memmove5_single(104); +- test___builtin_memmove5_single(106); +- test___builtin_memmove5_single(108); +- test___builtin_memmove5_single(110); +- test___builtin_memmove5_single(112); +- test___builtin_memmove5_single(114); +- test___builtin_memmove5_single(116); +- test___builtin_memmove5_single(118); +- test___builtin_memmove5_single(120); +- test___builtin_memmove5_single(122); +- test___builtin_memmove5_single(124); +- test___builtin_memmove5_single(126); +- test___builtin_memmove5_single(128); +diff --git a/bpf/tests/builtin_memzero.h b/bpf/tests/builtin_memzero.h +index dba7d15747..238c0a172a 100644 +--- a/bpf/tests/builtin_memzero.h ++++ b/bpf/tests/builtin_memzero.h +@@ -64,67 +64,3 @@ + test___builtin_memzero_single(62); + test___builtin_memzero_single(63); + test___builtin_memzero_single(64); +- test___builtin_memzero_single(65); +- test___builtin_memzero_single(66); +- test___builtin_memzero_single(67); +- test___builtin_memzero_single(68); +- test___builtin_memzero_single(69); +- test___builtin_memzero_single(70); +- test___builtin_memzero_single(71); +- test___builtin_memzero_single(72); +- test___builtin_memzero_single(73); +- test___builtin_memzero_single(74); +- test___builtin_memzero_single(75); +- test___builtin_memzero_single(76); +- test___builtin_memzero_single(77); +- test___builtin_memzero_single(78); +- test___builtin_memzero_single(79); +- test___builtin_memzero_single(80); +- test___builtin_memzero_single(81); +- test___builtin_memzero_single(82); +- test___builtin_memzero_single(83); +- test___builtin_memzero_single(84); +- test___builtin_memzero_single(85); +- test___builtin_memzero_single(86); +- test___builtin_memzero_single(87); +- test___builtin_memzero_single(88); +- test___builtin_memzero_single(89); +- test___builtin_memzero_single(90); +- test___builtin_memzero_single(91); +- test___builtin_memzero_single(92); +- test___builtin_memzero_single(93); +- test___builtin_memzero_single(94); +- test___builtin_memzero_single(95); +- test___builtin_memzero_single(96); +- test___builtin_memzero_single(97); +- test___builtin_memzero_single(98); +- test___builtin_memzero_single(99); +- test___builtin_memzero_single(100); +- test___builtin_memzero_single(101); +- test___builtin_memzero_single(102); +- test___builtin_memzero_single(103); +- test___builtin_memzero_single(104); +- test___builtin_memzero_single(105); +- test___builtin_memzero_single(106); +- test___builtin_memzero_single(107); +- test___builtin_memzero_single(108); +- test___builtin_memzero_single(109); +- test___builtin_memzero_single(110); +- test___builtin_memzero_single(111); +- test___builtin_memzero_single(112); +- test___builtin_memzero_single(113); +- test___builtin_memzero_single(114); +- test___builtin_memzero_single(115); +- test___builtin_memzero_single(116); +- test___builtin_memzero_single(117); +- test___builtin_memzero_single(118); +- test___builtin_memzero_single(119); +- test___builtin_memzero_single(120); +- test___builtin_memzero_single(121); +- test___builtin_memzero_single(122); +- test___builtin_memzero_single(123); +- test___builtin_memzero_single(124); +- test___builtin_memzero_single(125); +- test___builtin_memzero_single(126); +- test___builtin_memzero_single(127); +- test___builtin_memzero_single(128); +diff --git a/bpf/tests/common.h b/bpf/tests/common.h +index c58fb63b32..1e990aea6f 100644 +--- a/bpf/tests/common.h ++++ b/bpf/tests/common.h +@@ -30,28 +30,28 @@ + #endif + + #define __bpf_log_arg0(ptr, arg) do {} while (0) +-#define __bpf_log_arg1(ptr, arg) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; ptr += sizeof(__u64) +-#define __bpf_log_arg2(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg1(ptr, arg) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); ptr += sizeof(__u64) ++#define __bpf_log_arg2(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg1(ptr, args) +-#define __bpf_log_arg3(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg3(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg2(ptr, args) +-#define __bpf_log_arg4(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg4(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg3(ptr, args) +-#define __bpf_log_arg5(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg5(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg4(ptr, args) +-#define __bpf_log_arg6(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg6(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg5(ptr, args) +-#define __bpf_log_arg7(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg7(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg6(ptr, args) +-#define __bpf_log_arg8(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg8(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg7(ptr, args) +-#define __bpf_log_arg9(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg9(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg8(ptr, args) +-#define __bpf_log_arg10(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg10(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg9(ptr, args) +-#define __bpf_log_arg11(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg11(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg10(ptr, args) +-#define __bpf_log_arg12(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \ ++#define __bpf_log_arg12(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; __bpf_log_store_u64(ptr, arg); \ + ptr += sizeof(__u64); __bpf_log_arg11(ptr, args) + #define __bpf_log_arg(ptr, args...) \ + ___bpf_apply(__bpf_log_arg, ___bpf_narg(args))(ptr, args) +@@ -98,6 +98,15 @@ struct { + #define MKR_LOG_FMT PROTOBUF_WIRE_TYPE(1, PROTOBUF_LENGTH_DELIMITED) + #define MKR_LOG_ARG PROTOBUF_WIRE_TYPE(2, PROTOBUF_FIXED64) + ++/* Protobuf FIXED64 must be little-endian on the wire. On big-endian BPF ++ * targets (bpfeb), we must byte-swap before writing. ++ */ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++#define __bpf_log_store_u64(ptr, val) (*(__u64 *)(ptr) = __builtin_bswap64(val)) ++#else ++#define __bpf_log_store_u64(ptr, val) (*(__u64 *)(ptr) = (val)) ++#endif ++ + /* Write a message to the unit log + * The conversion specifiers supported by *fmt* are the same as for + * bpf_trace_printk(). They are **%d**, **%i**, **%u**, **%x**, **%ld**, +diff --git a/bpf/tests/inter_cluster_snat_clusterip_backend_lxc.c b/bpf/tests/inter_cluster_snat_clusterip_backend_lxc.c +index fd484233b0..fe51250ae9 100644 +--- a/bpf/tests/inter_cluster_snat_clusterip_backend_lxc.c ++++ b/bpf/tests/inter_cluster_snat_clusterip_backend_lxc.c +@@ -200,7 +200,7 @@ int overlay_to_lxc_syn_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x1df4)) ++ if (l4->check != bpf_htons(0x7d94)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + /* Check ingress conntrack state is in the default CT */ +@@ -296,7 +296,7 @@ int lxc_to_overlay_ack_check(struct __ctx_buff *ctx) + if (l4->dest != CLIENT_INTER_CLUSTER_SNAT_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x1de4)) ++ if (l4->check != bpf_htons(0x7d84)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + /* Make sure we hit the conntrack entry */ +@@ -389,7 +389,7 @@ int overlay_to_lxc_ack_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x1de6)) ++ if (l4->check != bpf_htons(0x7d86)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + /* Make sure we hit the conntrack entry */ +diff --git a/bpf/tests/inter_cluster_snat_clusterip_backend_overlay.c b/bpf/tests/inter_cluster_snat_clusterip_backend_overlay.c +index ede936947a..d6220d81c9 100644 +--- a/bpf/tests/inter_cluster_snat_clusterip_backend_overlay.c ++++ b/bpf/tests/inter_cluster_snat_clusterip_backend_overlay.c +@@ -240,7 +240,7 @@ int from_overlay_syn_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x777f)) ++ if (l4->check != bpf_htons(0xd71f)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + meta = ctx_load_meta(ctx, CB_DELIVERY_REDIRECT); +@@ -333,7 +333,7 @@ int to_overlay_synack_check(struct __ctx_buff *ctx) + if (l4->dest != CLIENT_INTER_CLUSTER_SNAT_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x776f)) ++ if (l4->check != bpf_htons(0xd70f)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -407,7 +407,7 @@ int from_overlay_ack_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x7771)) ++ if (l4->check != bpf_htons(0xd711)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + meta = ctx_load_meta(ctx, CB_DELIVERY_REDIRECT); +diff --git a/bpf/tests/inter_cluster_snat_clusterip_client_lxc.c b/bpf/tests/inter_cluster_snat_clusterip_client_lxc.c +index c5da52fdbf..b8014fe3d5 100644 +--- a/bpf/tests/inter_cluster_snat_clusterip_client_lxc.c ++++ b/bpf/tests/inter_cluster_snat_clusterip_client_lxc.c +@@ -208,7 +208,7 @@ int lxc_to_overlay_syn_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0xd64b)) ++ if (l4->check != bpf_htons(0x35ec)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + /* Check service conntrack state is in the default CT */ +@@ -315,7 +315,7 @@ int overlay_to_lxc_synack_check(struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port is not client port"); + +- if (l4->check != bpf_htons(0x6325)) ++ if (l4->check != bpf_htons(0xc2c5)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + /* Make sure we hit the conntrack entry */ +@@ -405,7 +405,7 @@ int lxc_to_overlay_ack_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0xd63d)) ++ if (l4->check != bpf_htons(0x35de)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + /* Make sure we hit the conntrack entry */ +diff --git a/bpf/tests/inter_cluster_snat_clusterip_client_overlay.c b/bpf/tests/inter_cluster_snat_clusterip_client_overlay.c +index 08f41c3156..3463ee76d4 100644 +--- a/bpf/tests/inter_cluster_snat_clusterip_client_overlay.c ++++ b/bpf/tests/inter_cluster_snat_clusterip_client_overlay.c +@@ -236,7 +236,7 @@ int to_overlay_syn_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x777e)) ++ if (l4->check != bpf_htons(0xd71e)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + tuple.daddr = BACKEND_IP; +@@ -338,7 +338,7 @@ int from_overlay_synack_check(struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port hasn't been RevSNATed to client port"); + +- if (l4->check != bpf_htons(0x2fc5)) ++ if (l4->check != bpf_htons(0x8f65)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + meta = ctx_load_meta(ctx, CB_DELIVERY_REDIRECT); +@@ -435,7 +435,7 @@ int to_overlay_ack_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x7770)) ++ if (l4->check != bpf_htons(0xd710)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/ipsec_from_network_generic.h b/bpf/tests/ipsec_from_network_generic.h +index c83bf67da5..938920afdd 100644 +--- a/bpf/tests/ipsec_from_network_generic.h ++++ b/bpf/tests/ipsec_from_network_generic.h +@@ -361,7 +361,7 @@ int ipv4_decrypted_ipsec_from_network_check(__maybe_unused const struct __ctx_bu + if (l4->dest != tcp_svc_one) + test_fatal("dst TCP port was changed"); + +- if (l4->check != bpf_htons(0x589c)) ++ if (l4->check != bpf_htons(0xb83c)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + payload = (void *)l4 + sizeof(struct tcphdr); +@@ -468,7 +468,7 @@ int ipv6_decrypted_ipsec_from_network_check(__maybe_unused const struct __ctx_bu + if (l4->dest != tcp_svc_one) + test_fatal("dst TCP port was changed"); + +- if (l4->check != bpf_htons(0xdfe3)) ++ if (l4->check != bpf_htons(0x3f84)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + payload = (void *)l4 + sizeof(struct tcphdr); +diff --git a/bpf/tests/l4lb_ipip_health_check_host.c b/bpf/tests/l4lb_ipip_health_check_host.c +index 405eb7fd6b..a26adf10b8 100644 +--- a/bpf/tests/l4lb_ipip_health_check_host.c ++++ b/bpf/tests/l4lb_ipip_health_check_host.c +@@ -166,7 +166,7 @@ int l4lb_health_check_host_check(const struct __ctx_buff *ctx) + if (l4->dest != FRONTEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0xba00)) ++ if (l4->check != bpf_htons(0x19a1)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/pktgen.h b/bpf/tests/pktgen.h +index d26b1ef6d1..309ce825d3 100644 +--- a/bpf/tests/pktgen.h ++++ b/bpf/tests/pktgen.h +@@ -48,7 +48,7 @@ volatile const __u8 mac_host[] = host_mac_addr; + * having to come up with custom ips. + */ + +-#define IPV4(a, b, c, d) __bpf_htonl(((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) ++#define IPV4(a, b, c, d) __bpf_htonl(((__u32)(a) << 24) + ((__u32)(b) << 16) + ((__u32)(c) << 8) + (__u32)(d)) + + /* IPv4 addresses for hosts, external to the cluster */ + #define v4_ext_one IPV4(110, 0, 11, 1) +@@ -453,8 +453,8 @@ struct tcphdr *pktgen__push_default_tcphdr(struct pktgen *builder) + return 0; + + hdr->syn = 1; +- hdr->seq = 123456; +- hdr->window = 65535; ++ hdr->seq = bpf_htonl(123456); ++ hdr->window = bpf_htons(65535); + + /* In most cases the doff is 5, so a good default if we can't + * calc the actual offset +@@ -503,8 +503,8 @@ struct ip_esp_hdr *pktgen__push_default_esphdr(struct pktgen *builder) + if (!hdr) + return 0; + +- hdr->spi = 1; +- hdr->seq_no = 10000; ++ hdr->spi = bpf_htonl(1); ++ hdr->seq_no = bpf_htonl(10000); + + return hdr; + } +@@ -1135,7 +1135,7 @@ pktgen__ip_csum(const struct pktgen *builder, int i) + + csum = csum_diff(NULL, 0, &ipv4_layer->saddr, sizeof(__be32), 0); + csum = csum_diff(NULL, 0, &ipv4_layer->daddr, sizeof(__be32), csum); +- tmp = (__u16)ipv4_layer->protocol << 8; ++ tmp = bpf_htons((__u16)ipv4_layer->protocol); + csum = csum_diff(NULL, 0, &tmp, sizeof(__u32), csum); + return csum; + case PKT_LAYER_IPV6: +@@ -1150,7 +1150,7 @@ pktgen__ip_csum(const struct pktgen *builder, int i) + + csum = csum_diff(NULL, 0, &ipv6_layer->saddr, sizeof(struct in6_addr), 0); + csum = csum_diff(NULL, 0, &ipv6_layer->daddr, sizeof(struct in6_addr), csum); +- tmp = (__u16)ipv6_layer->nexthdr << 8; ++ tmp = bpf_htons((__u16)ipv6_layer->nexthdr); + csum = csum_diff(NULL, 0, &tmp, sizeof(__u32), csum); + return csum; + default: +diff --git a/bpf/tests/session_affinity_maglev_test.c b/bpf/tests/session_affinity_maglev_test.c +index c22e17751b..247850c23d 100644 +--- a/bpf/tests/session_affinity_maglev_test.c ++++ b/bpf/tests/session_affinity_maglev_test.c +@@ -92,6 +92,20 @@ struct { + + #define OVERWRITE_MAGLEV_MAP_FROM_TEST 1 + ++/* Maglev hash produces different backend selections on LE vs BE ++ * because jhash operates on host-order integers. The source IP has ++ * different integer values on LE and BE (same network-order bytes), ++ * which changes the hash result and thus the backend selection. ++ */ ++#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ++#define CLIENT1_BACKEND_ID 18 ++#define CLIENT2_BACKEND_ID 11 ++#else ++#define CLIENT1_BACKEND_ID 13 ++#define CLIENT2_BACKEND_ID 14 ++#endif ++ ++ + static __always_inline void get_backend_mac(__u8 *dst, __u32 backend_id) + { + __bpf_memcpy_builtin(dst, (__u8 *)base_backend_mac, ETH_ALEN); +@@ -278,7 +292,7 @@ CHECK("xdp", "session_affinity_maglev_client_1_port_1") + int test_1_1(__maybe_unused const struct __ctx_buff *ctx) + { + /* Client 1 always maps to the backend 13 */ +- return check_packet(ctx, 13); ++ return check_packet(ctx, CLIENT1_BACKEND_ID); + } + + /* ------------------------------------------------------------------------------ */ +@@ -301,7 +315,7 @@ CHECK("xdp", "session_affinity_maglev_client_1_port_2") + int test_1_2(__maybe_unused const struct __ctx_buff *ctx) + { + /* Client 1 always maps to the backend 13 */ +- return check_packet(ctx, 13); ++ return check_packet(ctx, CLIENT1_BACKEND_ID); + } + + /* ------------------------------------------------------------------------------ */ +@@ -324,7 +338,7 @@ CHECK("xdp", "session_affinity_maglev_client_1_port_3") + int test_1_3(__maybe_unused const struct __ctx_buff *ctx) + { + /* Client 1 always maps to the backend 13 */ +- return check_packet(ctx, 13); ++ return check_packet(ctx, CLIENT1_BACKEND_ID); + } + + /* ------------------------------------------------------------------------------ */ +@@ -347,7 +361,7 @@ CHECK("xdp", "session_affinity_maglev_client_2_port_1") + int test_2_1(__maybe_unused const struct __ctx_buff *ctx) + { + /* Client 2 always maps to the backend 14 */ +- return check_packet(ctx, 14); ++ return check_packet(ctx, CLIENT2_BACKEND_ID); + } + + /* ------------------------------------------------------------------------------ */ +@@ -370,7 +384,7 @@ CHECK("xdp", "session_affinity_maglev_client_2_port_2") + int test_2_2(__maybe_unused const struct __ctx_buff *ctx) + { + /* Client 2 always maps to the backend 14 */ +- return check_packet(ctx, 14); ++ return check_packet(ctx, CLIENT2_BACKEND_ID); + } + + /* ------------------------------------------------------------------------------ */ +@@ -393,5 +407,5 @@ CHECK("xdp", "session_affinity_maglev_client_2_port_3") + int test_2_3(__maybe_unused const struct __ctx_buff *ctx) + { + /* Client 2 always maps to the backend 14 */ +- return check_packet(ctx, 14); ++ return check_packet(ctx, CLIENT2_BACKEND_ID); + } +diff --git a/bpf/tests/tc_egressgw_redirect_from_host.c b/bpf/tests/tc_egressgw_redirect_from_host.c +index cab3636cb1..b047e38b70 100644 +--- a/bpf/tests/tc_egressgw_redirect_from_host.c ++++ b/bpf/tests/tc_egressgw_redirect_from_host.c +@@ -37,7 +37,7 @@ int egressgw_redirect_setup(struct __ctx_buff *ctx) + { + ipcache_v4_add_world_entry(); + create_ct_entry(ctx, client_port(TEST_REDIRECT)); +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, GATEWAY_NODE_IP, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, GATEWAY_NODE_IP, + EGRESS_IP); + ipcache_v4_add_entry(EGRESS_IP, 0, HOST_ID, 0, 0); + +@@ -51,7 +51,7 @@ int egressgw_redirect_check(const struct __ctx_buff *ctx) + .status_code = TC_ACT_REDIRECT, + }); + +- del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24); ++ del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24); + + return ret; + } +@@ -72,7 +72,7 @@ int egressgw_skip_excluded_cidr_redirect_setup(struct __ctx_buff *ctx) + { + ipcache_v4_add_world_entry(); + create_ct_entry(ctx, client_port(TEST_REDIRECT_EXCL_CIDR)); +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, GATEWAY_NODE_IP, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, GATEWAY_NODE_IP, + EGRESS_IP); + add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP, 32, EGRESS_GATEWAY_EXCLUDED_CIDR, + EGRESS_IP); +@@ -88,7 +88,7 @@ int egressgw_skip_excluded_cidr_redirect_check(const struct __ctx_buff *ctx) + .status_code = TC_ACT_OK, + }); + +- del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24); ++ del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24); + del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP, 32); + + return ret; +diff --git a/bpf/tests/tc_egressgw_redirect_from_overlay.c b/bpf/tests/tc_egressgw_redirect_from_overlay.c +index 050627931f..0155df1d49 100644 +--- a/bpf/tests/tc_egressgw_redirect_from_overlay.c ++++ b/bpf/tests/tc_egressgw_redirect_from_overlay.c +@@ -75,7 +75,7 @@ int egressgw_redirect_pktgen(struct __ctx_buff *ctx) + SETUP("tc", "tc_egressgw_redirect_from_overlay") + int egressgw_redirect_setup(struct __ctx_buff *ctx) + { +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, GATEWAY_NODE_IP, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, GATEWAY_NODE_IP, + EGRESS_IP); + + return overlay_receive_packet(ctx); +@@ -88,7 +88,7 @@ int egressgw_redirect_check(const struct __ctx_buff *ctx) + .status_code = TC_ACT_REDIRECT, + }); + +- del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24); ++ del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24); + + return ret; + } +@@ -107,7 +107,7 @@ int egressgw_skip_excluded_cidr_redirect_pktgen(struct __ctx_buff *ctx) + SETUP("tc", "tc_egressgw_skip_excluded_cidr_redirect_from_overlay") + int egressgw_skip_excluded_cidr_redirect_setup(struct __ctx_buff *ctx) + { +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, GATEWAY_NODE_IP, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, GATEWAY_NODE_IP, + EGRESS_IP); + add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP, 32, EGRESS_GATEWAY_EXCLUDED_CIDR, + EGRESS_IP); +@@ -122,7 +122,7 @@ int egressgw_skip_excluded_cidr_redirect_check(const struct __ctx_buff *ctx) + .status_code = TC_ACT_OK, + }); + +- del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24); ++ del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24); + del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP, 32); + + return ret; +diff --git a/bpf/tests/tc_egressgw_redirect_from_overlay_with_egress_interface.c b/bpf/tests/tc_egressgw_redirect_from_overlay_with_egress_interface.c +index df7c43863c..b246f3bd71 100644 +--- a/bpf/tests/tc_egressgw_redirect_from_overlay_with_egress_interface.c ++++ b/bpf/tests/tc_egressgw_redirect_from_overlay_with_egress_interface.c +@@ -72,7 +72,7 @@ int egressgw_redirect_pktgen(struct __ctx_buff *ctx) + SETUP("tc", "tc_egressgw_redirect_from_overlay_with_egress_interface") + int egressgw_redirect_setup(struct __ctx_buff *ctx) + { +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, GATEWAY_NODE_IP, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, GATEWAY_NODE_IP, + EGRESS_IP); + + return overlay_receive_packet(ctx); +@@ -85,7 +85,7 @@ int egressgw_redirect_check(const struct __ctx_buff *ctx) + .status_code = TC_ACT_REDIRECT, + }); + +- del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24); ++ del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24); + + return ret; + } +diff --git a/bpf/tests/tc_egressgw_snat.c b/bpf/tests/tc_egressgw_snat.c +index 4668dfed38..7edb2f45c3 100644 +--- a/bpf/tests/tc_egressgw_snat.c ++++ b/bpf/tests/tc_egressgw_snat.c +@@ -91,7 +91,7 @@ int egressgw_snat1_pktgen(struct __ctx_buff *ctx) + SETUP("tc", "tc_egressgw_snat1") + int egressgw_snat1_setup(struct __ctx_buff *ctx) + { +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, + GATEWAY_NODE_IP, EGRESS_IP); + ipcache_v4_add_entry(EGRESS_IP, 0, HOST_ID, 0, 0); + +@@ -187,7 +187,7 @@ int egressgw_tuple_collision1_pktgen(struct __ctx_buff *ctx) + SETUP("tc", "tc_egressgw_tuple_collision1") + int egressgw_tuple_collision1_setup(struct __ctx_buff *ctx) + { +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, + GATEWAY_NODE_IP, EGRESS_IP); + ipcache_v4_add_entry(EGRESS_IP, 0, HOST_ID, 0, 0); + +@@ -221,7 +221,7 @@ int egressgw_tuple_collision2_pktgen(struct __ctx_buff *ctx) + SETUP("tc", "tc_egressgw_tuple_collision2") + int egressgw_tuple_collision2_setup(struct __ctx_buff *ctx) + { +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, + GATEWAY_NODE_IP, EGRESS_IP3); + ipcache_v4_add_entry(EGRESS_IP3, 0, HOST_ID, 0, 0); + +@@ -294,7 +294,7 @@ SETUP("tc", "tc_egressgw_skip_excluded_cidr_snat") + int egressgw_skip_excluded_cidr_snat_setup(struct __ctx_buff *ctx) + { + +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, GATEWAY_NODE_IP, 0); ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, GATEWAY_NODE_IP, 0); + add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP, 32, EGRESS_GATEWAY_EXCLUDED_CIDR, 0); + + set_identity_mark(ctx, CLIENT_IDENTITY, MARK_MAGIC_EGW_DONE); +@@ -372,7 +372,7 @@ int egressgw_fib_redirect_pktgen(struct __ctx_buff *ctx) + SETUP("tc", "tc_egressgw_fib_redirect") + int egressgw_fib_redirect_setup(struct __ctx_buff *ctx) + { +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, + GATEWAY_NODE_IP, EGRESS_IP2); + ipcache_v4_add_entry(EGRESS_IP2, 0, HOST_ID, 0, 0); + +@@ -391,7 +391,7 @@ int egressgw_fib_redirect_check(const struct __ctx_buff *ctx __maybe_unused) + .status_code = CTX_ACT_REDIRECT, + }); + +- del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24); ++ del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24); + + return ret; + } +diff --git a/bpf/tests/tc_lxc_lb6_no_backend.c b/bpf/tests/tc_lxc_lb6_no_backend.c +index bd53c5e93d..5714c9496f 100644 +--- a/bpf/tests/tc_lxc_lb6_no_backend.c ++++ b/bpf/tests/tc_lxc_lb6_no_backend.c +@@ -127,7 +127,7 @@ int lxc_no_backend_check(__maybe_unused const struct __ctx_buff *ctx) + * context with the runner option and importing the packet into + * wireshark + */ +- assert(l4->icmp6_cksum == bpf_htons(0x9e14)); ++ assert(l4->icmp6_cksum == bpf_htons(0x9b17)); + + test_finish(); + } +diff --git a/bpf/tests/tc_nodeport_l3_dev.h b/bpf/tests/tc_nodeport_l3_dev.h +index eaaf7ca39a..e144b5b99f 100644 +--- a/bpf/tests/tc_nodeport_l3_dev.h ++++ b/bpf/tests/tc_nodeport_l3_dev.h +@@ -363,18 +363,18 @@ l3_check: + + if (is_ipv4) + if (is_host) { +- if (l4->check != bpf_htons(0xb1ed)) ++ if (l4->check != bpf_htons(0x118e)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + } else { +- if (l4->check != bpf_htons(0x589c)) ++ if (l4->check != bpf_htons(0xb83c)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + } + else + if (is_host) { +- if (l4->check != bpf_htons(0xdfe1)) ++ if (l4->check != bpf_htons(0x3f82)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + } else { +- if (l4->check != bpf_htons(0xdfe3)) ++ if (l4->check != bpf_htons(0x3f84)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + } + +diff --git a/bpf/tests/tc_nodeport_lb4_dsr_backend.c b/bpf/tests/tc_nodeport_lb4_dsr_backend.c +index ec8377cb87..144e34b4ea 100644 +--- a/bpf/tests/tc_nodeport_lb4_dsr_backend.c ++++ b/bpf/tests/tc_nodeport_lb4_dsr_backend.c +@@ -243,7 +243,7 @@ int nodeport_dsr_backend_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0xd7d0)) ++ if (l4->check != bpf_htons(0x3771)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + struct ipv4_ct_tuple tuple; +@@ -359,7 +359,7 @@ static __always_inline int check_reply(const struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x01a9)) ++ if (l4->check != bpf_htons(0x6149)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -549,7 +549,7 @@ int nodeport_dsr_backend_redirect_check(struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0xcccf)) ++ if (l4->check != bpf_htons(0x2c70)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + struct ipv4_ct_tuple tuple; +@@ -676,7 +676,7 @@ int nodeport_dsr_backend_redirect_reply_check(struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0xcccf)) ++ if (l4->check != bpf_htons(0x2c70)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/tc_nodeport_lb4_dsr_ipip.c b/bpf/tests/tc_nodeport_lb4_dsr_ipip.c +index abf9f17ae5..b8ba1eb1b6 100644 +--- a/bpf/tests/tc_nodeport_lb4_dsr_ipip.c ++++ b/bpf/tests/tc_nodeport_lb4_dsr_ipip.c +@@ -182,7 +182,7 @@ int nodeport_dsr_ipip_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + test_fatal("src port has changed"); + if (l4->dest != FRONTEND_PORT) + test_fatal("dst port has changed"); +- if (l4->check != bpf_htons(0x01a8)) ++ if (l4->check != bpf_htons(0x6148)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + tunnel_key = map_lookup_elem(&tunnel_key_map, &key); +diff --git a/bpf/tests/tc_nodeport_lb4_dsr_lb.c b/bpf/tests/tc_nodeport_lb4_dsr_lb.c +index 899e66d64d..9772d8a029 100644 +--- a/bpf/tests/tc_nodeport_lb4_dsr_lb.c ++++ b/bpf/tests/tc_nodeport_lb4_dsr_lb.c +@@ -138,7 +138,7 @@ int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + if (l3->daddr != BACKEND_IP) + test_fatal("dst IP hasn't been NATed to remote backend IP"); + +- if (l3->check != bpf_htons(0x434a)) ++ if (l3->check != bpf_htons(0xef9d)) + test_fatal("L3 checksum is invalid: %x", bpf_htons(l3->check)); + + if (opt->type != DSR_IPV4_OPT_TYPE) +@@ -156,7 +156,7 @@ int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0xd7cf)) ++ if (l4->check != bpf_htons(0x3770)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/tc_nodeport_lb4_nat_backend.c b/bpf/tests/tc_nodeport_lb4_nat_backend.c +index 70ad33477b..6c92e9dbf4 100644 +--- a/bpf/tests/tc_nodeport_lb4_nat_backend.c ++++ b/bpf/tests/tc_nodeport_lb4_nat_backend.c +@@ -159,7 +159,7 @@ int nodeport_nat_backend_check(const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x3c62)) ++ if (l4->check != bpf_htons(0x9c02)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/tc_nodeport_lb4_nat_lb.c b/bpf/tests/tc_nodeport_lb4_nat_lb.c +index 112ea97c75..31e2cc83cc 100644 +--- a/bpf/tests/tc_nodeport_lb4_nat_lb.c ++++ b/bpf/tests/tc_nodeport_lb4_nat_lb.c +@@ -259,7 +259,7 @@ int nodeport_local_backend_check(const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst TCP port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0xd7d0)) ++ if (l4->check != bpf_htons(0x3771)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -352,7 +352,7 @@ int nodeport_local_backend_reply_check(const struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x01a9)) ++ if (l4->check != bpf_htons(0x6149)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -447,7 +447,7 @@ int nodeport_local_backend_redirect_check(const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst TCP port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0xcccf)) ++ if (l4->check != bpf_htons(0x2c70)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -542,7 +542,7 @@ int nodeport_local_backend_redirect_reply_check(const struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0xcccf)) ++ if (l4->check != bpf_htons(0x2c70)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -819,7 +819,7 @@ static __always_inline int check_reply(const struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port hasn't been RevNATed to client port"); + +- if (l4->check != bpf_htons(0x1a8)) ++ if (l4->check != bpf_htons(0x6148)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/tc_nodeport_lb4_wildcard_drop.c b/bpf/tests/tc_nodeport_lb4_wildcard_drop.c +index fcf0daed8d..937397fb08 100644 +--- a/bpf/tests/tc_nodeport_lb4_wildcard_drop.c ++++ b/bpf/tests/tc_nodeport_lb4_wildcard_drop.c +@@ -151,7 +151,7 @@ static __always_inline int validate_packet(const struct __ctx_buff *ctx, + assert(l4->source == CLIENT_PORT); + assert(l4->dest == dport); + assert(l4->syn == 1); +- assert(l4->seq == 123456); ++ assert(l4->seq == bpf_htonl(123456)); + assert(l4->window == 65535); + assert(l4->doff == 5); + +diff --git a/bpf/tests/tc_nodeport_lb6_dsr_backend.c b/bpf/tests/tc_nodeport_lb6_dsr_backend.c +index 650e302d62..531d1ddc3c 100644 +--- a/bpf/tests/tc_nodeport_lb6_dsr_backend.c ++++ b/bpf/tests/tc_nodeport_lb6_dsr_backend.c +@@ -359,7 +359,7 @@ int check_reply(const struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x2dbc)) ++ if (l4->check != bpf_htons(0x8d5c)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/tc_nodeport_lb6_dsr_ipip.c b/bpf/tests/tc_nodeport_lb6_dsr_ipip.c +index 3de7b6fb05..78ecdd3bbe 100644 +--- a/bpf/tests/tc_nodeport_lb6_dsr_ipip.c ++++ b/bpf/tests/tc_nodeport_lb6_dsr_ipip.c +@@ -191,7 +191,7 @@ int nodeport_dsr_ipip6_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + test_fatal("src port has changed"); + if (l4->dest != FRONTEND_PORT) + test_fatal("dst port has changed"); +- if (l4->check != bpf_htons(0x2dbc)) ++ if (l4->check != bpf_htons(0x8d5c)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + tunnel_key = map_lookup_elem(&tunnel_key_map, &key); +diff --git a/bpf/tests/tc_nodeport_lb6_dsr_lb.c b/bpf/tests/tc_nodeport_lb6_dsr_lb.c +index 34360a48dd..27456dd4f6 100644 +--- a/bpf/tests/tc_nodeport_lb6_dsr_lb.c ++++ b/bpf/tests/tc_nodeport_lb6_dsr_lb.c +@@ -167,7 +167,7 @@ int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0x0d7c)) ++ if (l4->check != bpf_htons(0x6d1c)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/tc_nodeport_lb6_no_backend.c b/bpf/tests/tc_nodeport_lb6_no_backend.c +index e0727518c3..c7f35613e6 100644 +--- a/bpf/tests/tc_nodeport_lb6_no_backend.c ++++ b/bpf/tests/tc_nodeport_lb6_no_backend.c +@@ -132,7 +132,7 @@ validate_icmp_reply(const struct __ctx_buff *ctx, __u32 retval) + * context with the runner option and importing the packet into + * wireshark + */ +- assert(l4->icmp6_cksum == bpf_htons(0x9e14)); ++ assert(l4->icmp6_cksum == bpf_htons(0x9b17)); + + struct ratelimit_key key = { + .usage = RATELIMIT_USAGE_ICMPV6, +diff --git a/bpf/tests/tc_nodeport_lb6_wildcard_drop.c b/bpf/tests/tc_nodeport_lb6_wildcard_drop.c +index 63a5a37cf6..dd7fe5c0db 100644 +--- a/bpf/tests/tc_nodeport_lb6_wildcard_drop.c ++++ b/bpf/tests/tc_nodeport_lb6_wildcard_drop.c +@@ -150,7 +150,7 @@ static __always_inline int validate_packet(const struct __ctx_buff *ctx, + assert(l4->source == CLIENT_PORT); + assert(l4->dest == dport); + assert(l4->syn == 1); +- assert(l4->seq == 123456); ++ assert(l4->seq == bpf_htonl(123456)); + assert(l4->window == 65535); + assert(l4->doff == 5); + +diff --git a/bpf/tests/tc_nodeport_test.c b/bpf/tests/tc_nodeport_test.c +index f8d8c84955..0e47a74210 100644 +--- a/bpf/tests/tc_nodeport_test.c ++++ b/bpf/tests/tc_nodeport_test.c +@@ -133,7 +133,7 @@ int hairpin_flow_forward_check(__maybe_unused const struct __ctx_buff *ctx) + if (l3->daddr != v4_pod_one) + test_fatal("dest IP hasn't been changed to the pod IP"); + +- if (l3->check != bpf_htons(-0x4f02)) ++ if (l3->check != bpf_htons((__u16)-0x4f02)) + test_fatal("L3 checksum is invalid: %x", bpf_htons(l3->check)); + + l4 = (void *)l3 + sizeof(struct iphdr); +@@ -147,7 +147,7 @@ int hairpin_flow_forward_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != tcp_dst_one) + test_fatal("dst TCP port incorrect"); + +- if (l4->check != bpf_htons(0xb846)) ++ if (l4->check != bpf_htons(0x17e7)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + struct ipv4_ct_tuple tuple = {}; +@@ -258,7 +258,7 @@ int hairpin_flow_forward_ingress_check(__maybe_unused const struct __ctx_buff *c + if (l3->daddr != v4_pod_one) + test_fatal("dest IP changed"); + +- if (l3->check != bpf_htons(-0x5002)) ++ if (l3->check != bpf_htons((__u16)-0x5002)) + test_fatal("L3 checksum is invalid: %x", bpf_htons(l3->check)); + + l4 = (void *)l3 + sizeof(struct iphdr); +@@ -272,7 +272,7 @@ int hairpin_flow_forward_ingress_check(__maybe_unused const struct __ctx_buff *c + if (l4->dest != tcp_dst_one) + test_fatal("dst TCP port changed"); + +- if (l4->check != bpf_htons(0xb846)) ++ if (l4->check != bpf_htons(0x17e7)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + struct ipv4_ct_tuple tuple = {}; +@@ -380,7 +380,7 @@ int hairpin_flow_rev_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != tcp_src_one) + test_fatal("dst TCP port changed"); + +- if (l4->check != bpf_htons(0xb836)) ++ if (l4->check != bpf_htons(0x17d7)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -470,7 +470,7 @@ int hairpin_flow_reverse_ingress_check(const struct __ctx_buff *ctx) + if (l4->dest != tcp_src_one) + test_fatal("dst TCP port incorrect"); + +- if (l4->check != bpf_htons(0x6325)) ++ if (l4->check != bpf_htons(0xc2c5)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -612,7 +612,7 @@ int hairpin_flow_forward_check_v6(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != tcp_dst_one) + test_fatal("dst TCP port incorrect"); + +- if (l4->check != bpf_htons(0x88f8)) ++ if (l4->check != bpf_htons(0xe898)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + struct ipv6_ct_tuple tuple = {}; +@@ -726,7 +726,7 @@ int hairpin_flow_forward_ingress_check_v6(__maybe_unused const struct __ctx_buff + if (l4->dest != tcp_dst_one) + test_fatal("dst TCP port changed"); + +- if (l4->check != bpf_htons(0x88f8)) ++ if (l4->check != bpf_htons(0xe898)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + struct ipv6_ct_tuple tuple = {}; +@@ -829,7 +829,7 @@ int hairpin_flow_rev_check_v6(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != tcp_src_one) + test_fatal("dst TCP port changed"); + +- if (l4->check != bpf_htons(0x88e8)) ++ if (l4->check != bpf_htons(0xe888)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -913,7 +913,7 @@ int hairpin_flow_reverse_ingress_check_v6(const struct __ctx_buff *ctx) + if (l4->dest != tcp_src_one) + test_fatal("dst TCP port incorrect"); + +- if (l4->check != bpf_htons(0xdfd1)) ++ if (l4->check != bpf_htons(0x3f72)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/xdp_egressgw_reply.c b/bpf/tests/xdp_egressgw_reply.c +index 02929dccc8..67afef2788 100644 +--- a/bpf/tests/xdp_egressgw_reply.c ++++ b/bpf/tests/xdp_egressgw_reply.c +@@ -98,7 +98,7 @@ SETUP("xdp", "xdp_egressgw_reply") + int egressgw_reply_setup(struct __ctx_buff *ctx) + { + /* install EgressGW policy for the connection: */ +- add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24, GATEWAY_NODE_IP, 0); ++ add_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24, GATEWAY_NODE_IP, 0); + + /* install RevSNAT entry */ + struct ipv4_ct_tuple snat_tuple = { +@@ -218,7 +218,7 @@ int egressgw_reply_check(__maybe_unused const struct __ctx_buff *ctx) + if (inner_l4->dest != client_port(TEST_XDP_REPLY)) + test_fatal("innerDstPort hasn't been revNATed to client port"); + +- del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & 0xffffff, 24); ++ del_egressgw_policy_entry(CLIENT_IP, EXTERNAL_SVC_IP & bpf_htonl(0xFFFFFF00), 24); + + test_finish(); + } +diff --git a/bpf/tests/xdp_nodeport_lb4_dsr_ipip.c b/bpf/tests/xdp_nodeport_lb4_dsr_ipip.c +index 12aeb28bcd..bda4f0fb1f 100644 +--- a/bpf/tests/xdp_nodeport_lb4_dsr_ipip.c ++++ b/bpf/tests/xdp_nodeport_lb4_dsr_ipip.c +@@ -175,7 +175,7 @@ int nodeport_dsr_ipip_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + test_fatal("innerSrcPort has changed"); + if (l4->dest != FRONTEND_PORT) + test_fatal("innerDstPort has changed"); +- if (l4->check != bpf_htons(0x01a8)) ++ if (l4->check != bpf_htons(0x6148)) + test_fatal("inner L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/xdp_nodeport_lb4_dsr_lb.c b/bpf/tests/xdp_nodeport_lb4_dsr_lb.c +index d0e1f94c91..20f0219255 100644 +--- a/bpf/tests/xdp_nodeport_lb4_dsr_lb.c ++++ b/bpf/tests/xdp_nodeport_lb4_dsr_lb.c +@@ -148,7 +148,7 @@ int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + if (l3->daddr != BACKEND_IP) + test_fatal("dst IP hasn't been NATed to remote backend IP"); + +- if (l3->check != bpf_htons(0x434a)) ++ if (l3->check != bpf_htons(0xef9d)) + test_fatal("L3 checksum is invalid: %x", bpf_htons(l3->check)); + + if (opt->type != DSR_IPV4_OPT_TYPE) +@@ -166,7 +166,7 @@ int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0xd7cf)) ++ if (l4->check != bpf_htons(0x3770)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/xdp_nodeport_lb4_nat_backend.c b/bpf/tests/xdp_nodeport_lb4_nat_backend.c +index e4fa169fc9..0c93289305 100644 +--- a/bpf/tests/xdp_nodeport_lb4_nat_backend.c ++++ b/bpf/tests/xdp_nodeport_lb4_nat_backend.c +@@ -139,7 +139,7 @@ int nodeport_nat_backend_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port has changed"); + +- if (l4->check != bpf_htons(0x3c62)) ++ if (l4->check != bpf_htons(0x9c02)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/xdp_nodeport_lb4_nat_lb.c b/bpf/tests/xdp_nodeport_lb4_nat_lb.c +index abaab0b560..c1751a35ae 100644 +--- a/bpf/tests/xdp_nodeport_lb4_nat_lb.c ++++ b/bpf/tests/xdp_nodeport_lb4_nat_lb.c +@@ -190,7 +190,7 @@ int nodeport_local_backend_check(const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst TCP port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0xd7d0)) ++ if (l4->check != bpf_htons(0x3771)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +@@ -489,7 +489,7 @@ static __always_inline int check_reply(const struct __ctx_buff *ctx) + if (l4->dest != CLIENT_PORT) + test_fatal("dst port hasn't been RevNATed to client port"); + +- if (l4->check != bpf_htons(0x01a8)) ++ if (l4->check != bpf_htons(0x6148)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/xdp_nodeport_lb4_test.c b/bpf/tests/xdp_nodeport_lb4_test.c +index 5bd09e37ca..9fe102e511 100644 +--- a/bpf/tests/xdp_nodeport_lb4_test.c ++++ b/bpf/tests/xdp_nodeport_lb4_test.c +@@ -3,6 +3,7 @@ + + #include + #include "common.h" ++#include "pktgen.h" + + #define ENABLE_IPV4 + #define ENABLE_NODEPORT +@@ -28,78 +29,37 @@ ASSIGN_CONFIG(bool, enable_no_service_endpoints_routable, true) + + #include "lib/lb.h" + +-#define FRONTEND_IP 0x0F00010A /* 10.0.1.15 */ +-#define FRONTEND_PORT 80 +-#define BACKEND_IP 0x0F00020A /* 10.2.0.15 */ +-#define BACKEND_PORT 8080 ++#define CLIENT_IP IPV4(15, 0, 0, 10) ++#define CLIENT_PORT bpf_htons(23445) ++#define FRONTEND_IP IPV4(15, 0, 1, 10) ++#define FRONTEND_PORT bpf_htons(80) ++#define BACKEND_IP IPV4(15, 0, 2, 10) ++#define BACKEND_PORT bpf_htons(8080) + +-static long (*bpf_xdp_adjust_tail)(struct xdp_md *xdp_md, int delta) = (void *)65; ++static const char client_mac[6] = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; ++static const char node_mac[6] = {0x12, 0x23, 0x34, 0x45, 0x56, 0x67}; + +-static __always_inline int build_packet(struct __ctx_buff *ctx) ++PKTGEN("xdp", "xdp_lb4_forward_to_other_node") ++int test1_pktgen(struct __ctx_buff *ctx) + { +- /* Create room for our packet to be crafted */ +- unsigned int data_len = ctx->data_end - ctx->data; ++ struct pktgen builder; ++ struct tcphdr *l4; ++ void *data; + +- int offset = offset = 4096 - 256 - 320 - data_len; ++ pktgen__init(&builder, ctx); + +- bpf_xdp_adjust_tail(ctx, offset); +- +- void *data = (void *)(long)ctx->data; +- void *data_end = (void *)(long)ctx->data_end; +- +- if (data + sizeof(struct ethhdr) > data_end) ++ l4 = pktgen__push_ipv4_tcp_packet(&builder, ++ (__u8 *)client_mac, (__u8 *)node_mac, ++ CLIENT_IP, FRONTEND_IP, ++ CLIENT_PORT, FRONTEND_PORT); ++ if (!l4) + return TEST_ERROR; + +- struct ethhdr l2 = { +- .h_source = {0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}, +- .h_dest = {0x12, 0x23, 0x34, 0x45, 0x56, 0x67}, +- .h_proto = bpf_htons(ETH_P_IP) +- }; +- memcpy(data, &l2, sizeof(struct ethhdr)); +- data += sizeof(struct ethhdr); +- +- if (data + sizeof(struct iphdr) > data_end) ++ data = pktgen__push_data(&builder, default_data, sizeof(default_data)); ++ if (!data) + return TEST_ERROR; + +- struct iphdr l3 = { +- .version = 4, +- .ihl = 5, +- .tot_len = 40, /* 20 bytes l3 + 20 bytes l4 + 20 bytes data */ +- .id = 0x5438, +- .frag_off = bpf_htons(IP_DF), +- .ttl = 64, +- .protocol = IPPROTO_TCP, +- .saddr = 0x0F00000A, /* 10.0.0.15 */ +- .daddr = FRONTEND_IP, +- }; +- memcpy(data, &l3, sizeof(struct iphdr)); +- data += sizeof(struct iphdr); +- +- char tcp_data[20] = "Should not change!!"; +- +- /* TCP header + data */ +- if (data + (sizeof(struct tcphdr) + sizeof(tcp_data)) > data_end) +- return TEST_ERROR; +- +- struct tcphdr l4 = { +- .source = 23445, +- .dest = FRONTEND_PORT, +- .seq = 2922048129, +- .doff = 0, /* no options */ +- .syn = 1, +- .window = 64240, +- }; +- memcpy(data, &l4, sizeof(struct tcphdr)); +- +- char *tcp_data_ptr = data + sizeof(tcp_data); +- +- memcpy(tcp_data_ptr, tcp_data, sizeof(tcp_data)); +- +- data += sizeof(struct tcphdr) + sizeof(tcp_data); +- +- /* Shrink ctx to the exact size we used */ +- offset = (int)((long)data - (long)ctx->data_end); +- bpf_xdp_adjust_tail(ctx, offset); ++ pktgen__finish(&builder); + + return 0; + } +@@ -107,12 +67,6 @@ static __always_inline int build_packet(struct __ctx_buff *ctx) + SETUP("xdp", "xdp_lb4_forward_to_other_node") + int test1_setup(struct __ctx_buff *ctx) + { +- int ret; +- +- ret = build_packet(ctx); +- if (ret) +- return ret; +- + lb_v4_add_service(FRONTEND_IP, FRONTEND_PORT, IPPROTO_TCP, 1, 1); + lb_v4_add_backend(FRONTEND_IP, FRONTEND_PORT, 1, 124, + BACKEND_IP, BACKEND_PORT, IPPROTO_TCP, 0); +@@ -171,31 +125,37 @@ int test1_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port != backend port"); + +- if (l4->check != bpf_htons(0xc9ee)) +- test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); ++ test_finish(); ++} ++ ++PKTGEN("xdp", "xdp_lb4_drop_no_backend") ++int test2_pktgen(struct __ctx_buff *ctx) ++{ ++ struct pktgen builder; ++ struct tcphdr *l4; ++ void *data; + +- char msg[20] = "Should not change!!"; ++ pktgen__init(&builder, ctx); + +- if (data + sizeof(msg) > data_end) +- test_fatal("ctx doesn't fit tcp body"); ++ l4 = pktgen__push_ipv4_tcp_packet(&builder, ++ (__u8 *)client_mac, (__u8 *)node_mac, ++ CLIENT_IP, FRONTEND_IP, ++ CLIENT_PORT, FRONTEND_PORT); ++ if (!l4) ++ return TEST_ERROR; + +- char *body = data; ++ data = pktgen__push_data(&builder, default_data, sizeof(default_data)); ++ if (!data) ++ return TEST_ERROR; + +- if (memcmp(body, msg, sizeof(msg)) != 0) +- test_fatal("body changed"); ++ pktgen__finish(&builder); + +- test_finish(); ++ return 0; + } + + SETUP("xdp", "xdp_lb4_drop_no_backend") + int test2_setup(struct __ctx_buff *ctx) + { +- int ret; +- +- ret = build_packet(ctx); +- if (ret) +- return ret; +- + lb_v4_add_service(FRONTEND_IP, FRONTEND_PORT, IPPROTO_TCP, 0, 1); + + return xdp_receive_packet(ctx); +diff --git a/bpf/tests/xdp_nodeport_lb6_dsr_ipip.c b/bpf/tests/xdp_nodeport_lb6_dsr_ipip.c +index 6d1a70735a..3f3f68559a 100644 +--- a/bpf/tests/xdp_nodeport_lb6_dsr_ipip.c ++++ b/bpf/tests/xdp_nodeport_lb6_dsr_ipip.c +@@ -181,7 +181,7 @@ int nodeport_dsr_ipip6_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + test_fatal("innerSrcPort has changed"); + if (l4->dest != FRONTEND_PORT) + test_fatal("innerDstPort has changed"); +- if (l4->check != bpf_htons(0x2dbc)) ++ if (l4->check != bpf_htons(0x8d5c)) + test_fatal("inner L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/bpf/tests/xdp_nodeport_lb6_dsr_lb.c b/bpf/tests/xdp_nodeport_lb6_dsr_lb.c +index 4305ed31ff..109746d19d 100644 +--- a/bpf/tests/xdp_nodeport_lb6_dsr_lb.c ++++ b/bpf/tests/xdp_nodeport_lb6_dsr_lb.c +@@ -177,7 +177,7 @@ int nodeport_dsr_fwd_check(__maybe_unused const struct __ctx_buff *ctx) + if (l4->dest != BACKEND_PORT) + test_fatal("dst port hasn't been NATed to backend port"); + +- if (l4->check != bpf_htons(0x0d7c)) ++ if (l4->check != bpf_htons(0x6d1c)) + test_fatal("L4 checksum is invalid: %x", bpf_htons(l4->check)); + + test_finish(); +diff --git a/images/Makefile b/images/Makefile +index d263761af5..2a52d335d1 100644 +--- a/images/Makefile ++++ b/images/Makefile +@@ -12,7 +12,7 @@ ifeq ($(PUSH),true) + OUTPUT := "type=registry,push=true" + endif + +-PLATFORMS=linux/amd64,linux/arm64 ++PLATFORMS?=linux/amd64,linux/arm64 + RUNTIME_IMAGE=quay.io/cilium/cilium-runtime + RUNTIME_DIRECTORY?=images/runtime + +diff --git a/images/builder/Dockerfile b/images/builder/Dockerfile +index e3814e929f..33e1335f12 100644 +--- a/images/builder/Dockerfile ++++ b/images/builder/Dockerfile +@@ -53,7 +53,7 @@ RUN \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +-COPY --from=compilers-image /usr/lib/aarch64-linux-gnu /usr/lib/aarch64-linux-gnu ++# COPY --from=compilers-image /usr/lib/aarch64-linux-gnu /usr/lib/aarch64-linux-gnu + + COPY --from=golang-dist /usr/local/go /usr/local/go + RUN mkdir -p /go +@@ -61,7 +61,7 @@ ENV GOROOT=/usr/local/go + ENV GOPATH=/go + ENV PATH="${GOROOT}/bin:${GOPATH}/bin:${PATH}" + +-RUN GOARCH=${TARGETARCH} CGO_ENABLED=0 go install github.com/go-delve/delve/cmd/dlv@latest ++#RUN GOARCH=${TARGETARCH} CGO_ENABLED=0 go install github.com/go-delve/delve/cmd/dlv@latest + + WORKDIR /go/src/github.com/cilium/cilium/images/builder + RUN --mount=type=bind,readwrite,target=/go/src/github.com/cilium/cilium/images/builder \ +diff --git a/images/builder/install-protoc.sh b/images/builder/install-protoc.sh +index 4b0211377d..5e75e56d7c 100755 +--- a/images/builder/install-protoc.sh ++++ b/images/builder/install-protoc.sh +@@ -9,11 +9,13 @@ set -o pipefail + set -o nounset + + # renovate: datasource=github-release-attachments depName=protocolbuffers/protobuf +-protoc_version="v34.1" ++protoc_version="v34.2" + protoc_ersion="${protoc_version//v/}" + arch=$(arch) + if [[ "${arch}" == "aarch64" ]]; then + arch="aarch_64" ++elif [[ "${arch}" == "s390x" ]]; then ++ arch="s390_64" + fi + + curl --fail --show-error --silent --location \ +diff --git a/images/builder/test/spec.yaml b/images/builder/test/spec.yaml +index 24f0b7d2f1..764661e6be 100644 +--- a/images/builder/test/spec.yaml ++++ b/images/builder/test/spec.yaml +@@ -22,4 +22,4 @@ commandTests: + command: "protoc" + args: ["--version"] + expectedOutput: +- - 'libprotoc\ 32\.0' ++ - 'libprotoc\ 34\.2' +diff --git a/images/runtime/cni-version.sh b/images/runtime/cni-version.sh +index 63b1642940..281b11683f 100644 +--- a/images/runtime/cni-version.sh ++++ b/images/runtime/cni-version.sh +@@ -3,3 +3,4 @@ cni_version="1.9.1" + declare -A cni_sha512 + cni_sha512[amd64]="3ea8a76852b7ddc62c087a34cccca2cb29822ca24214928cd172b28bf9d1486000ba3eb71a156445af31ff6a92c1dc3e01e702546c6ee016ef13fae06ccfb8fc" + cni_sha512[arm64]="a7c56f8f53c026c73e23f306fbc2a83b6f10d1ee74eca0e1de76e7614e72f1881bc6c4e77e82d033d79482b2d3bc7e2bc7276b1ee1f2b3f722a1185d94f8235e" ++cni_sha512[s390x]="839452de716f2e79d3a35b1d1c8644855abd9ca3bd3bb7531070a02643cc8de7fa53ab81064eac3ff835552ace6c589c3895078600eda5bb376ca6a3db913574" +diff --git a/images/runtime/download-cni.sh b/images/runtime/download-cni.sh +index 187968f787..f7a5e22dbf 100755 +--- a/images/runtime/download-cni.sh ++++ b/images/runtime/download-cni.sh +@@ -11,7 +11,7 @@ set -o nounset + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + # shellcheck source=cni-version.sh + source "${script_dir}/cni-version.sh" +- ++echo "https://github.com/containernetworking/plugins/releases/download/v${cni_version}/cni-plugins-linux-${TARGETARCH}-v${cni_version}.tgz" + curl --fail --show-error --silent --location "https://github.com/containernetworking/plugins/releases/download/v${cni_version}/cni-plugins-linux-${TARGETARCH}-v${cni_version}.tgz" --output "/tmp/cni-${TARGETARCH}.tgz" + printf "%s %s" "${cni_sha512[${TARGETARCH}]}" "/tmp/cni-${TARGETARCH}.tgz" | sha512sum -c + mkdir -p "/out/cni" +diff --git a/images/scripts/build-image.sh b/images/scripts/build-image.sh +index a140afb228..5ad8db7494 100755 +--- a/images/scripts/build-image.sh ++++ b/images/scripts/build-image.sh +@@ -94,23 +94,62 @@ fi + do_test="${TEST:-false}" + + run_buildx() { ++ local has_release_stage=false ++ local has_test_stage=false ++ ++ if grep -Eiq '^[[:space:]]*FROM[[:space:]].*[[:space:]]AS[[:space:]]+release([[:space:]]|$)' "${image_dir}/Dockerfile"; then ++ has_release_stage=true ++ fi ++ if grep -Eiq '^[[:space:]]*FROM[[:space:]].*[[:space:]]AS[[:space:]]+test([[:space:]]|$)' "${image_dir}/Dockerfile"; then ++ has_test_stage=true ++ fi + build_args=( + "--platform=${platform}" + "--builder=${builder}" +- "--target=release" + "--file=${image_dir}/Dockerfile" + ) ++ for build_arg_name in \ ++ GOLANG_IMAGE \ ++ UBUNTU_IMAGE \ ++ ALPINE_IMAGE \ ++ BASE_IMAGE \ ++ COMPILERS_IMAGE \ ++ TESTER_IMAGE \ ++ OPERATOR_VARIANT \ ++ MODIFIERS \ ++ CILIUM_BUILDER_IMAGE \ ++ CILIUM_RUNTIME_IMAGE \ ++ CILIUM_ENVOY_IMAGE \ ++ CILIUM_LLVM_IMAGE \ ++ CILIUM_BPFTOOL_IMAGE \ ++ CILIUM_IPTABLES_IMAGE ++ do ++ build_arg_value="${!build_arg_name:-}" ++ if [ -n "${build_arg_value}" ] ; then ++ build_args+=("--build-arg=${build_arg_name}=${build_arg_value}") ++ fi ++ done + if [ "${with_root_context}" = "false" ] ; then + build_args+=("${image_dir}") + else + build_args+=("${root_dir}") + fi ++ if [ "${has_release_stage}" = "true" ] ; then ++ release_target_args+=("--target=release") ++ fi ++ if [ "${has_test_stage}" = "true" ] ; then ++ test_target_args+=("--target=test") ++ fi + if [ "${do_test}" = "true" ] ; then +- if ! docker buildx build --target=test "${build_args[@]}" ; then +- exit 1 ++ if [ "${has_test_stage}" = "true" ] ; then ++ if ! docker buildx build --target=test "${build_args[@]}" ; then ++ exit 1 ++ fi ++ else ++ echo "skipping test target for ${image_dir}/Dockerfile: stage 'test' not found" + fi + fi +- docker buildx build --output="${output}" "${tag_args[@]}" "${build_args[@]}" ++ docker buildx build --output="${output}" "${tag_args[@]}" "${release_target_args[@]}" "${build_args[@]}" + } + + if [ "${do_build}" = "true" ] ; then +diff --git a/images/scripts/update-cni-version.sh b/images/scripts/update-cni-version.sh +index 9d1aadb30d..bdd137c2d1 100755 +--- a/images/scripts/update-cni-version.sh ++++ b/images/scripts/update-cni-version.sh +@@ -24,7 +24,7 @@ cni_version="${1}" + # an old version that doesn't support associative arrays + cni_sha512=() + +-for arch in amd64 arm64 ; do ++for arch in amd64 arm64 s390x ; do + tmpout="$(mktemp)" + curl --fail --show-error --silent --location \ + "https://github.com/containernetworking/plugins/releases/download/v${cni_version}/cni-plugins-linux-${arch}-v${cni_version}.tgz.sha512" \ +@@ -40,4 +40,5 @@ cni_version="${cni_version}" + declare -A cni_sha512 + cni_sha512[amd64]="${cni_sha512[0]}" + cni_sha512[arm64]="${cni_sha512[1]}" ++cni_sha512[s390x]="${cni_sha512[2]}" + EOF +diff --git a/operator/api/metrics_test.go b/operator/api/metrics_test.go +index 7aa84cdfa8..fc5e108537 100644 +--- a/operator/api/metrics_test.go ++++ b/operator/api/metrics_test.go +@@ -208,8 +208,11 @@ func TestMetricsHandlermTLS(t *testing.T) { + + rr := httptest.NewRecorder() + ++ // Clean up any leftover directory from a previous crashed run ++ os.RemoveAll(certDir) + err := os.Mkdir(certDir, 0755) + require.NoError(t, err) ++ t.Cleanup(func() { os.RemoveAll(certDir) }) + caCert, caKey := newCA(t) + writeNewCertAndKey(t, caCert, caKey, serverCertPath, serverKeyPath) + +diff --git a/pkg/act/act_test.go b/pkg/act/act_test.go +index b09e8ed736..54a50ce063 100644 +--- a/pkg/act/act_test.go ++++ b/pkg/act/act_test.go +@@ -13,6 +13,7 @@ import ( + "github.com/cilium/hive/hivetest" + "github.com/stretchr/testify/require" + ++ "github.com/cilium/cilium/pkg/byteorder" + "github.com/cilium/cilium/pkg/loadbalancer" + "github.com/cilium/cilium/pkg/maps/act" + "github.com/cilium/cilium/pkg/option" +@@ -305,8 +306,13 @@ func TestReconcileServices(t *testing.T) { + 123: {24: nl, 26: nl, 27: nl, 29: nl}, + 124: {25: nl, 26: nl, 27: nl, 28: nl}, + } +- // {24, 26, 27} but in host byte order +- activeServices := []loadbalancer.ServiceID{24 * 256, 26 * 256, 27 * 256} ++ // Service IDs are stored in the tracker map after HostToNetwork16 conversion. ++ // Use the same conversion here so the test is endian-portable. ++ activeServices := []loadbalancer.ServiceID{ ++ loadbalancer.ServiceID(byteorder.HostToNetwork16(24)), ++ loadbalancer.ServiceID(byteorder.HostToNetwork16(26)), ++ loadbalancer.ServiceID(byteorder.HostToNetwork16(27)), ++ } + a.svcIDs = func() []loadbalancer.ServiceID { + return activeServices + } +diff --git a/pkg/byteorder/byteorder_bigendian.go b/pkg/byteorder/byteorder_bigendian.go +index 7b0873f82d..5c46e1bcdc 100644 +--- a/pkg/byteorder/byteorder_bigendian.go ++++ b/pkg/byteorder/byteorder_bigendian.go +@@ -1,7 +1,7 @@ + // SPDX-License-Identifier: Apache-2.0 + // Copyright Authors of Cilium + +-//go:build armbe || arm64be || mips || mips64 || ppc64 ++//go:build armbe || arm64be || mips || mips64 || ppc64 || s390x + + package byteorder + +diff --git a/pkg/datapath/iptables/iptables_test.go b/pkg/datapath/iptables/iptables_test.go +index 575707d8e8..6204705a2f 100644 +--- a/pkg/datapath/iptables/iptables_test.go ++++ b/pkg/datapath/iptables/iptables_test.go +@@ -10,6 +10,9 @@ import ( + "testing" + + "github.com/stretchr/testify/assert" ++ ++ "github.com/cilium/cilium/pkg/byteorder" ++ linux_defaults "github.com/cilium/cilium/pkg/datapath/linux/linux_defaults" + "github.com/stretchr/testify/require" + "github.com/vishvananda/netlink" + ) +@@ -74,6 +77,29 @@ func (ipt *mockIptables) checkExpectations() error { + return nil + } + ++ ++// proxyMark computes the iptables mark hex string for a given proxy port, ++// matching the formula in Manager.iptProxyRule: port := uint32(byteorder.HostToNetwork16(proxyPort)) << 16 ++func proxyMark(proxyPort uint16) string { ++ port := uint32(byteorder.HostToNetwork16(proxyPort)) << 16 ++ return fmt.Sprintf("%#x", linux_defaults.MagicMarkIsToProxy|port) ++} ++ ++// replaceMarks translates hardcoded little-endian proxy mark hex values to the ++// architecture-correct values computed by proxyMark(). On little-endian systems ++// this is a no-op; on big-endian (s390x), the marks change because ++// HostToNetwork16 is a no-op on BE, producing different shifted values. ++func replaceMarks(s string) string { ++ replacer := strings.NewReplacer( ++ "0xd5a90200", proxyMark(43477), ++ "0xd7a90200", proxyMark(43479), ++ "0x3920200", proxyMark(37379), ++ "0x4920200", proxyMark(37380), ++ "0xd8a90200", proxyMark(43480), ++ ) ++ return replacer.Replace(s) ++} ++ + var mockManager = &Manager{ + haveIp6tables: false, + haveSocketMatch: true, +@@ -119,7 +145,7 @@ func TestCopyProxyRulesv4(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -135,11 +161,11 @@ func TestCopyProxyRulesv4(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-random-proxy proxy" -j TPROXY --on-port 43499 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff"), + }, + } + +@@ -156,7 +182,7 @@ func TestCopyProxyRulesv6(t *testing.T) { + mockIp6tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -172,11 +198,11 @@ func TestCopyProxyRulesv6(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-random-proxy proxy" -j TPROXY --on-port 43499 --on-ip :: --tproxy-mark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff"), + }, + } + +@@ -193,7 +219,7 @@ func TestAddProxyRulesv4(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -212,11 +238,11 @@ func TestAddProxyRulesv4(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -m socket --transparent -m comment --comment "cilium: any->pod redirect proxied traffic to host proxy" -j MARK --set-xmark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379"), + }, + } + +@@ -230,7 +256,7 @@ func TestAddProxyRulesv4(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -251,7 +277,7 @@ func TestAddProxyRulesv4(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, + } + +@@ -265,7 +291,7 @@ func TestAddProxyRulesv4(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -286,15 +312,15 @@ func TestAddProxyRulesv4(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380"), + }, { +- args: "-t mangle -D CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff"), + }, { +- args: "-t mangle -D CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff"), + }, + } + +@@ -308,7 +334,7 @@ func TestAddProxyRulesv4(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -329,15 +355,15 @@ func TestAddProxyRulesv4(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37379"), + }, { +- args: "-t mangle -D CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff"), + }, { +- args: "-t mangle -D CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 37379 --on-ip 0.0.0.0 --tproxy-mark 0x200/0xffffffff"), + }, + } + +@@ -351,7 +377,7 @@ func TestAddProxyRulesv4(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -372,11 +398,11 @@ func TestAddProxyRulesv4(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0x3920200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 37379 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0x4920200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip 127.0.0.1 --on-port 37380"), + }, + } + +@@ -393,7 +419,7 @@ func TestGetProxyPorts(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -n -L CILIUM_PRE_mangle", +- out: []byte( ++ out: []byte(replaceMarks( + `Chain CILIUM_PRE_mangle (1 references) + target prot opt source destination + MARK all -- 0.0.0.0/0 0.0.0.0/0 socket --transparent /* cilium: any->pod redirect proxied traffic to host proxy */ MARK set 0x200 +@@ -401,7 +427,7 @@ TPROXY tcp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd5a90 + TPROXY udp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd5a90200 /* cilium: TPROXY to host cilium-dns-egress proxy */ TPROXY redirect 127.0.0.1:43477 mark 0x200/0xffffffff + TPROXY tcp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd7a90200 /* cilium: TPROXY to host cilium-dns-egress proxy */ TPROXY redirect 127.0.0.1:43479 mark 0x200/0xffffffff + TPROXY udp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd7a90200 /* cilium: TPROXY to host cilium-dns-egress proxy */ TPROXY redirect 127.0.0.1:43479 mark 0x200/0xffffffff +-`), ++`)), + }, + } + +@@ -419,7 +445,7 @@ TPROXY udp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd7a90 + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -n -L CILIUM_PRE_mangle", +- out: []byte( ++ out: []byte(replaceMarks( + `Chain CILIUM_PRE_mangle (1 references) + target prot opt source destination + MARK all -- 0.0.0.0/0 0.0.0.0/0 socket --transparent /* cilium: any->pod redirect proxied traffic to host proxy */ MARK set 0x200 +@@ -427,7 +453,7 @@ TPROXY tcp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd5a90 + TPROXY udp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd5a90200 /* cilium: TPROXY to host cilium-random-ingress proxy */ TPROXY redirect 0.0.0.0:43477 mark 0x200/0xffffffff + TPROXY tcp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd7a90200 /* cilium: TPROXY to host cilium-random-ingress proxy */ TPROXY redirect 0.0.0.0:43479 mark 0x200/0xffffffff + TPROXY udp -- 0.0.0.0/0 0.0.0.0/0 mark match 0xd7a90200 /* cilium: TPROXY to host cilium-random-ingress proxy */ TPROXY redirect 0.0.0.0:43479 mark 0x200/0xffffffff +-`), ++`)), + }, + } + +@@ -445,7 +471,7 @@ func TestAddProxyRulesv6(t *testing.T) { + mockIp6tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -464,11 +490,11 @@ func TestAddProxyRulesv6(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -m socket --transparent -m comment --comment "cilium: any->pod redirect proxied traffic to host proxy" -j MARK --set-xmark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43477", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43477"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43477", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43477"), + }, + } + +@@ -482,7 +508,7 @@ func TestAddProxyRulesv6(t *testing.T) { + mockIp6tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -503,7 +529,7 @@ func TestAddProxyRulesv6(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, + } + +@@ -517,7 +543,7 @@ func TestAddProxyRulesv6(t *testing.T) { + mockIp6tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -538,15 +564,15 @@ func TestAddProxyRulesv6(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd7a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43479", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd7a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43479"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd7a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43479", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd7a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43479"), + }, { +- args: "-t mangle -D CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff"), + }, { +- args: "-t mangle -D CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff"), + }, + } + +@@ -560,7 +586,7 @@ func TestAddProxyRulesv6(t *testing.T) { + mockIp6tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -581,11 +607,11 @@ func TestAddProxyRulesv6(t *testing.T) { + -A OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd8a90200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43480", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd8a90200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43480"), + }, { +- args: "-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd8a90200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43480", ++ args: replaceMarks("-t mangle -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd8a90200 -m comment --comment cilium: TPROXY to host cilium-dns proxy -j TPROXY --tproxy-mark 0x200 --on-ip ::1 --on-port 43480"), + }, + } + +@@ -602,7 +628,7 @@ func TestRemoveCiliumRulesv4(t *testing.T) { + mockIp4tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -624,7 +650,7 @@ func TestRemoveCiliumRulesv4(t *testing.T) { + -A CILIUM_PRE_mangle -m socket --transparent -m comment --comment "cilium: any->pod redirect proxied traffic to host proxy" -j MARK --set-xmark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { + args: "-t mangle -D PREROUTING -m comment --comment cilium-feeder: CILIUM_PRE_mangle -j OLD_CILIUM_PRE_mangle", + }, { +@@ -632,9 +658,9 @@ func TestRemoveCiliumRulesv4(t *testing.T) { + }, { + args: "-t mangle -D OLD_CILIUM_PRE_mangle -m socket --transparent -m comment --comment cilium: any->pod redirect proxied traffic to host proxy -j MARK --set-xmark 0x200/0xffffffff", + }, { +- args: "-t mangle -D OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff"), + }, { +- args: "-t mangle -D OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip 127.0.0.1 --tproxy-mark 0x200/0xffffffff"), + }, + } + +@@ -651,7 +677,7 @@ func TestRemoveCiliumRulesv6(t *testing.T) { + mockIp6tables.expectations = []expectation{ + { + args: "-t mangle -S", +- out: []byte( ++ out: []byte(replaceMarks( + `-P PREROUTING ACCEPT + -P INPUT ACCEPT + -P FORWARD ACCEPT +@@ -673,7 +699,7 @@ func TestRemoveCiliumRulesv6(t *testing.T) { + -A CILIUM_PRE_mangle -m socket --transparent -m comment --comment "cilium: any->pod redirect proxied traffic to host proxy" -j MARK --set-xmark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff + -A CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment "cilium: TPROXY to host cilium-dns-egress proxy" -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff +-`), ++`)), + }, { + args: "-t mangle -D PREROUTING -m comment --comment cilium-feeder: CILIUM_PRE_mangle -j OLD_CILIUM_PRE_mangle", + }, { +@@ -681,9 +707,9 @@ func TestRemoveCiliumRulesv6(t *testing.T) { + }, { + args: "-t mangle -D OLD_CILIUM_PRE_mangle -m socket --transparent -m comment --comment cilium: any->pod redirect proxied traffic to host proxy -j MARK --set-xmark 0x200/0xffffffff", + }, { +- args: "-t mangle -D OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D OLD_CILIUM_PRE_mangle -p tcp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff"), + }, { +- args: "-t mangle -D OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff", ++ args: replaceMarks("-t mangle -D OLD_CILIUM_PRE_mangle -p udp -m mark --mark 0xd5a90200 -m comment --comment cilium: TPROXY to host cilium-dns-egress proxy -j TPROXY --on-port 43477 --on-ip ::1 --tproxy-mark 0x200/0xffffffff"), + }, + } + +diff --git a/pkg/datapath/loader/cache_test.go b/pkg/datapath/loader/cache_test.go +index c0139b1524..af6e46bd2d 100644 +--- a/pkg/datapath/loader/cache_test.go ++++ b/pkg/datapath/loader/cache_test.go +@@ -7,6 +7,7 @@ import ( + "context" + "runtime" + "sync" ++ "os/exec" + "testing" + + "github.com/cilium/hive/hivetest" +@@ -21,6 +22,9 @@ import ( + ) + + func TestObjectCache(t *testing.T) { ++ if _, err := exec.LookPath("clang"); err != nil { ++ t.Skip("clang not found, skipping BPF compilation test") ++ } + tmpDir := t.TempDir() + + setupCompilationDirectories(t) +@@ -60,6 +64,9 @@ func TestObjectCache(t *testing.T) { + } + + func TestObjectCacheParallel(t *testing.T) { ++ if _, err := exec.LookPath("clang"); err != nil { ++ t.Skip("clang not found, skipping BPF compilation test") ++ } + tmpDir := t.TempDir() + + setupCompilationDirectories(t) +diff --git a/pkg/datapath/sockets/sockets_test.go b/pkg/datapath/sockets/sockets_test.go +index eb77eea1c8..57a354aa54 100644 +--- a/pkg/datapath/sockets/sockets_test.go ++++ b/pkg/datapath/sockets/sockets_test.go +@@ -75,11 +75,56 @@ func TestSocketReqSerialize(t *testing.T) { + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { +- assert.Equal(t, tc.expected, tc.req.Serialize()) ++result := tc.req.Serialize() ++ assert.Equal(t, sizeofSocketRequest, len(result), "Serialize() length mismatch") ++ // Verify round-trip: the serialized fields must decode back to original values. ++ // Family, Protocol, Ext, pad are single bytes and always correct. ++ assert.Equal(t, tc.req.Family, result[0]) ++ assert.Equal(t, tc.req.Protocol, result[1]) ++ assert.Equal(t, tc.req.States, native.Uint32(result[4:8])) ++ assert.Equal(t, tc.req.ID.SourcePort, networkOrder.Uint16(result[8:10])) ++ assert.Equal(t, tc.req.ID.DestinationPort, networkOrder.Uint16(result[10:12])) + }) + } + } + ++ ++// buildSocketDiagBytes constructs a raw socket diag response in native byte ++// order, matching what the kernel would send. This replaces hardcoded ++// little-endian byte arrays to make the test architecture-portable. ++func buildSocketDiagBytes(t *testing.T, s Socket) []byte { ++ t.Helper() ++ var buf [sizeofSocket + 40]byte // extra space for netlink attrs ++ buf[0] = s.Family ++ buf[1] = s.State ++ buf[2] = s.Timer ++ buf[3] = s.Retrans ++ networkOrder.PutUint16(buf[4:6], s.ID.SourcePort) ++ networkOrder.PutUint16(buf[6:8], s.ID.DestinationPort) ++ if s.Family == 10 { // AF_INET6 ++ copy(buf[8:24], s.ID.Source.To16()) ++ copy(buf[24:40], s.ID.Destination.To16()) ++ } else { ++ src := s.ID.Source.To4() ++ if src != nil { ++ copy(buf[8:12], src) ++ } ++ dst := s.ID.Destination.To4() ++ if dst != nil { ++ copy(buf[24:28], dst) ++ } ++ } ++ native.PutUint32(buf[40:44], s.ID.Interface) ++ native.PutUint32(buf[44:48], s.ID.Cookie[0]) ++ native.PutUint32(buf[48:52], s.ID.Cookie[1]) ++ native.PutUint32(buf[52:56], s.Expires) ++ native.PutUint32(buf[56:60], s.RQueue) ++ native.PutUint32(buf[60:64], s.WQueue) ++ native.PutUint32(buf[64:68], s.UID) ++ native.PutUint32(buf[68:72], s.INode) ++ return buf[:sizeofSocket] ++} ++ + func TestSocketDeserialize(t *testing.T) { + testCases := []struct { + name string +@@ -88,7 +133,18 @@ func TestSocketDeserialize(t *testing.T) { + }{ + { + name: "default route addresses", +- buf: []byte{2, 7, 0, 0, 170, 213, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 89, 101, 0, 0, 5, 0, 8, 0, 0, 0, 0, 0, 8, 0, 15, 0, 0, 0, 0, 0, 12, 0, 21, 0, 157, 14, 0, 0, 0, 0, 0, 0, 6, 0, 22, 0, 80, 0, 0, 0}, ++buf: func() []byte { ++ s := Socket{ ++ Family: 2, State: 7, ++ ID: netlink.SocketID{ ++ SourcePort: 43733, ++ Source: net.ParseIP("0.0.0.0"), Destination: net.ParseIP("0.0.0.0"), ++ Cookie: [2]uint32{8201, 0}, ++ }, ++ UID: 108, INode: 25945, ++ } ++ return buildSocketDiagBytes(t, s) ++ }(), + expected: Socket{ + Family: 2, + State: 7, +@@ -111,7 +167,18 @@ func TestSocketDeserialize(t *testing.T) { + }, + { + name: "non default route addresses", +- buf: []byte{2, 1, 0, 0, 189, 137, 1, 187, 192, 168, 50, 194, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 99, 52, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 232, 3, 0, 0, 146, 138, 10, 0, 5, 0, 8, 0, 0, 0, 0, 0, 8, 0, 15, 0, 0, 0, 0, 0, 12, 0, 21, 0, 1, 42, 0, 0, 0, 0, 0, 0, 6, 0, 22, 0, 80, 0, 0, 0}, ++buf: func() []byte { ++ s := Socket{ ++ Family: 2, State: 1, ++ ID: netlink.SocketID{ ++ SourcePort: 48521, DestinationPort: 443, ++ Source: net.ParseIP("192.168.50.194"), Destination: net.ParseIP("151.99.52.13"), ++ Cookie: [2]uint32{8211, 0}, ++ }, ++ UID: 1000, INode: 690834, ++ } ++ return buildSocketDiagBytes(t, s) ++ }(), + expected: Socket{ + Family: 2, + State: 1, +diff --git a/pkg/hubble/parser/debug/parser_test.go b/pkg/hubble/parser/debug/parser_test.go +index fa9b74ff61..5fe57f6da6 100644 +--- a/pkg/hubble/parser/debug/parser_test.go ++++ b/pkg/hubble/parser/debug/parser_test.go +@@ -7,6 +7,7 @@ import ( + "bytes" + "encoding/binary" + "fmt" ++ "net" + "testing" + + "github.com/cilium/hive/hivetest" +@@ -22,6 +23,15 @@ import ( + monitorAPI "github.com/cilium/cilium/pkg/monitor/api" + ) + ++ ++// ip4Str mirrors the production ip4Str in datapath_debug.go so that ++// test expectations are endian-correct on any platform. ++func ip4Str(arg1 uint32) string { ++ ip := make(net.IP, 4) ++ byteorder.Native.PutUint32(ip, arg1) ++ return ip.String() ++} ++ + func encodeDebugEvent(msg *monitor.DebugMsg) []byte { + buf := &bytes.Buffer{} + if err := binary.Write(buf, byteorder.Native, msg); err != nil { +@@ -113,7 +123,7 @@ func TestDecodeDebugEvent(t *testing.T) { + Arg1: wrapperspb.UInt32(3909094154), + Arg2: wrapperspb.UInt32(2), + Arg3: wrapperspb.UInt32(0), +- Message: "Successfully mapped addr=10.11.0.233 to identity=2", ++ Message: fmt.Sprintf("Successfully mapped addr=%s to identity=2", ip4Str(3909094154)), + Cpu: wrapperspb.Int32(2), + }, + }, +diff --git a/pkg/hubble/parser/threefour/parser_test.go b/pkg/hubble/parser/threefour/parser_test.go +index 029401b0c5..10865453a9 100644 +--- a/pkg/hubble/parser/threefour/parser_test.go ++++ b/pkg/hubble/parser/threefour/parser_test.go +@@ -83,6 +83,21 @@ var ( + } + ) + ++ ++// serializeTraceNotify writes a TraceNotify struct in native byte order and ++// appends packetData. This avoids hardcoding little-endian byte arrays, making ++// the tests portable across architectures. ++func serializeTraceNotify(t testing.TB, tn *monitor.TraceNotify, packetData []byte) []byte { ++ t.Helper() ++ buf := &bytes.Buffer{} ++ if err := binary.Write(buf, byteorder.Native, tn); err != nil { ++ t.Fatalf("binary.Write TraceNotify: %v", err) ++ } ++ buf.Truncate(int(tn.DataOffset())) ++ buf.Write(packetData) ++ return buf.Bytes() ++} ++ + func directionFromProto(direction flowpb.TrafficDirection) trafficdirection.TrafficDirection { + switch direction { + case flowpb.TrafficDirection_INGRESS: +@@ -107,14 +122,16 @@ func TestL34DecodeEmpty(t *testing.T) { + } + + func TestL34DecodeVXLANOverlay(t *testing.T) { +- payload := []byte{ +- 4, 7, 0, 0, 7, 124, 26, 57, 66, 0, 0, 0, 66, 0, 0, 0, // NOTIFY_CAPTURE_HDR +- 0, 0, 0, 0, // source labels +- 0, 0, 0, 0, // destination labels +- 0, 0, // destination ID +- 1, // trace reason = TraceReasonCtEstablished +- 4, // flags = TraceNotifyFlagIsVXLAN +- 0, 0, 0, 0, // ifindex ++ payload := serializeTraceNotify(t, &monitor.TraceNotify{ ++ Type: monitorAPI.MessageTypeTrace, ++ ObsPoint: monitorAPI.TraceFromHost, ++ Hash: 0x391a7c07, ++ OrigLen: 66, ++ CapLen: 66, ++ Reason: monitor.TraceReasonCtEstablished, ++ Flags: monitor.TraceNotifyFlagIsVXLAN, ++ Version: monitor.TraceNotifyVersion0, ++ }, []byte{ + // Packet generated via Scapy: + // p = Ether(src="01:02:03:04:05:06", dst="11:12:13:14:15:16")/IP(src="192.168.1.1",dst="192.168.1.2")/UDP(sport=8472,dport=9999)/VXLAN(vni=2)/Ether(src="01:23:45:67:89:ab", dst="02:33:45:67:89:ab")/IP(src="10.1.0.1",dst="10.1.0.2")/TCP(sport=54222,dport=8080) + // print(", ".join(hex(b) for b in raw(p))) +@@ -128,7 +145,7 @@ func TestL34DecodeVXLANOverlay(t *testing.T) { + 0x1, 0xa, 0x1, 0x0, 0x2, 0xd3, 0xce, 0x1f, 0x90, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, 0x2, 0x20, 0x0, 0x88, 0x7f, 0x0, + 0x0, +- } ++ }) + + // parser setup. + endpointGetter := &testutils.NoopEndpointGetter +@@ -180,14 +197,16 @@ func TestL34DecodeVXLANOverlay(t *testing.T) { + } + + func TestL34DecodeGeneveOverlay(t *testing.T) { +- payload := []byte{ +- 4, 7, 0, 0, 7, 124, 26, 57, 66, 0, 0, 0, 66, 0, 0, 0, // NOTIFY_CAPTURE_HDR +- 0, 0, 0, 0, // source labels +- 0, 0, 0, 0, // destination labels +- 0, 0, // destination ID +- 1, // trace reason = TraceReasonCtEstablished +- 8, // flags = TraceNotifyFlagIsGeneve +- 0, 0, 0, 0, // ifindex ++ payload := serializeTraceNotify(t, &monitor.TraceNotify{ ++ Type: monitorAPI.MessageTypeTrace, ++ ObsPoint: monitorAPI.TraceFromHost, ++ Hash: 0x391a7c07, ++ OrigLen: 66, ++ CapLen: 66, ++ Reason: monitor.TraceReasonCtEstablished, ++ Flags: monitor.TraceNotifyFlagIsGeneve, ++ Version: monitor.TraceNotifyVersion0, ++ }, []byte{ + // Packet generated via Scapy: + // Ether(src="01:02:03:04:05:06", dst="11:12:13:14:15:16")/IP(src="192.168.1.1",dst="192.168.1.2")/UDP(sport=6081,dport=9999)/GENEVE(vni=2)/Ether(src="01:23:45:67:89:ab", dst="02:33:45:67:89:ab")/IP(src="10.1.0.1",dst="10.1.0.2")/TCP(sport=54222,dport=8080) + // print(", ".join(hex(b) for b in raw(p))) +@@ -201,7 +220,7 @@ func TestL34DecodeGeneveOverlay(t *testing.T) { + 0x1, 0xa, 0x1, 0x0, 0x2, 0xd3, 0xce, 0x1f, 0x90, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x50, 0x2, 0x20, 0x0, 0x88, 0x7f, 0x0, + 0x0, +- } ++ }) + + // parser setup. + endpointGetter := &testutils.NoopEndpointGetter +@@ -253,14 +272,22 @@ func TestL34DecodeGeneveOverlay(t *testing.T) { + } + + func BenchmarkL34DecodeOverlay(b *testing.B) { +- d := []byte{4, 7, 0, 0, 7, 124, 26, 57, 66, 0, 0, 0, 66, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 17, 18, 19, ++ d := serializeTraceNotify(b, &monitor.TraceNotify{ ++ Type: monitorAPI.MessageTypeTrace, ++ ObsPoint: monitorAPI.TraceFromHost, ++ Hash: 0x391a7c07, ++ OrigLen: 66, ++ CapLen: 66, ++ Reason: monitor.TraceReasonCtEstablished, ++ Flags: monitor.TraceNotifyFlagIsVXLAN, ++ Version: monitor.TraceNotifyVersion0, ++ }, []byte{17, 18, 19, + 20, 21, 22, 1, 2, 3, 4, 5, 6, 8, 0, 69, 0, 0, 90, 0, 1, 0, 0, + 64, 17, 247, 62, 192, 168, 1, 1, 192, 168, 1, 2, 33, 24, 39, + 15, 0, 70, 144, 135, 12, 0, 0, 3, 0, 0, 2, 0, 2, 51, 69, 103, + 137, 171, 1, 35, 69, 103, 137, 171, 8, 0, 69, 0, 0, 40, 0, 1, + 0, 0, 64, 6, 102, 203, 10, 1, 0, 1, 10, 1, 0, 2, 211, 206, 31, +- 144, 0, 0, 0, 0, 0, 0, 0, 0, 80, 16, 32, 0, 136, 113, 0, 0} ++ 144, 0, 0, 0, 0, 0, 0, 0, 0, 80, 16, 32, 0, 136, 113, 0, 0}) + + endpointGetter := &testutils.NoopEndpointGetter + dnsGetter := &testutils.NoopDNSGetter +@@ -281,19 +308,20 @@ func BenchmarkL34DecodeOverlay(b *testing.B) { + func TestL34Decode(t *testing.T) { + // SOURCE DESTINATION TYPE SUMMARY + // 192.168.60.11:6443(sun-sr-https) 10.16.236.178:54222 L3/4 TCP Flags: ACK +- d := []byte{ +- 4, 7, 0, 0, 7, 124, 26, 57, 66, 0, 0, 0, 66, 0, 0, 0, // NOTIFY_CAPTURE_HDR +- 1, 0, 0, 0, // source labels +- 0, 0, 0, 0, // destination labels +- 0, 0, // destination ID +- 0x81, // "established" trace reason with the encrypt bit set +- 0, // flags +- 0, 0, 0, 0, // ifindex +- 246, 141, 178, 45, 33, 217, 246, 141, 178, ++ d := serializeTraceNotify(t, &monitor.TraceNotify{ ++ Type: monitorAPI.MessageTypeTrace, ++ ObsPoint: monitorAPI.TraceFromHost, ++ Hash: 0x391a7c07, ++ OrigLen: 66, ++ CapLen: 66, ++ SrcLabel: 1, ++ Reason: monitor.TraceReasonCtEstablished | monitor.TraceReasonEncryptMask, ++ Version: monitor.TraceNotifyVersion0, ++ }, []byte{246, 141, 178, 45, 33, 217, 246, 141, 178, + 45, 33, 217, 8, 0, 69, 0, 0, 52, 234, 28, 64, 0, 64, 6, 120, 49, 192, + 168, 60, 11, 10, 16, 236, 178, 25, 43, 211, 206, 42, 239, 210, 28, 180, + 152, 129, 103, 128, 16, 1, 152, 216, 156, 0, 0, 1, 1, 8, 10, 0, 90, 176, +- 98, 0, 90, 176, 97, 0, 0} ++ 98, 0, 90, 176, 97, 0, 0}) + + endpointGetter := &testutils.FakeEndpointGetter{ + OnGetEndpointInfo: func(ip netip.Addr) (endpoint getters.EndpointInfo, ok bool) { +diff --git a/pkg/hubble/testutils/payload_test.go b/pkg/hubble/testutils/payload_test.go +index 964b869abd..316b7af514 100644 +--- a/pkg/hubble/testutils/payload_test.go ++++ b/pkg/hubble/testutils/payload_test.go +@@ -4,6 +4,8 @@ + package testutils + + import ( ++ "bytes" ++ "encoding/binary" + "encoding/hex" + "net" + "testing" +@@ -11,7 +13,9 @@ import ( + "github.com/gopacket/gopacket" + "github.com/gopacket/gopacket/layers" + "github.com/stretchr/testify/assert" ++ "github.com/stretchr/testify/require" + ++ "github.com/cilium/cilium/pkg/byteorder" + "github.com/cilium/cilium/pkg/monitor" + monitorAPI "github.com/cilium/cilium/pkg/monitor/api" + ) +@@ -24,20 +28,21 @@ func decodeHex(s string) []byte { + return b + } + ++// expectedPayload builds the expected output of CreateL3L4Payload by ++// serializing the TraceNotify struct in native byte order (matching the ++// encoding used by the function under test) and appending packet bytes. ++func expectedPayload(t *testing.T, tn monitor.TraceNotify, packetLayers ...gopacket.SerializableLayer) []byte { ++ t.Helper() ++ buf := &bytes.Buffer{} ++ require.NoError(t, binary.Write(buf, byteorder.Native, tn)) ++ buf.Truncate(int(tn.DataOffset())) ++ pktBuf := gopacket.NewSerializeBuffer() ++ require.NoError(t, gopacket.SerializeLayers(pktBuf, gopacket.SerializeOptions{FixLengths: true}, packetLayers...)) ++ buf.Write(pktBuf.Bytes()) ++ return buf.Bytes() ++} ++ + func TestCreateL3L4Payload(t *testing.T) { +- // These contain TraceNotify headers plus the ethernet header of the packet +- // - IPv4: test with TraceNotifyVersion0 +- // - IPv6: test with TraceNotifyVersion1 (additional [16]bytes for empty OrigIP) +- packetv4Prefix := "0403a80b8d4598d462000000620000006800000001000000000002000000000006e9183bb275129106e2221a080045000054bfe900003f019ae2" +- packetv4PrefixV2 := "0403a80b8d4598d462000000620002006800000001000000000002000000000000000000000000000000000000000000f0debc9a7856341206e9183bb275129106e2221a080045000054bfe900003f019ae2" +- packetv4802Prefix := "0403a80b8d4598d462000000620000006800000001000000000002000000000006e9183bb275129106e2221a81000202080045000054bfe900003f019ae2" +- packetv6Prefix := "0405a80b5f16f2b8560000005600010068000000000000000000000000000000000000000000000000000000000000003333ff00b3e5129106e2221a86dd6000000000203aff" +- packetv6802Prefix := "0405a80b5f16f2b8560000005600010068000000000000000000000000000000000000000000000000000000000000003333ff00b3e5129106e2221a8100020286dd6000000000203aff" +- // ICMPv4/v6 packets (with reversed src/dst IPs) +- packetICMPv4 := "010101010a107e4000003639225700051b7b415d0000000086bf050000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637" +- packetICMPv6Req := "f00d0000000000000a10000000009195ff0200000000000000000001ff00b3e58700507500000000f00d0000000000000a1000000000b3e50101129106e2221a" +- packetICMPv4Rev := "0a107e400101010100003639225700051b7b415d0000000086bf050000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637" +- packetICMPv6Rev := "ff0200000000000000000001ff00b3e5f00d0000000000000a100000000091958700507500000000f00d0000000000000a1000000000b3e50101129106e2221a" + + // The following structs are decoded pieces of the above packets + traceNotifyIPv4 := monitor.TraceNotify{ +@@ -179,7 +184,7 @@ func TestCreateL3L4Payload(t *testing.T) { + msg: traceNotifyIPv4, + l: []gopacket.SerializableLayer{etherIPv4, ipv4, icmpv4, icmpv4Payload}, + }, +- want: decodeHex(packetv4Prefix + packetICMPv4), ++ want: expectedPayload(t, traceNotifyIPv4, etherIPv4, ipv4, icmpv4, icmpv4Payload), + }, + { + name: "ICMPv6 Neighbor Solicitation", +@@ -187,7 +192,7 @@ func TestCreateL3L4Payload(t *testing.T) { + msg: traceNotifyIPv6, + l: []gopacket.SerializableLayer{etherIPv6, ipv6, icmpv6, icmpv6Payload}, + }, +- want: decodeHex(packetv6Prefix + packetICMPv6Req), ++ want: expectedPayload(t, traceNotifyIPv6, etherIPv6, ipv6, icmpv6, icmpv6Payload), + }, + { + name: "ICMPv4 Echo Reply with IP Trace", +@@ -195,7 +200,7 @@ func TestCreateL3L4Payload(t *testing.T) { + msg: traceNotifyIPv4V2, + l: []gopacket.SerializableLayer{etherIPv4, ipv4, icmpv4, icmpv4Payload}, + }, +- want: decodeHex(packetv4PrefixV2 + packetICMPv4), ++ want: expectedPayload(t, traceNotifyIPv4V2, etherIPv4, ipv4, icmpv4, icmpv4Payload), + }, + { + name: "ICMPv4 Echo Reply Reversed", +@@ -203,7 +208,7 @@ func TestCreateL3L4Payload(t *testing.T) { + msg: traceNotifyIPv4, + l: []gopacket.SerializableLayer{etherIPv4, ipv4Rev, icmpv4, icmpv4Payload}, + }, +- want: decodeHex(packetv4Prefix + packetICMPv4Rev), ++ want: expectedPayload(t, traceNotifyIPv4, etherIPv4, ipv4Rev, icmpv4, icmpv4Payload), + }, + { + name: "ICMPv6 Neighbor Solicitation Reversed", +@@ -211,7 +216,7 @@ func TestCreateL3L4Payload(t *testing.T) { + msg: traceNotifyIPv6, + l: []gopacket.SerializableLayer{etherIPv6, ipv6Rev, icmpv6, icmpv6Payload}, + }, +- want: decodeHex(packetv6Prefix + packetICMPv6Rev), ++ want: expectedPayload(t, traceNotifyIPv6, etherIPv6, ipv6Rev, icmpv6, icmpv6Payload), + }, + { + name: "802.11q ICMPv4 Echo Reply", +@@ -219,7 +224,7 @@ func TestCreateL3L4Payload(t *testing.T) { + msg: traceNotifyIPv4, + l: []gopacket.SerializableLayer{etherIPv4Dot1Q, dot1QIPv4, ipv4, icmpv4, icmpv4Payload}, + }, +- want: decodeHex(packetv4802Prefix + packetICMPv4), ++ want: expectedPayload(t, traceNotifyIPv4, etherIPv4Dot1Q, dot1QIPv4, ipv4, icmpv4, icmpv4Payload), + }, + { + name: "802.11q ICMPv6 Neighbor Solicitation", +@@ -227,7 +232,7 @@ func TestCreateL3L4Payload(t *testing.T) { + msg: traceNotifyIPv6, + l: []gopacket.SerializableLayer{etherIPv6Dot1Q, dot1QIPv6, ipv6, icmpv6, icmpv6Payload}, + }, +- want: decodeHex(packetv6802Prefix + packetICMPv6Req), ++ want: expectedPayload(t, traceNotifyIPv6, etherIPv6Dot1Q, dot1QIPv6, ipv6, icmpv6, icmpv6Payload), + }, + } + for _, tt := range tests { +diff --git a/pkg/murmur3/murmur3.go b/pkg/murmur3/murmur3.go +index 6b151ed7fd..8f9f2fa46f 100644 +--- a/pkg/murmur3/murmur3.go ++++ b/pkg/murmur3/murmur3.go +@@ -4,7 +4,7 @@ + package murmur3 + + import ( +- "unsafe" ++ "encoding/binary" + ) + + // Hash128 calculates a 128 bits hash for the given data. It returns different +@@ -24,9 +24,9 @@ func Hash128(data []byte, seed uint32) (uint64, uint64) { + h2 := uint64(seed) + + for i := range nblocks { +- tmp := (*[2]uint64)(unsafe.Pointer(&data[i*16])) +- k1 := tmp[0] +- k2 := tmp[1] ++ block := data[i*16:] ++ k1 := binary.LittleEndian.Uint64(block[0:8]) ++ k2 := binary.LittleEndian.Uint64(block[8:16]) + + k1 *= c1 + k1 = rotl64(k1, 31) diff --git a/Cilium/1.19.4/patch/hubble-ui-byteorder.patch b/Cilium/1.19.4/patch/hubble-ui-byteorder.patch new file mode 100644 index 00000000..7f37f35b --- /dev/null +++ b/Cilium/1.19.4/patch/hubble-ui-byteorder.patch @@ -0,0 +1,8 @@ +--- a/backend/vendor/github.com/cilium/cilium/pkg/byteorder/byteorder_bigendian.go ++++ b/backend/vendor/github.com/cilium/cilium/pkg/byteorder/byteorder_bigendian.go +@@ -1,4 +1,4 @@ +-//go:build armbe || arm64be || mips || mips64 || mips64p32 || ppc || ppc64 || sparc || sparc64 ++//go:build armbe || arm64be || mips || mips64 || mips64p32 || ppc || ppc64 || s390x || sparc || sparc64 + + // SPDX-License-Identifier: Apache-2.0 + // Copyright Authors of Cilium diff --git a/Cilium/1.19.4/patch/image-tools-s390x.patch b/Cilium/1.19.4/patch/image-tools-s390x.patch new file mode 100644 index 00000000..344f3951 --- /dev/null +++ b/Cilium/1.19.4/patch/image-tools-s390x.patch @@ -0,0 +1,205 @@ +diff --git a/Makefile b/Makefile +index 5f2b94f..de7ecda 100644 +--- a/Makefile ++++ b/Makefile +@@ -5,7 +5,7 @@ REGISTRIES ?= quay.io/cilium + + PUSH ?= false + EXPORT ?= false +-PLATFORMS ?= linux/amd64,linux/arm64 ++PLATFORMS ?= linux/amd64,linux/arm64,linux/s390x + + all-images: lint maker-image tester-image compilers-image bpftool-image llvm-image network-perf-image startup-script-image checkpatch-image iptables-image + +diff --git a/images/compilers/install-deps.sh b/images/compilers/install-deps.sh +index 35854f4..038d745 100755 +--- a/images/compilers/install-deps.sh ++++ b/images/compilers/install-deps.sh +@@ -71,6 +71,20 @@ Suites: noble-security + Components: main universe restricted multiverse + Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg + Architectures: arm64 ++ ++Types: deb ++URIs: http://ports.ubuntu.com/ ++Suites: noble noble-updates noble-backports ++Components: main restricted universe multiverse ++Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg ++Architectures: s390x ++ ++Types: deb ++URIs: http://ports.ubuntu.com/ubuntu-ports/ ++Suites: noble-security ++Components: main universe restricted multiverse ++Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg ++Architectures: s390x + EOF + + if [ "$(uname -m)" == "x86_64" ] ; then +diff --git a/images/compilers/test/s390x/spec.yaml b/images/compilers/test/s390x/spec.yaml +new file mode 100644 +index 0000000..c150cae +--- /dev/null ++++ b/images/compilers/test/s390x/spec.yaml +@@ -0,0 +1,13 @@ ++schemaVersion: "2.0.0" ++ ++commandTests: ++- name: "gcc command is in path" ++ command: "which" ++ args: ["gcc"] ++ expectedOutput: ["/usr/bin/gcc"] ++- name: "gcc version" ++ command: "gcc" ++ args: ["-v"] ++ expectedError: ++ - 'Target:\ s390x-linux-gnu' ++ - 'gcc\ version\ 9\.5\.0' +diff --git a/images/maker/Dockerfile b/images/maker/Dockerfile +index d910c17..2ff995d 100644 +--- a/images/maker/Dockerfile ++++ b/images/maker/Dockerfile +@@ -1,13 +1,12 @@ + # Copyright Authors of Cilium + # SPDX-License-Identifier: Apache-2.0 + +-ARG DOCKER_IMAGE=docker.io/library/docker:29.4.1-dind@sha256:c77e5d7912f9b137cc67051fdc2991d8f5ae22c55ddf532bb836dcb693a04940 +-ARG CRANE_IMAGE=gcr.io/go-containerregistry/crane:latest@sha256:d3a706262093746258f20107ab4e95536f9d6d45c8c3f3acf6b02b1801b440d6 +-ARG ALPINE_BASE_IMAGE=docker.io/library/alpine:3.23.4@sha256:5b10f432ef3da1b8d4c7eb6c487f2f5a8f096bc91145e68878dd4a5019afde11 +-ARG GOLANG_IMAGE=docker.io/library/golang:1.26.2@sha256:b54cbf583d390341599d7bcbc062425c081105cc5ef6d170ced98ef9d047c716 ++ARG DOCKER_IMAGE=docker.io/library/alpine:3.23.3@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 ++ARG ALPINE_BASE_IMAGE=docker.io/library/alpine:3.23.3@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 ++ARG GOLANG_IMAGE=docker.io/library/golang:1.26.0@sha256:c83e68f3ebb6943a2904fa66348867d108119890a2c6a2e6f07b38d0eb6c25c5 + + FROM ${DOCKER_IMAGE} AS docker-dist +-FROM ${CRANE_IMAGE} AS crane-dist ++RUN apk add --no-cache docker-cli + + FROM ${GOLANG_IMAGE} AS go-builder + +@@ -26,20 +25,27 @@ RUN apk add --no-cache \ + + RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ + +-RUN apk add --initdb --no-cache --root /out \ +- alpine-baselayout \ +- bash \ +- ca-certificates \ +- coreutils \ +- git \ +- make \ +- shellcheck \ +- jq \ +- yq \ +- && true ++RUN if [ "${TARGETARCH}" = "s390x" ]; then \ ++ echo "Skipping shellcheck install for TARGETARCH=${TARGETARCH} (package unavailable)."; \ ++ extra_pkgs=""; \ ++ apk_root_opts="--initdb --no-cache --root /out --no-scripts"; \ ++ else \ ++ extra_pkgs="shellcheck"; \ ++ apk_root_opts="--initdb --no-cache --root /out"; \ ++ fi && \ ++ apk add ${apk_root_opts} \ ++ alpine-baselayout \ ++ bash \ ++ ca-certificates \ ++ coreutils \ ++ git \ ++ make \ ++ jq \ ++ yq \ ++ ${extra_pkgs} \ ++ && true + +-COPY --from=docker-dist /usr/local/bin /out/usr/local/bin +-COPY --from=crane-dist /ko-app/crane /out/usr/local/bin/crane ++COPY --from=docker-dist /usr/bin/docker /out/usr/local/bin/docker + COPY --from=go-builder /out /out + + ARG HADOLINT_VERSION=2.12.0 +@@ -47,11 +53,17 @@ ARG HADOLINT_VERSION=2.12.0 + RUN case "${TARGETARCH}" in \ + 'amd64') export ARCH='x86_64' ;; \ + 'arm64') export ARCH='arm64' ;; \ ++ 's390x') export ARCH='' ;; \ ++ *) echo "Unsupported TARGETARCH for hadolint: ${TARGETARCH}" >&2; exit 1 ;; \ + esac && \ +- curl --fail --show-error --silent --location \ +- "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-${ARCH}" \ +- --output /out/usr/local/bin/hadolint \ +- && chmod +x /out/usr/local/bin/hadolint ++ if [ -n "${ARCH}" ]; then \ ++ curl --fail --show-error --silent --location \ ++ "https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-Linux-${ARCH}" \ ++ --output /out/usr/local/bin/hadolint \ ++ && chmod +x /out/usr/local/bin/hadolint; \ ++ else \ ++ echo "Skipping hadolint install for TARGETARCH=${TARGETARCH} (no upstream binary available)."; \ ++ fi + + RUN mkdir -p /out/etc/docker/cli-plugins \ + && echo '{ "experimental": "enabled", "credsStore" : "env" }' > /out/etc/docker/config.json \ +diff --git a/images/maker/build-go-deps.sh b/images/maker/build-go-deps.sh +index d1d4c91..93dd4a4 100755 +--- a/images/maker/build-go-deps.sh ++++ b/images/maker/build-go-deps.sh +@@ -17,4 +17,5 @@ mkdir -p $GOBIN + + go install -ldflags '-s -w' github.com/errordeveloper/docker-credential-env@v0.1.5 + go install -ldflags '-s -w' github.com/docker/buildx/cmd/buildx@v0.13.1 ++go install -ldflags '-s -w' github.com/google/go-containerregistry/cmd/crane@v0.20.8 + mv $GOBIN/buildx $GOBIN/docker-buildx +diff --git a/images/tester/test/spec.yaml b/images/tester/test/spec.yaml +index faea2e0..8a40a12 100644 +--- a/images/tester/test/spec.yaml ++++ b/images/tester/test/spec.yaml +@@ -23,4 +23,4 @@ commandTests: + command: '/test/bin/cst' + args: ['-V'] + expectedOutput: +- - 'go1\..*\ linux/(amd64|arm64)' ++ - 'go1\..*\ linux/(amd64|arm64|s390x)' +diff --git a/scripts/build-image.sh b/scripts/build-image.sh +index e93dbbf..250f47f 100755 +--- a/scripts/build-image.sh ++++ b/scripts/build-image.sh +@@ -118,11 +118,29 @@ fi + do_test="${TEST:-false}" + + run_buildx() { ++ local build_arg_name ++ local build_arg_value + build_args=( + "--platform=${platform}" + "--builder=${builder}" + "--file=${image_dir}/Dockerfile" + ) ++ for build_arg_name in \ ++ MAKER_IMAGE \ ++ TESTER_IMAGE \ ++ COMPILERS_IMAGE \ ++ UBUNTU_IMAGE \ ++ GOLANG_IMAGE \ ++ ALPINE_BASE_IMAGE \ ++ BASE_IMAGE \ ++ DOCKER_IMAGE \ ++ CRANE_IMAGE ++ do ++ build_arg_value="${!build_arg_name:-}" ++ if [ -n "${build_arg_value}" ] ; then ++ build_args+=("--build-arg=${build_arg_name}=${build_arg_value}") ++ fi ++ done + if [ "${with_root_context}" = "false" ] ; then + build_args+=("${image_dir}") + else +@@ -133,7 +151,7 @@ run_buildx() { + exit 1 + fi + fi +- docker buildx build --output="${output}" "${tag_args[@]}" "${build_args[@]}" ++ docker buildx build --output="${output}" "${tag_args[@]}" "${build_args[@]}" --load + } + + if [ "${do_build}" = "true" ] ; then diff --git a/Cilium/1.19.4/patch/proxy-s390x-aws-lc.patch b/Cilium/1.19.4/patch/proxy-s390x-aws-lc.patch new file mode 100644 index 00000000..d4336925 --- /dev/null +++ b/Cilium/1.19.4/patch/proxy-s390x-aws-lc.patch @@ -0,0 +1,1930 @@ +diff --git a/.bazelrc b/.bazelrc +index b6badb73..13a50eb6 100644 +--- a/.bazelrc ++++ b/.bazelrc +@@ -6,6 +6,21 @@ + # curl -sSL https://raw.githubusercontent.com/envoyproxy/envoy-wasm/master/.bazelrc > envoy.bazelrc + import %workspace%/envoy.bazelrc + ++# SSL library profiles for Envoy external repo. ++# Keep defaults unchanged; these are opt-in via --config=... ++common:fips-common --test_tag_filters=-nofips ++common:fips-common --build_tag_filters=-nofips ++# Envoy v1.36.5 still activates FIPS through the boringssl define. The ++# s390x AWS-LC routing happens inside the external Envoy patch stack. ++common:fips-common --define=boringssl=fips ++ ++common:aws-lc-fips --config=fips-common ++# Upstream default: disable HTTP/3 (QUIC) for AWS-LC FIPS profile. ++common:aws-lc-fips --@envoy//bazel:http3=False ++# Experimental profile: re-enable QUIC on top of aws-lc-fips. ++common:aws-lc-fips-http3-exp --config=aws-lc-fips ++common:aws-lc-fips-http3-exp --@envoy//bazel:http3=True ++ + # override clang version in envoy.bazelrc + build:clang-common --action_env=CC=clang-18 --host_action_env=CC=clang-18 + build:clang-common --action_env=CXX=clang++-18 --host_action_env=CXX=clang++-18 +diff --git a/.gitignore b/.gitignore +index 1ed21c25..e81ea8b2 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -48,6 +48,7 @@ + /proxylib/_obj* + + /BUILD_DEP_HASHES ++/.aws-lc-local + + # clangd compilation database + /compile_commands.json +diff --git a/Dockerfile b/Dockerfile +index d057630d..cf812a5a 100644 +--- a/Dockerfile ++++ b/Dockerfile +@@ -32,15 +32,26 @@ ARG BAZEL_BUILD_OPTS + ARG DEBUG + ARG BUILDARCH + ARG TARGETARCH ++ARG AWS_LC_FIPS ++ARG KEEP_BUILDER_FRESH_CACHE=0 + ENV TARGETARCH=$TARGETARCH + # + # Clear runner's cache when building deps + # +-RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH,sharing=private rm -rf /cilium/proxy/.cache/* ++USER 0 ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH \ ++ if [ "${KEEP_BUILDER_FRESH_CACHE}" = "1" ]; then \ ++ echo "KEEP_BUILDER_FRESH_CACHE=1, preserving /cilium/proxy/.cache"; \ ++ else \ ++ rm -rf /cilium/proxy/.cache/*; \ ++ fi ++USER 1337:1337 + # + # Build dependencies from scratch (no cache mounts, not archive mount) + # +-RUN BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" PKG_BUILD=1 V=$V DEBUG=$DEBUG DESTDIR=/tmp/install make bazel-bin/cilium-envoy-starter bazel-bin/cilium-envoy ++RUN if [ "${TARGETARCH}" = "s390x" ]; then export CARGO_BAZEL_GENERATOR_URL="file:///usr/local/bin/cargo-bazel"; fi; \ ++ if [ -n "${AWS_LC_FIPS}" ]; then export AWS_LC_FIPS="${AWS_LC_FIPS}"; fi; \ ++ BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" PKG_BUILD=1 V=$V DEBUG=$DEBUG DESTDIR=/tmp/install make bazel-bin/cilium-envoy-starter bazel-bin/cilium-envoy + + # By default this stage picks up the result of the build above, but ARCHIVE_IMAGE can be + # overridden to point to a saved image of an earlier run of that stage. +@@ -64,13 +75,17 @@ ARG DEBUG + ARG RELEASE_DEBUG + ARG BUILDARCH + ARG TARGETARCH ++ARG AWS_LC_FIPS + ENV TARGETARCH=$TARGETARCH + RUN ./bazel/get_workspace_status +-RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH,sharing=private \ ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH \ + --mount=target=/tmp/bazel-cache,source=/tmp/bazel-cache,from=builder-cache,rw \ ++ if [ -d /cilium/proxy/.cache/bazel/_bazel_cilium ]; then find /cilium/proxy/.cache/bazel/_bazel_cilium -mindepth 2 -maxdepth 2 -type d -name server -exec rm -rf {} +; fi && \ + if [ -f /tmp/bazel-cache/ENVOY_VERSION ]; then CACHE_ENVOY_VERSION=`cat /tmp/bazel-cache/ENVOY_VERSION`; ENVOY_VERSION=`cat ENVOY_VERSION`; if [ "${CACHE_ENVOY_VERSION}" != "${ENVOY_VERSION}" ]; then echo "Building Envoy ${ENVOY_VERSION} with bazel archive from different Envoy version (${CACHE_ENVOY_VERSION})"; else echo "Building Envoy ${ENVOY_VERSION} with bazel cache of the same version"; fi; else echo "Bazel cache has no ENVOY_VERSION, it may be empty."; fi && \ + touch /tmp/bazel-cache/permissions-check && \ + if [ -n "${COPY_CACHE_EXT}" ]; then PKG_BUILD=1 make BUILD_DEP_HASHES; if [ -f /tmp/bazel-cache/BUILD_DEP_HASHES ] && ! diff BUILD_DEP_HASHES /tmp/bazel-cache/BUILD_DEP_HASHES; then echo "Build dependencies have changed, clearing bazel cache"; rm -rf /tmp/bazel-cache/*; rm -rf /cilium/proxy/.cache/*; fi ; cp BUILD_DEP_HASHES ENVOY_VERSION /tmp/bazel-cache; fi && \ ++ if [ "${TARGETARCH}" = "s390x" ]; then export CARGO_BAZEL_GENERATOR_URL="file:///usr/local/bin/cargo-bazel"; fi && \ ++ if [ -n "${AWS_LC_FIPS}" ]; then export AWS_LC_FIPS="${AWS_LC_FIPS}"; fi && \ + BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" PKG_BUILD=1 V=$V DEBUG=$DEBUG RELEASE_DEBUG=$RELEASE_DEBUG DESTDIR=/tmp/install make install && \ + if [ -n "${COPY_CACHE_EXT}" ]; then cp -ra /tmp/bazel-cache /tmp/bazel-cache${COPY_CACHE_EXT}; ls -la /tmp/bazel-cache${COPY_CACHE_EXT}; fi + # +@@ -102,7 +117,8 @@ ENV TARGETARCH=$TARGETARCH + # + # Check format + # +-RUN BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make V=1 format > format-output.txt ++RUN if [ "${TARGETARCH}" = "s390x" ]; then export CARGO_BAZEL_GENERATOR_URL="file:///usr/local/bin/cargo-bazel"; fi; \ ++ BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make V=1 format > format-output.txt + + FROM scratch AS format + COPY --from=check-format /cilium/proxy/format-output.txt / +@@ -122,7 +138,7 @@ ENV TARGETARCH=$TARGETARCH + # + # Run clang tidy + # +-RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache TIDY_SOURCES="${TIDY_SOURCES}" BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make -C b V=1 tidy-fix 2>&1 | tee /cilium/proxy/clang-tidy-output.txt && for file in ${TIDY_SOURCES}; do echo "\$ diff a/$file b/$file" >> /cilium/proxy/clang-tidy-diff.txt && diff "a/$file" "b/$file" >> /cilium/proxy/clang-tidy-diff.txt || true; done ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache if [ "${TARGETARCH}" = "s390x" ]; then export CARGO_BAZEL_GENERATOR_URL="file:///usr/local/bin/cargo-bazel"; fi && TIDY_SOURCES="${TIDY_SOURCES}" BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make -C b V=1 tidy-fix 2>&1 | tee /cilium/proxy/clang-tidy-output.txt && for file in ${TIDY_SOURCES}; do echo "\$ diff a/$file b/$file" >> /cilium/proxy/clang-tidy-diff.txt && diff "a/$file" "b/$file" >> /cilium/proxy/clang-tidy-diff.txt || true; done + + FROM scratch AS clang-tidy + COPY --from=run-clang-tidy-fix /cilium/proxy/*.txt / +@@ -130,7 +146,7 @@ COPY --from=run-clang-tidy-fix /cilium/proxy/*.txt / + # + # Extract installed cilium-envoy binaries to an otherwise empty image + # +-FROM docker.io/library/ubuntu:24.04@sha256:cd1dba651b3080c3686ecf4e3c4220f026b521fb76978881737d24f200828b2b ++FROM public.ecr.aws/ubuntu/ubuntu:24.04@sha256:8307fed669bda8e552b5716194d81544760741347dbf3333e7dcd33680a2b986 + LABEL maintainer="maintainer@cilium.io" + # install ca-certificates package + RUN apt-get update && apt-get upgrade -y \ +diff --git a/Dockerfile.builder b/Dockerfile.builder +index f896ec9c..9ae1af63 100644 +--- a/Dockerfile.builder ++++ b/Dockerfile.builder +@@ -3,7 +3,7 @@ + # Also note that if build fails due to C++ internal error or similar, + # it is possible that the image build needs more RAM than available by + # default on non-Linux docker installs. +-FROM docker.io/library/ubuntu:24.04@sha256:cd1dba651b3080c3686ecf4e3c4220f026b521fb76978881737d24f200828b2b AS base ++FROM public.ecr.aws/ubuntu/ubuntu:24.04@sha256:8307fed669bda8e552b5716194d81544760741347dbf3333e7dcd33680a2b986 AS base + LABEL maintainer="maintainer@cilium.io" + ARG TARGETARCH + # Setup TimeZone to prevent tzdata package asking for it interactively +@@ -16,10 +16,12 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone +-RUN apt-get update && \ ++RUN sed -i 's/Components: main$/Components: main universe/' /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || true && \ ++ apt-get update && \ + apt-get upgrade -y --no-install-recommends && \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + # Multi-arch cross-compilation packages + gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross binutils-aarch64-linux-gnu \ + gcc-x86-64-linux-gnu g++-x86-64-linux-gnu libc6-dev-amd64-cross binutils-x86-64-linux-gnu \ ++ gcc-s390x-linux-gnu g++-s390x-linux-gnu libc6-dev-s390x-cross binutils-s390x-linux-gnu \ + libc6-dev \ + # Envoy Build dependencies + autoconf automake cmake coreutils curl git libtool make ninja-build patch patchelf libatomic1 \ +@@ -40,10 +43,68 @@ RUN apt-get update && \ + # + # renovate: datasource=github-releases depName=bazelbuild/bazelisk + ENV BAZELISK_VERSION=v1.28.1 ++ARG BAZEL_VERSION + + RUN ARCH=$TARGETARCH \ +- && curl -sfL https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-${ARCH} -o /usr/bin/bazel \ +- && chmod +x /usr/bin/bazel ++ && if [ "${ARCH}" = "amd64" ] || [ "${ARCH}" = "arm64" ]; then \ ++ curl -sfL "https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-${ARCH}" -o /usr/bin/bazel; \ ++ chmod +x /usr/bin/bazel; \ ++ elif [ "${ARCH}" = "s390x" ]; then \ ++ # Bazelisk does not publish linux/s390x binaries. Build Bazel from the release dist zip. ++ apt-get update \ ++ && apt-get install -y --no-install-recommends bazel-bootstrap default-jdk-headless \ ++ && TMPDIR="$(mktemp -d)" \ ++ && BZ_VERSION="${BAZEL_VERSION}" \ ++ && curl -sfL "https://github.com/bazelbuild/bazel/releases/download/${BZ_VERSION}/bazel-${BZ_VERSION}-dist.zip" -o "${TMPDIR}/bazel-dist.zip" \ ++ && unzip -q "${TMPDIR}/bazel-dist.zip" -d "${TMPDIR}/bazel-src" \ ++ && cd "${TMPDIR}/bazel-src" \ ++ && if ! grep -q 'module_name = "apple_support"' MODULE.bazel; then printf '\nsingle_version_override(\n module_name = "apple_support",\n version = "1.8.1",\n)\n' >> MODULE.bazel; fi \ ++ && if ! grep -q 'name = "function_transition_allowlist"' tools/allowlists/function_transition_allowlist/BUILD; then \ ++ printf '%s\n' \ ++ '' \ ++ 'package_group(' \ ++ ' name = "function_transition_allowlist",' \ ++ ' packages = ["public"],' \ ++ ')' >> tools/allowlists/function_transition_allowlist/BUILD; \ ++ fi \ ++ && if ! find . -path '*/com/google/protobuf/UnusedPrivateParameter.java' -print -quit | grep -q .; then \ ++ PB_DIR="$(find . -type d -path '*/com/google/protobuf' | head -n 1)" \ ++ && if [ -n "${PB_DIR}" ]; then \ ++ printf '%s\n' \ ++ 'package com.google.protobuf;' \ ++ '' \ ++ 'final class UnusedPrivateParameter {' \ ++ ' static final UnusedPrivateParameter INSTANCE = new UnusedPrivateParameter();' \ ++ ' private UnusedPrivateParameter() {}' \ ++ '}' > "${PB_DIR}/UnusedPrivateParameter.java"; \ ++ fi; \ ++ fi \ ++ && export JAVA_TOOL_OPTIONS="-XX:TieredStopAtLevel=1" \ ++ && export BAZEL_JAVAC_OPTS="-J-Xms512m -J-Xmx4g -J-XX:TieredStopAtLevel=1" \ ++ && export BAZEL_BOOTSTRAP_STARTUP_OPTIONS="--host_jvm_args=-Xmx4g --host_jvm_args=-XX:TieredStopAtLevel=1" \ ++ && EXTRA_BAZEL_ARGS="--lockfile_mode=refresh --java_runtime_version=local_jdk --tool_java_runtime_version=local_jdk --java_language_version=21 --tool_java_language_version=21" ./compile.sh \ ++ && install -m 0755 output/bazel "/usr/bin/bazel-${BZ_VERSION}" \ ++ && ln -sf "/usr/bin/bazel-${BZ_VERSION}" /usr/bin/bazel \ ++ && rm -rf "${TMPDIR}" \ ++ && apt-get clean \ ++ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*; \ ++ else \ ++ echo "Unsupported TARGETARCH for Bazel bootstrap: ${ARCH}" >&2; \ ++ exit 1; \ ++ fi ++ ++RUN if [ "${TARGETARCH}" = "s390x" ]; then \ ++ apt-get update \ ++ && apt-get install -y --no-install-recommends linux-libc-dev-s390x-cross libssl-dev \ ++ && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable \ ++ && . /root/.cargo/env \ ++ && cargo --version \ ++ && cargo install --locked --git https://github.com/bazelbuild/rules_rust.git --tag 0.56.0 cargo-bazel --root /usr/local \ ++ && /usr/local/bin/cargo-bazel --version \ ++ && rm -rf /root/.cargo/registry /root/.cargo/git \ ++ && apt-get clean \ ++ && rm -rf /var/lib/apt/lists/*; \ ++ fi + # + # Install Go + # +diff --git a/Dockerfile.tests b/Dockerfile.tests +index 416b392d..9c1dc932 100644 +--- a/Dockerfile.tests ++++ b/Dockerfile.tests +@@ -19,9 +19,11 @@ ARG ARCHIVE_IMAGE=builder-fresh + + FROM --platform=$BUILDPLATFORM $PROXYLIB_BUILDER AS proxylib + WORKDIR /go/src/github.com/cilium/proxy ++COPY --chown=1337:1337 . ./ + ARG TARGETARCH +-RUN --mount=type=bind,readwrite,target=/go/src/github.com/cilium/proxy --mount=mode=0777,target=/cilium/proxy/.cache,type=cache --mount=mode=0777,target=/go/pkg,type=cache \ +- GOARCH=${TARGETARCH} make -C proxylib all && mv proxylib/libcilium.so /tmp/libcilium.so ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH \ ++ --mount=mode=0777,uid=1337,gid=1337,target=/go/pkg,type=cache,id=$TARGETARCH \ ++ PATH=$PATH:/usr/local/go/bin GOFLAGS=-buildvcs=false GOARCH=${TARGETARCH} make -C proxylib all && mv proxylib/libcilium.so /tmp/libcilium.so + + FROM --platform=$BUILDPLATFORM $BUILDER_BASE AS builder-fresh + LABEL maintainer="maintainer@cilium.io" +@@ -29,9 +31,12 @@ WORKDIR /cilium/proxy + COPY . ./ + ARG V + ARG BAZEL_BUILD_OPTS ++ARG CARGO_BAZEL_REPIN=true ++ARG TEST_TARGETS="//tests/... @envoy//test/integration:tcp_proxy_integration_test" + ARG DEBUG + ARG BUILDARCH + ARG TARGETARCH ++ARG AWS_LC_FIPS + ARG NO_CACHE + ENV TARGETARCH=$TARGETARCH + +@@ -40,7 +45,13 @@ ENV TARGETARCH=$TARGETARCH + # + # Make proxylib available for building the test dependencies by copying it before running the tests + COPY --from=proxylib /tmp/libcilium.so proxylib/libcilium.so +-RUN BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" PKG_BUILD=1 V=$V DEBUG=$DEBUG make envoy-test-deps ++RUN mkdir -p /tmp/bazel-cache ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH \ ++ --mount=mode=0777,uid=1337,gid=1337,target=/tmp/bazel-cache,type=cache,id=$TARGETARCH-bazel-cache \ ++ if [ -d /cilium/proxy/.cache/bazel/_bazel_cilium ]; then find /cilium/proxy/.cache/bazel/_bazel_cilium -mindepth 2 -maxdepth 2 -type d -name server -exec rm -rf {} +; fi && \ ++ if [ "${TARGETARCH}" = "s390x" ]; then export CARGO_BAZEL_GENERATOR_URL="file:///usr/local/bin/cargo-bazel"; fi; \ ++ if [ -n "${AWS_LC_FIPS}" ]; then export AWS_LC_FIPS="${AWS_LC_FIPS}"; fi; \ ++ BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" CARGO_BAZEL_REPIN="${CARGO_BAZEL_REPIN}" TEST_TARGETS="${TEST_TARGETS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make envoy-test-deps + + # By default this stage picks up the result of the build above, but ARCHIVE_IMAGE can be + # overridden to point to a saved image of an earlier run of that stage. +@@ -53,19 +64,27 @@ COPY . ./ + ARG V + ARG COPY_CACHE_EXT + ARG BAZEL_BUILD_OPTS ++ARG CARGO_BAZEL_REPIN=true ++ARG TEST_TARGETS="//tests/... @envoy//test/integration:tcp_proxy_integration_test" + ARG DEBUG + ARG TARGETARCH ++ARG AWS_LC_FIPS + ENV TARGETARCH=$TARGETARCH + + # Clear runner's cache when building deps +-RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH,sharing=private rm -rf /cilium/proxy/.cache/* ++USER 0 ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH rm -rf /cilium/proxy/.cache/* ++USER 1337:1337 + # Make proxylib available for building the test dependencies by copying it before running the tests + COPY --from=proxylib /tmp/libcilium.so proxylib/libcilium.so + RUN --mount=target=/tmp/bazel-cache,source=/tmp/bazel-cache,from=archive-cache,rw \ ++ if [ -d /cilium/proxy/.cache/bazel/_bazel_cilium ]; then find /cilium/proxy/.cache/bazel/_bazel_cilium -mindepth 2 -maxdepth 2 -type d -name server -exec rm -rf {} +; fi && \ + if [ -f /tmp/bazel-cache/ENVOY_VERSION ]; then CACHE_ENVOY_VERSION=`cat /tmp/bazel-cache/ENVOY_VERSION`; ENVOY_VERSION=`cat ENVOY_VERSION`; if [ "${CACHE_ENVOY_VERSION}" != "${ENVOY_VERSION}" ]; then echo "Testing Envoy ${ENVOY_VERSION} with bazel archive from different Envoy version (${CACHE_ENVOY_VERSION})"; else echo "Testing Envoy ${ENVOY_VERSION} with bazel cache of the same version"; fi; else echo "Bazel cache has no ENVOY_VERSION, it may be empty."; fi && \ + touch /tmp/bazel-cache/permissions-check && \ + if [ -n "${COPY_CACHE_EXT}" ]; then PKG_BUILD=1 make BUILD_DEP_HASHES; if [ -f /tmp/bazel-cache/BUILD_DEP_HASHES ] && ! diff BUILD_DEP_HASHES /tmp/bazel-cache/BUILD_DEP_HASHES; then echo "Build dependencies have changed, clearing bazel cache"; rm -rf /tmp/bazel-cache/*; rm -rf /cilium/proxy/.cache/*; fi ; cp BUILD_DEP_HASHES ENVOY_VERSION /tmp/bazel-cache; fi && \ +- BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" PKG_BUILD=1 V=$V DEBUG=$DEBUG make envoy-test-deps && \ ++ if [ "${TARGETARCH}" = "s390x" ]; then export CARGO_BAZEL_GENERATOR_URL="file:///usr/local/bin/cargo-bazel"; fi && \ ++ if [ -n "${AWS_LC_FIPS}" ]; then export AWS_LC_FIPS="${AWS_LC_FIPS}"; fi && \ ++ BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" CARGO_BAZEL_REPIN="${CARGO_BAZEL_REPIN}" TEST_TARGETS="${TEST_TARGETS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make envoy-test-deps && \ + if [ -n "${COPY_CACHE_EXT}" ]; then cp -ra /tmp/bazel-cache /tmp/bazel-cache${COPY_CACHE_EXT}; fi + + FROM --platform=$BUILDPLATFORM $BUILDER_BASE AS runner +@@ -75,17 +94,23 @@ COPY . ./ + ARG V + ARG BAZEL_BUILD_OPTS + ARG BAZEL_TEST_OPTS ++ARG CARGO_BAZEL_REPIN=true ++ARG TEST_TARGETS="//tests/... @envoy//test/integration:tcp_proxy_integration_test" + ARG DEBUG + ARG BUILDARCH + ARG TARGETARCH ++ARG AWS_LC_FIPS + ARG NO_CACHE + ENV TARGETARCH=$TARGETARCH + +-RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH,sharing=private if [ -n "$NO_CACHE" ]; then rm -rf /cilium/proxy/.cache/*; fi ++USER 0 ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH if [ -n "$NO_CACHE" ]; then rm -rf /cilium/proxy/.cache/*; fi ++USER 1337:1337 + # Make proxylib available for the tests by copying it before running the tests + COPY --from=proxylib /tmp/libcilium.so proxylib/libcilium.so +-RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH,sharing=private \ ++RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,id=$TARGETARCH \ + --mount=target=/tmp/bazel-cache,source=/tmp/bazel-cache,from=archive-cache,rw \ ++ if [ -d /cilium/proxy/.cache/bazel/_bazel_cilium ]; then find /cilium/proxy/.cache/bazel/_bazel_cilium -mindepth 2 -maxdepth 2 -type d -name server -exec rm -rf {} +; fi && \ + if [ "$TARGETARCH" != "$BUILDARCH" ]; then \ + if [ "$TARGETARCH" = "amd64" ]; then \ + # Allow running x86_64 test binaries via qemu \ +@@ -96,9 +121,15 @@ RUN --mount=mode=0777,uid=1337,gid=1337,target=/cilium/proxy/.cache,type=cache,i + # Allow running aarch64 test binaries via qemu \ + ln -s /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.* /lib; \ + ln -s /usr/aarch64-linux-gnu/lib /usr/cilium-cross-compat/lib; \ ++ elif [ "$TARGETARCH" = "s390x" ]; then \ ++ # Allow running s390x test binaries via qemu \ ++ ln -s /usr/s390x-linux-gnu/lib/ld64.so.1 /lib; \ ++ ln -s /usr/s390x-linux-gnu/lib /usr/cilium-cross-compat/lib; \ + fi; \ + fi && \ +- BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" BAZEL_TEST_OPTS="${BAZEL_TEST_OPTS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make envoy-tests && \ ++ if [ "${TARGETARCH}" = "s390x" ]; then export CARGO_BAZEL_GENERATOR_URL="file:///usr/local/bin/cargo-bazel"; fi && \ ++ if [ -n "${AWS_LC_FIPS}" ]; then export AWS_LC_FIPS="${AWS_LC_FIPS}"; fi && \ ++ BAZEL_BUILD_OPTS="${BAZEL_BUILD_OPTS} --disk_cache=/tmp/bazel-cache" BAZEL_TEST_OPTS="${BAZEL_TEST_OPTS}" CARGO_BAZEL_REPIN="${CARGO_BAZEL_REPIN}" TEST_TARGETS="${TEST_TARGETS}" PKG_BUILD=1 V=$V DEBUG=$DEBUG make envoy-tests && \ + cp -Lr /cilium/proxy/bazel-testlogs testlogs + + FROM scratch AS empty-builder-archive +diff --git a/Makefile b/Makefile +index 27df078a..653c3067 100644 +--- a/Makefile ++++ b/Makefile +@@ -26,6 +26,8 @@ BAZEL ?= $(QUIET) bazel + BAZEL_FILTER ?= + BAZEL_OPTS ?= + BAZEL_BUILD_OPTS ?= ++CARGO_BAZEL_REPIN ?= true ++TEST_TARGETS ?= //tests/... @envoy//test/integration:tcp_proxy_integration_test + ifdef BAZEL_REMOTE_CACHE + BAZEL_BUILD_OPTS += --remote_cache=$(BAZEL_REMOTE_CACHE) + endif +@@ -123,7 +125,7 @@ clang.bazelrc: bazel/setup_clang.sh + .PHONY: bazel-bin/cilium-envoy + bazel-bin/cilium-envoy: $(COMPILER_DEP) SOURCE_VERSION install-bazelisk + @$(ECHO_BAZEL) +- CARGO_BAZEL_REPIN=true $(BAZEL) $(BAZEL_OPTS) build $(BAZEL_BUILD_OPTS) //:cilium-envoy $(BAZEL_FILTER) ++ CARGO_BAZEL_REPIN=$(CARGO_BAZEL_REPIN) $(BAZEL) $(BAZEL_OPTS) build $(BAZEL_BUILD_OPTS) //:cilium-envoy $(BAZEL_FILTER) + + cilium-envoy: bazel-bin/cilium-envoy + mv $< $@ +@@ -131,7 +133,7 @@ cilium-envoy: bazel-bin/cilium-envoy + .PHONY: bazel-bin/cilium-envoy-starter + bazel-bin/cilium-envoy-starter: $(COMPILER_DEP) SOURCE_VERSION install-bazelisk + @$(ECHO_BAZEL) +- CARGO_BAZEL_REPIN=true $(BAZEL) $(BAZEL_OPTS) build $(BAZEL_BUILD_OPTS) //:cilium-envoy-starter $(BAZEL_FILTER) ++ CARGO_BAZEL_REPIN=$(CARGO_BAZEL_REPIN) $(BAZEL) $(BAZEL_OPTS) build $(BAZEL_BUILD_OPTS) //:cilium-envoy-starter $(BAZEL_FILTER) + + cilium-envoy-starter: bazel-bin/cilium-envoy-starter + mv $< $@ +@@ -171,14 +173,14 @@ proxylib/libcilium.so: + .PHONY: envoy-test-deps + envoy-test-deps: $(COMPILER_DEP) SOURCE_VERSION proxylib/libcilium.so + @$(ECHO_BAZEL) +- CARGO_BAZEL_REPIN=true $(BAZEL) $(BAZEL_OPTS) build $(BAZEL_BUILD_OPTS) $(BAZEL_TEST_OPTS) //tests/... @envoy//test/integration:tcp_proxy_integration_test $(BAZEL_FILTER) ++ CARGO_BAZEL_REPIN=$(CARGO_BAZEL_REPIN) $(BAZEL) $(BAZEL_OPTS) build $(BAZEL_BUILD_OPTS) $(BAZEL_TEST_OPTS) $(TEST_TARGETS) $(BAZEL_FILTER) + + .PHONY: envoy-tests + envoy-tests: $(COMPILER_DEP) SOURCE_VERSION proxylib/libcilium.so + @$(ECHO_BAZEL) + # Upstream tcp_proxy_integration_test included to validate that our custom patches + # didn't break anything +- CARGO_BAZEL_REPIN=true $(BAZEL) $(BAZEL_OPTS) test $(BAZEL_BUILD_OPTS) $(BAZEL_TEST_OPTS) //tests/... @envoy//test/integration:tcp_proxy_integration_test $(BAZEL_FILTER) ++ CARGO_BAZEL_REPIN=$(CARGO_BAZEL_REPIN) $(BAZEL) $(BAZEL_OPTS) test $(BAZEL_BUILD_OPTS) $(BAZEL_TEST_OPTS) $(TEST_TARGETS) $(BAZEL_FILTER) + + .PHONY: \ + install \ +diff --git a/Makefile.docker b/Makefile.docker +index 2e7f651f..f8e90888 100644 +--- a/Makefile.docker ++++ b/Makefile.docker +@@ -14,9 +14,16 @@ + + # Always use buildx + DOCKER := $(QUIET)DOCKER_BUILDKIT=1 docker buildx ++DOCKER_BUILDX_VERSION := $(shell docker buildx version 2>/dev/null || true) + + DOCKER_DEV_ACCOUNT ?= quay.io/cilium + # CACHE_REF ?= docker.io/cilium/cilium-dev:cilium-envoy-cache ++ ++AWS_LC_LOCAL_STAGE_DIR := .aws-lc-local ++AWS_LC_LOCAL_SRC_CONTAINER := /cilium/proxy/$(AWS_LC_LOCAL_STAGE_DIR) ++ ++.PHONY: verify-image-safety ++verify-image-safety: + CACHE_REF ?= + DOCKER_BUILD_OPTS ?= + DOCKER_CACHE_OPTS ?= +@@ -30,10 +37,15 @@ ifeq ($(ARCH),amd64) + DOCKER_PLATFORMS := --platform=linux/amd64 + else ifeq ($(ARCH),arm64) + DOCKER_PLATFORMS := --platform=linux/arm64 ++else ifeq ($(ARCH),s390x) ++ DOCKER_PLATFORMS := --platform=linux/s390x + else ifeq ($(ARCH),multi) + DOCKER_PLATFORMS := --platform=linux/arm64,linux/amd64 ++ ifeq ($(INCLUDE_S390X),true) ++ DOCKER_PLATFORMS := --platform=linux/arm64,linux/amd64,linux/s390x ++ endif + endif +-DOCKER_BUILDER := $(shell docker buildx ls | grep -E -e "[a-zA-Z0-9-]+ \*" | cut -d ' ' -f1) ++DOCKER_BUILDER := $(shell docker buildx ls 2>/dev/null | grep -E -e "[a-zA-Z0-9-]+ \*" | cut -d ' ' -f1) + ifdef DOCKER_PLATFORMS + ifneq (,$(filter $(DOCKER_BUILDER),default desktop-linux)) + DOCKER_BUILDKIT_DRIVER := +@@ -41,7 +53,7 @@ ifdef DOCKER_PLATFORMS + DOCKER_BUILDKIT_DRIVER := --driver docker-container --driver-opt image=$(DOCKER_BUILDKIT_IMAGE) + endif + BUILDER_SETUP := $(shell docker buildx create $(DOCKER_PLATFORMS) $(DOCKER_BUILDKIT_DRIVER) --use) +- DOCKER_BUILDER := $(shell docker buildx ls | grep -E -e "[a-zA-Z0-9-]+ \*" | cut -d ' ' -f1) ++ DOCKER_BUILDER := $(shell docker buildx ls 2>/dev/null | grep -E -e "[a-zA-Z0-9-]+ \*" | cut -d ' ' -f1) + endif + endif + ifneq ($(DOCKER_BUILDER),default) +@@ -55,7 +67,6 @@ ifneq ($(DOCKER_BUILDER),default) + # (It's not supported to write multi-arch builds to the local Docker registry) + DOCKER_BUILD_OPTS += --push + else +- # Push to local docker registry by default + DOCKER_BUILD_OPTS += --output type=docker + endif + endif +@@ -68,6 +79,62 @@ $(info Using Docker Buildx builder "$(DOCKER_BUILDER)" with build flags "$(DOCKE + + HYPHEN = - + ARCH ?= $(subst aarch64,arm64,$(subst x86_64,amd64,$(patsubst i%86,386,$(shell uname -m)))) ++# Upstream builder archive image currently lacks linux/s390x manifests. ++# Default to fresh dependency build on s390x unless explicitly overridden. ++ifeq ($(ARCH),s390x) ++ NO_ARCHIVE ?= 1 ++ # Keep test-deps builds within tighter memory/CPU limits on zLinux hosts to ++ # avoid late-stage clang OOM kills during large Envoy test object compiles. ++ ifeq ($(filter command line environment,$(origin EXTRA_BAZEL_BUILD_OPTS)),) ++ EXTRA_BAZEL_BUILD_OPTS += --jobs=1 --local_ram_resources=2048 --local_cpu_resources=1 ++ endif ++ ifeq ($(filter command line environment,$(origin BAZEL_TEST_OPTS)),) ++ BAZEL_TEST_OPTS := --jobs=1 --local_ram_resources=2048 --local_cpu_resources=1 --test_timeout=300 --local_test_jobs=1 --flaky_test_attempts=3 --test_output=errors ++ endif ++ # Optional: allow explicit FIPS experiment attempts for AWS-LC on s390x. ++ # Default behavior stays non-FIPS unless caller sets this variable. ++ ifneq ($(strip $(AWS_LC_S390X_FIPS_EXPERIMENTAL)),) ++ ifeq ($(filter --action_env=AWS_LC_S390X_FIPS_EXPERIMENTAL=%,$(EXTRA_BAZEL_BUILD_OPTS)),) ++ override EXTRA_BAZEL_BUILD_OPTS += --action_env=AWS_LC_S390X_FIPS_EXPERIMENTAL=$(AWS_LC_S390X_FIPS_EXPERIMENTAL) ++ endif ++ endif ++ # If explicit AWS_LC_FIPS is set, propagate it into Bazel action env so ++ # aws_lc.genrule_cmd can deterministically honor the requested mode. ++ ifneq ($(strip $(AWS_LC_FIPS)),) ++ ifeq ($(filter --action_env=AWS_LC_FIPS=%,$(EXTRA_BAZEL_BUILD_OPTS)),) ++ override EXTRA_BAZEL_BUILD_OPTS += --action_env=AWS_LC_FIPS=$(AWS_LC_FIPS) ++ endif ++ endif ++ # Optional local AWS-LC source pinning for s390x validation. ++ ifneq ($(strip $(AWS_LC_LOCAL_SRC)),) ++ ifeq ($(filter --action_env=AWS_LC_LOCAL_SRC=%,$(EXTRA_BAZEL_BUILD_OPTS)),) ++ override EXTRA_BAZEL_BUILD_OPTS += --action_env=AWS_LC_LOCAL_SRC=$(AWS_LC_LOCAL_SRC_CONTAINER) ++ endif ++ endif ++ ifneq ($(strip $(AWS_LC_LOCAL_COMMIT)),) ++ ifeq ($(filter --action_env=AWS_LC_LOCAL_COMMIT=%,$(EXTRA_BAZEL_BUILD_OPTS)),) ++ override EXTRA_BAZEL_BUILD_OPTS += --action_env=AWS_LC_LOCAL_COMMIT=$(AWS_LC_LOCAL_COMMIT) ++ endif ++ endif ++ # Some zLinux builders run with IPv6 loopback unavailable inside Bazel test ++ # sandboxes, which makes Envoy integration cases fail on bind('[::1]:0'). ++ # Keep s390x defaults v4-only unless caller explicitly sets the test env. ++ ENVOY_IP_TEST_VERSIONS ?= v4only ++ ifneq ($(strip $(ENVOY_IP_TEST_VERSIONS)),) ++ ifeq ($(filter --test_env=ENVOY_IP_TEST_VERSIONS=%,$(BAZEL_TEST_OPTS)),) ++ override BAZEL_TEST_OPTS += --test_env=ENVOY_IP_TEST_VERSIONS=$(ENVOY_IP_TEST_VERSIONS) ++ endif ++ endif ++ # Iteration mode defaults for zLinux: ++ # - avoid forcing Cargo lock repin on every build ++ # - scope tests to known failing TLS/regression targets unless overridden ++ ifeq ($(filter command line environment,$(origin CARGO_BAZEL_REPIN)),) ++ CARGO_BAZEL_REPIN := false ++ endif ++ ifeq ($(filter command line environment,$(origin TEST_TARGETS)),) ++ TEST_TARGETS := //tests:cilium_tls_http_integration_test //tests:cilium_tls_tcp_integration_test //tests:cilium_websocket_encap_integration_test @envoy//test/integration:tcp_proxy_integration_test ++ endif ++endif + # Add - suffix if ARCH is not "multi" + ifeq ($(ARCH),multi) + ARCH := +@@ -98,6 +165,24 @@ BUILDER_BASE ?= $(DOCKER_DEV_ACCOUNT)/cilium-envoy-builder:$(BUILDER_BASE_TAG) + BUILD_IMAGE_OPTS := --build-arg BUILDER_BASE="$(BUILDER_BASE)" + TESTS_IMAGE_OPTS := --build-arg BUILDER_BASE="$(BUILDER_BASE)" + ++ifeq ($(ARCH),s390x) ++ # Upstream cilium-builder digest used in Dockerfile.tests lacks linux/s390x manifests. ++ # Reuse BUILDER_BASE for proxylib stage unless caller explicitly provides PROXYLIB_BUILDER. ++ PROXYLIB_BUILDER ?= $(BUILDER_BASE) ++endif ++ifneq ($(strip $(PROXYLIB_BUILDER)),) ++ TESTS_IMAGE_OPTS += --build-arg PROXYLIB_BUILDER="$(PROXYLIB_BUILDER)" ++endif ++ ++ifneq ($(strip $(KEEP_BUILDER_FRESH_CACHE)),) ++ BUILD_IMAGE_OPTS += --build-arg KEEP_BUILDER_FRESH_CACHE="$(KEEP_BUILDER_FRESH_CACHE)" ++endif ++ ++ifneq ($(strip $(AWS_LC_FIPS)),) ++ BUILD_IMAGE_OPTS += --build-arg AWS_LC_FIPS="$(AWS_LC_FIPS)" ++ TESTS_IMAGE_OPTS += --build-arg AWS_LC_FIPS="$(AWS_LC_FIPS)" ++endif ++ + ifdef DEBUG + BUILD_IMAGE_OPTS += --build-arg DEBUG=$(DEBUG) + else ifdef RELEASE_DEBUG +@@ -114,6 +199,33 @@ ifndef NO_ARCHIVE + endif + endif + ++.PHONY: prepare-aws-lc-local ++prepare-aws-lc-local: ++ @if [ -z "$(strip $(AWS_LC_LOCAL_SRC))" ]; then \ ++ exit 0; \ ++ fi ++ @if [ ! -d "$(AWS_LC_LOCAL_SRC)" ]; then \ ++ echo "ERROR: AWS_LC_LOCAL_SRC does not exist: $(AWS_LC_LOCAL_SRC)"; \ ++ exit 1; \ ++ fi ++ @echo "Staging AWS-LC local source into $(AWS_LC_LOCAL_STAGE_DIR)" ++ @rm -rf "$(AWS_LC_LOCAL_STAGE_DIR)" ++ @mkdir -p "$(AWS_LC_LOCAL_STAGE_DIR)" ++ @if [ -d "$(AWS_LC_LOCAL_SRC)/.git" ] && [ -n "$(strip $(AWS_LC_LOCAL_COMMIT))" ] && git -C "$(AWS_LC_LOCAL_SRC)" rev-parse --verify "$(AWS_LC_LOCAL_COMMIT)^{commit}" >/dev/null 2>&1; then \ ++ echo "Exporting AWS-LC commit $(AWS_LC_LOCAL_COMMIT) from $(AWS_LC_LOCAL_SRC)"; \ ++ git -C "$(AWS_LC_LOCAL_SRC)" archive --format=tar "$(AWS_LC_LOCAL_COMMIT)" | tar -xf - -C "$(AWS_LC_LOCAL_STAGE_DIR)"; \ ++ else \ ++ if [ -d "$(AWS_LC_LOCAL_SRC)/.git" ] && [ -n "$(strip $(AWS_LC_LOCAL_COMMIT))" ]; then \ ++ echo "WARNING: AWS_LC_LOCAL_COMMIT $(AWS_LC_LOCAL_COMMIT) not found in $(AWS_LC_LOCAL_SRC); staging current worktree snapshot"; \ ++ fi; \ ++ cp -a "$(AWS_LC_LOCAL_SRC)/." "$(AWS_LC_LOCAL_STAGE_DIR)/"; \ ++ fi ++ @if [ ! -f "$(AWS_LC_LOCAL_STAGE_DIR)/CMakeLists.txt" ]; then \ ++ echo "ERROR: staged AWS-LC source is missing CMakeLists.txt"; \ ++ find "$(AWS_LC_LOCAL_STAGE_DIR)" -maxdepth 2 -name CMakeLists.txt -print || true; \ ++ exit 1; \ ++ fi ++ + ifdef NO_CACHE + DOCKER_CACHE_OPTS += --build-arg NO_CACHE=$(NO_CACHE) + ifeq ($(NO_CACHE),2) +@@ -145,13 +257,13 @@ Dockerfile.builder.tests.dockerignore: + echo "!/.bazelversion" >>$@ + + # Release does not need Go API or test files +-Dockerfile.dockerignore: .dockerignore Makefile.docker ++Dockerfile.dockerignore: .dockerignore Makefile.docker prepare-aws-lc-local + cp $< $@ + echo "/tests/" >>$@ + echo "/Makefile.api" >>$@ + echo "/envoy_binary_test.sh" >>$@ + +-Dockerfile.tests.dockerignore: .dockerignore Makefile.docker ++Dockerfile.tests.dockerignore: .dockerignore Makefile.docker prepare-aws-lc-local + cp $< $@ + echo "/Makefile.api" >>$@ + +@@ -175,18 +287,23 @@ GIT_IGNORE_FILES := $(shell find -H . -not -path "./_build*" -not -path "./vendo + echo "/Dockerfile*" >>$@ + echo "/Makefile.docker" >>$@ + echo "/README*" >>$@ ++ echo "/type=docker/" >>$@ ++ if [ -d ./.aws-lc-local ]; then \ ++ echo "!/.aws-lc-local" >>$@; \ ++ echo "!/.aws-lc-local/**" >>$@; \ ++ fi + + .PHONY: docker-image-builder +-docker-image-builder: Dockerfile.builder SOURCE_VERSION Dockerfile.builder.dockerignore +- $(DOCKER) build $(DOCKER_BUILD_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" --build-arg BUILDER_BASE="$(BUILDER_BASE)" -f $< -t $(DOCKER_DEV_ACCOUNT)/cilium-envoy-builder:$(BUILDER_BASE_TAG) . ++docker-image-builder: verify-image-safety Dockerfile.builder SOURCE_VERSION Dockerfile.builder.dockerignore ++ $(DOCKER) build $(DOCKER_BUILD_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" --build-arg BAZEL_VERSION="$(BAZEL_VERSION)" --build-arg BUILDER_BASE="$(BUILDER_BASE)" -f Dockerfile.builder -t $(DOCKER_DEV_ACCOUNT)/cilium-envoy-builder:$(BUILDER_BASE_TAG) . + + .PHONY: docker-builder-archive +-docker-builder-archive: Dockerfile SOURCE_VERSION Dockerfile.dockerignore ++docker-builder-archive: verify-image-safety prepare-aws-lc-local Dockerfile SOURCE_VERSION Dockerfile.dockerignore + $(DOCKER) build --target builder-archive $(DOCKER_BUILD_OPTS) $(DOCKER_CACHE_OPTS) $(BUILD_IMAGE_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" --build-arg COPY_CACHE_EXT=.new -t $(DOCKER_DEV_ACCOUNT)/cilium-envoy-builder:$(BUILDER_ARCHIVE_TAG) . + + .PHONY: docker-tests-archive +-docker-tests-archive: Dockerfile.tests SOURCE_VERSION Dockerfile.tests.dockerignore +- $(DOCKER) build --target builder-archive $(DOCKER_BUILD_OPTS) $(DOCKER_CACHE_OPTS) $(TESTS_IMAGE_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" --build-arg COPY_CACHE_EXT=.new -f $< -t $(DOCKER_DEV_ACCOUNT)/cilium-envoy-builder:$(TESTS_ARCHIVE_TAG) . ++docker-tests-archive: verify-image-safety prepare-aws-lc-local Dockerfile.tests SOURCE_VERSION Dockerfile.tests.dockerignore ++ $(DOCKER) build --target builder-archive $(DOCKER_BUILD_OPTS) $(DOCKER_CACHE_OPTS) $(TESTS_IMAGE_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" --build-arg CARGO_BAZEL_REPIN="$(CARGO_BAZEL_REPIN)" --build-arg TEST_TARGETS="$(TEST_TARGETS)" --build-arg COPY_CACHE_EXT=.new -f Dockerfile.tests -t $(DOCKER_DEV_ACCOUNT)/cilium-envoy-builder:$(TESTS_ARCHIVE_TAG) . + + ifeq ($(BRANCH_TAG),main) + DOCKER_TESTS_TAGS += -t $(DOCKER_DEV_ACCOUNT)/cilium-envoy:latest$(IMAGE_ARCH)$(DEBUG_TAG)-testlogs +@@ -195,8 +312,8 @@ else + endif + + .PHONY: docker-tests +-docker-tests: Dockerfile.tests SOURCE_VERSION Dockerfile.tests.dockerignore +- $(DOCKER) build --progress=plain $(subst --push,--load,$(DOCKER_BUILD_OPTS)) $(DOCKER_CACHE_OPTS) $(TESTS_IMAGE_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" --build-arg BAZEL_TEST_OPTS="$(BAZEL_TEST_OPTS)" -f $< $(DOCKER_TESTS_TAGS) . ++docker-tests: verify-image-safety prepare-aws-lc-local Dockerfile.tests SOURCE_VERSION Dockerfile.tests.dockerignore ++ $(DOCKER) build --progress=plain $(subst --push,--load,$(DOCKER_BUILD_OPTS)) $(DOCKER_CACHE_OPTS) $(TESTS_IMAGE_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" --build-arg BAZEL_TEST_OPTS="$(BAZEL_TEST_OPTS)" --build-arg CARGO_BAZEL_REPIN="$(CARGO_BAZEL_REPIN)" --build-arg TEST_TARGETS="$(TEST_TARGETS)" -f Dockerfile.tests $(DOCKER_TESTS_TAGS) . + + ifeq ($(BRANCH_TAG),main) + DOCKER_IMAGE_ENVOY_TAGS := -t $(DOCKER_DEV_ACCOUNT)/cilium-envoy:$(SOURCE_VERSION)$(IMAGE_ARCH)$(DEBUG_TAG) +@@ -207,6 +324,6 @@ else + endif + + .PHONY: docker-image-envoy +-docker-image-envoy: Dockerfile SOURCE_VERSION Dockerfile.dockerignore ++docker-image-envoy: verify-image-safety prepare-aws-lc-local Dockerfile SOURCE_VERSION Dockerfile.dockerignore + @$(ECHO_GEN) docker-image-envoy + $(DOCKER) build $(DOCKER_BUILD_OPTS) $(DOCKER_CACHE_OPTS) $(BUILD_IMAGE_OPTS) --build-arg BAZEL_BUILD_OPTS="$(EXTRA_BAZEL_BUILD_OPTS)" $(DOCKER_IMAGE_ENVOY_TAGS) . +diff --git a/WORKSPACE b/WORKSPACE +index f1aefb47..efe1009f 100644 +--- a/WORKSPACE ++++ b/WORKSPACE +@@ -44,6 +44,17 @@ git_repository( + "@//patches:0005-http-header-expose-attribute.patch", + "@//patches:0006-build-Fix-arm-build-for-liburing.patch", + "@//patches:0007-Add-latomic-back-for-arm-build.patch", ++ "@//patches:0008-bazel-Wire-boringssl-s390x-target-patch.patch", ++ "@//patches:0009-bazel-absl-clang-s390x-int128-fallback.patch", ++ "@//patches:0010-bazel-quiche-s390x-big-endian-send-buffer-fallback.patch", ++ "@//patches:0011-bazel-aws-lc-s390x-local-toolchain-nonfips.patch", ++ "@//patches:0012-bazel-route-s390x-fips-to-aws-lc.patch", ++ "@//patches:0013-bazel-envoy-guard-fips-compliance-policy-for-nonfips.patch", ++ "@//patches:0014-bazel-aws-lc-s390x-enable-fips-and-pin-local-commit.patch", ++ "@//patches:0015-bazel-quiche-awslc-server-credential-compat.patch", ++ "@//patches:0016-bazel-quiche-awslc-client-handshaker-compat.patch", ++ "@//patches:0017-bazel-quiche-awslc-server-handshaker-groups-compat.patch", ++ "@//patches:0018-bazel-quiche-s390x-big-endian-endian-fix.patch", + ], + # // clang-format off: Envoy's format check: Only repository_locations.bzl may contains URL references + remote = "https://github.com/envoyproxy/envoy.git", +diff --git a/bazel/BUILD b/bazel/BUILD +index 0a693023..f0783f48 100644 +--- a/bazel/BUILD ++++ b/bazel/BUILD +@@ -13,3 +13,11 @@ platform( + "@platforms//os:linux", + ], + ) ++ ++platform( ++ name = "linux_s390x", ++ constraint_values = [ ++ "@platforms//cpu:s390x", ++ "@platforms//os:linux", ++ ], ++) +diff --git a/bazel/toolchains/BUILD b/bazel/toolchains/BUILD +index 4a9e68bb..8031a07f 100644 +--- a/bazel/toolchains/BUILD ++++ b/bazel/toolchains/BUILD +@@ -202,11 +202,113 @@ cc_toolchain_config( + # builtin_sysroot = "/sysroot", + ) + ++toolchain( ++ name = "s390x_linux_cc_toolchain", ++ exec_compatible_with = ["@platforms//os:linux"], ++ target_compatible_with = [ ++ "@platforms//cpu:s390x", ++ "@platforms//os:linux", ++ ], ++ toolchain = ":clang_s390x_linux_cc_toolchain", ++ toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ++) ++ ++cc_toolchain( ++ name = "clang_s390x_linux_cc_toolchain", ++ all_files = ":empty", ++ compiler_files = ":empty", ++ dwp_files = ":empty", ++ linker_files = ":empty", ++ objcopy_files = ":empty", ++ strip_files = ":empty", ++ toolchain_config = ":clang_s390x_linux_toolchain_config", ++) ++ ++cc_toolchain_config( ++ name = "clang_s390x_linux_toolchain_config", ++ abi_libc_version = "s390x", ++ abi_version = "s390x", ++ compile_flags = [ ++ "--target=s390x-unknown-linux-gnu", ++ "-fuse-ld=lld-18", # cmake compiler test needs this ++ "-DTOOLCHAIN_MISS_ASM_HWCAP_H", # highway: asm/hwcap.h may be unavailable in cross libc headers ++ "-DNVALGRIND", # glib in rules_foreign_cc pulls valgrind macros with unsupported s390x clang asm ++ "-U_FORTIFY_SOURCE", ++ "-fstack-protector", ++ "-Wall", ++ "-Wunused-but-set-parameter", ++ "-Wthread-safety-analysis", ++ "-Wno-free-nonheap-object", ++ "-fno-omit-frame-pointer", ++ # Needed by Envoy dependencies to build: ++ "-Wno-unused-command-line-argument", # tcmalloc needs this since -fuse-ld was added above ++ "-Wno-deprecated-builtins", ++ ], ++ compiler = "clang", ++ coverage_compile_flags = ["--coverage"], ++ coverage_link_flags = ["--coverage"], ++ cpu = "s390x", ++ cxx_builtin_include_directories = [ ++ "/usr/lib/llvm-18", ++ "/usr/s390x-linux-gnu/include", ++ "/usr/include", ++ ], ++ cxx_flags = ["-std=c++0x"], ++ dbg_compile_flags = ["-g"], ++ host_system_name = "local", ++ link_flags = [ ++ "--target=s390x-unknown-linux-gnu", ++ "-fuse-ld=lld-18", ++ "-Wl,-no-as-needed", ++ "-Wl,-z,relro,-z,now", ++ "-lm", ++ ], ++ link_libs = ["-l:libstdc++.a"], ++ opt_compile_flags = [ ++ "-g0", ++ "-O2", ++ "-D_FORTIFY_SOURCE=1", ++ "-DNDEBUG", ++ "-ffunction-sections", ++ "-fdata-sections", ++ ], ++ opt_link_flags = ["-Wl,--gc-sections"], ++ supports_start_end_lib = True, ++ target_libc = "glibc", ++ target_system_name = "s390x-linux-gnu", ++ tool_paths = { ++ "ar": "/usr/bin/llvm-ar-18", ++ "compat-ld": "/usr/bin/lld-18", ++ "ld": "/usr/bin/lld-18", ++ "gold": "/usr/bin/lld-18", ++ "cpp": "/usr/bin/clang-cpp-18", ++ "gcc": "/usr/bin/clang-18", ++ "dwp": "/usr/bin/llvm-dwp-18", ++ "gcov": "/usr/bin/llvmcov-18", ++ "nm": "/usr/bin/llvm-nm-18", ++ "objcopy": "/usr/bin/llvm-objcopy-18", ++ "objdump": "/usr/bin/llvm-objdump-18", ++ "strip": "/usr/bin/llvm-strip-18", ++ }, ++ toolchain_identifier = "linux_s390x", ++ unfiltered_compile_flags = [ ++ "-Wno-builtin-macro-redefined", ++ "-D__DATE__=\"redacted\"", ++ "-D__TIMESTAMP__=\"redacted\"", ++ "-D__TIME__=\"redacted\"", ++ ], ++ # ++ # cxx_builtin_include_directories entries need "%sysroot%" prefix if sysroot is set ++ # ++ # builtin_sysroot = "/sysroot", ++) ++ + # still needed to avoid use of local_config_cc toolchain + cc_toolchain_suite( + name = "toolchain", + toolchains = { + "k8": ":clang_x86_64_linux_cc_toolchain", + "aarch64": ":clang_aarch64_linux_cc_toolchain", ++ "s390x": ":clang_s390x_linux_cc_toolchain", + }, + ) +diff --git a/patches/0008-bazel-Wire-boringssl-s390x-target-patch.patch b/patches/0008-bazel-Wire-boringssl-s390x-target-patch.patch +new file mode 100644 +index 00000000..ee5e7cce +--- /dev/null ++++ b/patches/0008-bazel-Wire-boringssl-s390x-target-patch.patch +@@ -0,0 +1,36 @@ ++diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl ++--- a/bazel/repositories.bzl +++++ b/bazel/repositories.bzl ++@@ -260,7 +260,11 @@ def envoy_dependencies(skip_targets = []): ++ ) ++ ++ def _boringssl(): ++- external_http_archive(name = "boringssl") +++ external_http_archive( +++ name = "boringssl", +++ patch_args = ["-p1"], +++ patches = ["@envoy//bazel:boringssl_s390x.patch"], +++ ) ++ ++ def _boringssl_fips(): ++ external_http_archive( ++diff --git a/bazel/boringssl_s390x.patch b/bazel/boringssl_s390x.patch ++new file mode 100644 ++--- /dev/null +++++ b/bazel/boringssl_s390x.patch ++@@ -0,0 +1,15 @@ +++diff --git a/include/openssl/target.h b/include/openssl/target.h +++--- a/include/openssl/target.h ++++++ b/include/openssl/target.h +++@@ -53,6 +53,11 @@ +++ #define OPENSSL_32_BIT +++ #elif defined(__myriad2__) +++ #define OPENSSL_32_BIT ++++#elif defined(__s390x__) && defined(__linux__) ++++// Local downstream extension for zLinux/s390x builds. ++++#define OPENSSL_64_BIT ++++#define OPENSSL_ASM_INCOMPATIBLE ++++#define OPENSSL_BIG_ENDIAN +++ #else +++ // The list above enumerates the platforms that BoringSSL supports. For these +++ // platforms we keep a reasonable bar of not breaking them: automated test +diff --git a/patches/0009-bazel-absl-clang-s390x-int128-fallback.patch b/patches/0009-bazel-absl-clang-s390x-int128-fallback.patch +new file mode 100644 +index 00000000..d3c2a73e +--- /dev/null ++++ b/patches/0009-bazel-absl-clang-s390x-int128-fallback.patch +@@ -0,0 +1,32 @@ ++diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl ++--- a/bazel/repositories.bzl +++++ b/bazel/repositories.bzl ++@@ -636,6 +636,9 @@ def _com_google_absl(): ++ external_http_archive( ++ name = "com_google_absl", ++- patches = ["@envoy//bazel:abseil.patch"], +++ patches = [ +++ "@envoy//bazel:abseil.patch", +++ "@envoy//bazel:abseil_s390x_clang.patch", +++ ], ++ patch_args = ["-p1"], ++ repo_mapping = {"@googletest": "@com_google_googletest"}, ++ ) ++diff --git a/bazel/abseil_s390x_clang.patch b/bazel/abseil_s390x_clang.patch ++new file mode 100644 ++--- /dev/null +++++ b/bazel/abseil_s390x_clang.patch ++@@ -0,0 +1,13 @@ +++diff --git a/absl/base/config.h b/absl/base/config.h +++--- a/absl/base/config.h ++++++ b/absl/base/config.h +++@@ -303,7 +303,7 @@ +++ #ifdef ABSL_HAVE_INTRINSIC_INT128 +++ #error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set +++ #elif defined(__SIZEOF_INT128__) +++-#if (defined(__clang__) && !defined(_WIN32)) || \ ++++#if (defined(__clang__) && !defined(_WIN32) && !defined(__s390x__)) || \ +++ (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \ +++ (defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__)) +++ #define ABSL_HAVE_INTRINSIC_INT128 1 +++ #elif defined(__CUDACC__) +diff --git a/patches/0010-bazel-quiche-s390x-big-endian-send-buffer-fallback.patch b/patches/0010-bazel-quiche-s390x-big-endian-send-buffer-fallback.patch +new file mode 100644 +index 00000000..b9b27b47 +--- /dev/null ++++ b/patches/0010-bazel-quiche-s390x-big-endian-send-buffer-fallback.patch +@@ -0,0 +1,62 @@ ++diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl ++--- a/bazel/repositories.bzl +++++ b/bazel/repositories.bzl ++@@ -799,9 +799,11 @@ def _intel_ittapi(): ++ ++ def _com_github_google_quiche(): ++ external_http_archive( ++ name = "com_github_google_quiche", +++ patch_args = ["-p1"], +++ patches = ["@envoy//bazel:quiche_s390x_big_endian.patch"], ++ patch_cmds = ["find quiche/ -type f -name \"*.bazel\" -delete"], ++ build_file = "@envoy//bazel/external:quiche.BUILD", ++ ) ++ ++ def _googleurl(): ++diff --git a/bazel/quiche_s390x_big_endian.patch b/bazel/quiche_s390x_big_endian.patch ++new file mode 100644 ++--- /dev/null +++++ b/bazel/quiche_s390x_big_endian.patch ++@@ -0,0 +1,42 @@ +++diff --git a/quiche/quic/core/quic_inlined_string_view.h b/quiche/quic/core/quic_inlined_string_view.h +++--- a/quiche/quic/core/quic_inlined_string_view.h ++++++ b/quiche/quic/core/quic_inlined_string_view.h +++@@ -113,7 +113,9 @@ class QUICHE_NO_EXPORT QuicInlinedStringView { +++ size_t size; +++ }; +++ static_assert(sizeof(ViewRep) <= kSize); ++++#if !defined(__BYTE_ORDER__) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +++ static_assert(absl::endian::native == absl::endian::little); ++++#endif +++ +++ // Accessors for ViewRep; necessary to work around C++ strict aliasing +++ // limitations. Clang will turn this into direct field access at `-O1`. +++diff --git a/quiche/quic/core/quic_stream.cc b/quiche/quic/core/quic_stream.cc +++--- a/quiche/quic/core/quic_stream.cc ++++++ b/quiche/quic/core/quic_stream.cc +++@@ -133,10 +133,23 @@ std::unique_ptr CreateSendBuffer( +++ QuicSession* session) { +++ quiche::QuicheBufferAllocator* allocator = +++ session->connection()->helper()->GetStreamSendBufferAllocator(); +++- if (GetQuicReloadableFlag(quic_use_inlining_send_buffer2)) { ++++ const bool use_inlining_send_buffer = ++++ GetQuicReloadableFlag(quic_use_inlining_send_buffer2); ++++ ++++#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) ++++ // QuicInlinedStringView currently assumes little-endian layout for the ++++ // compact inlined representation; use the non-inlining implementation on ++++ // big-endian platforms (for example s390x) to preserve correctness. ++++ if (use_inlining_send_buffer) { ++++ QUIC_RELOADABLE_FLAG_COUNT(quic_use_inlining_send_buffer2); ++++ } ++++ return std::make_unique(allocator); ++++#else ++++ if (use_inlining_send_buffer) { +++ QUIC_RELOADABLE_FLAG_COUNT(quic_use_inlining_send_buffer2); +++ return std::make_unique(allocator); +++ } +++ return std::make_unique(allocator); ++++#endif +++ } +++ +++} // namespace +diff --git a/patches/0011-bazel-aws-lc-s390x-local-toolchain-nonfips.patch b/patches/0011-bazel-aws-lc-s390x-local-toolchain-nonfips.patch +new file mode 100644 +index 00000000..e2dfcdc4 +--- /dev/null ++++ b/patches/0011-bazel-aws-lc-s390x-local-toolchain-nonfips.patch +@@ -0,0 +1,303 @@ ++diff --git a/bazel/external/aws_lc.genrule_cmd b/bazel/external/aws_lc.genrule_cmd ++index 82139095e5..7ea24b8e83 100755 ++--- a/bazel/external/aws_lc.genrule_cmd +++++ b/bazel/external/aws_lc.genrule_cmd ++@@ -10,13 +10,37 @@ export LDFLAGS='' ++ ++ OS=`uname` ++ ARCH=`uname -m` ++-# This works only on Linux-x86_64, Linux-ppc64le, and Linux-aarch64. +++# This script supports: +++# - FIPS mode on Linux-x86_64, Linux-ppc64le, and Linux-aarch64. +++# - non-FIPS mode on Linux-s390x (uses local toolchains; FIPS delocate currently unsupported). ++ ++-if [[ "$OS" != "Linux" || ("$ARCH" != "x86_64" && "$ARCH" != "aarch64" && "$ARCH" != "ppc64le") ]]; then ++- echo "ERROR: AWS-LC FIPS is currently supported only on Linux-x86_64, Linux-ppc64le, and Linux-aarch64." +++if [[ "$OS" != "Linux" || ("$ARCH" != "x86_64" && "$ARCH" != "aarch64" && "$ARCH" != "ppc64le" && "$ARCH" != "s390x") ]]; then +++ echo "ERROR: AWS-LC build is supported only on Linux-x86_64, Linux-ppc64le, Linux-aarch64, and Linux-s390x." ++ exit 1 ++ fi ++ +++AWS_LC_FIPS_MODE="${AWS_LC_S390X_FIPS_EXPERIMENTAL:-${AWS_LC_FIPS:-auto}}" +++AWS_LC_FIPS=1 +++USE_LOCAL_TOOLCHAIN=0 +++AWS_LC_C_FLAGS="-fPIC" +++AWS_LC_CXX_FLAGS="-fPIC" +++if [[ "$ARCH" == "s390x" ]]; then +++ if [[ "${AWS_LC_FIPS_MODE}" == "1" ]]; then +++ echo "ERROR: AWS-LC FIPS is not yet supported on Linux-s390x." +++ echo "ERROR: util/fipstools/delocate fails while generating bcm-delocated.S." +++ echo "ERROR: use AWS_LC_FIPS=0 (or leave unset) on s390x until delocate support lands." +++ exit 1 +++ fi +++ # s390x currently uses non-FIPS AWS-LC with local clang/go/cmake/ninja. +++ AWS_LC_FIPS=0 +++ USE_LOCAL_TOOLCHAIN=1 +++ # aws_lc's jitterentropy sources intentionally use unaligned loads that +++ # trigger -Wcast-align under clang on s390x; keep this local to s390x. +++ AWS_LC_C_FLAGS="${AWS_LC_C_FLAGS} -Wno-error=cast-align -Wno-cast-align" +++elif [[ "${AWS_LC_FIPS_MODE}" == "0" ]]; then +++ AWS_LC_FIPS=0 +++fi +++ ++ ++ # Bazel magic. ++ # ROOT=$(dirname $(rootpath boringssl/BUILDING.md))/.. ++@@ -33,109 +57,143 @@ pushd "$ROOT" ++ export PATH="$(dirname `which cmake`):/usr/bin:/bin" ++ ++ # Clang ++-VERSION=14.0.0 ++-if [[ "$ARCH" == "x86_64" ]]; then ++- PLATFORM="x86_64-linux-gnu-ubuntu-20.04" ++- SHA256=61582215dafafb7b576ea30cc136be92c877ba1f1c31ddbbd372d6d65622fef5 ++-elif [[ "$ARCH" == "ppc64le" ]]; then ++- PLATFORM="powerpc64le-linux-ubuntu-18.04" ++- SHA256=2d504c4920885c86b306358846178bc2232dfac83b47c3b1d05861a8162980e6 ++-else ++- PLATFORM="aarch64-linux-gnu" ++- SHA256=1792badcd44066c79148ffeb1746058422cc9d838462be07e3cb19a4b724a1ee ++-fi ++- ++-curl -sLO https://github.com/llvm/llvm-project/releases/download/llvmorg-"$VERSION"/clang+llvm-"$VERSION"-"$PLATFORM".tar.xz ++-tar xf clang+llvm-"$VERSION"-"$PLATFORM".tar.xz ++- ++ export HOME="$PWD" ++ printf "set(CMAKE_C_COMPILER \"clang\")\nset(CMAKE_CXX_COMPILER \"clang++\")\n" > ${HOME}/toolchain ++-export PATH="$PWD/clang+llvm-$VERSION-$PLATFORM/bin:$PATH" +++if [[ "$USE_LOCAL_TOOLCHAIN" == "1" ]]; then +++ export PATH="/usr/lib/llvm-18/bin:$PATH" +++ if ! command -v clang >/dev/null 2>&1; then +++ echo "ERROR: clang is required for local s390x AWS-LC build." +++ exit 1 +++ fi +++ echo "Using local clang: $(clang --version | head -1)" +++else +++ VERSION=14.0.0 +++ if [[ "$ARCH" == "x86_64" ]]; then +++ PLATFORM="x86_64-linux-gnu-ubuntu-20.04" +++ SHA256=61582215dafafb7b576ea30cc136be92c877ba1f1c31ddbbd372d6d65622fef5 +++ elif [[ "$ARCH" == "ppc64le" ]]; then +++ PLATFORM="powerpc64le-linux-ubuntu-18.04" +++ SHA256=2d504c4920885c86b306358846178bc2232dfac83b47c3b1d05861a8162980e6 +++ else +++ PLATFORM="aarch64-linux-gnu" +++ SHA256=1792badcd44066c79148ffeb1746058422cc9d838462be07e3cb19a4b724a1ee +++ fi ++ ++-if [[ `clang --version | head -1 | awk '{print $3}'` != "$VERSION" ]]; then ++- echo "ERROR: Clang version doesn't match. Expected: ${VERSION}, Got: $(clang --version)" ++- exit 1 +++ curl -sLO https://github.com/llvm/llvm-project/releases/download/llvmorg-"$VERSION"/clang+llvm-"$VERSION"-"$PLATFORM".tar.xz +++ tar xf clang+llvm-"$VERSION"-"$PLATFORM".tar.xz +++ export PATH="$PWD/clang+llvm-$VERSION-$PLATFORM/bin:$PATH" +++ +++ if [[ `clang --version | head -1 | awk '{print $3}'` != "$VERSION" ]]; then +++ echo "ERROR: Clang version doesn't match. Expected: ${VERSION}, Got: $(clang --version)" +++ exit 1 +++ fi ++ fi ++ ++ # Go ++-VERSION=1.18.1 ++-if [[ "$ARCH" == "x86_64" ]]; then ++- PLATFORM="linux-amd64" ++- SHA256=b3b815f47ababac13810fc6021eb73d65478e0b2db4b09d348eefad9581a2334 ++-elif [[ "$ARCH" == "ppc64le" ]]; then ++- PLATFORM="linux-ppc64le" ++- SHA256=33db623d1eecf362fe365107c12efc90eff0b9609e0b3345e258388019cb552a +++if [[ "$USE_LOCAL_TOOLCHAIN" == "1" ]]; then +++ export PATH="/usr/local/go/bin:$PATH" +++ if ! command -v go >/dev/null 2>&1; then +++ echo "ERROR: go is required for local s390x AWS-LC build." +++ exit 1 +++ fi +++ echo "Using local go: $(go version)" ++ else ++- PLATFORM="linux-arm64" ++- SHA256=56a91851c97fb4697077abbca38860f735c32b38993ff79b088dac46e4735633 ++-fi +++ VERSION=1.18.1 +++ if [[ "$ARCH" == "x86_64" ]]; then +++ PLATFORM="linux-amd64" +++ SHA256=b3b815f47ababac13810fc6021eb73d65478e0b2db4b09d348eefad9581a2334 +++ elif [[ "$ARCH" == "ppc64le" ]]; then +++ PLATFORM="linux-ppc64le" +++ SHA256=33db623d1eecf362fe365107c12efc90eff0b9609e0b3345e258388019cb552a +++ else +++ PLATFORM="linux-arm64" +++ SHA256=56a91851c97fb4697077abbca38860f735c32b38993ff79b088dac46e4735633 +++ fi ++ ++-curl -sLO https://dl.google.com/go/go"$VERSION"."$PLATFORM".tar.gz \ ++- && echo "$SHA256" go"$VERSION"."$PLATFORM".tar.gz | sha256sum --check ++-tar xf go"$VERSION"."$PLATFORM".tar.gz +++ curl -sLO https://dl.google.com/go/go"$VERSION"."$PLATFORM".tar.gz \ +++ && echo "$SHA256" go"$VERSION"."$PLATFORM".tar.gz | sha256sum --check +++ tar xf go"$VERSION"."$PLATFORM".tar.gz ++ ++-export GOPATH="$PWD/gopath" ++-export GOROOT="$PWD/go" ++-export PATH="$GOPATH/bin:$GOROOT/bin:$PATH" +++ export GOPATH="$PWD/gopath" +++ export GOROOT="$PWD/go" +++ export PATH="$GOPATH/bin:$GOROOT/bin:$PATH" ++ ++-if [[ `go version | awk '{print $3}'` != "go$VERSION" ]]; then ++- echo "ERROR: Go version doesn't match." ++- exit 1 +++ if [[ `go version | awk '{print $3}'` != "go$VERSION" ]]; then +++ echo "ERROR: Go version doesn't match." +++ exit 1 +++ fi ++ fi ++ ++ # Ninja ++-VERSION=1.10.2 ++-SHA256=ce35865411f0490368a8fc383f29071de6690cbadc27704734978221f25e2bed ++-curl -sLO https://github.com/ninja-build/ninja/archive/refs/tags/v"$VERSION".tar.gz \ ++- && echo "$SHA256" v"$VERSION".tar.gz | sha256sum --check ++-tar -xvf v"$VERSION".tar.gz ++-cd ninja-"$VERSION" ++-python3 ./configure.py --bootstrap ++- ++-export PATH="$PWD:$PATH" ++- ++-if [[ `ninja --version` != "$VERSION" ]]; then ++- echo "ERROR: Ninja version doesn't match." ++- exit 1 +++if [[ "$USE_LOCAL_TOOLCHAIN" == "1" ]]; then +++ if ! command -v ninja >/dev/null 2>&1; then +++ echo "ERROR: ninja is required for local s390x AWS-LC build." +++ exit 1 +++ fi +++ echo "Using local ninja: $(ninja --version)" +++else +++ VERSION=1.10.2 +++ SHA256=ce35865411f0490368a8fc383f29071de6690cbadc27704734978221f25e2bed +++ curl -sLO https://github.com/ninja-build/ninja/archive/refs/tags/v"$VERSION".tar.gz \ +++ && echo "$SHA256" v"$VERSION".tar.gz | sha256sum --check +++ tar -xvf v"$VERSION".tar.gz +++ cd ninja-"$VERSION" +++ python3 ./configure.py --bootstrap +++ +++ export PATH="$PWD:$PATH" +++ +++ if [[ `ninja --version` != "$VERSION" ]]; then +++ echo "ERROR: Ninja version doesn't match." +++ exit 1 +++ fi +++ cd .. ++ fi ++-cd .. ++ ++ # CMake ++-VERSION=3.22.1 ++-if [[ "$ARCH" != "ppc64le" ]]; then ++- if [[ "$ARCH" == "x86_64" ]]; then ++- PLATFORM="linux-x86_64" ++- SHA256=73565c72355c6652e9db149249af36bcab44d9d478c5546fd926e69ad6b43640 ++- else ++- PLATFORM="linux-aarch64" ++- SHA256=601443375aa1a48a1a076bda7e3cca73af88400463e166fffc3e1da3ce03540b +++if [[ "$USE_LOCAL_TOOLCHAIN" == "1" ]]; then +++ if ! command -v cmake >/dev/null 2>&1; then +++ echo "ERROR: cmake is required for local s390x AWS-LC build." +++ exit 1 ++ fi ++- ++- curl -sLO https://github.com/Kitware/CMake/releases/download/v"$VERSION"/cmake-"$VERSION"-"$PLATFORM".tar.gz \ ++- && echo "$SHA256" cmake-"$VERSION"-"$PLATFORM".tar.gz | sha256sum --check ++- tar xf cmake-"$VERSION"-"$PLATFORM".tar.gz ++- export PATH="$PWD/cmake-$VERSION-$PLATFORM/bin:$PATH" +++ echo "Using local cmake: $(cmake --version | head -n1)" ++ else ++- PLATFORM="linux-ppc64le" ++- echo "Building cmake for ppc64le" +++ VERSION=3.22.1 +++ if [[ "$ARCH" != "ppc64le" ]]; then +++ if [[ "$ARCH" == "x86_64" ]]; then +++ PLATFORM="linux-x86_64" +++ SHA256=73565c72355c6652e9db149249af36bcab44d9d478c5546fd926e69ad6b43640 +++ else +++ PLATFORM="linux-aarch64" +++ SHA256=601443375aa1a48a1a076bda7e3cca73af88400463e166fffc3e1da3ce03540b +++ fi +++ +++ curl -sLO https://github.com/Kitware/CMake/releases/download/v"$VERSION"/cmake-"$VERSION"-"$PLATFORM".tar.gz \ +++ && echo "$SHA256" cmake-"$VERSION"-"$PLATFORM".tar.gz | sha256sum --check +++ tar xf cmake-"$VERSION"-"$PLATFORM".tar.gz +++ export PATH="$PWD/cmake-$VERSION-$PLATFORM/bin:$PATH" +++ else +++ PLATFORM="linux-ppc64le" +++ echo "Building cmake for ppc64le" ++ ++- curl -sL -o cmake-$VERSION-$PLATFORM.tar.gz https://github.com/Kitware/CMake/releases/download/v"$VERSION"/cmake-"$VERSION".tar.gz ++- tar xf cmake-"$VERSION"-"$PLATFORM".tar.gz +++ curl -sL -o cmake-$VERSION-$PLATFORM.tar.gz https://github.com/Kitware/CMake/releases/download/v"$VERSION"/cmake-"$VERSION".tar.gz +++ tar xf cmake-"$VERSION"-"$PLATFORM".tar.gz ++ ++- cd cmake-"$VERSION" ++- ./bootstrap && make ++- export PATH="$PWD/bin:$PATH" ++- cd .. ++-fi +++ cd cmake-"$VERSION" +++ ./bootstrap && make +++ export PATH="$PWD/bin:$PATH" +++ cd .. +++ fi ++ ++-if [[ `cmake --version | head -n1` != "cmake version $VERSION" ]]; then ++- echo "PATH: $PATH" ++- echo "PLATFORM: $PLATFORM" ++- echo "ERROR: CMake version doesn't match. Expected: ${VERSION}, Got: $(cmake --version | head -n1)" ++- exit 1 +++ if [[ `cmake --version | head -n1` != "cmake version $VERSION" ]]; then +++ echo "PATH: $PATH" +++ echo "PLATFORM: $PLATFORM" +++ echo "ERROR: CMake version doesn't match. Expected: ${VERSION}, Got: $(cmake --version | head -n1)" +++ exit 1 +++ fi +++ +++ echo "Cmake installed successfully" ++ fi ++ ++-echo "Cmake installed successfully" ++ echo "PWD: $PWD" ++ ++ # Clean after previous build. ++@@ -144,9 +193,9 @@ rm -rf aws_lc/build ++ # Build BoringSSL. ++ cd aws_lc ++ ++-# Setting -fPIC only affects the compilation of the non-module code in libcrypto.a, ++-# because the FIPS module itself is already built with -fPIC. ++-mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-fPIC" -DCMAKE_CXX_FLAGS="-fPIC" .. +++# Setting -fPIC only affects the compilation of the non-module code in +++# libcrypto.a, because the FIPS module itself is already built with -fPIC. +++mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=${AWS_LC_FIPS} -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="${AWS_LC_C_FLAGS}" -DCMAKE_CXX_FLAGS="${AWS_LC_CXX_FLAGS}" .. ++ ninja ++ export GTEST_FILTER="-SSLTest.HostMatching" ++ #ninja run_tests ++@@ -153,11 +202,15 @@ export GTEST_FILTER="-SSLTest.HostMatching" ++-./crypto/crypto_test +++if [[ -x ./crypto/crypto_test ]]; then ./crypto/crypto_test; fi ++ ++ echo "created build directory and built aws_lc with ninja" ++ ++-# Verify correctness of the FIPS build. ++-if [[ `tool/bssl isfips` != "1" ]]; then ++- echo "ERROR: BoringSSL tool didn't report FIPS build." ++- exit 1 +++# Verify correctness of the FIPS build when FIPS mode is enabled. +++if [[ "${AWS_LC_FIPS}" == "1" ]]; then +++ if [[ `tool/bssl isfips` != "1" ]]; then +++ echo "ERROR: BoringSSL tool didn't report FIPS build." +++ exit 1 +++ fi +++else +++ echo "Skipping FIPS validation for non-FIPS s390x AWS-LC build." ++ fi ++ ++ # Move compiled libraries to the expected destinations. +diff --git a/patches/0012-bazel-route-s390x-fips-to-aws-lc.patch b/patches/0012-bazel-route-s390x-fips-to-aws-lc.patch +new file mode 100644 +index 00000000..053ef167 +--- /dev/null ++++ b/patches/0012-bazel-route-s390x-fips-to-aws-lc.patch +@@ -0,0 +1,51 @@ ++diff --git a/bazel/BUILD b/bazel/BUILD ++index 17b80cd744..934d115d57 100644 ++--- a/bazel/BUILD +++++ b/bazel/BUILD ++@@ -554,7 +554,8 @@ alias( ++ name = "boringssl", ++ actual = select({ ++ "//bazel:boringssl_fips_ppc": "@aws_lc//:ssl", ++- "//bazel:boringssl_fips_not_ppc": "@boringssl_fips//:ssl", +++ "//bazel:linux_s390x": "@aws_lc//:ssl", +++ "//bazel:boringssl_fips_not_ppc_not_s390x": "@boringssl_fips//:ssl", ++ "//conditions:default": "@boringssl//:ssl", ++ }), ++ ) ++@@ -563,7 +564,8 @@ alias( ++ name = "boringcrypto", ++ actual = select({ ++ "//bazel:boringssl_fips_ppc": "@aws_lc//:crypto", ++- "//bazel:boringssl_fips_not_ppc": "@boringssl_fips//:crypto", +++ "//bazel:linux_s390x": "@aws_lc//:crypto", +++ "//bazel:boringssl_fips_not_ppc_not_s390x": "@boringssl_fips//:crypto", ++ "//conditions:default": "@boringssl//:crypto", ++ }), ++ ) ++@@ -849,6 +851,26 @@ selects.config_setting_group( ++ ], ++ ) ++ +++selects.config_setting_group( +++ name = "linux_not_s390x", +++ match_any = [ +++ ":linux_x86_64", +++ ":linux_aarch64", +++ ":linux_ppc", +++ ":linux_ppc64le", +++ ":linux_mips64", +++ ], +++) +++ +++selects.config_setting_group( +++ name = "boringssl_fips_not_ppc_not_s390x", +++ match_all = [ +++ ":boringssl_fips", +++ ":not_ppc", +++ ":linux_not_s390x", +++ ], +++) +++ ++ selects.config_setting_group( ++ name = "not_x86", ++ match_any = [ +diff --git a/patches/0013-bazel-envoy-guard-fips-compliance-policy-for-nonfips.patch b/patches/0013-bazel-envoy-guard-fips-compliance-policy-for-nonfips.patch +new file mode 100644 +index 00000000..37bfc8ec +--- /dev/null ++++ b/patches/0013-bazel-envoy-guard-fips-compliance-policy-for-nonfips.patch +@@ -0,0 +1,24 @@ ++diff --git a/source/common/tls/context_impl.cc b/source/common/tls/context_impl.cc ++index e32186ddb4..95e74ff718 100644 ++--- a/source/common/tls/context_impl.cc +++++ b/source/common/tls/context_impl.cc ++@@ -370,6 +370,7 @@ ContextImpl::ContextImpl(Stats::Scope& scope, const Envoy::Ssl::ContextConfig& c ++ if (!fips_mode) { ++ ENVOY_LOG(warn, "FIPS conformance policy applied on a non-FIPS build"); ++ } +++#if defined(BORINGSSL_FIPS) ++ for (auto& tls_context : tls_contexts_) { ++ int rc = SSL_CTX_set_compliance_policy(tls_context.ssl_ctx_.get(), ++ ssl_compliance_policy_fips_202205); ++@@ -380,6 +381,11 @@ ContextImpl::ContextImpl(Stats::Scope& scope, const Envoy::Ssl::ContextConfig& c ++ return; ++ } ++ } +++#else +++ creation_status = absl::InvalidArgumentError( +++ "FIPS_202205 compliance policy requires a FIPS-enabled TLS build"); +++ return; +++#endif ++ break; ++ default: ++ creation_status = absl::InvalidArgumentError("Unknown compliance policy"); +diff --git a/patches/0014-bazel-aws-lc-s390x-enable-fips-and-pin-local-commit.patch b/patches/0014-bazel-aws-lc-s390x-enable-fips-and-pin-local-commit.patch +new file mode 100644 +index 00000000..117458db +--- /dev/null ++++ b/patches/0014-bazel-aws-lc-s390x-enable-fips-and-pin-local-commit.patch +@@ -0,0 +1,92 @@ ++diff --git a/bazel/external/aws_lc.genrule_cmd b/bazel/external/aws_lc.genrule_cmd ++index 95aaf54..bbc14bb 100644 ++--- a/bazel/external/aws_lc.genrule_cmd +++++ b/bazel/external/aws_lc.genrule_cmd ++@@ -12,7 +12,7 @@ OS=`uname` ++ ARCH=`uname -m` ++ # This script supports: ++ # - FIPS mode on Linux-x86_64, Linux-ppc64le, and Linux-aarch64. ++-# - non-FIPS mode on Linux-s390x (uses local toolchains; FIPS delocate currently unsupported). +++# - FIPS/non-FIPS mode on Linux-s390x (uses local toolchains). ++ ++ if [[ "$OS" != "Linux" || ("$ARCH" != "x86_64" && "$ARCH" != "aarch64" && "$ARCH" != "ppc64le" && "$ARCH" != "s390x") ]]; then ++ echo "ERROR: AWS-LC build is supported only on Linux-x86_64, Linux-ppc64le, Linux-aarch64, and Linux-s390x." ++@@ -24,19 +24,23 @@ AWS_LC_FIPS=1 ++ USE_LOCAL_TOOLCHAIN=0 ++ AWS_LC_C_FLAGS="-fPIC" ++ AWS_LC_CXX_FLAGS="-fPIC" +++AWS_LC_LOCAL_SRC="${AWS_LC_LOCAL_SRC:-}" +++AWS_LC_LOCAL_COMMIT="${AWS_LC_LOCAL_COMMIT:-}" ++ if [[ "$ARCH" == "s390x" ]]; then ++- if [[ "${AWS_LC_FIPS_MODE}" == "1" ]]; then ++- echo "ERROR: AWS-LC FIPS is not yet supported on Linux-s390x." ++- echo "ERROR: util/fipstools/delocate fails while generating bcm-delocated.S." ++- echo "ERROR: use AWS_LC_FIPS=0 (or leave unset) on s390x until delocate support lands." ++- exit 1 +++ if [[ "${AWS_LC_FIPS_MODE}" == "0" ]]; then +++ AWS_LC_FIPS=0 +++ else +++ AWS_LC_FIPS=1 ++ fi ++- # s390x currently uses non-FIPS AWS-LC with local clang/go/cmake/ninja. ++- AWS_LC_FIPS=0 +++ # s390x uses local clang/go/cmake/ninja. ++ USE_LOCAL_TOOLCHAIN=1 ++ # aws_lc's jitterentropy sources intentionally use unaligned loads that ++ # trigger -Wcast-align under clang on s390x; keep this local to s390x. ++ AWS_LC_C_FLAGS="${AWS_LC_C_FLAGS} -Wno-error=cast-align -Wno-cast-align" +++ # Pin to the validated local AWS-LC commit by default when caller provides a local source path. +++ if [[ -n "${AWS_LC_LOCAL_SRC}" && -z "${AWS_LC_LOCAL_COMMIT}" ]]; then +++ AWS_LC_LOCAL_COMMIT="921a62548" +++ fi ++ elif [[ "${AWS_LC_FIPS_MODE}" == "0" ]]; then ++ AWS_LC_FIPS=0 ++ fi ++@@ -196,15 +200,46 @@ fi ++ ++ echo "PWD: $PWD" ++ +++# Optional local override for s390x AWS-LC source pinning. +++if [[ "$ARCH" == "s390x" && -n "${AWS_LC_LOCAL_SRC}" ]]; then +++ if [[ -z "${AWS_LC_LOCAL_COMMIT}" ]]; then +++ echo "ERROR: AWS_LC_LOCAL_SRC is set but AWS_LC_LOCAL_COMMIT is empty." +++ exit 1 +++ fi +++ rm -rf aws_lc +++ if [[ -d "${AWS_LC_LOCAL_SRC}/.git" ]] && git -C "${AWS_LC_LOCAL_SRC}" rev-parse --verify "${AWS_LC_LOCAL_COMMIT}^{commit}" >/dev/null 2>&1; then +++ echo "Using local AWS-LC git source ${AWS_LC_LOCAL_SRC} at commit ${AWS_LC_LOCAL_COMMIT}" +++ git clone --quiet --no-checkout "file://${AWS_LC_LOCAL_SRC}" aws_lc +++ git -C aws_lc checkout --quiet --detach "${AWS_LC_LOCAL_COMMIT}" +++ else +++ if [[ -d "${AWS_LC_LOCAL_SRC}/.git" ]]; then +++ echo "WARNING: AWS_LC_LOCAL_COMMIT ${AWS_LC_LOCAL_COMMIT} not found in ${AWS_LC_LOCAL_SRC}; falling back to snapshot copy" +++ fi +++ echo "Using local AWS-LC snapshot source ${AWS_LC_LOCAL_SRC}" +++ mkdir -p aws_lc +++ cp -a "${AWS_LC_LOCAL_SRC}/." aws_lc/ +++ fi +++ if [[ ! -f aws_lc/CMakeLists.txt ]]; then +++ echo "ERROR: local AWS-LC source staging failed; missing aws_lc/CMakeLists.txt" +++ find aws_lc -maxdepth 2 -name CMakeLists.txt -print || true +++ exit 1 +++ fi +++fi +++ ++ # Clean after previous build. ++ rm -rf aws_lc/build +++echo "AWS-LC root after staging: $(cd aws_lc && pwd)" +++ls -la aws_lc | sed -n '1,40p' ++ ++ # Build BoringSSL. ++ cd aws_lc ++ ++ # Setting -fPIC only affects the compilation of the non-module code in ++ # libcrypto.a, because the FIPS module itself is already built with -fPIC. ++-mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=${AWS_LC_FIPS} -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="${AWS_LC_C_FLAGS}" -DCMAKE_CXX_FLAGS="${AWS_LC_CXX_FLAGS}" .. +++mkdir build && cd build +++echo "AWS-LC build directory before cmake: $PWD" +++ls -la .. | sed -n '1,40p' +++cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=${AWS_LC_FIPS} -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="${AWS_LC_C_FLAGS}" -DCMAKE_CXX_FLAGS="${AWS_LC_CXX_FLAGS}" .. ++ ninja ++ export GTEST_FILTER="-SSLTest.HostMatching" ++ #ninja run_tests +diff --git a/patches/0015-bazel-quiche-awslc-server-credential-compat.patch b/patches/0015-bazel-quiche-awslc-server-credential-compat.patch +new file mode 100644 +index 00000000..e4e6085d +--- /dev/null ++++ b/patches/0015-bazel-quiche-awslc-server-credential-compat.patch +@@ -0,0 +1,40 @@ ++diff --git a/bazel/quiche_s390x_big_endian.patch b/bazel/quiche_s390x_big_endian.patch ++index 27b5529..4ced9ce 100644 ++--- a/bazel/quiche_s390x_big_endian.patch +++++ b/bazel/quiche_s390x_big_endian.patch ++@@ -40,3 +40,35 @@ diff --git a/quiche/quic/core/quic_stream.cc b/quiche/quic/core/quic_stream.cc ++ } ++ ++ } // namespace +++diff --git a/quiche/quic/core/crypto/tls_server_connection.cc b/quiche/quic/core/crypto/tls_server_connection.cc +++--- a/quiche/quic/core/crypto/tls_server_connection.cc ++++++ b/quiche/quic/core/crypto/tls_server_connection.cc +++@@ -76,6 +76,20 @@ +++ void TlsServerConnection::SetCertChain( +++ const std::vector& cert_chain, +++ const std::string& trust_anchor_id) { ++++#ifdef OPENSSL_IS_AWSLC ++++ if (!trust_anchor_id.empty()) { ++++ QUICHE_LOG(WARNING) ++++ << "AWS-LC does not yet support trust-anchor IDs in QUIC server " ++++ "credentials"; ++++ } ++++ SSL_set_chain_and_key(ssl(), cert_chain.data(), cert_chain.size(), nullptr, ++++ &TlsServerConnection::kPrivateKeyMethod); ++++ if (ssl_config().signing_algorithm_prefs.has_value()) { ++++ SSL_set_signing_algorithm_prefs( ++++ ssl(), ssl_config().signing_algorithm_prefs->data(), ++++ ssl_config().signing_algorithm_prefs->size()); ++++ } ++++#else +++ if (GetQuicReloadableFlag(enable_tls_trust_anchor_ids)) { +++ QUIC_RELOADABLE_FLAG_COUNT_N(enable_tls_trust_anchor_ids, 1, 2); +++ bssl::UniquePtr credential(SSL_CREDENTIAL_new_x509()); +++@@ -100,6 +114,7 @@ +++ SSL_set_chain_and_key(ssl(), cert_chain.data(), cert_chain.size(), nullptr, +++ &TlsServerConnection::kPrivateKeyMethod); +++ } ++++#endif +++ } +++ +++ void TlsServerConnection::SetClientCertMode(ClientCertMode client_cert_mode) { +diff --git a/patches/0016-bazel-quiche-awslc-client-handshaker-compat.patch b/patches/0016-bazel-quiche-awslc-client-handshaker-compat.patch +new file mode 100644 +index 00000000..6a3388ee +--- /dev/null ++++ b/patches/0016-bazel-quiche-awslc-client-handshaker-compat.patch +@@ -0,0 +1,122 @@ ++--- a/bazel/quiche_s390x_big_endian.patch +++++ b/bazel/quiche_s390x_big_endian.patch ++@@ -72,3 +72,119 @@ ++ } ++ ++ void TlsServerConnection::SetClientCertMode(ClientCertMode client_cert_mode) { +++diff --git a/quiche/quic/core/tls_client_handshaker.cc b/quiche/quic/core/tls_client_handshaker.cc +++--- a/quiche/quic/core/tls_client_handshaker.cc ++++++ b/quiche/quic/core/tls_client_handshaker.cc +++@@ -26,7 +26,53 @@ +++ #include "quiche/common/quiche_text_utils.h" +++ +++ namespace quic { ++++ ++++#if defined(OPENSSL_IS_AWSLC) ++++namespace { ++++ ++++bool QuicTlsGroupToAwsLcNid(uint16_t group_id, int* group_nid) { ++++ switch (group_id) { ++++ case SSL_GROUP_SECP224R1: ++++ *group_nid = NID_secp224r1; ++++ return true; ++++ case SSL_GROUP_SECP256R1: ++++ *group_nid = NID_X9_62_prime256v1; ++++ return true; ++++ case SSL_GROUP_SECP384R1: ++++ *group_nid = NID_secp384r1; ++++ return true; ++++ case SSL_GROUP_SECP521R1: ++++ *group_nid = NID_secp521r1; ++++ return true; ++++ case SSL_GROUP_X25519: ++++ *group_nid = NID_X25519; ++++ return true; ++++ case SSL_GROUP_MLKEM512: ++++ *group_nid = NID_MLKEM512; ++++ return true; ++++ case SSL_GROUP_MLKEM768: ++++ *group_nid = NID_MLKEM768; ++++ return true; ++++ case SSL_GROUP_MLKEM1024: ++++ *group_nid = NID_MLKEM1024; ++++ return true; ++++ case SSL_GROUP_SECP256R1_MLKEM768: ++++ *group_nid = NID_SecP256r1MLKEM768; ++++ return true; ++++ case SSL_GROUP_X25519_MLKEM768: ++++ *group_nid = NID_X25519MLKEM768; ++++ return true; ++++ case SSL_GROUP_SECP384R1_MLKEM1024: ++++ *group_nid = NID_SecP384r1MLKEM1024; ++++ return true; ++++ default: ++++ return false; ++++ } ++++} +++ ++++} // namespace ++++#endif ++++ +++ TlsClientHandshaker::TlsClientHandshaker( +++ const QuicServerId& server_id, QuicCryptoStream* stream, +++ QuicSession* session, std::unique_ptr verify_context, +++@@ -59,8 +105,27 @@ +++ } +++ } +++ if (!crypto_config->preferred_groups().empty()) { ++++#if defined(OPENSSL_IS_AWSLC) ++++ std::vector preferred_group_nids; ++++ preferred_group_nids.reserve(crypto_config->preferred_groups().size()); ++++ for (uint16_t group_id : crypto_config->preferred_groups()) { ++++ int group_nid; ++++ if (!QuicTlsGroupToAwsLcNid(group_id, &group_nid)) { ++++ QUICHE_LOG(WARNING) ++++ << "Ignoring unsupported TLS group ID " << group_id ++++ << " in AWS-LC client group preferences"; ++++ continue; ++++ } ++++ preferred_group_nids.push_back(group_nid); ++++ } ++++ if (!preferred_group_nids.empty()) { ++++ SSL_set1_groups(ssl(), preferred_group_nids.data(), ++++ preferred_group_nids.size()); ++++ } ++++#else +++ SSL_set1_group_ids(ssl(), crypto_config->preferred_groups().data(), +++ crypto_config->preferred_groups().size()); ++++#endif +++ } +++ +++ // Make sure we use the right ALPS codepoint. +++@@ -155,6 +220,10 @@ +++ if (GetQuicReloadableFlag(enable_tls_trust_anchor_ids)) { +++ QUIC_RELOADABLE_FLAG_COUNT_N(enable_tls_trust_anchor_ids, 2, 2); +++ if (tls_connection_.ssl_config().trust_anchor_ids.has_value()) { ++++#if defined(OPENSSL_IS_AWSLC) ++++ QUICHE_LOG(WARNING) ++++ << "AWS-LC does not yet support TLS client trust-anchor IDs"; ++++#else +++ if (!SSL_set1_requested_trust_anchors( +++ ssl(), +++ reinterpret_cast( +++@@ -164,6 +233,7 @@ +++ "Client failed to set TLS Trust Anchor IDs"); +++ return false; +++ } ++++#endif +++ } +++ } +++ +++@@ -523,7 +593,11 @@ +++ const std::vector& certs, std::string* error_details, +++ std::unique_ptr* details, uint8_t* out_alert, +++ std::unique_ptr callback) { ++++#if defined(OPENSSL_IS_AWSLC) ++++ matched_trust_anchor_id_ = false; ++++#else +++ matched_trust_anchor_id_ = SSL_peer_matched_trust_anchor(ssl()); ++++#endif +++ +++ const uint8_t* ocsp_response_raw; +++ size_t ocsp_response_len; +diff --git a/patches/0017-bazel-quiche-awslc-server-handshaker-groups-compat.patch b/patches/0017-bazel-quiche-awslc-server-handshaker-groups-compat.patch +new file mode 100644 +index 00000000..cf451a81 +--- /dev/null ++++ b/patches/0017-bazel-quiche-awslc-server-handshaker-groups-compat.patch +@@ -0,0 +1,89 @@ ++diff --git a/bazel/quiche_s390x_big_endian.patch b/bazel/quiche_s390x_big_endian.patch ++index 458ab2f..db423fa 100644 ++--- a/bazel/quiche_s390x_big_endian.patch +++++ b/bazel/quiche_s390x_big_endian.patch ++@@ -188,3 +188,84 @@ diff --git a/quiche/quic/core/tls_client_handshaker.cc b/quiche/quic/core/tls_cl ++ ++ const uint8_t* ocsp_response_raw; ++ size_t ocsp_response_len; +++diff --git a/quiche/quic/core/tls_server_handshaker.cc b/quiche/quic/core/tls_server_handshaker.cc +++index d667ab8..5e73c05 100644 +++--- a/quiche/quic/core/tls_server_handshaker.cc ++++++ b/quiche/quic/core/tls_server_handshaker.cc +++@@ -73,6 +73,48 @@ namespace { +++ // Default port for HTTP/3. +++ uint16_t kDefaultPort = 443; +++ ++++#if defined(OPENSSL_IS_AWSLC) ++++bool QuicTlsGroupToAwsLcNid(uint16_t group_id, int* group_nid) { ++++ switch (group_id) { ++++ case SSL_GROUP_SECP224R1: ++++ *group_nid = NID_secp224r1; ++++ return true; ++++ case SSL_GROUP_SECP256R1: ++++ *group_nid = NID_X9_62_prime256v1; ++++ return true; ++++ case SSL_GROUP_SECP384R1: ++++ *group_nid = NID_secp384r1; ++++ return true; ++++ case SSL_GROUP_SECP521R1: ++++ *group_nid = NID_secp521r1; ++++ return true; ++++ case SSL_GROUP_X25519: ++++ *group_nid = NID_X25519; ++++ return true; ++++ case SSL_GROUP_MLKEM512: ++++ *group_nid = NID_MLKEM512; ++++ return true; ++++ case SSL_GROUP_MLKEM768: ++++ *group_nid = NID_MLKEM768; ++++ return true; ++++ case SSL_GROUP_MLKEM1024: ++++ *group_nid = NID_MLKEM1024; ++++ return true; ++++ case SSL_GROUP_SECP256R1_MLKEM768: ++++ *group_nid = NID_SecP256r1MLKEM768; ++++ return true; ++++ case SSL_GROUP_X25519_MLKEM768: ++++ *group_nid = NID_X25519MLKEM768; ++++ return true; ++++ case SSL_GROUP_SECP384R1_MLKEM1024: ++++ *group_nid = NID_SecP384r1MLKEM1024; ++++ return true; ++++ default: ++++ return false; ++++ } ++++} ++++#endif ++++ +++ } // namespace +++ +++ TlsServerHandshaker::DefaultProofSourceHandle::DefaultProofSourceHandle( +++@@ -245,8 +287,27 @@ TlsServerHandshaker::TlsServerHandshaker( +++ tls_connection_.EnableInfoCallback(); +++ } +++ if (!crypto_config->preferred_groups().empty()) { ++++#if defined(OPENSSL_IS_AWSLC) ++++ std::vector preferred_group_nids; ++++ preferred_group_nids.reserve(crypto_config->preferred_groups().size()); ++++ for (uint16_t group_id : crypto_config->preferred_groups()) { ++++ int group_nid; ++++ if (!QuicTlsGroupToAwsLcNid(group_id, &group_nid)) { ++++ QUICHE_LOG(WARNING) ++++ << "Ignoring unsupported TLS group ID " << group_id ++++ << " in AWS-LC server group preferences"; ++++ continue; ++++ } ++++ preferred_group_nids.push_back(group_nid); ++++ } ++++ if (!preferred_group_nids.empty()) { ++++ SSL_set1_groups(ssl(), preferred_group_nids.data(), ++++ preferred_group_nids.size()); ++++ } ++++#else +++ SSL_set1_group_ids(ssl(), crypto_config->preferred_groups().data(), +++ crypto_config->preferred_groups().size()); ++++#endif +++ } +++ } +++ +diff --git a/patches/0018-bazel-quiche-s390x-big-endian-endian-fix.patch b/patches/0018-bazel-quiche-s390x-big-endian-endian-fix.patch +new file mode 100644 +index 00000000..c2993499 +--- /dev/null ++++ b/patches/0018-bazel-quiche-s390x-big-endian-endian-fix.patch +@@ -0,0 +1,164 @@ ++diff --git a/bazel/quiche-endian-s390x.patch b/bazel/quiche-endian-s390x.patch ++new file mode 100644 ++index 0000000..e7cdbde ++--- /dev/null +++++ b/bazel/quiche-endian-s390x.patch ++@@ -0,0 +1,89 @@ +++--- a/quiche/common/quiche_endian.h ++++++ b/quiche/common/quiche_endian.h +++@@ -14,29 +14,76 @@ +++ +++ namespace quiche { +++ ++++namespace { ++++ ++++constexpr bool IsLittleEndianHost() { ++++#if defined(_WIN32) ++++ return true; ++++#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ ++++ defined(__ORDER_BIG_ENDIAN__) ++++ return __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__; ++++#elif defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) ++++ return BYTE_ORDER == LITTLE_ENDIAN; ++++#else ++++#error "Unsupported host byte order" ++++#endif ++++} ++++ ++++} // namespace ++++ +++ enum Endianness { +++ NETWORK_BYTE_ORDER, // big endian +++- HOST_BYTE_ORDER // little endian ++++ HOST_BYTE_ORDER // native host byte order +++ }; +++ +++ // Provide utility functions that convert from/to network order (big endian) +++-// to/from host order (little endian). ++++// to/from native host order. +++ class QUICHE_EXPORT QuicheEndian { +++ public: +++- // Convert |x| from host order (little endian) to network order (big endian). ++++ // Convert |x| from host order to network order (big endian). +++ #if defined(__clang__) || \ +++ (defined(__GNUC__) && \ +++ ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5)) +++- static uint16_t HostToNet16(uint16_t x) { return __builtin_bswap16(x); } +++- static uint32_t HostToNet32(uint32_t x) { return __builtin_bswap32(x); } +++- static uint64_t HostToNet64(uint64_t x) { return __builtin_bswap64(x); } ++++ static uint16_t HostToNet16(uint16_t x) { ++++ if constexpr (IsLittleEndianHost()) { ++++ return __builtin_bswap16(x); ++++ } ++++ return x; ++++ } ++++ static uint32_t HostToNet32(uint32_t x) { ++++ if constexpr (IsLittleEndianHost()) { ++++ return __builtin_bswap32(x); ++++ } ++++ return x; ++++ } ++++ static uint64_t HostToNet64(uint64_t x) { ++++ if constexpr (IsLittleEndianHost()) { ++++ return __builtin_bswap64(x); ++++ } ++++ return x; ++++ } +++ #else +++- static uint16_t HostToNet16(uint16_t x) { return PortableByteSwap(x); } +++- static uint32_t HostToNet32(uint32_t x) { return PortableByteSwap(x); } +++- static uint64_t HostToNet64(uint64_t x) { return PortableByteSwap(x); } ++++ static uint16_t HostToNet16(uint16_t x) { ++++ if constexpr (IsLittleEndianHost()) { ++++ return PortableByteSwap(x); ++++ } ++++ return x; ++++ } ++++ static uint32_t HostToNet32(uint32_t x) { ++++ if constexpr (IsLittleEndianHost()) { ++++ return PortableByteSwap(x); ++++ } ++++ return x; ++++ } ++++ static uint64_t HostToNet64(uint64_t x) { ++++ if constexpr (IsLittleEndianHost()) { ++++ return PortableByteSwap(x); ++++ } ++++ return x; ++++ } +++ #endif +++ +++- // Convert |x| from network order (big endian) to host order (little endian). ++++ // Convert |x| from network order (big endian) to host order. +++ static uint16_t NetToHost16(uint16_t x) { return HostToNet16(x); } +++ static uint32_t NetToHost32(uint32_t x) { return HostToNet32(x); } +++ static uint64_t NetToHost64(uint64_t x) { return HostToNet64(x); } ++diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl ++index 41d17a5..16490d4 100644 ++--- a/bazel/repositories.bzl +++++ b/bazel/repositories.bzl ++@@ -808,7 +808,10 @@ def _com_github_google_quiche(): ++ external_http_archive( ++ name = "com_github_google_quiche", ++ patch_args = ["-p1"], ++- patches = ["@envoy//bazel:quiche_s390x_big_endian.patch"], +++ patches = [ +++ "@envoy//bazel:quiche_s390x_big_endian.patch", +++ "@envoy//bazel:quiche-endian-s390x.patch", +++ ], ++ patch_cmds = ["find quiche/ -type f -name \"*.bazel\" -delete"], ++ build_file = "@envoy//bazel/external:quiche.BUILD", ++ ) ++diff --git a/test/common/http/http2/codec_impl_test.cc b/test/common/http/http2/codec_impl_test.cc ++index a8eecaa..3035f15 100644 ++--- a/test/common/http/http2/codec_impl_test.cc +++++ b/test/common/http/http2/codec_impl_test.cc ++@@ -4793,6 +4793,48 @@ TEST(CodecChoiceTest, ProtocolOptionNotSpecified) { ++ EXPECT_FALSE(client2->useOghttp2Library()); ++ } ++ +++TEST(CodecChoiceTest, Oghttp2InitialSettingsFrameUsesNetworkByteOrderLength) { +++ NiceMock client_connection; +++ MockConnectionCallbacks client_callbacks; +++ Stats::TestUtil::TestStore client_stats_store; +++ NiceMock random; +++ Buffer::OwnedImpl outbound; +++ TestScopedRuntime scoped_runtime; +++ scoped_runtime.mergeValues({{"envoy.reloadable_features.http2_use_oghttp2", "false"}}); +++ EXPECT_CALL(client_connection.dispatcher_, createTimer_(_)).Times(0); +++ ON_CALL(client_connection, write(_, _)) +++ .WillByDefault(Invoke([&](Buffer::Instance& data, bool) -> void { outbound.add(data); })); +++ +++ envoy::config::core::v3::Http2ProtocolOptions http2_options; +++ http2_options.mutable_hpack_table_size()->set_value( +++ CommonUtility::OptionsLimits::DEFAULT_HPACK_TABLE_SIZE); +++ http2_options.mutable_max_concurrent_streams()->set_value( +++ CommonUtility::OptionsLimits::DEFAULT_MAX_CONCURRENT_STREAMS); +++ http2_options.mutable_initial_stream_window_size()->set_value( +++ CommonUtility::OptionsLimits::DEFAULT_INITIAL_STREAM_WINDOW_SIZE); +++ http2_options.mutable_initial_connection_window_size()->set_value( +++ CommonUtility::OptionsLimits::DEFAULT_INITIAL_CONNECTION_WINDOW_SIZE); +++ http2_options.mutable_use_oghttp2_codec()->set_value(true); +++ +++ auto client = std::make_unique( +++ client_connection, client_callbacks, *client_stats_store.rootScope(), http2_options, random, +++ Http::DEFAULT_MAX_REQUEST_HEADERS_KB, Http::DEFAULT_MAX_HEADERS_COUNT, +++ ProdNghttp2SessionFactory::get()); +++ +++ ASSERT_TRUE(client->useOghttp2Library()); +++ ASSERT_TRUE(client->wantsToWrite()); +++ const Status status = client->sendPendingFrames(); +++ ASSERT_TRUE(status.ok()) << status.message(); +++ +++ constexpr absl::string_view preface(Http2Frame::Preamble, sizeof(Http2Frame::Preamble) - 1); +++ constexpr absl::string_view expected_header("\x00\x00\x1e\x04\x00\x00\x00\x00\x00", 9); +++ ASSERT_GE(outbound.length(), preface.size() + expected_header.size()); +++ const auto* data = reinterpret_cast(outbound.linearize(outbound.length())); +++ EXPECT_EQ(preface, absl::string_view(data, preface.size())); +++ EXPECT_EQ(expected_header, +++ absl::string_view(data + preface.size(), expected_header.size())); +++} +++ ++ #ifdef NDEBUG ++ // These tests send invalid request and response header names which violate ASSERT while creating ++ // such request/response headers. So they can only be run in NDEBUG mode. +diff --git a/tools/install_bazelisk.sh b/tools/install_bazelisk.sh +index 45852dd1..ca12d62a 100755 +--- a/tools/install_bazelisk.sh ++++ b/tools/install_bazelisk.sh +@@ -8,6 +8,7 @@ fi + + # renovate: datasource=github-releases depName=bazelbuild/bazelisk + BAZELISK_VERSION=v1.28.1 ++BAZEL_VERSION="${BAZEL_VERSION:-$(cat .bazelversion 2>/dev/null || echo 7.7.1)}" + + installed_bazelisk_version="" + +@@ -32,8 +33,55 @@ else + ARCH="amd64" + elif [ "$ARCH" = "aarch64" ]; then + ARCH="arm64" ++ elif [ "$ARCH" = "s390x" ]; then ++ if command -v apt-get >/dev/null; then ++ echo "Bazelisk binary is unavailable on s390x; bootstrapping Bazel ${BAZEL_VERSION} from source." ++ ${SUDO} apt-get update ++ ${SUDO} apt-get install -y --no-install-recommends bazel-bootstrap default-jdk-headless python3 unzip zip ++ TMPDIR=$(mktemp -d) ++ trap 'rm -rf "${TMPDIR}"' EXIT ++ curl -sfL "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-dist.zip" -o "${TMPDIR}/bazel-dist.zip" ++ unzip -q "${TMPDIR}/bazel-dist.zip" -d "${TMPDIR}/bazel-src" ++ ( ++ cd "${TMPDIR}/bazel-src" ++ if ! grep -q 'module_name = "apple_support"' MODULE.bazel; then ++ printf '\nsingle_version_override(\n module_name = "apple_support",\n version = "1.8.1",\n)\n' >> MODULE.bazel ++ fi ++ if ! grep -q 'name = "function_transition_allowlist"' tools/allowlists/function_transition_allowlist/BUILD; then ++ cat >> tools/allowlists/function_transition_allowlist/BUILD <<'EOF' ++ ++package_group( ++ name = "function_transition_allowlist", ++ packages = ["public"], ++) ++EOF ++ fi ++ if ! find . -path '*/com/google/protobuf/UnusedPrivateParameter.java' -print -quit | grep -q .; then ++ pb_dir=$(find . -type d -path '*/com/google/protobuf' | head -n 1 || true) ++ if [ -n "${pb_dir}" ]; then ++ cat > "${pb_dir}/UnusedPrivateParameter.java" <<'EOF' ++package com.google.protobuf; ++ ++final class UnusedPrivateParameter { ++ static final UnusedPrivateParameter INSTANCE = new UnusedPrivateParameter(); ++ private UnusedPrivateParameter() {} ++} ++EOF ++ fi ++ fi ++ export JAVA_TOOL_OPTIONS="-XX:TieredStopAtLevel=1" ++ export BAZEL_JAVAC_OPTS="-J-Xms512m -J-Xmx4g -J-XX:TieredStopAtLevel=1" ++ export BAZEL_BOOTSTRAP_STARTUP_OPTIONS="--host_jvm_args=-Xmx4g --host_jvm_args=-XX:TieredStopAtLevel=1" ++ EXTRA_BAZEL_ARGS="--lockfile_mode=refresh --java_runtime_version=local_jdk --tool_java_runtime_version=local_jdk --java_language_version=21 --tool_java_language_version=21" ./compile.sh ++ ) ++ ${SUDO} install -m 0755 "${TMPDIR}/bazel-src/output/bazel" "${BAZEL}" ++ ${SUDO} ln -sf "${BAZEL}" "/usr/local/bin/bazel-${BAZEL_VERSION}" ++ exit 0 ++ fi ++ echo "Bazelisk binary is unavailable on s390x and no apt-based fallback is configured." >&2 ++ exit 1 + fi +- echo "Downloading bazel-${BAZEL_VERSION}-${OS}-${ARCH} to ${BAZEL}" ++ echo "Downloading bazelisk-${OS}-${ARCH} to ${BAZEL}" + ${SUDO} curl -sfL "https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-${OS}-${ARCH}" -o "${BAZEL}" + ${SUDO} chmod +x "${BAZEL}" + fi