ibverbs_rs/ibverbs/queue_pair/config.rs
1//! Queue pair tuning parameters.
2//!
3//! This module provides typed wrappers for the hardware knobs that control queue pair
4//! behaviour during connection setup:
5//!
6//! | Type | Controls |
7//! |------|----------|
8//! | [`PacketSequenceNumber`] | Initial PSN for send and receive queues |
9//! | [`MaximumTransferUnit`] | Per-packet payload size for the path |
10//! | [`MinRnrTimer`] | How long the sender waits after an RNR NAK before retrying |
11//! | [`MaxRnrRetries`] | How many RNR retries before the QP raises an error |
12//! | [`AckTimeout`] | How long to wait for an ACK before retransmitting |
13//! | [`MaxAckRetries`] | How many ACK-timeout retransmissions before the QP raises an error |
14//!
15//! All types implement [`Default`] with conservative values suitable for most workloads.
16
17use std::time::Duration;
18
19/// A 24-bit Packet Sequence Number (PSN).
20#[derive(Debug, Copy, Clone, Default)]
21pub struct PacketSequenceNumber(u32);
22
23impl PacketSequenceNumber {
24 /// Creates a new PSN. Returns `None` if the value exceeds the 24-bit limit (`0xFFFFFF`).
25 pub const fn new(psn: u32) -> Option<Self> {
26 if psn < (1 << 24) {
27 Some(Self(psn))
28 } else {
29 None
30 }
31 }
32
33 /// Returns the raw 24-bit value.
34 pub const fn code(&self) -> u32 {
35 self.0
36 }
37}
38
39/// The Maximum Transfer Unit (MTU) for the path.
40#[derive(Debug, Copy, Clone, Default)]
41pub enum MaximumTransferUnit {
42 MTU256 = 1,
43 MTU512 = 2,
44 MTU1024 = 3,
45 MTU2048 = 4,
46 #[default]
47 MTU4096 = 5,
48}
49
50impl MaximumTransferUnit {
51 /// Returns the ibverbs code for this MTU.
52 pub const fn code(&self) -> u8 {
53 *self as u8
54 }
55}
56
57/// Minimum RNR NAK Timer Field Value.
58///
59/// When an incoming message arrives but no Receive WQE is posted, the QP sends an
60/// RNR NAK (Receiver Not Ready) to the sender. This timer tells the sender how long
61/// to wait before retrying.
62///
63/// See [RDMAMojo](https://www.rdmamojo.com/2013/01/12/ibv_modify_qp/) for details.
64#[derive(Debug, Copy, Clone)]
65pub struct MinRnrTimer(u8);
66
67impl MinRnrTimer {
68 /// Value 0 encodes the maximum duration (approx 655.36 ms).
69 const DURATION_ZERO: Duration = Duration::from_micros(655360);
70
71 /// Lookup table for codes 1..31 mapping to durations in microseconds.
72 /// Derived from InfiniBand Architecture Specification Vol 1.
73 const DURATION_TABLE: [Duration; 31] = [
74 Duration::from_micros(10), // 0.01 ms
75 Duration::from_micros(20), // 0.02 ms
76 Duration::from_micros(30), // 0.03 ms
77 Duration::from_micros(40), // 0.04 ms
78 Duration::from_micros(60), // 0.06 ms
79 Duration::from_micros(80), // 0.08 ms
80 Duration::from_micros(120), // 0.12 ms
81 Duration::from_micros(160), // 0.16 ms
82 Duration::from_micros(240), // 0.24 ms
83 Duration::from_micros(320), // 0.32 ms
84 Duration::from_micros(480), // 0.48 ms
85 Duration::from_micros(640), // 0.64 ms
86 Duration::from_micros(960), // 0.96 ms
87 Duration::from_micros(1280), // 1.28 ms
88 Duration::from_micros(1920), // 1.92 ms
89 Duration::from_micros(2560), // 2.56 ms
90 Duration::from_micros(3840), // 3.84 ms
91 Duration::from_micros(5120), // 5.12 ms
92 Duration::from_micros(7680), // 7.68 ms
93 Duration::from_micros(10240), // 10.24 ms
94 Duration::from_micros(15360), // 15.36 ms
95 Duration::from_micros(20480), // 20.48 ms
96 Duration::from_micros(30720), // 30.72 ms
97 Duration::from_micros(40960), // 40.96 ms
98 Duration::from_micros(61440), // 61.44 ms
99 Duration::from_micros(81920), // 81.92 ms
100 Duration::from_micros(122880), // 122.88 ms
101 Duration::from_micros(163840), // 163.84 ms
102 Duration::from_micros(245760), // 245.76 ms
103 Duration::from_micros(327680), // 327.68 ms
104 Duration::from_micros(491520), // 491.52 ms
105 ];
106
107 /// Creates a timer from a raw 5-bit code (1-31). Returns `None` if out of range.
108 pub const fn limited(code: u8) -> Option<Self> {
109 if code > 0 && code < 32 {
110 Some(MinRnrTimer(code))
111 } else {
112 None
113 }
114 }
115
116 /// Finds the smallest RNR timer code that represents a duration greater than `timeout`.
117 // binary_search on a 31-element table yields idx ≤ 30, so idx+1 ≤ 31, fits in u8
118 #[allow(clippy::cast_possible_truncation)]
119 pub fn min_duration_greater_than(timeout: Duration) -> Self {
120 MinRnrTimer(match Self::DURATION_TABLE.binary_search(&timeout) {
121 Ok(idx) => (idx + 1) as u8, // Exact match found
122 Err(idx) if idx < Self::DURATION_TABLE.len() => (idx + 1) as u8, // Min greater
123 _ => 0, // Zero encodes greatest duration
124 })
125 }
126
127 /// Returns the approximate duration represented by this timer code.
128 pub fn duration(&self) -> Duration {
129 if self.0 > 0 {
130 *Self::DURATION_TABLE
131 .get(self.0 as usize - 1)
132 .expect("rnr_timeout cannot be greater than 31")
133 } else {
134 Self::DURATION_ZERO
135 }
136 }
137
138 /// Returns the ibverbs code for this `MinRnrTimer`.
139 pub const fn code(&self) -> u8 {
140 self.0
141 }
142}
143
144impl Default for MinRnrTimer {
145 fn default() -> MinRnrTimer {
146 MinRnrTimer(16)
147 }
148}
149
150/// Configures how many times the sender should retry after receiving an RNR NACK.
151///
152/// If the receiver is busy (no WQEs posted), it sends an RNR NACK. This setting controls
153/// how many times the sender retries before giving up and reporting an error.
154#[derive(Debug, Copy, Clone)]
155pub enum MaxRnrRetries {
156 /// Retry a specific number of times (0-6).
157 Limited(u8),
158 /// Retry infinitely until the receiver posts a WQE.
159 Unlimited,
160}
161
162impl MaxRnrRetries {
163 /// Retry `retries` times. Returns `None` if `retries > 6`.
164 pub const fn limited(retries: u8) -> Option<Self> {
165 if retries < 7 {
166 Some(MaxRnrRetries::Limited(retries))
167 } else {
168 None
169 }
170 }
171
172 /// Retry forever.
173 pub const fn unlimited() -> Self {
174 MaxRnrRetries::Unlimited
175 }
176
177 /// Returns the number of retries, or `None` if `Unlimited`.
178 pub const fn retries(&self) -> Option<u8> {
179 match self {
180 MaxRnrRetries::Limited(retries) => Some(*retries),
181 MaxRnrRetries::Unlimited => None,
182 }
183 }
184
185 /// Returns the ibverbs code for this `MaxRnrRetries`.
186 pub const fn code(&self) -> u8 {
187 match self {
188 MaxRnrRetries::Limited(retries) => *retries,
189 MaxRnrRetries::Unlimited => 7,
190 }
191 }
192}
193
194impl Default for MaxRnrRetries {
195 fn default() -> MaxRnrRetries {
196 MaxRnrRetries::Limited(6)
197 }
198}
199
200/// Configures the transport-level Acknowledgement Timeout.
201///
202/// This determines how long the QP waits for an ACK from the remote peer before
203/// retransmitting a packet.
204///
205/// Formula: `4.096 microseconds * 2^timeout`.
206#[derive(Debug, Copy, Clone)]
207pub enum AckTimeout {
208 /// Timeout code (1-31).
209 Limited(u8),
210 /// Wait infinitely (useful for debugging, prevents retransmission).
211 Unlimited,
212}
213
214impl AckTimeout {
215 /// Creates a timeout from a raw code (1-31).
216 pub const fn limited(code: u8) -> Option<Self> {
217 if code > 0 && code < 32 {
218 Some(AckTimeout::Limited(code))
219 } else {
220 None
221 }
222 }
223
224 /// Wait infinitely (code 0).
225 pub const fn unlimited() -> Self {
226 AckTimeout::Unlimited
227 }
228
229 /// Calculates the smallest timeout code that covers the given `timeout` duration.
230 // code is checked to be in 1..31 before the cast
231 #[allow(clippy::cast_possible_truncation)]
232 pub const fn min_duration_greater_than(timeout: Duration) -> Option<Self> {
233 let code = (timeout.as_nanos() / 4096).next_power_of_two().ilog2();
234 if code > 0 && code < 32 {
235 Some(AckTimeout::Limited(code as u8))
236 } else {
237 None
238 }
239 }
240
241 /// Returns the approximate duration for this timeout.
242 pub fn duration(&self) -> Option<Duration> {
243 match self {
244 AckTimeout::Limited(code) => Some(Duration::from_nanos(4096u64 << code)),
245 AckTimeout::Unlimited => None,
246 }
247 }
248
249 /// Returns the ibverbs code for this `AckTimeout`.
250 pub const fn code(&self) -> u8 {
251 match self {
252 AckTimeout::Limited(code) => *code,
253 AckTimeout::Unlimited => 0,
254 }
255 }
256}
257
258impl Default for AckTimeout {
259 fn default() -> AckTimeout {
260 AckTimeout::Limited(4)
261 }
262}
263
264/// Configures the number of transport-level retransmissions.
265///
266/// If an ACK is not received within [`AckTimeout`], the QP retransmits.
267/// This controls how many times it retries before declaring the connection broken.
268#[derive(Debug, Copy, Clone)]
269pub struct MaxAckRetries(u8);
270
271impl MaxAckRetries {
272 /// Sets the number of retries (0-7).
273 pub const fn limited(retries: u8) -> Option<Self> {
274 if retries <= 7 {
275 Some(MaxAckRetries(retries))
276 } else {
277 None
278 }
279 }
280
281 /// Returns the number of retries.
282 pub const fn retries(&self) -> u8 {
283 self.0
284 }
285
286 /// Returns the ibverbs code for this `MaxAckRetries`.
287 pub const fn code(&self) -> u8 {
288 self.retries()
289 }
290}
291
292impl Default for MaxAckRetries {
293 fn default() -> MaxAckRetries {
294 MaxAckRetries(6)
295 }
296}