Skip to content

Commit dc8d6bc

Browse files
authored
Expose context gid table and allow setting qp gid (#45)
1 parent 122f5d3 commit dc8d6bc

File tree

3 files changed

+87
-13
lines changed

3 files changed

+87
-13
lines changed

ibverbs-sys/build.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ fn main() {
5252
.header("vendor/rdma-core/libibverbs/verbs.h")
5353
.clang_arg(format!("-I{built_in}/include/"))
5454
.allowlist_function("ibv_.*")
55+
.allowlist_function("_ibv_.*")
5556
.allowlist_type("ibv_.*")
5657
.allowlist_var("IBV_LINK_LAYER_.*")
5758
.bitfield_enum("ibv_access_flags")

ibverbs/examples/loopback.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ fn main() {
1212

1313
let qp_builder = pd
1414
.create_qp(&cq, &cq, ibverbs::ibv_qp_type::IBV_QPT_RC)
15+
.set_gid_index(1)
1516
.build()
1617
.unwrap();
1718

ibverbs/src/lib.rs

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ use std::ptr;
7676
const PORT_NUM: u8 = 1;
7777

7878
/// Direct access to low-level libverbs FFI.
79+
pub use ffi::ibv_gid_type;
7980
pub use ffi::ibv_qp_type;
8081
pub use ffi::ibv_wc;
8182
pub use ffi::ibv_wc_opcode;
@@ -323,7 +324,7 @@ impl<'devlist> Device<'devlist> {
323324
pub struct Context {
324325
ctx: *mut ffi::ibv_context,
325326
port_attr: ffi::ibv_port_attr,
326-
gid: Gid,
327+
gid_table: Vec<GidEntry>,
327328
}
328329

329330
unsafe impl Sync for Context {}
@@ -377,17 +378,29 @@ impl Context {
377378
}
378379
}
379380

380-
// let mut gid = ffi::ibv_gid::default();
381-
let mut gid = Gid::default();
382-
let ok = unsafe { ffi::ibv_query_gid(ctx, PORT_NUM, 0, gid.as_mut()) };
383-
if ok != 0 {
384-
return Err(io::Error::last_os_error());
381+
let mut gid_table = vec![ffi::ibv_gid_entry::default(); port_attr.gid_tbl_len as usize];
382+
let num_entries = unsafe {
383+
ffi::_ibv_query_gid_table(
384+
ctx,
385+
gid_table.as_mut_ptr(),
386+
gid_table.len(),
387+
0,
388+
size_of::<ffi::ibv_gid_entry>(),
389+
)
390+
};
391+
if num_entries < 0 {
392+
return Err(io::Error::new(
393+
io::ErrorKind::Other,
394+
format!("failed to query gid table, error={}", -num_entries),
395+
));
385396
}
397+
gid_table.truncate(num_entries as usize);
398+
let gid_table = gid_table.into_iter().map(GidEntry::from).collect();
386399

387400
Ok(Context {
388401
ctx,
389402
port_attr,
390-
gid,
403+
gid_table,
391404
})
392405
}
393406

@@ -449,6 +462,11 @@ impl Context {
449462
Ok(ProtectionDomain { ctx: self, pd })
450463
}
451464
}
465+
466+
/// Returns the valid GID table entries of this RDMA device context.
467+
pub fn gid_table(&self) -> &[GidEntry] {
468+
&self.gid_table
469+
}
452470
}
453471

454472
impl Drop for Context {
@@ -542,6 +560,7 @@ pub struct QueuePairBuilder<'res> {
542560
recv: &'res CompletionQueue<'res>,
543561
max_recv_wr: u32,
544562

563+
gid_index: Option<u32>,
545564
max_send_sge: u32,
546565
max_recv_sge: u32,
547566
max_inline_data: u32,
@@ -599,6 +618,7 @@ impl<'res> QueuePairBuilder<'res> {
599618
ctx: 0,
600619
pd,
601620

621+
gid_index: None,
602622
send,
603623
max_send_wr,
604624
recv,
@@ -658,6 +678,17 @@ impl<'res> QueuePairBuilder<'res> {
658678
self
659679
}
660680

681+
/// Sets the GID table index that should be used for the new `QueuePair`.
682+
/// The entry corresponds to the index in `Context::gid_table()`. This is only used if the
683+
/// `QueuePairEndpoint` that is passed to `QueuePair::handshake()` has a `gid`.
684+
///
685+
/// Defaults to unset.
686+
pub fn set_gid_index(&mut self, gid_index: u32) -> &mut Self {
687+
assert!(gid_index < self.pd.ctx.gid_table.len() as u32);
688+
self.gid_index = Some(gid_index);
689+
self
690+
}
691+
661692
/// Sets the minimum RNR NAK Timer Field Value for the new `QueuePair`.
662693
///
663694
/// Defaults to 16 (2.56 ms delay).
@@ -913,6 +944,7 @@ impl<'res> QueuePairBuilder<'res> {
913944
_phantom: PhantomData,
914945
qp,
915946
},
947+
gid_index: self.gid_index,
916948
access: self.access,
917949
timeout: self.timeout,
918950
retry_count: self.retry_count,
@@ -956,6 +988,7 @@ pub struct PreparedQueuePair<'res> {
956988
qp: QueuePair<'res>,
957989

958990
// carried from builder
991+
gid_index: Option<u32>,
959992
/// only valid for RC and UC
960993
access: Option<ffi::ibv_access_flags>,
961994
/// only valid for RC
@@ -1006,16 +1039,14 @@ impl Gid {
10061039
/// Expose the subnet_prefix component of the `Gid` as a u64. This is
10071040
/// equivalent to accessing the `global.subnet_prefix` component of the
10081041
/// `ffi::ibv_gid` union.
1009-
#[allow(dead_code)]
1010-
fn subnet_prefix(&self) -> u64 {
1042+
pub fn subnet_prefix(&self) -> u64 {
10111043
u64::from_be_bytes(self.raw[..8].try_into().unwrap())
10121044
}
10131045

10141046
/// Expose the interface_id component of the `Gid` as a u64. This is
10151047
/// equivalent to accessing the `global.interface_id` component of the
10161048
/// `ffi::ibv_gid` union.
1017-
#[allow(dead_code)]
1018-
fn interface_id(&self) -> u64 {
1049+
pub fn interface_id(&self) -> u64 {
10191050
u64::from_be_bytes(self.raw[8..].try_into().unwrap())
10201051
}
10211052
}
@@ -1046,6 +1077,38 @@ impl AsMut<ffi::ibv_gid> for Gid {
10461077
}
10471078
}
10481079

1080+
/// A Global identifier entry for ibv.
1081+
///
1082+
/// This struct acts as a rust wrapper for `ffi::ibv_gid_entry`. We use it instead of
1083+
/// `ffi::ibv_gid_entry` because `ffi::ibv_gid` is wrapped by `Gid`.
1084+
#[derive(Debug, Clone)]
1085+
pub struct GidEntry {
1086+
/// The GID entry.
1087+
pub gid: Gid,
1088+
/// The GID table index of this entry.
1089+
pub gid_index: u32,
1090+
/// The port number that this GID belongs to.
1091+
pub port_num: u32,
1092+
/// enum ibv_gid_type, can be one of IBV_GID_TYPE_IB, IBV_GID_TYPE_ROCE_V1 or IBV_GID_TYPE_ROCE_V2.
1093+
pub gid_type: ffi::ibv_gid_type,
1094+
/// The interface index of the net device associated with this GID.
1095+
///
1096+
/// It is 0 if there is no net device associated with it.
1097+
pub ndev_ifindex: u32,
1098+
}
1099+
1100+
impl From<ffi::ibv_gid_entry> for GidEntry {
1101+
fn from(gid_entry: ffi::ibv_gid_entry) -> Self {
1102+
Self {
1103+
gid: gid_entry.gid.into(),
1104+
gid_index: gid_entry.gid_index,
1105+
port_num: gid_entry.port_num,
1106+
gid_type: gid_entry.gid_type as ffi::ibv_gid_type,
1107+
ndev_ifindex: gid_entry.ndev_ifindex,
1108+
}
1109+
}
1110+
}
1111+
10491112
/// An identifier for the network endpoint of a `QueuePair`.
10501113
///
10511114
/// Internally, this contains the `QueuePair`'s `qp_num`, as well as the context's `lid` and `gid`.
@@ -1066,11 +1129,16 @@ impl<'res> PreparedQueuePair<'res> {
10661129
/// This endpoint will need to be communicated to the `QueuePair` on the remote end.
10671130
pub fn endpoint(&self) -> QueuePairEndpoint {
10681131
let num = unsafe { &*self.qp.qp }.qp_num;
1069-
1132+
let gid = self.gid_index.map(|gid_index| {
1133+
// NOTE: bounds check happened in `set_gid_index`.
1134+
let gid_entry = &self.ctx.gid_table[gid_index as usize];
1135+
assert_eq!(gid_entry.gid_index, gid_index);
1136+
gid_entry.gid
1137+
});
10701138
QueuePairEndpoint {
10711139
num,
10721140
lid: self.ctx.port_attr.lid,
1073-
gid: Some(self.ctx.gid),
1141+
gid,
10741142
}
10751143
}
10761144

@@ -1145,6 +1213,10 @@ impl<'res> PreparedQueuePair<'res> {
11451213
attr.ah_attr.is_global = 1;
11461214
attr.ah_attr.grh.dgid = gid.into();
11471215
attr.ah_attr.grh.hop_limit = 0xff;
1216+
attr.ah_attr.grh.sgid_index = self
1217+
.gid_index
1218+
.ok_or_else(|| io::Error::other("gid was set for remote but not local"))?
1219+
as u8;
11481220
}
11491221
let mut mask = ffi::ibv_qp_attr_mask::IBV_QP_STATE
11501222
| ffi::ibv_qp_attr_mask::IBV_QP_AV

0 commit comments

Comments
 (0)