use crate::{
completion_queue::WorkRequestId,
memory_region::{
local::{LocalMrReadAccess, LocalMrWriteAccess},
remote::{RemoteMrReadAccess, RemoteMrWriteAccess},
},
};
use clippy_utilities::Cast;
use rdma_sys::{ibv_recv_wr, ibv_send_flags, ibv_send_wr, ibv_sge, ibv_wr_opcode};
use std::borrow::Borrow;
#[repr(C)]
pub(crate) struct SendWr {
inner: ibv_send_wr,
sges: Vec<ibv_sge>,
}
impl SendWr {
fn new<LR>(lms: &[&LR], wr_id: WorkRequestId) -> Self
where
LR: LocalMrReadAccess,
{
assert!(!lms.is_empty());
let mut sges: Vec<ibv_sge> = lms
.iter()
.map(|lm| {
let lm: &LR = lm.borrow();
sge_from_mr(lm)
})
.collect();
let mut inner = unsafe { std::mem::zeroed::<ibv_send_wr>() };
inner.next = std::ptr::null_mut();
inner.wr_id = wr_id.into();
inner.sg_list = sges.as_mut_ptr();
inner.num_sge = sges.len().cast();
Self { inner, sges }
}
pub(crate) fn new_send<LR>(lms: &[&LR], wr_id: WorkRequestId, imm: Option<u32>) -> Self
where
LR: LocalMrReadAccess,
{
let mut sr = Self::new(lms, wr_id);
sr.inner.send_flags = ibv_send_flags::IBV_SEND_SIGNALED.0;
match imm {
None => sr.inner.opcode = ibv_wr_opcode::IBV_WR_SEND,
Some(imm_num) => {
sr.inner.opcode = ibv_wr_opcode::IBV_WR_SEND_WITH_IMM;
sr.inner.imm_data_invalidated_rkey_union.imm_data = imm_num;
}
}
sr
}
#[allow(clippy::as_conversions)] pub(crate) fn new_read<LW, RR>(lms: &[&mut LW], wr_id: WorkRequestId, rm: &RR) -> Self
where
LW: LocalMrWriteAccess,
RR: RemoteMrReadAccess,
{
assert!(!lms.is_empty());
let mut sges: Vec<ibv_sge> = lms
.iter()
.map(|lm| {
let lm: &LW = lm.borrow();
sge_from_mr(lm)
})
.collect();
let mut inner = unsafe { std::mem::zeroed::<ibv_send_wr>() };
inner.next = std::ptr::null_mut();
inner.wr_id = wr_id.into();
inner.sg_list = sges.as_mut_ptr();
inner.num_sge = sges.len().cast();
let mut sr = Self { inner, sges };
sr.inner.opcode = ibv_wr_opcode::IBV_WR_RDMA_READ;
sr.inner.send_flags = ibv_send_flags::IBV_SEND_SIGNALED.0;
sr.inner.wr.rdma.remote_addr = rm.addr().cast();
sr.inner.wr.rdma.rkey = rm.rkey();
sr
}
#[allow(clippy::as_conversions)] pub(crate) fn new_write<LR, RW>(
lms: &[&LR],
wr_id: WorkRequestId,
rm: &mut RW,
imm: Option<u32>,
) -> Self
where
LR: LocalMrReadAccess,
RW: RemoteMrWriteAccess,
{
let mut sr = Self::new(lms, wr_id);
sr.inner.send_flags = ibv_send_flags::IBV_SEND_SIGNALED.0;
sr.inner.wr.rdma.remote_addr = rm.addr().cast();
sr.inner.wr.rdma.rkey = rm.rkey();
match imm {
Some(imm_num) => {
sr.inner.opcode = ibv_wr_opcode::IBV_WR_RDMA_WRITE_WITH_IMM;
sr.inner.imm_data_invalidated_rkey_union.imm_data = imm_num;
sr.inner.wr.rdma.remote_addr = rm.addr().cast();
sr.inner.wr.rdma.rkey = rm.rkey().cast();
}
None => sr.inner.opcode = ibv_wr_opcode::IBV_WR_RDMA_WRITE,
}
sr
}
}
impl AsRef<ibv_send_wr> for SendWr {
fn as_ref(&self) -> &ibv_send_wr {
&self.inner
}
}
impl<'lm> AsMut<ibv_send_wr> for SendWr {
fn as_mut(&mut self) -> &mut ibv_send_wr {
&mut self.inner
}
}
#[repr(C)]
pub(crate) struct RecvWr {
inner: ibv_recv_wr,
sges: Vec<ibv_sge>,
}
impl RecvWr {
fn new<LW>(lms: &[&mut LW], wr_id: WorkRequestId) -> Self
where
LW: LocalMrWriteAccess,
{
assert!(!lms.is_empty());
let mut sges: Vec<ibv_sge> = lms
.iter()
.map(|lm| {
let lm: &LW = lm.borrow();
sge_from_mr(lm)
})
.collect();
let mut inner = unsafe { std::mem::zeroed::<ibv_recv_wr>() };
inner.next = std::ptr::null_mut();
inner.wr_id = wr_id.into();
inner.sg_list = sges.as_mut_ptr();
inner.num_sge = sges.len().cast();
Self { inner, sges }
}
pub(crate) fn new_recv<LW>(lms: &[&mut LW], wr_id: WorkRequestId) -> Self
where
LW: LocalMrWriteAccess,
{
Self::new(lms, wr_id)
}
}
impl AsRef<ibv_recv_wr> for RecvWr {
fn as_ref(&self) -> &ibv_recv_wr {
&self.inner
}
}
impl AsMut<ibv_recv_wr> for RecvWr {
fn as_mut(&mut self) -> &mut ibv_recv_wr {
&mut self.inner
}
}
fn sge_from_mr<LR>(lmr: &LR) -> ibv_sge
where
LR: LocalMrReadAccess,
{
ibv_sge {
addr: lmr.addr().cast(),
length: lmr.length().cast(),
lkey: unsafe { lmr.lkey_unchecked() },
}
}