Skip to main content

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}