This is an automated email from the ASF dual-hosted git repository.

sureshanaparti pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 2c493d19336 Add support for nvidia vGPU support with vendor specific 
framework (#11432)
2c493d19336 is described below

commit 2c493d193364dd448d93912b7961bdc6a499bebd
Author: Vishesh <vishes...@gmail.com>
AuthorDate: Fri Aug 15 15:54:11 2025 +0530

    Add support for nvidia vGPU support with vendor specific framework (#11432)
---
 .../hypervisor/kvm/resource/LibvirtGpuDef.java     |  11 +-
 scripts/vm/hypervisor/kvm/gpudiscovery.sh          | 162 ++++++++++++++++++++-
 2 files changed, 163 insertions(+), 10 deletions(-)

diff --git 
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtGpuDef.java
 
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtGpuDef.java
index 06457b1d071..08086859fb7 100644
--- 
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtGpuDef.java
+++ 
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtGpuDef.java
@@ -47,7 +47,7 @@ public class LibvirtGpuDef {
 
     private void generateMdevXml(StringBuilder gpuBuilder) {
         String mdevUuid = vgpuType.getBusAddress(); // For MDEV devices, 
busAddress contains the UUID
-        String displayAttribute = vgpuType.isDisplay() ? "on" : "off";
+        String displayAttribute = vgpuType.isDisplay() ? "on' ramfb='on" : 
"off";
 
         gpuBuilder.append("<hostdev mode='subsystem' type='mdev' 
model='vfio-pci' display='").append(displayAttribute).append("'>\n");
         gpuBuilder.append("  <source>\n");
@@ -65,11 +65,16 @@ public class LibvirtGpuDef {
         // - UEFI/OVMF firmware environments
         // - ARM64 hosts (cache coherency issues with traditional VGA)
         // - Multi-monitor VDI setups (primary display)
+        String managed = "yes";
+        // To support passthrough NVIDIA GPUs with SR-IOV & vendor specific 
GPU integration
+        if (vgpuType.getVendorId().equals("10de") && 
!vgpuType.getModelName().equals("passthrough")) {
+            managed = "no";
+        }
         if (vgpuType.isDisplay()) {
-            gpuBuilder.append("<hostdev mode='subsystem' type='pci' 
managed='yes' display='on' ramfb='on'>\n");
+            gpuBuilder.append("<hostdev mode='subsystem' type='pci' 
managed='").append(managed).append("' display='on' ramfb='on'>\n");
         } else {
             // Compute-only workloads don't need display or ramfb
-            gpuBuilder.append("<hostdev mode='subsystem' type='pci' 
managed='yes' display='off'>\n");
+            gpuBuilder.append("<hostdev mode='subsystem' type='pci' 
managed='").append(managed).append("' display='off'>\n");
         }
         gpuBuilder.append("  <driver name='vfio'/>\n");
         gpuBuilder.append("  <source>\n");
diff --git a/scripts/vm/hypervisor/kvm/gpudiscovery.sh 
b/scripts/vm/hypervisor/kvm/gpudiscovery.sh
index 662abaed2cb..d27f6daf8c5 100755
--- a/scripts/vm/hypervisor/kvm/gpudiscovery.sh
+++ b/scripts/vm/hypervisor/kvm/gpudiscovery.sh
@@ -349,6 +349,130 @@ json_escape() {
 # Cache for nodedev XML data to avoid repeated virsh calls
 declare -A nodedev_cache
 
+# Cache for nvidia-smi vgpu profile data
+declare -A nvidia_vgpu_profiles
+
+# Parse nvidia-smi vgpu -s -v output and populate profile cache
+parse_nvidia_vgpu_profiles() {
+       local gpu_address=""
+       local profile_id=""
+       local profile_name=""
+       local max_instances=""
+       local fb_memory=""
+       local max_heads=""
+       local max_x_res=""
+       local max_y_res=""
+
+       # Function to store current profile data
+       store_profile_data() {
+               if [[ -n "$gpu_address" && -n "$profile_id" && -n 
"$profile_name" ]]; then
+                       local key="${gpu_address}:${profile_id}"
+                       
nvidia_vgpu_profiles["$key"]="$profile_name|${max_instances:-0}|${fb_memory:-0}|${max_heads:-0}|${max_x_res:-0}|${max_y_res:-0}"
+               fi
+       }
+
+       # Skip if nvidia-smi is not available
+       if ! command -v nvidia-smi >/dev/null 2>&1; then
+               return
+       fi
+
+       while IFS= read -r line; do
+               # Match GPU address line
+               if [[ $line =~ ^GPU[[:space:]]+([0-9A-Fa-f:]+\.[0-9A-Fa-f]+) 
]]; then
+                       # Store previous profile data before starting new GPU
+                       store_profile_data
+
+                       gpu_address="${BASH_REMATCH[1]}"
+                       # Convert from format like 00000000:AF:00.0 to AF:00.0 
and normalize to lowercase
+                       if [[ $gpu_address =~ 
[0-9A-Fa-f]+:([0-9A-Fa-f]+:[0-9A-Fa-f]+\.[0-9A-Fa-f]+) ]]; then
+                               gpu_address="${BASH_REMATCH[1],,}"
+                       else
+                               gpu_address="${gpu_address,,}"
+                       fi
+                       # Reset profile variables for new GPU
+                       profile_id=""
+                       profile_name=""
+                       max_instances=""
+                       fb_memory=""
+                       max_heads=""
+                       max_x_res=""
+                       max_y_res=""
+               elif [[ $line =~ 
^[[:space:]]*vGPU[[:space:]]+Type[[:space:]]+ID[[:space:]]*:[[:space:]]*0x([0-9A-Fa-f]+)
 ]]; then
+                       # Store previous profile data before starting new 
profile
+                       store_profile_data
+
+                       # Normalize to lowercase hex without 0x prefix
+                       profile_id="${BASH_REMATCH[1],,}"
+                       # Reset profile-specific variables
+                       profile_name=""
+                       max_instances=""
+                       fb_memory=""
+                       max_heads=""
+                       max_x_res=""
+                       max_y_res=""
+               elif [[ $line =~ 
^[[:space:]]*Name[[:space:]]*:[[:space:]]*(.+)$ ]]; then
+                       profile_name="${BASH_REMATCH[1]}"
+               elif [[ $line =~ 
^[[:space:]]*Max[[:space:]]+Instances[[:space:]]*:[[:space:]]*([0-9]+) ]]; then
+                       max_instances="${BASH_REMATCH[1]}"
+               elif [[ $line =~ 
^[[:space:]]*FB[[:space:]]+Memory[[:space:]]*:[[:space:]]*([0-9]+)[[:space:]]*MiB
 ]]; then
+                       fb_memory="${BASH_REMATCH[1]}"
+               elif [[ $line =~ 
^[[:space:]]*Display[[:space:]]+Heads[[:space:]]*:[[:space:]]*([0-9]+) ]]; then
+                       max_heads="${BASH_REMATCH[1]}"
+               elif [[ $line =~ 
^[[:space:]]*Maximum[[:space:]]+X[[:space:]]+Resolution[[:space:]]*:[[:space:]]*([0-9]+)
 ]]; then
+                       max_x_res="${BASH_REMATCH[1]}"
+               elif [[ $line =~ 
^[[:space:]]*Maximum[[:space:]]+Y[[:space:]]+Resolution[[:space:]]*:[[:space:]]*([0-9]+)
 ]]; then
+                       max_y_res="${BASH_REMATCH[1]}"
+               fi
+       done < <(nvidia-smi vgpu -s -v 2>/dev/null || true)
+
+       # Store the last profile data after processing all lines
+       store_profile_data
+}
+
+# Get current vGPU type ID for a VF from sysfs
+get_current_vgpu_type() {
+       local vf_path="$1"
+       local current_type_file="$vf_path/nvidia/current_vgpu_type"
+
+       if [[ -f "$current_type_file" ]]; then
+               local type_id
+               type_id=$(<"$current_type_file")
+
+               # Remove any whitespace
+               type_id="${type_id// /}"
+
+               # Handle different input formats and normalize to lowercase hex 
without 0x
+               if [[ $type_id =~ ^0x([0-9A-Fa-f]+)$ ]]; then
+                       # Input is hex with 0x prefix (e.g., "0x252")
+                       echo "${BASH_REMATCH[1],,}"
+               elif [[ $type_id =~ ^[0-9]+$ ]]; then
+                       # Input is decimal (e.g., "594")
+                       printf "%x" "$type_id"
+               elif [[ $type_id =~ ^[0-9A-Fa-f]+$ ]]; then
+                       # Input is hex without 0x prefix (e.g., "252")
+                       echo "${type_id,,}"
+               else
+                       # Fallback for unknown format
+                       echo "0"
+               fi
+       else
+               echo "0"
+       fi
+}
+
+# Get profile information from nvidia-smi cache
+get_nvidia_profile_info() {
+       local gpu_address="$1"
+       local profile_id="$2"
+       local key="${gpu_address}:${profile_id}"
+
+       if [[ -n "${nvidia_vgpu_profiles[$key]:-}" ]]; then
+               echo "${nvidia_vgpu_profiles[$key]}"
+       else
+               echo "|0|0|0|0|0"  # Default empty values
+       fi
+}
+
 # Get nodedev name for a PCI address (e.g. "00:02.0" -> "pci_0000_00_02_0")
 get_nodedev_name() {
        local addr="$1"
@@ -567,6 +691,9 @@ process_mdev_instances() {
 
 # === GPU Discovery ===
 
+# Parse nvidia-smi vgpu profiles once at the beginning
+parse_nvidia_vgpu_profiles
+
 mapfile -t LINES < <(lspci -nnm)
 
 echo '{ "gpus": ['
@@ -575,7 +702,7 @@ first_gpu=true
 for LINE in "${LINES[@]}"; do
        # Parse lspci -nnm fields: SLOT "CLASS [CODE]" "VENDOR [VID]" "DEVICE 
[DID]" ...
        if [[ $LINE =~ 
^([^[:space:]]+)[[:space:]]\"([^\"]+)\"[[:space:]]\"([^\"]+)\"[[:space:]]\"([^\"]+)\"
 ]]; then
-               PCI_ADDR="${BASH_REMATCH[1]}"
+               PCI_ADDR="${BASH_REMATCH[1],,}"  # Normalize to lowercase
                PCI_CLASS="${BASH_REMATCH[2]}"
                VENDOR_FIELD="${BASH_REMATCH[3]}"
                DEVICE_FIELD="${BASH_REMATCH[4]}"
@@ -662,12 +789,33 @@ for LINE in "${LINES[@]}"; do
                        SLOT="0x${VF_BDF:3:2}"
                        FUNC="0x${VF_BDF:6:1}"
 
-                       # Determine vf_profile
+                       # Determine vf_profile using nvidia-smi information
                        VF_PROFILE=""
-                       if VF_LINE=$(lspci -nnm -s "$VF_BDF" 2>/dev/null); then
-                               if [[ $VF_LINE =~ 
\"([^\"]+)\"[[:space:]]\"([^\"]+)\"[[:space:]]\"([^\"]+)\"[[:space:]]\"([^\"]+)\"
 ]]; then
-                                       VF_DEVICE_FIELD="${BASH_REMATCH[4]}"
-                                       VF_PROFILE=$(sed -E 's/ 
\[[0-9A-Fa-f]{4}\]$//' <<<"$VF_DEVICE_FIELD")
+                       VF_PROFILE_NAME=""
+                       VF_MAX_INSTANCES="null"
+                       VF_VIDEO_RAM="null"
+                       VF_MAX_HEADS="null"
+                       VF_MAX_RESOLUTION_X="null"
+                       VF_MAX_RESOLUTION_Y="null"
+
+                       if [[ "$VENDOR_ID" == "10de" ]]; then
+                               # For NVIDIA GPUs, check current vGPU type
+                               current_vgpu_type=$(get_current_vgpu_type 
"$VF_PATH")
+                               if [[ "$current_vgpu_type" != "0" ]]; then
+                                       # Get profile info from nvidia-smi cache
+                                       profile_info=$(get_nvidia_profile_info 
"$PCI_ADDR" "$current_vgpu_type")
+                                       IFS='|' read -r VF_PROFILE_NAME 
VF_MAX_INSTANCES VF_VIDEO_RAM VF_MAX_HEADS VF_MAX_RESOLUTION_X 
VF_MAX_RESOLUTION_Y <<< "$profile_info"
+                                       VF_PROFILE="$VF_PROFILE_NAME"
+                               fi
+                       fi
+
+                       # Fallback to lspci parsing if no nvidia-smi profile 
found
+                       if [[ -z "$VF_PROFILE" ]]; then
+                               if VF_LINE=$(lspci -nnm -s "$VF_BDF" 
2>/dev/null); then
+                                       if [[ $VF_LINE =~ 
\"([^\"]+)\"[[:space:]]\"([^\"]+)\"[[:space:]]\"([^\"]+)\"[[:space:]]\"([^\"]+)\"
 ]]; then
+                                               
VF_DEVICE_FIELD="${BASH_REMATCH[4]}"
+                                               VF_PROFILE=$(sed -E 's/ 
\[[0-9A-Fa-f]{4}\]$//' <<<"$VF_DEVICE_FIELD")
+                                       fi
                                fi
                        fi
                        VF_PROFILE_JSON=$(json_escape "$VF_PROFILE")
@@ -677,7 +825,7 @@ for LINE in "${LINES[@]}"; do
                        USED_JSON=$(to_json_vm "$raw")
 
                        flist+=(
-                               
"{\"vf_pci_address\":\"$VF_BDF\",\"vf_profile\":$VF_PROFILE_JSON,\"libvirt_address\":{\"domain\":\"$DOMAIN\",\"bus\":\"$BUS\",\"slot\":\"$SLOT\",\"function\":\"$FUNC\"},\"used_by_vm\":$USED_JSON}")
+                               
"{\"vf_pci_address\":\"$VF_BDF\",\"vf_profile\":$VF_PROFILE_JSON,\"max_instances\":$VF_MAX_INSTANCES,\"video_ram\":$VF_VIDEO_RAM,\"max_heads\":$VF_MAX_HEADS,\"max_resolution_x\":$VF_MAX_RESOLUTION_X,\"max_resolution_y\":$VF_MAX_RESOLUTION_Y,\"libvirt_address\":{\"domain\":\"$DOMAIN\",\"bus\":\"$BUS\",\"slot\":\"$SLOT\",\"function\":\"$FUNC\"},\"used_by_vm\":$USED_JSON}")
                done
                if [ ${#flist[@]} -gt 0 ]; then
                        VF_ARRAY="[$(

Reply via email to