github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/functional/vfio/run.sh (about)

     1  #!/bin/bash
     2  #
     3  # Copyright (c) 2021 Intel Corporation
     4  #
     5  # SPDX-License-Identifier: Apache-2.0
     6  #
     7  
     8  set -x
     9  set -o errexit
    10  set -o nounset
    11  set -o pipefail
    12  set -o errtrace
    13  
    14  script_path=$(dirname "$0")
    15  source "${script_path}/../../lib/common.bash"
    16  
    17  declare -r container_id="vfiotest${RANDOM}"
    18  
    19  tmp_data_dir="$(mktemp -d)"
    20  trap cleanup EXIT
    21  
    22  # kata-runtime options
    23  SANDBOX_CGROUP_ONLY=""
    24  HYPERVISOR=
    25  MACHINE_TYPE=
    26  IMAGE_TYPE=
    27  
    28  cleanup() {
    29  	sudo ctr t kill -a -s 9 $(sudo ctr task list -q) && sleep 3
    30  	sudo ctr t rm -f $(sudo ctr task list -q) && sleep 3
    31  	sudo ctr c rm $(sudo ctr c list -q)
    32  	sudo rm -rf "${tmp_data_dir}"
    33  }
    34  
    35  get_eth_addr() {
    36  	lspci | grep "Ethernet controller" | grep "Virtio network device" | tail -1 | cut -d' ' -f1
    37  }
    38  
    39  unbind_pci_dev() {
    40  	addr="$1"
    41  	echo "0000:${addr}" | sudo tee "/sys/bus/pci/devices/0000:${addr}/driver/unbind"
    42  }
    43  
    44  get_pci_dev_vendor_id() {
    45  	addr="$1"
    46  	lspci -n -s "${addr}" | cut -d' ' -f3 | sed 's|:| |'
    47  }
    48  
    49  bind_to_vfio() {
    50  	dev_vendor_id="$1"
    51  	echo "${dev_vendor_id}" | sudo tee "/sys/bus/pci/drivers/vfio-pci/new_id"
    52  }
    53  
    54  get_vfio_path() {
    55  	addr="$1"
    56  	echo "/dev/vfio/$(basename $(realpath /sys/bus/pci/drivers/vfio-pci/0000:${addr}/iommu_group))"
    57  }
    58  
    59  create_bundle() {
    60  	bundle_dir="$1"
    61  	mkdir -p "${bundle_dir}"
    62  
    63  	# pull and export busybox image in tar file
    64  	rootfs_tar="${tmp_data_dir}/rootfs.tar"
    65  	image="quay.io/prometheus/busybox:latest"
    66  	sudo -E ctr i pull ${image}
    67  	sudo -E ctr i export "${rootfs_tar}" "${image}"
    68  	sudo chown ${USER}:${USER} "${rootfs_tar}"
    69  	sync
    70  
    71  	# extract busybox rootfs
    72  	rootfs_dir="${bundle_dir}/rootfs"
    73  	mkdir -p "${rootfs_dir}"
    74  	layers_dir="$(mktemp -d)"
    75  	tar -C "${layers_dir}" -pxf "${rootfs_tar}"
    76  	for ((i=0;i<$(cat ${layers_dir}/manifest.json | jq -r ".[].Layers | length");i++)); do
    77  		tar -C ${rootfs_dir} -xf ${layers_dir}/$(cat ${layers_dir}/manifest.json | jq -r ".[].Layers[${i}]")
    78  	done
    79  	sync
    80  
    81  	# Copy config.json
    82  	cp -a "${script_path}/config.json" "${bundle_dir}/config.json"
    83  }
    84  
    85  run_container() {
    86  	bundle_dir="$1"
    87  	sudo -E ctr run -d --runtime io.containerd.run.kata.v2 --config "${bundle_dir}/config.json" "${container_id}"
    88  }
    89  
    90  check_eth_dev() {
    91  	# container MUST have a eth net interface
    92  	sudo -E ctr t exec --exec-id 2 "${container_id}" ip a | grep "eth"
    93  }
    94  
    95  # Show help about this script
    96  help(){
    97  cat << EOF
    98  Usage: $0 [-h] [options]
    99      Description:
   100          This script runs a kata container and passthrough a vfio device
   101      Options:
   102          -h,          Help
   103          -i <string>, Specify initrd or image
   104          -m <string>, Specify kata-runtime machine type for qemu hypervisor
   105          -p <string>, Specify kata-runtime hypervisor
   106          -s <value>,  Set sandbox_cgroup_only in the configuration file
   107  EOF
   108  }
   109  
   110  setup_configuration_file() {
   111  	local qemu_config_file="configuration-qemu.toml"
   112  	local clh_config_file="configuration-clh.toml"
   113  	local image_file="/usr/share/kata-containers/kata-containers.img"
   114  	local initrd_file="/usr/share/kata-containers/kata-containers-initrd.img"
   115  	local kata_config_file=""
   116  
   117  	for file in $(kata-runtime --kata-show-default-config-paths); do
   118  		if [ ! -f "${file}" ]; then
   119  			continue
   120  		fi
   121  
   122  		kata_config_file="${file}"
   123  		config_dir=$(dirname ${file})
   124  		config_filename=""
   125  
   126  		if [ "$HYPERVISOR" = "qemu" ]; then
   127  			config_filename="${qemu_config_file}"
   128  		elif [ "$HYPERVISOR" = "clh" ]; then
   129  			config_filename="${clh_config_file}"
   130  		fi
   131  
   132  		config_file="${config_dir}/${config_filename}"
   133  		if [ -f "${config_file}" ]; then
   134  			rm -f "${kata_config_file}"
   135  			cp -a $(realpath "${config_file}") "${kata_config_file}"
   136  			break
   137  		fi
   138  	done
   139  
   140  	# machine type applies to configuration.toml and configuration-qemu.toml
   141  	if [ -n "$MACHINE_TYPE" ]; then
   142  		if [ "$HYPERVISOR" = "qemu" ]; then
   143  			sed -i 's|^machine_type.*|machine_type = "'${MACHINE_TYPE}'"|g' "${kata_config_file}"
   144  		else
   145  			warn "Variable machine_type only applies to qemu. It will be ignored"
   146  		fi
   147  	fi
   148  
   149  	if [ -n "${SANDBOX_CGROUP_ONLY}" ]; then
   150  	   sed -i 's|^sandbox_cgroup_only.*|sandbox_cgroup_only='${SANDBOX_CGROUP_ONLY}'|g' "${kata_config_file}"
   151  	fi
   152  
   153  	# Change to initrd or image depending on user input.
   154  	# Non-default configs must be changed to specify either initrd or image, image is default.
   155  	if [ "$IMAGE_TYPE" = "initrd" ]; then
   156  		if $(grep -q "^image.*" ${kata_config_file}); then
   157  			if $(grep -q "^initrd.*" ${kata_config_file}); then
   158  				sed -i '/^image.*/d' "${kata_config_file}"
   159  			else
   160  				sed -i 's|^image.*|initrd = "'${initrd_file}'"|g' "${kata_config_file}"
   161  			fi
   162  		fi
   163  	else
   164  		if $(grep -q "^initrd.*" ${kata_config_file}); then
   165  			if $(grep -q "^image.*" ${kata_config_file}); then
   166  				sed -i '/^initrd.*/d' "${kata_config_file}"
   167  			else
   168  				sed -i 's|^initrd.*|image = "'${image_file}'"|g' "${kata_config_file}"
   169  			fi
   170  		fi
   171  	fi
   172  
   173  	# enable debug
   174  	sed -i -e 's/^#\(enable_debug\).*=.*$/\1 = true/g' \
   175  	       -e 's/^kernel_params = "\(.*\)"/kernel_params = "\1 agent.log=debug"/g' \
   176  	       "${kata_config_file}"
   177  }
   178  
   179  main() {
   180  	local OPTIND
   181  	while getopts "hi:m:p:s:" opt;do
   182  		case ${opt} in
   183  		h)
   184  		    help
   185  		    exit 0;
   186  		    ;;
   187  		i)
   188  		    IMAGE_TYPE="${OPTARG}"
   189  		    ;;
   190  		m)
   191  		    MACHINE_TYPE="${OPTARG}"
   192  		    ;;
   193  		p)
   194  		    HYPERVISOR="${OPTARG}"
   195  		    ;;
   196  		s)
   197  		    SANDBOX_CGROUP_ONLY="${OPTARG}"
   198  		    ;;
   199  		?)
   200  		    # parse failure
   201  		    help
   202  		    die "Failed to parse arguments"
   203  		    ;;
   204  		esac
   205  	done
   206  	shift $((OPTIND-1))
   207  
   208  	setup_configuration_file
   209  
   210  	sudo systemctl restart containerd
   211  	sudo modprobe vfio
   212  	sudo modprobe vfio-pci
   213  
   214  	addr=$(get_eth_addr)
   215  	[ -n "${addr}" ] || die "virtio ethernet controller address not found"
   216  
   217  	unbind_pci_dev "${addr}"
   218  
   219  	dev_vendor_id="$(get_pci_dev_vendor_id "${addr}")"
   220  	bind_to_vfio "${dev_vendor_id}"
   221  
   222  	# get vfio information
   223  	vfio_device="$(get_vfio_path "${addr}")"
   224  	[ -n "${vfio_device}" ] || die "vfio device not found"
   225  	vfio_major="$(printf '%d' $(stat -c '0x%t' ${vfio_device}))"
   226  	vfio_minor="$(printf '%d' $(stat -c '0x%T' ${vfio_device}))"
   227  
   228  	# create container bundle
   229  	bundle_dir="${tmp_data_dir}/bundle"
   230  
   231  	# generate final config.json
   232  	config_json_in="${script_path}/config.json.in"
   233  	sed -e '/^#.*/d' \
   234  		-e 's|@VFIO_PATH@|'"${vfio_device}"'|g' \
   235  		-e 's|@VFIO_MAJOR@|'"${vfio_major}"'|g' \
   236  		-e 's|@VFIO_MINOR@|'"${vfio_minor}"'|g' \
   237  		-e 's|@ROOTFS@|'"${bundle_dir}/rootfs"'|g' \
   238  		"${config_json_in}" > "${script_path}/config.json"
   239  
   240  	create_bundle "${bundle_dir}"
   241  
   242  	# run container
   243  	run_container "${bundle_dir}"
   244  
   245  	# run container checks
   246  	check_eth_dev
   247  }
   248  
   249  main $@