use crate::ibverbs::access_config::AccessFlags;
use crate::ibverbs::device::Context;
use crate::ibverbs::error::{IbvError, IbvResult};
use crate::ibverbs::memory::MemoryRegion;
use crate::ibverbs::queue_pair::QueuePair;
use crate::ibverbs::queue_pair::builder::QueuePairBuilder;
use crate::ibverbs::queue_pair::builder::queue_pair_builder::SetPd;
use ibverbs_sys::*;
use std::io;
use std::sync::Arc;
#[doc(alias = "ibv_pd")]
#[doc(alias = "ibv_alloc_pd")]
#[derive(Debug, Clone)]
pub struct ProtectionDomain {
pub(super) inner: Arc<ProtectionDomainInner>,
}
impl ProtectionDomain {
pub fn allocate(context: &Context) -> IbvResult<ProtectionDomain> {
let pd = unsafe { ibv_alloc_pd(context.inner.ctx) };
if pd.is_null() {
Err(IbvError::from_errno_with_msg(
io::Error::last_os_error()
.raw_os_error()
.expect("ibv_alloc_pd should set errno on error"),
"Failed to allocate protection domain",
))
} else {
log::debug!("ProtectionDomain allocated");
Ok(ProtectionDomain {
inner: Arc::new(ProtectionDomainInner {
context: context.clone(),
pd,
}),
})
}
}
pub fn context(&self) -> &Context {
&self.inner.context
}
pub fn create_qp(&self) -> QueuePairBuilder<'_, '_, '_, SetPd> {
QueuePair::builder().pd(self)
}
pub unsafe fn register_mr_with_permissions(
&self,
address: *mut u8,
length: usize,
access_flags: AccessFlags,
) -> IbvResult<MemoryRegion> {
unsafe { MemoryRegion::register_mr_with_access(self, address, length, access_flags) }
}
pub fn register_local_mr(&self, address: *mut u8, length: usize) -> IbvResult<MemoryRegion> {
MemoryRegion::register_local_mr(self, address, length)
}
pub fn register_local_mr_slice(&self, mem: &[u8]) -> IbvResult<MemoryRegion> {
MemoryRegion::register_local_mr(self, mem.as_ptr() as *mut u8, mem.len())
}
pub unsafe fn register_shared_mr(
&self,
address: *mut u8,
length: usize,
) -> IbvResult<MemoryRegion> {
unsafe { MemoryRegion::register_shared_mr(self, address, length) }
}
pub unsafe fn register_dmabuf(
&self,
fd: i32,
offset: u64,
length: usize,
iova: u64,
access_flags: AccessFlags,
) -> IbvResult<MemoryRegion> {
unsafe {
MemoryRegion::register_dmabuf_mr_with_access(
self,
fd,
offset,
length,
iova,
access_flags,
)
}
}
pub fn register_local_dmabuf(
&self,
fd: i32,
offset: u64,
length: usize,
iova: u64,
) -> IbvResult<MemoryRegion> {
MemoryRegion::register_local_dmabuf_mr(self, fd, offset, length, iova)
}
pub unsafe fn register_shared_dmabuf(
&self,
fd: i32,
offset: u64,
length: usize,
iova: u64,
) -> IbvResult<MemoryRegion> {
unsafe { MemoryRegion::register_shared_dmabuf_mr(self, fd, offset, length, iova) }
}
}
pub(super) struct ProtectionDomainInner {
pub(super) context: Context,
pub(super) pd: *mut ibv_pd,
}
unsafe impl Sync for ProtectionDomainInner {}
unsafe impl Send for ProtectionDomainInner {}
impl Drop for ProtectionDomainInner {
fn drop(&mut self) {
log::debug!("ProtectionDomain deallocated");
let errno = unsafe { ibv_dealloc_pd(self.pd) };
if errno != 0 {
let error =
IbvError::from_errno_with_msg(errno, "Failed to deallocate protection domain");
log::error!("{error}");
}
}
}
impl std::fmt::Debug for ProtectionDomainInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ProtectionDomainInner")
.field("handle", &(unsafe { *self.pd }).handle)
.field("context", &self.context)
.finish()
}
}