From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id F28EC1FF13C for ; Thu, 05 Mar 2026 10:17:53 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 36DA61F067; Thu, 5 Mar 2026 10:18:18 +0100 (CET) From: Dominik Csapak To: pve-devel@lists.proxmox.com Subject: [PATCH proxmox-perl-rs 1/1] pve: add binding for accessing vgpu info Date: Thu, 5 Mar 2026 10:16:53 +0100 Message-ID: <20260305091711.1221589-10-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260305091711.1221589-1-d.csapak@proxmox.com> References: <20260305091711.1221589-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.037 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: O2VOG5X6LBWG2HBQV6D3KBUCOCTFSAH5 X-Message-ID-Hash: O2VOG5X6LBWG2HBQV6D3KBUCOCTFSAH5 X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Adds some basic perl bindings to return the creatable and supported vGPU types for NVIDIA GPUs. The 'supported' helper is not yet used, but it'll be useful when we want to have a better api response for the available mdevs. The description generated here is in the format that used to be exposed by the sysfs via the standard mdev api. Co-developed-by: Christoph Heiss Signed-off-by: Dominik Csapak --- pve-rs/Cargo.toml | 1 + pve-rs/Makefile | 1 + pve-rs/src/bindings/mod.rs | 3 ++ pve-rs/src/bindings/nvml.rs | 91 +++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 pve-rs/src/bindings/nvml.rs diff --git a/pve-rs/Cargo.toml b/pve-rs/Cargo.toml index 45389b5..3b6c2fc 100644 --- a/pve-rs/Cargo.toml +++ b/pve-rs/Cargo.toml @@ -20,6 +20,7 @@ hex = "0.4" http = "1" libc = "0.2" nix = "0.29" +nvml-wrapper = "0.12" openssl = "0.10.40" serde = "1.0" serde_bytes = "0.11" diff --git a/pve-rs/Makefile b/pve-rs/Makefile index aa7181e..4698358 100644 --- a/pve-rs/Makefile +++ b/pve-rs/Makefile @@ -27,6 +27,7 @@ PERLMOD_GENPACKAGE := /usr/lib/perlmod/genpackage.pl \ PERLMOD_PACKAGES := \ PVE::RS::Firewall::SDN \ + PVE::RS::NVML \ PVE::RS::OCI \ PVE::RS::OpenId \ PVE::RS::ResourceScheduling::Static \ diff --git a/pve-rs/src/bindings/mod.rs b/pve-rs/src/bindings/mod.rs index c21b328..132079a 100644 --- a/pve-rs/src/bindings/mod.rs +++ b/pve-rs/src/bindings/mod.rs @@ -12,6 +12,9 @@ pub use tfa::pve_rs_tfa; mod openid; pub use openid::pve_rs_open_id; +mod nvml; +pub use nvml::pve_rs_nvml; + pub mod firewall; mod sdn; diff --git a/pve-rs/src/bindings/nvml.rs b/pve-rs/src/bindings/nvml.rs new file mode 100644 index 0000000..0f4c81e --- /dev/null +++ b/pve-rs/src/bindings/nvml.rs @@ -0,0 +1,91 @@ +//! Provides access to the state of NVIDIA (v)GPU devices connected to the system. + +#[perlmod::package(name = "PVE::RS::NVML", lib = "pve_rs")] +pub mod pve_rs_nvml { + //! The `PVE::RS::NVML` package. + //! + //! Provides high level helpers to get info from the system with NVML. + + use anyhow::Result; + use nvml_wrapper::Nvml; + use perlmod::Value; + + /// Retrieves a list of *creatable* vGPU types for the specified GPU by bus id. + /// + /// The [`bus_id`] is of format "\:\:\.\", + /// e.g. "0000:01:01.0". + /// + /// # See also + /// + /// [`nvmlDeviceGetCreatableVgpus`]: + /// [`nvmlDeviceGetHandleByPciBusId_v2`]: + /// [`struct nvmlPciInfo_t`]: + #[export] + fn creatable_vgpu_types_for_dev(bus_id: &str) -> Result> { + let nvml = Nvml::init()?; + let device = nvml.device_by_pci_bus_id(bus_id)?; + + build_vgpu_type_list(device.vgpu_creatable_types()?) + } + + /// Retrieves a list of *supported* vGPU types for the specified GPU by bus id. + /// + /// The [`bus_id`] is of format "\:\:\.\", + /// e.g. "0000:01:01.0". + /// + /// # See also + /// + /// [`nvmlDeviceGetSupportedVgpus`]: + /// [`nvmlDeviceGetHandleByPciBusId_v2`]: + /// [`struct nvmlPciInfo_t`]: + #[export] + fn supported_vgpu_types_for_dev(bus_id: &str) -> Result> { + let nvml = Nvml::init()?; + let device = nvml.device_by_pci_bus_id(bus_id)?; + + build_vgpu_type_list(device.vgpu_supported_types()?) + } + + fn build_vgpu_type_list(vgpu_types: Vec) -> Result> { + let mut result = Vec::with_capacity(vgpu_types.len()); + for vgpu in vgpu_types { + let mut value = perlmod::Value::new_hash(); + if let Some(hash) = value.as_hash_mut() { + hash.insert("id", Value::new_uint(vgpu.id() as usize)); + hash.insert("name", Value::new_string(&vgpu.name()?)); + hash.insert("description", Value::new_string(&description(&vgpu)?)); + } + + result.push(Value::new_ref(&value)); + } + + Ok(result) + } + + // a description like it used to exist in the sysfs with the standard mdev interface + fn description(vgpu_type: &nvml_wrapper::vgpu::VgpuType) -> Result { + let class_name = vgpu_type.class_name()?; + let max_instances = vgpu_type.max_instances()?; + let max_instances_per_vm = vgpu_type.max_instances_per_vm()?; + + let framebuffer_size_mb = vgpu_type.framebuffer_size()? / 1024 / 1024; // bytes to MiB + let num_heads = vgpu_type.num_display_heads()?; + + let (max_res_x, max_res_y) = (0..num_heads) + .filter_map(|head| vgpu_type.resolution(head).ok()) + .max() + .unwrap_or((0, 0)); + + let license = vgpu_type.license()?; + + Ok(format!( + "class={class_name}\n\ + max-instances={max_instances}\n\ + max-instances-per-vm={max_instances_per_vm}\n\ + framebuffer-size={framebuffer_size_mb}MiB\n\ + num-heads={num_heads}\n\ + max-resolution={max_res_x}x{max_res_y}\n\ + license={license}" + )) + } +} -- 2.47.3