Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ser/der for QueuePairEndpoint #7

Merged
merged 5 commits into from
Apr 10, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[package]
name = "ibverbs"
version = "0.4.4"
edition = "2018"

description = "Bindings for RDMA ibverbs through rdma-core"
readme = "README.md"
Expand All @@ -26,5 +27,16 @@ exclude = ["vendor/rdma-core/build/"]
travis-ci = { repository = "jonhoo/rust-ibverbs" }
maintenance = { status = "looking-for-maintainer" }

[dependencies.serde]
version = "1.0"
optional = true
features = ["derive"]

[build-dependencies]
bindgen = "0.36"

[features]
default = ["serde"]

[dev-dependencies]
bincode = "1.3"
118 changes: 112 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
// avoid warnings about RDMAmojo, iWARP, InfiniBand, etc. not being in backticks
#![cfg_attr(feature = "cargo-clippy", allow(doc_markdown))]

use std::convert::TryInto;
use std::ffi::CStr;
use std::io;
use std::marker::PhantomData;
Expand All @@ -85,6 +86,9 @@ pub use ffi::ibv_wc;
pub use ffi::ibv_wc_opcode;
pub use ffi::ibv_wc_status;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// Access flags for use with `QueuePair` and `MemoryRegion`.
pub use ffi::ibv_access_flags;

Expand Down Expand Up @@ -260,7 +264,7 @@ impl<'devlist> Device<'devlist> {
pub struct Context {
ctx: *mut ffi::ibv_context,
port_attr: ffi::ibv_port_attr,
gid: ffi::ibv_gid,
gid: Gid,
}

unsafe impl Sync for Context {}
Expand Down Expand Up @@ -308,8 +312,9 @@ impl Context {
}
}

let mut gid = ffi::ibv_gid::default();
let ok = unsafe { ffi::ibv_query_gid(ctx, PORT_NUM, 0, &mut gid as *mut _) };
// let mut gid = ffi::ibv_gid::default();
let mut gid = Gid::default();
let ok = unsafe { ffi::ibv_query_gid(ctx, PORT_NUM, 0, gid.as_mut() as _) };
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
if ok != 0 {
return Err(io::Error::last_os_error());
}
Expand Down Expand Up @@ -766,14 +771,91 @@ pub struct PreparedQueuePair<'res> {
rnr_retry: u8,
}

/// A Global identifier for ibv.
///
/// This struct acts as a rust wrapper for `ffi::ibv_gid`. We use it instead of
/// `ffi::ibv_giv` because `ffi::ibv_gid` is actually an untagged union.
///
/// ```c
/// union ibv_gid {
/// uint8_t raw[16];
/// struct {
/// __be64 subnet_prefix;
/// __be64 interface_id;
/// } global;
/// };
/// ```
///
/// It appears that `global` exists for convenience, but can be safely ignored.
/// For continuity, the methods `subnet_prefix` and `interface_id` are provided.
/// These methods read the array as big endian, regardless of native cpu
/// endianness.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[repr(transparent)]
struct Gid {
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
raw: [u8; 16],
}

impl Gid {
/// Expose the subnet_prefix component of the `Gid` as a u64. This is
/// equivalent to accessing the `global.subnet_prefix` component of the
/// `ffi::ibv_gid` union.
#[allow(dead_code)]
fn subnet_prefix(&self) -> u64 {
u64::from_be_bytes(self.raw[..8].try_into().unwrap())
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
}

/// Expose the interface_id component of the `Gid` as a u64. This is
/// equivalent to accessing the `global.interface_id` component of the
/// `ffi::ibv_gid` union.
#[allow(dead_code)]
fn interface_id(&self) -> u64 {
u64::from_be_bytes(self.raw[8..].try_into().unwrap())
}
}

impl From<ffi::ibv_gid> for Gid {
fn from(gid: ffi::ibv_gid) -> Self {
Self {
raw: unsafe { gid.raw },
}
}
}

impl From<Gid> for ffi::ibv_gid {
fn from(mut gid: Gid) -> Self {
*gid.as_mut()
}
}

impl AsRef<ffi::ibv_gid> for Gid {
fn as_ref(&self) -> &ffi::ibv_gid {
unsafe { self.raw.as_ptr().cast::<ffi::ibv_gid>().as_ref().unwrap() }
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
}
}

impl AsMut<ffi::ibv_gid> for Gid {
fn as_mut(&mut self) -> &mut ffi::ibv_gid {
unsafe {
self.raw
.as_mut_ptr()
.cast::<ffi::ibv_gid>()
.as_mut()
.unwrap()
}
jonhoo marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// An identifier for the network endpoint of a `QueuePair`.
///
/// Internally, this contains the `QueuePair`'s `qp_num`, as well as the context's `lid` and `gid`.
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct QueuePairEndpoint {
num: u32,
lid: u16,
gid: ffi::ibv_gid,
gid: Gid,
}

impl<'res> PreparedQueuePair<'res> {
Expand Down Expand Up @@ -850,7 +932,7 @@ impl<'res> PreparedQueuePair<'res> {
attr.ah_attr.sl = 0;
attr.ah_attr.src_path_bits = 0;
attr.ah_attr.port_num = PORT_NUM;
attr.ah_attr.grh.dgid = remote.gid;
attr.ah_attr.grh.dgid = remote.gid.into();
attr.ah_attr.grh.hop_limit = 0xff;
let mask = ffi::ibv_qp_attr_mask::IBV_QP_STATE
| ffi::ibv_qp_attr_mask::IBV_QP_AV
Expand Down Expand Up @@ -1238,3 +1320,27 @@ impl<'a> Drop for QueuePair<'a> {
}
}
}

#[cfg(all(test, feature = "serde"))]
mod test_serde {
use super::*;
extern crate bincode;
#[test]
fn encode_decode() {
let qpe_default = QueuePairEndpoint {
num: 72,
lid: 9,
gid: Default::default(),
};

let mut qpe = qpe_default;
qpe.gid.raw = unsafe { std::mem::transmute([87_u64.to_be(), 192_u64.to_be()]) };
let encoded = bincode::serialize(&qpe).unwrap();

let decoded: QueuePairEndpoint = bincode::deserialize(&encoded).unwrap();
assert_eq!(decoded.gid.subnet_prefix(), 87);
assert_eq!(decoded.gid.interface_id(), 192);
assert_eq!(qpe, decoded);
assert_ne!(qpe, qpe_default);
}
}