Skip to main content

rdma_io/
pd.rs

1//! Protection Domain.
2
3use std::sync::Arc;
4
5use rdma_io_sys::ibverbs::*;
6
7use crate::Result;
8use crate::cq::CompletionQueue;
9use crate::device::Context;
10use crate::error::from_ptr;
11use crate::mr::{AccessFlags, MemoryRegion, OwnedMemoryRegion};
12use crate::qp::{QpInitAttr, QueuePair};
13
14/// An RDMA Protection Domain (`ibv_pd`).
15///
16/// All memory registrations and QPs belong to a PD.
17pub struct ProtectionDomain {
18    pub(crate) inner: *mut ibv_pd,
19    pub(crate) ctx: Arc<Context>,
20}
21
22// Safety: ibv_pd is thread-safe.
23unsafe impl Send for ProtectionDomain {}
24unsafe impl Sync for ProtectionDomain {}
25
26impl Drop for ProtectionDomain {
27    fn drop(&mut self) {
28        let ret = unsafe { ibv_dealloc_pd(self.inner) };
29        if ret != 0 {
30            tracing::error!(
31                "ibv_dealloc_pd failed: {}",
32                std::io::Error::from_raw_os_error(-ret)
33            );
34        }
35    }
36}
37
38impl ProtectionDomain {
39    /// Allocate a new PD on the given context.
40    pub fn new(ctx: Arc<Context>) -> Result<Arc<Self>> {
41        let pd = from_ptr(unsafe { ibv_alloc_pd(ctx.inner) })?;
42        Ok(Arc::new(Self { inner: pd, ctx }))
43    }
44
45    /// Wrap a raw `ibv_pd` pointer.
46    ///
47    /// # Safety
48    /// The pointer must be valid and the caller must ensure `ctx` is the
49    /// correct parent context.
50    pub unsafe fn from_raw(pd: *mut ibv_pd, ctx: Arc<Context>) -> Arc<Self> {
51        Arc::new(Self { inner: pd, ctx })
52    }
53
54    /// Register a borrowed memory region.
55    ///
56    /// The returned `MemoryRegion` borrows `buf` and keeps `self` alive via `Arc`.
57    pub fn reg_mr<'a>(
58        self: &Arc<Self>,
59        buf: &'a mut [u8],
60        access: AccessFlags,
61    ) -> Result<MemoryRegion<'a>> {
62        let mr = from_ptr(unsafe {
63            ibv_reg_mr(
64                self.inner,
65                buf.as_mut_ptr().cast(),
66                buf.len() as u64,
67                access.bits() as i32,
68            )
69        })?;
70        Ok(MemoryRegion {
71            inner: mr,
72            _pd: Arc::clone(self),
73            _lifetime: std::marker::PhantomData,
74        })
75    }
76
77    /// Register an owned memory region.
78    ///
79    /// The buffer is moved into the `OwnedMemoryRegion` and freed when it is dropped.
80    pub fn reg_mr_owned(
81        self: &Arc<Self>,
82        buf: Vec<u8>,
83        access: AccessFlags,
84    ) -> Result<OwnedMemoryRegion> {
85        let mut buf = buf.into_boxed_slice();
86        let mr = from_ptr(unsafe {
87            ibv_reg_mr(
88                self.inner,
89                buf.as_mut_ptr().cast(),
90                buf.len() as u64,
91                access.bits() as i32,
92            )
93        })?;
94        Ok(OwnedMemoryRegion {
95            inner: mr,
96            _pd: Arc::clone(self),
97            _buf: buf,
98        })
99    }
100
101    /// Create a Queue Pair on this PD.
102    pub fn create_qp(
103        self: &Arc<Self>,
104        send_cq: &Arc<CompletionQueue>,
105        recv_cq: &Arc<CompletionQueue>,
106        init_attr: &QpInitAttr,
107    ) -> Result<QueuePair> {
108        let mut raw_attr = ibv_qp_init_attr {
109            send_cq: send_cq.inner,
110            recv_cq: recv_cq.inner,
111            cap: ibv_qp_cap {
112                max_send_wr: init_attr.max_send_wr,
113                max_recv_wr: init_attr.max_recv_wr,
114                max_send_sge: init_attr.max_send_sge,
115                max_recv_sge: init_attr.max_recv_sge,
116                max_inline_data: init_attr.max_inline_data,
117            },
118            qp_type: init_attr.qp_type.as_raw(),
119            sq_sig_all: i32::from(init_attr.sq_sig_all),
120            ..Default::default()
121        };
122        let qp = from_ptr(unsafe { ibv_create_qp(self.inner, &mut raw_attr) })?;
123        Ok(QueuePair {
124            inner: qp,
125            _pd: Arc::clone(self),
126            _send_cq: Arc::clone(send_cq),
127            _recv_cq: Arc::clone(recv_cq),
128        })
129    }
130
131    /// Raw pointer (for advanced/FFI use).
132    pub fn as_raw(&self) -> *mut ibv_pd {
133        self.inner
134    }
135
136    /// The parent context.
137    pub fn context(&self) -> &Arc<Context> {
138        &self.ctx
139    }
140}
141
142impl Context {
143    /// Allocate a Protection Domain.
144    pub fn alloc_pd(self: &Arc<Self>) -> Result<Arc<ProtectionDomain>> {
145        ProtectionDomain::new(Arc::clone(self))
146    }
147}