@@ -76,6 +76,7 @@ use std::ptr;
76
76
const PORT_NUM : u8 = 1 ;
77
77
78
78
/// Direct access to low-level libverbs FFI.
79
+ pub use ffi:: ibv_gid_type;
79
80
pub use ffi:: ibv_qp_type;
80
81
pub use ffi:: ibv_wc;
81
82
pub use ffi:: ibv_wc_opcode;
@@ -323,7 +324,7 @@ impl<'devlist> Device<'devlist> {
323
324
pub struct Context {
324
325
ctx : * mut ffi:: ibv_context ,
325
326
port_attr : ffi:: ibv_port_attr ,
326
- gid : Gid ,
327
+ gid_table : Vec < GidEntry > ,
327
328
}
328
329
329
330
unsafe impl Sync for Context { }
@@ -377,17 +378,29 @@ impl Context {
377
378
}
378
379
}
379
380
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
+ ) ) ;
385
396
}
397
+ gid_table. truncate ( num_entries as usize ) ;
398
+ let gid_table = gid_table. into_iter ( ) . map ( GidEntry :: from) . collect ( ) ;
386
399
387
400
Ok ( Context {
388
401
ctx,
389
402
port_attr,
390
- gid ,
403
+ gid_table ,
391
404
} )
392
405
}
393
406
@@ -449,6 +462,11 @@ impl Context {
449
462
Ok ( ProtectionDomain { ctx : self , pd } )
450
463
}
451
464
}
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
+ }
452
470
}
453
471
454
472
impl Drop for Context {
@@ -542,6 +560,7 @@ pub struct QueuePairBuilder<'res> {
542
560
recv : & ' res CompletionQueue < ' res > ,
543
561
max_recv_wr : u32 ,
544
562
563
+ gid_index : Option < u32 > ,
545
564
max_send_sge : u32 ,
546
565
max_recv_sge : u32 ,
547
566
max_inline_data : u32 ,
@@ -599,6 +618,7 @@ impl<'res> QueuePairBuilder<'res> {
599
618
ctx : 0 ,
600
619
pd,
601
620
621
+ gid_index : None ,
602
622
send,
603
623
max_send_wr,
604
624
recv,
@@ -658,6 +678,17 @@ impl<'res> QueuePairBuilder<'res> {
658
678
self
659
679
}
660
680
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
+
661
692
/// Sets the minimum RNR NAK Timer Field Value for the new `QueuePair`.
662
693
///
663
694
/// Defaults to 16 (2.56 ms delay).
@@ -913,6 +944,7 @@ impl<'res> QueuePairBuilder<'res> {
913
944
_phantom : PhantomData ,
914
945
qp,
915
946
} ,
947
+ gid_index : self . gid_index ,
916
948
access : self . access ,
917
949
timeout : self . timeout ,
918
950
retry_count : self . retry_count ,
@@ -956,6 +988,7 @@ pub struct PreparedQueuePair<'res> {
956
988
qp : QueuePair < ' res > ,
957
989
958
990
// carried from builder
991
+ gid_index : Option < u32 > ,
959
992
/// only valid for RC and UC
960
993
access : Option < ffi:: ibv_access_flags > ,
961
994
/// only valid for RC
@@ -1006,16 +1039,14 @@ impl Gid {
1006
1039
/// Expose the subnet_prefix component of the `Gid` as a u64. This is
1007
1040
/// equivalent to accessing the `global.subnet_prefix` component of the
1008
1041
/// `ffi::ibv_gid` union.
1009
- #[ allow( dead_code) ]
1010
- fn subnet_prefix ( & self ) -> u64 {
1042
+ pub fn subnet_prefix ( & self ) -> u64 {
1011
1043
u64:: from_be_bytes ( self . raw [ ..8 ] . try_into ( ) . unwrap ( ) )
1012
1044
}
1013
1045
1014
1046
/// Expose the interface_id component of the `Gid` as a u64. This is
1015
1047
/// equivalent to accessing the `global.interface_id` component of the
1016
1048
/// `ffi::ibv_gid` union.
1017
- #[ allow( dead_code) ]
1018
- fn interface_id ( & self ) -> u64 {
1049
+ pub fn interface_id ( & self ) -> u64 {
1019
1050
u64:: from_be_bytes ( self . raw [ 8 ..] . try_into ( ) . unwrap ( ) )
1020
1051
}
1021
1052
}
@@ -1046,6 +1077,38 @@ impl AsMut<ffi::ibv_gid> for Gid {
1046
1077
}
1047
1078
}
1048
1079
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
+
1049
1112
/// An identifier for the network endpoint of a `QueuePair`.
1050
1113
///
1051
1114
/// 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> {
1066
1129
/// This endpoint will need to be communicated to the `QueuePair` on the remote end.
1067
1130
pub fn endpoint ( & self ) -> QueuePairEndpoint {
1068
1131
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
+ } ) ;
1070
1138
QueuePairEndpoint {
1071
1139
num,
1072
1140
lid : self . ctx . port_attr . lid ,
1073
- gid : Some ( self . ctx . gid ) ,
1141
+ gid,
1074
1142
}
1075
1143
}
1076
1144
@@ -1145,6 +1213,10 @@ impl<'res> PreparedQueuePair<'res> {
1145
1213
attr. ah_attr . is_global = 1 ;
1146
1214
attr. ah_attr . grh . dgid = gid. into ( ) ;
1147
1215
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 ;
1148
1220
}
1149
1221
let mut mask = ffi:: ibv_qp_attr_mask:: IBV_QP_STATE
1150
1222
| ffi:: ibv_qp_attr_mask:: IBV_QP_AV
0 commit comments