1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2022 Intel Corporation. 4# All rights reserved. 5 6spdk_conf=${spdk_conf:-"$1"} 7 8if [[ ! -f $spdk_conf ]]; then 9 echo "ERROR: SPDK test configuration not specified" 10 return 1 11fi 12 13source "$spdk_conf" 14source "$rootdir/test/common/autotest_common.sh" 15source "$rootdir/scripts/common.sh" 16 17_ocf_precompile() { 18 # We compile OCF sources ourselves 19 # They don't need to be checked with scanbuild and code coverage is not applicable 20 # So we precompile OCF now for further use as standalone static library 21 "$rootdir/configure" $(echo $config_params | sed 's/--enable-coverage//g') 22 $MAKE $MAKEFLAGS include/spdk/config.h 23 CC=gcc CCAR=ar $MAKE $MAKEFLAGS -C "$rootdir/lib/env_ocf" exportlib O="$rootdir/ocf.a" 24 # Set config to use precompiled library 25 config_params="$config_params --with-ocf=/$rootdir/ocf.a" 26 # need to reconfigure to avoid clearing ocf related files on future make clean. 27 "$rootdir/configure" $config_params 28} 29 30# Find matching llvm fuzzer library and clang compiler version 31_llvm_precompile() { 32 [[ $(clang --version) =~ "version "(([0-9]+).([0-9]+).([0-9]+)) ]] 33 clang_num=${BASH_REMATCH[2]} 34 35 export CC=clang-$clang_num 36 export CXX=clang++-$clang_num 37 38 fuzzer_libs=(/usr/lib*/clang/@("$clang_num"|"$clang_version")/lib/*linux*/libclang_rt.fuzzer_no_main?(-x86_64).a) 39 fuzzer_lib=${fuzzer_libs[0]} 40 [[ -e $fuzzer_lib ]] 41 42 config_params="$config_params --with-fuzzer=$fuzzer_lib" 43 # need to reconfigure to avoid clearing llvm related files on future make clean. 44 "$rootdir/configure" $config_params 45} 46 47_build_native_dpdk() { 48 local external_dpdk_dir 49 local external_dpdk_base_dir 50 local compiler_version 51 local compiler 52 local dpdk_kmods 53 local repo='dpdk' 54 55 compiler=${CC:-gcc} 56 57 # Export CC to be absolutely sure it's set. 58 # If CC was not set and we defaulted to "gcc" then we need to do the export 59 # so that "meson build" command a few lines below is aware of which compiler 60 # to use. 61 export CC="$compiler" 62 63 if [[ $compiler != *clang* && $compiler != *gcc* ]]; then 64 echo "Unsupported compiler detected ($compiler), failing the test" >&2 65 return 1 66 fi 67 68 compiler_version=$("$compiler" -dumpversion) 69 compiler_version=${compiler_version%%.*} 70 external_dpdk_dir="$SPDK_RUN_EXTERNAL_DPDK" 71 external_dpdk_base_dir="$(dirname $external_dpdk_dir)" 72 73 if [[ ! -d "$external_dpdk_base_dir" ]]; then 74 if [[ $SPDK_TEST_NATIVE_DPDK != 'main' ]]; then 75 repo='dpdk-stable' 76 fi 77 echo "DPDK directory does not exist at the provided location." 78 sudo mkdir -p "$external_dpdk_base_dir" 79 sudo chown -R $(whoami) "$external_dpdk_base_dir"/.. 80 git clone --branch "$SPDK_TEST_NATIVE_DPDK" --depth 1 http://dpdk.org/git/${repo} "$external_dpdk_base_dir" 81 fi 82 orgdir=$PWD 83 git -C "$external_dpdk_base_dir" log --oneline -n 5 84 85 dpdk_cflags="-fPIC -g -fcommon" 86 dpdk_ldflags="" 87 dpdk_ver=$(< "$external_dpdk_base_dir/VERSION") 88 89 if [[ $compiler == *gcc* && $compiler_version -ge 5 ]]; then 90 dpdk_cflags+=" -Werror" 91 fi 92 93 if [[ $compiler == *gcc* && $compiler_version -ge 10 ]]; then 94 dpdk_cflags+=" -Wno-stringop-overflow" 95 fi 96 97 # the drivers we use 98 # net/i40e driver is not really needed by us, but it's built as a workaround 99 # for DPDK issue: https://bugs.dpdk.org/show_bug.cgi?id=576 100 DPDK_DRIVERS=("bus" "bus/pci" "bus/vdev" "mempool/ring" "net/i40e" "net/i40e/base" 101 "power/acpi" "power/amd_pstate" "power/cppc" "power/intel_pstate" 102 "power/intel_uncore" "power/kvm_vm") 103 local mlx5_libs_added="n" 104 if [[ "$SPDK_TEST_CRYPTO" -eq 1 || "$SPDK_TEST_SMA" -eq 1 ]]; then 105 intel_ipsec_mb_ver=v0.54 106 intel_ipsec_mb_drv=crypto/aesni_mb 107 intel_ipsec_lib="" 108 if ge "$dpdk_ver" 24.11.0; then 109 # Starting from 24.11.0, the minimum supported version of intel-ipsec-mb is 110 # v1.5. 111 intel_ipsec_mb_ver=v1.5 112 intel_ipsec_mb_drv=crypto/ipsec_mb 113 intel_ipsec_lib=lib 114 elif ge "$dpdk_ver" 21.11.0; then 115 # Minimum supported version of intel-ipsec-mb, for DPDK >= 21.11, is 1.0. 116 # Source of the aesni_mb driver was moved to ipsec_mb. .{h,so,a} were moved 117 # to ./lib. 118 # https://github.com/dpdk/dpdk/commit/918fd2f1466b0e3b21a033df7012a77a83665582. 119 intel_ipsec_mb_ver=v1.0 120 intel_ipsec_mb_drv=crypto/ipsec_mb 121 intel_ipsec_lib=lib 122 fi 123 git clone --branch "$intel_ipsec_mb_ver" --depth 1 https://github.com/intel/intel-ipsec-mb.git "$external_dpdk_base_dir/intel-ipsec-mb" 124 cd "$external_dpdk_base_dir/intel-ipsec-mb" 125 $MAKE $MAKEFLAGS all SHARED=y EXTRA_CFLAGS=-fPIC 126 DPDK_DRIVERS+=("crypto") 127 DPDK_DRIVERS+=("$intel_ipsec_mb_drv") 128 DPDK_DRIVERS+=("crypto/qat") 129 DPDK_DRIVERS+=("compress/qat") 130 DPDK_DRIVERS+=("common/qat") 131 # 21.11.0 is version of DPDK with stable support for mlx5 crypto. 132 if ge "$dpdk_ver" 21.11.0; then 133 # SPDK enables CRYPTO_MLX in case supported version of DPDK is detected 134 # so make sure proper libs are built. 135 DPDK_DRIVERS+=("bus/auxiliary") 136 DPDK_DRIVERS+=("common/mlx5") 137 DPDK_DRIVERS+=("common/mlx5/linux") 138 DPDK_DRIVERS+=("crypto/mlx5") 139 mlx5_libs_added="y" 140 fi 141 dpdk_cflags+=" -I$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 142 dpdk_ldflags+=" -L$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 143 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$external_dpdk_base_dir/intel-ipsec-mb/$intel_ipsec_lib" 144 fi 145 146 if [[ "$SPDK_TEST_VBDEV_COMPRESS" -eq 1 ]]; then 147 isal_dir="$external_dpdk_base_dir/isa-l" 148 git clone --branch v2.29.0 --depth 1 https://github.com/intel/isa-l.git "$isal_dir" 149 150 cd $isal_dir 151 ./autogen.sh 152 ./configure CFLAGS="-fPIC -g -O2" --enable-shared=yes --prefix="$isal_dir/build" 153 ln -s $PWD/include $PWD/isa-l 154 $MAKE $MAKEFLAGS all 155 $MAKE install 156 DPDK_DRIVERS+=("compress") 157 DPDK_DRIVERS+=("compress/isal") 158 DPDK_DRIVERS+=("compress/qat") 159 DPDK_DRIVERS+=("common/qat") 160 if ge "$dpdk_ver" 21.02.0; then 161 # SPDK enables REDUCE_MLX in case supported version of DPDK is detected 162 # so make sure proper libs are built. 163 if test $mlx5_libs_added = "n"; then 164 DPDK_DRIVERS+=("bus/auxiliary") 165 DPDK_DRIVERS+=("common/mlx5") 166 DPDK_DRIVERS+=("common/mlx5/linux") 167 fi 168 DPDK_DRIVERS+=("compress/mlx5") 169 fi 170 export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$isal_dir/build/lib/pkgconfig" 171 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$isal_dir/build/lib" 172 fi 173 174 cd $external_dpdk_base_dir 175 if [ "$(uname -s)" = "Linux" ]; then 176 if lt $dpdk_ver 21.11.0; then 177 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/20.11/dpdk_pci.patch" 178 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/20.11/dpdk_qat.patch" 179 else 180 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/21.11+/dpdk_qat.patch" 181 fi 182 fi 183 if lt "$dpdk_ver" 24.07.0; then 184 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/24.03/pcapng-add-memcpy-check.patch" 185 fi 186 if ge "$dpdk_ver" 24.07.0; then 187 patch -p1 < "$rootdir/test/common/config/pkgdep/patches/dpdk/24.07/uio-open-in-primary.patch" 188 fi 189 190 dpdk_kmods="false" 191 if [ "$(uname -s)" = "FreeBSD" ]; then 192 dpdk_kmods="true" 193 fi 194 195 meson build-tmp --prefix="$external_dpdk_dir" --libdir lib \ 196 -Denable_docs=false -Denable_kmods="$dpdk_kmods" -Dtests=false \ 197 -Dc_link_args="$dpdk_ldflags" -Dc_args="$dpdk_cflags" \ 198 -Dmachine=native -Denable_drivers=$(printf "%s," "${DPDK_DRIVERS[@]}") 199 ninja -C "$external_dpdk_base_dir/build-tmp" $MAKEFLAGS 200 201 if [[ $(uname -s) == "FreeBSD" ]]; then 202 # Under FreeBSD, install requires root privileges since it also attempts to install 203 # requested drivers under /boot. 204 sudo -E ninja -C "$external_dpdk_base_dir/build-tmp" $MAKEFLAGS install 205 # Sanitize ownership of the target directory post sudo above 206 sudo chown -R "$USER" "$external_dpdk_base_dir" 207 # Make sure kernel modules are available for freebsd_update_contigmem_mod() to fetch 208 mapfile -t drivers < <(find "$external_dpdk_base_dir/build-tmp" -name '*.ko') 209 if ((${#drivers[@]} > 0)); then 210 mkdir -p "$external_dpdk_dir/kmod" 211 cp -f "${drivers[@]}" "$external_dpdk_dir/kmod/" 212 fi 213 else 214 ninja -C "$external_dpdk_base_dir/build-tmp" $MAKEFLAGS install 215 216 fi 217 218 # Save this path. In tests are run using autorun.sh then autotest.sh 219 # script will be unaware of LD_LIBRARY_PATH and will fail tests. 220 cat <<- LD_PATH > /tmp/spdk-ld-path 221 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH 222 export PKG_CONFIG_PATH=$PKG_CONFIG_PATH 223 LD_PATH 224 225 cd "$orgdir" 226} 227 228check_dpdk_pci_api() { 229 local dpdk_dir 230 231 if [[ -n "$SPDK_TEST_NATIVE_DPDK" ]]; then 232 dpdk_dir=$(dirname "$SPDK_RUN_EXTERNAL_DPDK") 233 fi 234 235 "$rootdir/scripts/env_dpdk/check_dpdk_pci_api.sh" check "$dpdk_dir" 236} 237 238make_fail_cleanup() { 239 if [ -d $out/scan-build-tmp ]; then 240 scanoutput=$(ls -1 $out/scan-build-tmp/) 241 mv $out/scan-build-tmp/$scanoutput $out/scan-build 242 rm -rf $out/scan-build-tmp 243 chmod -R a+rX $out/scan-build 244 fi 245 false 246} 247 248_scanbuild_make() { 249 pass=true 250 "$rootdir/configure" $config_params --without-shared 251 $scanbuild $MAKE $MAKEFLAGS > $out/build_output.txt && rm -rf $out/scan-build-tmp || make_fail_cleanup 252 xtrace_disable 253 254 rm -f $out/*files.txt 255 for ent in $(find app examples lib module test -type f | grep -vF ".h"); do 256 if [[ $ent == lib/env_ocf* ]]; then continue; fi 257 if file -bi $ent | grep -q 'text/x-c'; then 258 echo $ent | sed 's/\.cp\{0,2\}$//g' >> $out/all_c_files.txt 259 fi 260 done 261 xtrace_restore 262 263 grep -E "CC|CXX" $out/build_output.txt | sed 's/\s\s\(CC\|CXX\)\s//g' | sed 's/\.o//g' > $out/built_c_files.txt 264 cat $rootdir/test/common/skipped_build_files.txt >> $out/built_c_files.txt 265 266 sort -o $out/all_c_files.txt $out/all_c_files.txt 267 sort -o $out/built_c_files.txt $out/built_c_files.txt 268 # from comm manual: 269 # -2 suppress column 2 (lines unique to FILE2) 270 # -3 suppress column 3 (lines that appear in both files) 271 # comm may exit 1 if no lines were printed (undocumented, unreliable) 272 comm -2 -3 $out/all_c_files.txt $out/built_c_files.txt > $out/unbuilt_c_files.txt || true 273 274 if [ $(wc -l < $out/unbuilt_c_files.txt) -ge 1 ]; then 275 echo "missing files" 276 cat <<- ERROR 277 The following C files were not built. Either scanbuild CI job needs to 278 be updated with proper flags to build these files, or exceptions need 279 to be added to test/common/skipped_build_files.txt 280 281 $(< "$out/unbuilt_c_files.txt") 282 ERROR 283 pass=false 284 fi 285 286 $pass 287} 288 289porcelain_check() { 290 if [ $(git status --porcelain --ignore-submodules | wc -l) -ne 0 ]; then 291 echo "Generated files missing from .gitignore:" 292 git status --porcelain --ignore-submodules 293 exit 1 294 fi 295} 296 297# Check that header file dependencies are working correctly by 298# capturing a binary's stat data before and after touching a 299# header file and re-making. 300header_dependency_check() { 301 STAT1=$(stat $SPDK_BIN_DIR/spdk_tgt) 302 sleep 1 303 touch "$rootdir/lib/nvme/nvme_internal.h" 304 $MAKE $MAKEFLAGS 305 STAT2=$(stat $SPDK_BIN_DIR/spdk_tgt) 306 307 if [ "$STAT1" == "$STAT2" ]; then 308 echo "Header dependency check failed" 309 false 310 fi 311} 312 313test_make_install() { 314 $MAKE $MAKEFLAGS install DESTDIR="$SPDK_WORKSPACE" prefix=/usr 315} 316 317test_make_uninstall() { 318 # Create empty file to check if it is not deleted by target uninstall 319 touch "$SPDK_WORKSPACE/usr/lib/sample_xyz.a" 320 $MAKE $MAKEFLAGS uninstall DESTDIR="$SPDK_WORKSPACE" prefix=/usr 321 if [[ $(find "$SPDK_WORKSPACE/usr" -type f -print | wc -l) -ne 1 ]]; then 322 ls -lR "$SPDK_WORKSPACE" 323 echo "Make uninstall failed" 324 exit 1 325 fi 326} 327 328_build_doc() { 329 local doxygenv 330 doxygenv=$(doxygen --version) 331 332 $MAKE -C "$rootdir"/doc --no-print-directory $MAKEFLAGS Q=@ &> "$out"/doxygen.log 333 if [ -s "$out"/doxygen.log ]; then 334 if [[ "$doxygenv" == "1.8.20" ]]; then 335 # Doxygen 1.8.20 produces false positives, see: 336 # https://github.com/doxygen/doxygen/issues/7948 337 grep -vE '\\ilinebr' 338 elif [[ "$doxygenv" == "1.9.5" ]]; then 339 # Doxygen 1.9.5 produces false positives, see: 340 # https://github.com/doxygen/doxygen/issues/9552 and 341 # https://github.com/doxygen/doxygen/issues/9678 342 grep -vE '\\ifile|@param' 343 else 344 cat - 345 fi < "$out/doxygen.log" && echo "Doxygen errors found!" && return 1 346 347 echo "Doxygen $doxygenv detected. No warnings except false positives, continuing the test" 348 fi 349 if hash pdflatex 2> /dev/null; then 350 $MAKE -C "$rootdir"/doc/output/latex --no-print-directory $MAKEFLAGS &>> "$out"/doxygen.log 351 fi 352 mkdir -p "$out"/doc 353 # Copy and remove files to avoid mv: failed to preserve ownership error 354 cp -r --preserve=mode "$rootdir"/doc/output/html "$out"/doc 355 rm -rf "$rootdir"/doc/output/html 356 if [ -f "$rootdir"/doc/output/latex/refman.pdf ]; then 357 mv "$rootdir"/doc/output/latex/refman.pdf "$out"/doc/spdk.pdf 358 fi 359 $MAKE -C "$rootdir"/doc --no-print-directory $MAKEFLAGS clean &>> "$out"/doxygen.log 360 if [ -s "$out"/doxygen.log ]; then 361 # Save the log as an artifact in case we are working with potentially broken version 362 eq "$doxygenv" 1.8.20 || rm "$out"/doxygen.log 363 fi 364 rm -rf "$rootdir"/doc/output 365} 366 367check_format() { 368 run_test "autobuild_check_format" "$rootdir/scripts/check_format.sh" 369} 370 371check_so_deps() { 372 run_test "autobuild_check_so_deps" "$rootdir/test/make/check_so_deps.sh" -c "$spdk_conf" -a "$SPDK_ABI_DIR" 373} 374 375external_code() { 376 run_test "autobuild_external_code" "$rootdir/test/external_code/test_make.sh" "$rootdir" 377} 378 379dpdk_pci_api() { 380 run_test "autobuild_check_dpdk_pci_api" check_dpdk_pci_api 381} 382 383build_files() { 384 "$rootdir/configure" $config_params --without-shared 385 $MAKE $MAKEFLAGS 386 run_test "autobuild_generated_files_check" porcelain_check 387 run_test "autobuild_header_dependency_check" header_dependency_check 388 run_test "autobuild_make_install" test_make_install 389 run_test "autobuild_make_uninstall" test_make_uninstall 390 $MAKE clean 391 run_test "autobuild_generated_files_check_post_clean" porcelain_check 392} 393 394build_doc() { 395 run_test "autobuild_build_doc" _build_doc 396} 397 398autobuild_test_suite_tiny() { 399 check_format 400 check_so_deps 401 dpdk_pci_api 402} 403 404autobuild_test_suite_ext() { 405 external_code 406} 407 408autobuild_test_suite_full() { 409 autobuild_test_suite_tiny 410 autobuild_test_suite_ext 411 build_files 412 build_doc 413} 414 415_autobuild_test_suite() { 416 case "$SPDK_TEST_AUTOBUILD" in 417 tiny) autobuild_test_suite_tiny ;; 418 ext) autobuild_test_suite_ext ;; 419 full) autobuild_test_suite_full ;; 420 esac 421} 422 423_unittest_build() { 424 "$rootdir/configure" $config_params --without-shared 425 $MAKE $MAKEFLAGS 426} 427 428autobuild_test_suite() { 429 run_test "autobuild" _autobuild_test_suite 430} 431 432unittest_build() { 433 run_test "unittest_build" _unittest_build 434} 435 436scanbuild_make() { 437 run_test "scanbuild_make" _scanbuild_make 438} 439 440ocf_precompile() { 441 run_test "autobuild_ocf_precompile" _ocf_precompile 442} 443 444llvm_precompile() { 445 run_test "autobuild_llvm_precompile" _llvm_precompile 446} 447 448build_native_dpdk() { 449 run_test "build_native_dpdk" _build_native_dpdk 450} 451 452build_packaging() { 453 run_test "packaging" "$rootdir/test/packaging/packaging.sh" 454} 455 456_build_release() ( 457 local jobs LD 458 459 if [[ -n $SPDK_TEST_NATIVE_DPDK && -e /tmp/spdk-ld-path ]]; then 460 source /tmp/spdk-ld-path 461 fi 462 463 if [[ $CC == *clang* ]]; then 464 jobs=$(($(nproc) / 2)) 465 case "$(uname -s)" in 466 Linux) 467 # ld.gold is shipped by default with binutils under most of the Linux distros. 468 # But just in case, look for ld.lld as it's still better suited for the LTO 469 # build under clang. 470 if ! LD=$(type -P ld.lld); then 471 LD=ld.gold LDFLAGS="-Wl,--threads,--thread-count=$jobs" MAKEFLAGS="-j$jobs" 472 fi 473 export LD LDFLAGS MAKEFLAGS 474 ;; 475 FreeBSD) # Default compiler which does support LTO, set it explicitly for visibility 476 export LD=ld.lld ;; 477 esac 478 fi 479 480 "$rootdir/configure" $config_params \ 481 --disable-debug \ 482 --disable-unit-tests \ 483 --enable-lto 484 485 $MAKE -C "$rootdir" $MAKEFLAGS 486) 487 488build_release() { 489 run_test "build_release" _build_release 490} 491 492out=$output_dir 493SPDK_WORKSPACE=$(mktemp -dt "spdk_$(date +%s).XXXXXX") 494 495if [[ -n $EXTERNAL_MAKE_HUGEMEM ]]; then 496 export EXTERNAL_MAKE_HUGEMEM 497fi 498 499if [ -n "$SPDK_TEST_NATIVE_DPDK" ]; then 500 scanbuild_exclude=" --exclude $(dirname $SPDK_RUN_EXTERNAL_DPDK)" 501else 502 scanbuild_exclude="--exclude $rootdir/dpdk/" 503fi 504# We exclude /tmp as it's used by xnvme's liburing subproject for storing 505# temporary .c files which are picked up as buggy by the scanbuild. 506scanbuild_exclude+=" --exclude $rootdir/xnvme --exclude /tmp" 507 508scanbuild="scan-build -o $output_dir/scan-build-tmp $scanbuild_exclude --status-bugs" 509config_params=$(get_config_params) 510 511start_monitor_resources 512trap 'stop_monitor_resources' EXIT 513