//! RDMA device discovery use super::types::{RdmaDeviceInfo, RdmaNodeType}; use crate::error::Result; #[cfg(feature = "rdma")] use super::ffi::{ IbvDeviceAttr, ibv_close_device, ibv_free_device_list, ibv_get_device_list, ibv_get_device_name, ibv_open_device, ibv_query_device, }; #[cfg(feature = "rdma")] use std::ffi::CStr; /// Discover available RDMA devices pub fn discover_rdma_devices() -> Result> { let mut devices = Vec::new(); #[cfg(feature = "rdma")] unsafe { let mut num_devices: i32 = 0; let device_list = ibv_get_device_list(&mut num_devices); if device_list.is_null() || num_devices == 0 { return Ok(devices); } for i in 0..num_devices as isize { let device = *device_list.offset(i); if device.is_null() { continue; } let name_ptr = ibv_get_device_name(device); let name = if name_ptr.is_null() { "unknown".to_string() } else { CStr::from_ptr(name_ptr).to_string_lossy().into_owned() }; // Open device to query properties let context = ibv_open_device(device); if context.is_null() { continue; } let mut attr = IbvDeviceAttr::default(); if ibv_query_device(context, &mut attr) == 0 { devices.push(RdmaDeviceInfo { name, guid: attr.node_guid, num_ports: attr.phys_port_cnt, node_type: RdmaNodeType::ChannelAdapter, max_msg_size: attr.max_mr_size.min(1 << 30), max_qp: attr.max_qp as u32, max_cq: attr.max_cq as u32, max_mr: attr.max_mr as u32, }); } let _ = ibv_close_device(context); } ibv_free_device_list(device_list); } #[cfg(not(feature = "rdma"))] { // Return stub device info when RDMA is not available devices.push(RdmaDeviceInfo { name: "stub_device".to_string(), guid: 0, num_ports: 1, node_type: RdmaNodeType::ChannelAdapter, max_msg_size: 1 << 30, max_qp: 65536, max_cq: 65536, max_mr: 65536, }); } Ok(devices) } /// Check if RDMA is available on this system pub fn is_rdma_available() -> bool { #[cfg(feature = "rdma")] { discover_rdma_devices() .map(|devices| !devices.is_empty()) .unwrap_or(false) } #[cfg(not(feature = "rdma"))] { false } }