rdma_sys/
verbs.rs

1use crate::*;
2
3use std::mem;
4use std::ptr;
5
6/// Inline functions from <infiniband/verbs.h>
7
8pub type ibv_advise_mr_advice = ib_uverbs_advise_mr_advice::Type;
9
10// ibv_qp_ex related inline functions
11#[inline]
12pub unsafe fn ibv_wr_atomic_cmp_swp(
13    qp: *mut ibv_qp_ex,
14    rkey: u32,
15    remote_addr: u64,
16    compare: u64,
17    swap: u64,
18) {
19    (*qp).wr_atomic_cmp_swp.unwrap()(qp, rkey, remote_addr, compare, swap);
20}
21
22#[inline]
23pub unsafe fn ibv_wr_atomic_fetch_add(qp: *mut ibv_qp_ex, rkey: u32, remote_addr: u64, add: u64) {
24    (*qp).wr_atomic_fetch_add.unwrap()(qp, rkey, remote_addr, add);
25}
26
27#[inline]
28pub unsafe fn ibv_wr_bind_mw(
29    qp: *mut ibv_qp_ex,
30    mw: *mut ibv_mw,
31    rkey: u32,
32    bind_info: *const ibv_mw_bind_info,
33) {
34    (*qp).wr_bind_mw.unwrap()(qp, mw, rkey, bind_info);
35}
36
37#[inline]
38pub unsafe fn ibv_wr_local_inv(qp: *mut ibv_qp_ex, invalidate_rkey: u32) {
39    (*qp).wr_local_inv.unwrap()(qp, invalidate_rkey);
40}
41
42#[inline]
43pub unsafe fn ibv_wr_rdma_read(qp: *mut ibv_qp_ex, rkey: u32, remote_addr: u64) {
44    (*qp).wr_rdma_read.unwrap()(qp, rkey, remote_addr);
45}
46
47#[inline]
48pub unsafe fn ibv_wr_rdma_write(qp: *mut ibv_qp_ex, rkey: u32, remote_addr: u64) {
49    (*qp).wr_rdma_write.unwrap()(qp, rkey, remote_addr);
50}
51
52#[inline]
53pub unsafe fn ibv_wr_rdma_write_imm(
54    qp: *mut ibv_qp_ex,
55    rkey: u32,
56    remote_addr: u64,
57    imm_data: __be32,
58) {
59    (*qp).wr_rdma_write_imm.unwrap()(qp, rkey, remote_addr, imm_data);
60}
61
62#[inline]
63pub unsafe fn ibv_wr_send(qp: *mut ibv_qp_ex) {
64    (*qp).wr_send.unwrap()(qp);
65}
66
67#[inline]
68pub unsafe fn ibv_wr_send_imm(qp: *mut ibv_qp_ex, imm_data: __be32) {
69    (*qp).wr_send_imm.unwrap()(qp, imm_data);
70}
71
72#[inline]
73pub unsafe fn ibv_wr_send_inv(qp: *mut ibv_qp_ex, invalidate_rkey: u32) {
74    (*qp).wr_send_inv.unwrap()(qp, invalidate_rkey);
75}
76
77#[inline]
78pub unsafe fn ibv_wr_send_tso(qp: *mut ibv_qp_ex, hdr: *mut c_void, hdr_sz: u16, mss: u16) {
79    (*qp).wr_send_tso.unwrap()(qp, hdr, hdr_sz, mss);
80}
81
82#[inline]
83pub unsafe fn ibv_wr_set_ud_addr(
84    qp: *mut ibv_qp_ex,
85    ah: *mut ibv_ah,
86    remote_qpn: u32,
87    remote_qkey: u32,
88) {
89    (*qp).wr_set_ud_addr.unwrap()(qp, ah, remote_qpn, remote_qkey);
90}
91
92#[inline]
93pub unsafe fn ibv_wr_set_xrc_srqn(qp: *mut ibv_qp_ex, remote_srqn: u32) {
94    (*qp).wr_set_xrc_srqn.unwrap()(qp, remote_srqn);
95}
96
97#[inline]
98pub unsafe fn ibv_wr_set_inline_data(qp: *mut ibv_qp_ex, addr: *mut c_void, length: usize) {
99    (*qp).wr_set_inline_data.unwrap()(qp, addr, length);
100}
101
102#[inline]
103pub unsafe fn ibv_wr_set_inline_data_list(
104    qp: *mut ibv_qp_ex,
105    num_buf: usize,
106    buf_list: *const ibv_data_buf,
107) {
108    (*qp).wr_set_inline_data_list.unwrap()(qp, num_buf, buf_list);
109}
110
111#[inline]
112pub unsafe fn ibv_wr_set_sge(qp: *mut ibv_qp_ex, lkey: u32, addr: u64, length: u32) {
113    (*qp).wr_set_sge.unwrap()(qp, lkey, addr, length);
114}
115
116#[inline]
117pub unsafe fn ibv_wr_set_sge_list(qp: *mut ibv_qp_ex, num_sge: usize, sg_list: *const ibv_sge) {
118    (*qp).wr_set_sge_list.unwrap()(qp, num_sge, sg_list);
119}
120
121#[inline]
122pub unsafe fn ibv_wr_start(qp: *mut ibv_qp_ex) {
123    (*qp).wr_start.unwrap()(qp);
124}
125
126#[inline]
127pub unsafe fn ibv_wr_complete(qp: *mut ibv_qp_ex) -> c_int {
128    (*qp).wr_complete.unwrap()(qp)
129}
130
131#[inline]
132pub unsafe fn ibv_wr_abort(qp: *mut ibv_qp_ex) {
133    (*qp).wr_abort.unwrap()(qp)
134}
135
136// ibv_cq_ex related inline functions
137#[inline]
138pub unsafe fn ibv_cq_ex_to_cq(cq: *mut ibv_cq_ex) -> *mut ibv_cq {
139    cq as *mut ibv_cq_ex as *mut ibv_cq
140}
141
142#[inline]
143pub unsafe fn ibv_start_poll(cq: *mut ibv_cq_ex, attr: *mut ibv_poll_cq_attr) -> c_int {
144    (*cq).start_poll.unwrap()(cq, attr)
145}
146
147#[inline]
148pub unsafe fn ibv_next_poll(cq: *mut ibv_cq_ex) -> c_int {
149    (*cq).next_poll.unwrap()(cq)
150}
151
152#[inline]
153pub unsafe fn ibv_end_poll(cq: *mut ibv_cq_ex) {
154    (*cq).end_poll.unwrap()(cq)
155}
156
157#[inline]
158pub unsafe fn ibv_wc_read_opcode(cq: *mut ibv_cq_ex) -> ibv_wc_opcode::Type {
159    (*cq).read_opcode.unwrap()(cq)
160}
161
162#[inline]
163pub unsafe fn ibv_wc_read_vendor_err(cq: *mut ibv_cq_ex) -> u32 {
164    (*cq).read_vendor_err.unwrap()(cq)
165}
166
167#[inline]
168pub unsafe fn ibv_wc_read_byte_len(cq: *mut ibv_cq_ex) -> u32 {
169    (*cq).read_byte_len.unwrap()(cq)
170}
171
172#[inline]
173pub unsafe fn ibv_wc_read_imm_data(cq: *mut ibv_cq_ex) -> __be32 {
174    (*cq).read_imm_data.unwrap()(cq)
175}
176
177#[inline]
178pub unsafe fn ibv_wc_read_invalidated_rkey(cq: *mut ibv_cq_ex) -> u32 {
179    // #ifdef __CHECKER__
180    //     return (__attribute__((force)) uint32_t)cq->read_imm_data(cq);
181    // #else
182    //     return cq->read_imm_data(cq);
183    // #endif
184    (*cq).read_imm_data.unwrap()(cq)
185}
186
187#[inline]
188pub unsafe fn ibv_wc_read_qp_num(cq: *mut ibv_cq_ex) -> u32 {
189    (*cq).read_qp_num.unwrap()(cq)
190}
191
192#[inline]
193pub unsafe fn ibv_wc_read_src_qp(cq: *mut ibv_cq_ex) -> u32 {
194    (*cq).read_src_qp.unwrap()(cq)
195}
196
197#[inline]
198pub unsafe fn ibv_wc_read_wc_flags(cq: *mut ibv_cq_ex) -> c_uint {
199    (*cq).read_wc_flags.unwrap()(cq)
200}
201
202#[inline]
203pub unsafe fn ibv_wc_read_slid(cq: *mut ibv_cq_ex) -> u32 {
204    (*cq).read_slid.unwrap()(cq)
205}
206
207#[inline]
208pub unsafe fn ibv_wc_read_sl(cq: *mut ibv_cq_ex) -> u8 {
209    (*cq).read_sl.unwrap()(cq)
210}
211
212#[inline]
213pub unsafe fn ibv_wc_read_dlid_path_bits(cq: *mut ibv_cq_ex) -> u8 {
214    (*cq).read_dlid_path_bits.unwrap()(cq)
215}
216
217#[inline]
218pub unsafe fn ibv_wc_read_completion_ts(cq: *mut ibv_cq_ex) -> u64 {
219    (*cq).read_completion_ts.unwrap()(cq)
220}
221
222#[inline]
223pub unsafe fn ibv_wc_read_completion_wallclock_ns(cq: *mut ibv_cq_ex) -> u64 {
224    (*cq).read_completion_wallclock_ns.unwrap()(cq)
225}
226
227#[inline]
228pub unsafe fn ibv_wc_read_cvlan(cq: *mut ibv_cq_ex) -> u16 {
229    (*cq).read_cvlan.unwrap()(cq)
230}
231
232#[inline]
233pub unsafe fn ibv_wc_read_flow_tag(cq: *mut ibv_cq_ex) -> u32 {
234    (*cq).read_flow_tag.unwrap()(cq)
235}
236
237#[inline]
238pub unsafe fn ibv_wc_read_tm_info(cq: *mut ibv_cq_ex, tm_info: *mut ibv_wc_tm_info) {
239    (*cq).read_tm_info.unwrap()(cq, tm_info)
240}
241
242// ibv_wq related inline function
243#[inline]
244pub unsafe fn ibv_post_wq_recv(
245    wq: *mut ibv_wq,
246    recv_wr: *mut ibv_recv_wr,
247    bad_recv_wr: *mut *mut ibv_recv_wr,
248) -> c_int {
249    (*wq).post_recv.unwrap()(wq, recv_wr, bad_recv_wr)
250}
251
252// Use intrusive_collections::container_of! instread, once it's stable not nightly
253macro_rules! container_of {
254    ($ptr:expr, $container:path, $field:ident) => {{
255        ($ptr as *const _ as *const u8).sub(memoffset::offset_of!($container, $field))
256            as *const $container
257    }};
258}
259
260// Utility function to get verbs_context from ibv_context
261#[inline]
262unsafe fn verbs_get_ctx(ctx: *const ibv_context) -> Option<*mut verbs_context> {
263    if (*ctx).abi_compat as usize != u32::MAX as usize {
264        None
265    } else {
266        let vcp = container_of!(ctx, verbs_context, context) as *mut _;
267        Some(vcp)
268    }
269}
270
271macro_rules! verbs_get_ctx_op {
272    ($vcr:expr, $field:ident) => {
273        if let Some(vc) = verbs_get_ctx($vcr) {
274            if (*vc).sz < mem::size_of_val(&*vc) - memoffset::offset_of!(verbs_context, $field) {
275                None
276            } else {
277                if (*vc).$field.is_some() {
278                    Some(vc)
279                } else {
280                    None
281                }
282            }
283        } else {
284            None
285        }
286    };
287}
288
289// TODO: note that ibv_query_port, ibv_get_device_list, ibv_reg_mr, and
290// ibv_reg_mr_iova are redefined using ___ibv_query_port,
291// __ibv_get_device_list, __ibv_reg_mr, and __ibv_reg_mr_iova in C, which
292// should be handled properly in Rust.
293
294// When statically linking the user can set RDMA_STATIC_PROVIDERS to a comma
295// separated list of provider names to include in the static link, and this
296// machinery will cause those providers to be included statically.
297//
298// Linking will fail if this is set for dynamic linking.
299//
300// #define ibv_get_device_list(num_devices) __ibv_get_device_list(num_devices)
301// #endif
302// #ifdef RDMA_STATIC_PROVIDERS
303// #define _RDMA_STATIC_PREFIX_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11,     \
304//                              _12, _13, _14, _15, _16, _17, ...)                \
305//         &verbs_provider_##_1, &verbs_provider_##_2, &verbs_provider_##_3,      \
306//                 &verbs_provider_##_4, &verbs_provider_##_5,                    \
307//                 &verbs_provider_##_6, &verbs_provider_##_7,                    \
308//                 &verbs_provider_##_8, &verbs_provider_##_9,                    \
309//                 &verbs_provider_##_10, &verbs_provider_##_11,                  \
310//                 &verbs_provider_##_12, &verbs_provider_##_13,                  \
311//                 &verbs_provider_##_14, &verbs_provider_##_15,                  \
312//                 &verbs_provider_##_16, &verbs_provider_##_17
313// #define _RDMA_STATIC_PREFIX(arg)                                               \
314//         _RDMA_STATIC_PREFIX_(arg, none, none, none, none, none, none, none,    \
315//                              none, none, none, none, none, none, none, none,   \
316//                              none)
317pub unsafe fn __ibv_get_device_list(num_devices: *mut c_int) -> *mut *mut ibv_device {
318    // TODO: check static linking compatibility
319    // ibv_static_providers(NULL, _RDMA_STATIC_PREFIX(RDMA_STATIC_PROVIDERS), NULL);
320    ibv_get_device_list(num_devices)
321}
322
323// TODO: missing variable args function
324// void ibv_static_providers(void *unused, ...);
325
326// ibv_context related inline function
327#[inline]
328pub unsafe fn ___ibv_query_port(
329    context: *mut ibv_context,
330    port_num: u8,
331    port_attr: *mut ibv_port_attr,
332) -> c_int {
333    let vcr = verbs_get_ctx_op!(context, query_port);
334
335    if let Some(vctx) = vcr {
336        (*vctx).query_port.unwrap()(context, port_num, port_attr, mem::size_of_val(&*port_attr))
337    } else {
338        // TODO: memset(port_attr, 0, sizeof(*port_attr));
339        let compat_attr = port_attr as *mut _ as *mut _compat_ibv_port_attr;
340        ibv_query_port(context, port_num, compat_attr)
341    }
342}
343
344// ibv_flow related inline functions
345#[inline]
346pub unsafe fn ibv_create_flow(qp: *mut ibv_qp, flow: *mut ibv_flow_attr) -> Option<*mut ibv_flow> {
347    let vcr = verbs_get_ctx_op!((*qp).context, ibv_create_flow);
348
349    if let Some(vctx) = vcr {
350        Some((*vctx).ibv_create_flow.unwrap()(qp, flow))
351    } else {
352        *libc::__errno_location() = libc::EOPNOTSUPP;
353        None
354    }
355}
356
357#[inline]
358pub unsafe fn ibv_destroy_flow(flow_id: *mut ibv_flow) -> c_int {
359    let vcr = verbs_get_ctx_op!((*flow_id).context, ibv_destroy_flow);
360
361    if let Some(vctx) = vcr {
362        (*vctx).ibv_destroy_flow.unwrap()(flow_id)
363    } else {
364        libc::EOPNOTSUPP
365    }
366}
367
368#[inline]
369pub unsafe fn ibv_create_flow_action_esp(
370    ctx: *mut ibv_context,
371    esp: *mut ibv_flow_action_esp_attr,
372) -> Option<*mut ibv_flow_action> {
373    let vcr = verbs_get_ctx_op!(ctx, create_flow_action_esp);
374
375    if let Some(vctx) = vcr {
376        Some((*vctx).create_flow_action_esp.unwrap()(ctx, esp))
377    } else {
378        *libc::__errno_location() = libc::EOPNOTSUPP;
379        None
380    }
381}
382
383#[inline]
384pub unsafe fn ibv_modify_flow_action_esp(
385    action: *mut ibv_flow_action,
386    esp: *mut ibv_flow_action_esp_attr,
387) -> c_int {
388    let vcr = verbs_get_ctx_op!((*action).context, modify_flow_action_esp);
389
390    if let Some(vctx) = vcr {
391        (*vctx).modify_flow_action_esp.unwrap()(action, esp)
392    } else {
393        libc::EOPNOTSUPP
394    }
395}
396
397#[inline]
398pub unsafe fn ibv_destroy_flow_action(action: *mut ibv_flow_action) -> c_int {
399    let vcr = verbs_get_ctx_op!((*action).context, destroy_flow_action);
400
401    if let Some(vctx) = vcr {
402        (*vctx).destroy_flow_action.unwrap()(action)
403    } else {
404        libc::EOPNOTSUPP
405    }
406}
407
408// ibv_xrcd related inline functions
409#[inline]
410pub unsafe fn ibv_open_xrcd(
411    context: *mut ibv_context,
412    xrcd_init_attr: *mut ibv_xrcd_init_attr,
413) -> Option<*mut ibv_xrcd> {
414    let vcr = verbs_get_ctx_op!(context, open_xrcd);
415
416    if let Some(vctx) = vcr {
417        Some((*vctx).open_xrcd.unwrap()(context, xrcd_init_attr))
418    } else {
419        *libc::__errno_location() = libc::EOPNOTSUPP;
420        None
421    }
422}
423
424#[inline]
425pub unsafe fn ibv_close_xrcd(xrcd: *mut ibv_xrcd) -> c_int {
426    let vctx = verbs_get_ctx((*xrcd).context);
427
428    (*vctx.unwrap()).close_xrcd.unwrap()(xrcd)
429}
430
431// use new ibv_reg_mr version only if access flags that require it are used
432#[inline]
433pub unsafe fn __ibv_reg_mr(
434    pd: *mut ibv_pd,
435    addr: *mut c_void,
436    length: usize,
437    access: c_uint,
438    is_access_const: c_int,
439) -> *mut ibv_mr {
440    if is_access_const != 0
441        && (ib_uverbs_access_flags(access)
442            & ib_uverbs_access_flags::IB_UVERBS_ACCESS_OPTIONAL_RANGE)
443            == ib_uverbs_access_flags(0)
444    {
445        ibv_reg_mr(pd, addr, length, access as c_int)
446    } else {
447        ibv_reg_mr_iova2(pd, addr, length, addr as u64, access)
448    }
449}
450// TODO: handle C macro defined function
451// #define ibv_reg_mr(pd, addr, length, access) \
452//     __ibv_reg_mr(pd, addr, length, access,      \
453//              __builtin_constant_p(              \
454//                  ((access) & IBV_ACCESS_OPTIONAL_RANGE) == 0))
455
456// use new ibv_reg_mr version only if access flags that require it are used
457#[inline]
458pub unsafe fn __ibv_reg_mr_iova(
459    pd: *mut ibv_pd,
460    addr: *mut c_void,
461    length: usize,
462    iova: u64,
463    access: c_uint,
464    is_access_const: c_int,
465) -> *mut ibv_mr {
466    if is_access_const != 0
467        && (ib_uverbs_access_flags(access)
468            & ib_uverbs_access_flags::IB_UVERBS_ACCESS_OPTIONAL_RANGE)
469            == ib_uverbs_access_flags(0)
470    {
471        ibv_reg_mr_iova(pd, addr, length, iova, access as c_int)
472    } else {
473        ibv_reg_mr_iova2(pd, addr, length, iova, access)
474    }
475}
476// TODO: handle C macro defined function
477// #define ibv_reg_mr_iova(pd, addr, length, iova, access)                        \
478//     __ibv_reg_mr_iova(pd, addr, length, iova, access,                      \
479//               __builtin_constant_p(                                \
480//                   ((access) & IBV_ACCESS_OPTIONAL_RANGE) == 0))
481
482// ibv_mw related inline functions
483#[inline]
484pub unsafe fn ibv_alloc_mw(pd: *mut ibv_pd, type_: ibv_mw_type::Type) -> Option<*mut ibv_mw> {
485    if (*(*pd).context).ops.alloc_mw.is_some() {
486        Some((*(*pd).context).ops.alloc_mw.unwrap()(pd, type_))
487    } else {
488        *libc::__errno_location() = libc::EOPNOTSUPP;
489        None
490    }
491}
492
493#[inline]
494pub unsafe fn ibv_dealloc_mw(mw: *mut ibv_mw) -> c_int {
495    (*(*mw).context).ops.dealloc_mw.unwrap()(mw)
496}
497
498// ibv_inc_rkey - Increase the 8 lsb in the given rkey
499#[inline]
500pub unsafe fn ibv_inc_rkey(rkey: u32) -> u32 {
501    let mask: u32 = 0x000000ff;
502    let newtag = ((rkey + 1) & mask) as u8;
503
504    (rkey & !mask) | (newtag as u32)
505}
506
507#[inline]
508pub unsafe fn ibv_bind_mw(qp: *mut ibv_qp, mw: *mut ibv_mw, mw_bind: *mut ibv_mw_bind) -> c_int {
509    if (*mw).type_ != ibv_mw_type::IBV_MW_TYPE_1 {
510        libc::EINVAL
511    } else {
512        (*(*mw).context).ops.bind_mw.unwrap()(qp, mw, mw_bind)
513    }
514}
515
516#[inline]
517pub unsafe fn ibv_advise_mr(
518    pd: *mut ibv_pd,
519    advice: ibv_advise_mr_advice,
520    flags: u32,
521    sg_list: *mut ibv_sge,
522    num_sge: u32,
523) -> c_int {
524    let vcr = verbs_get_ctx_op!((*pd).context, advise_mr);
525
526    if let Some(vctx) = vcr {
527        (*vctx).advise_mr.unwrap()(pd, advice, flags, sg_list, num_sge)
528    } else {
529        libc::EOPNOTSUPP
530    }
531}
532
533// ibv_dm related inline functions
534#[inline]
535pub unsafe fn ibv_alloc_dm(
536    context: *mut ibv_context,
537    attr: *mut ibv_alloc_dm_attr,
538) -> Option<*mut ibv_dm> {
539    let vcr = verbs_get_ctx_op!(context, alloc_dm);
540
541    if let Some(vctx) = vcr {
542        Some((*vctx).alloc_dm.unwrap()(context, attr))
543    } else {
544        *libc::__errno_location() = libc::EOPNOTSUPP;
545        None
546    }
547}
548
549#[inline]
550pub unsafe fn ibv_free_dm(dm: *mut ibv_dm) -> c_int {
551    let vcr = verbs_get_ctx_op!((*dm).context, free_dm);
552
553    if let Some(vctx) = vcr {
554        (*vctx).free_dm.unwrap()(dm)
555    } else {
556        libc::EOPNOTSUPP
557    }
558}
559
560#[inline]
561pub unsafe fn ibv_memcpy_to_dm(
562    dm: *mut ibv_dm,
563    dm_offset: u64,
564    host_addr: *const c_void,
565    length: usize,
566) -> c_int {
567    (*dm).memcpy_to_dm.unwrap()(dm, dm_offset, host_addr, length)
568}
569
570#[inline]
571pub unsafe fn ibv_memcpy_from_dm(
572    host_addr: *mut c_void,
573    dm: *mut ibv_dm,
574    dm_offset: u64,
575    length: usize,
576) -> c_int {
577    (*dm).memcpy_from_dm.unwrap()(host_addr, dm, dm_offset, length)
578}
579
580#[inline]
581pub unsafe fn ibv_alloc_null_mr(pd: *mut ibv_pd) -> Option<*mut ibv_mr> {
582    let vcr = verbs_get_ctx_op!((*pd).context, alloc_null_mr);
583
584    if let Some(vctx) = vcr {
585        Some((*vctx).alloc_null_mr.unwrap()(pd))
586    } else {
587        *libc::__errno_location() = libc::EOPNOTSUPP;
588        None
589    }
590}
591
592#[inline]
593pub unsafe fn ibv_reg_dm_mr(
594    pd: *mut ibv_pd,
595    dm: *mut ibv_dm,
596    dm_offset: u64,
597    length: usize,
598    access: u32,
599) -> Option<*mut ibv_mr> {
600    let vcr = verbs_get_ctx_op!((*pd).context, reg_dm_mr);
601
602    if let Some(vctx) = vcr {
603        Some((*vctx).reg_dm_mr.unwrap()(
604            pd, dm, dm_offset, length, access,
605        ))
606    } else {
607        *libc::__errno_location() = libc::EOPNOTSUPP;
608        None
609    }
610}
611
612// ibv_cq_ex related inline function
613#[inline]
614pub unsafe fn ibv_create_cq_ex(
615    context: *mut ibv_context,
616    cq_attr: *mut ibv_cq_init_attr_ex,
617) -> Option<*mut ibv_cq_ex> {
618    let vcr = verbs_get_ctx_op!(context, create_cq_ex);
619
620    if let Some(vctx) = vcr {
621        Some((*vctx).create_cq_ex.unwrap()(context, cq_attr))
622    } else {
623        *libc::__errno_location() = libc::EOPNOTSUPP;
624        None
625    }
626}
627
628// ibv_cq related inline functions
629#[inline]
630pub unsafe fn ibv_poll_cq(cq: *mut ibv_cq, num_entries: i32, wc: *mut ibv_wc) -> c_int {
631    (*(*cq).context).ops.poll_cq.unwrap()(cq, num_entries, wc)
632}
633
634#[inline]
635pub unsafe fn ibv_req_notify_cq(cq: *mut ibv_cq, solicited_only: i32) -> c_int {
636    (*(*cq).context).ops.req_notify_cq.unwrap()(cq, solicited_only)
637}
638
639#[inline]
640pub unsafe fn ibv_modify_cq(cq: *mut ibv_cq, attr: *mut ibv_modify_cq_attr) -> c_int {
641    let vcr = verbs_get_ctx_op!((*cq).context, modify_cq);
642
643    if let Some(vctx) = vcr {
644        (*vctx).modify_cq.unwrap()(cq, attr)
645    } else {
646        libc::EOPNOTSUPP
647    }
648}
649
650// ibv_srq related inline functions
651#[inline]
652pub unsafe fn ibv_create_srq_ex(
653    context: *mut ibv_context,
654    srq_init_attr_ex: *mut ibv_srq_init_attr_ex,
655) -> Option<*mut ibv_srq> {
656    let mask = ibv_srq_init_attr_mask((*srq_init_attr_ex).comp_mask);
657    let mask_inv = ibv_srq_init_attr_mask(!(*srq_init_attr_ex).comp_mask);
658    let zero = ibv_srq_init_attr_mask(0);
659
660    // TODO: verify the condition
661    let cond = (mask_inv
662        | (ibv_srq_init_attr_mask::IBV_SRQ_INIT_ATTR_PD
663            & ibv_srq_init_attr_mask::IBV_SRQ_INIT_ATTR_TYPE))
664        != zero
665        && (mask & ibv_srq_init_attr_mask::IBV_SRQ_INIT_ATTR_PD) != zero
666        && ((mask & ibv_srq_init_attr_mask::IBV_SRQ_INIT_ATTR_TYPE) != zero
667            || ((*srq_init_attr_ex).srq_type == ibv_srq_type::IBV_SRQT_BASIC));
668    if cond {
669        Some(ibv_create_srq(
670            (*srq_init_attr_ex).pd,
671            srq_init_attr_ex as *mut ibv_srq_init_attr,
672        ))
673    } else {
674        let vcr = verbs_get_ctx_op!(context, create_srq_ex);
675
676        if let Some(vctx) = vcr {
677            Some((*vctx).create_srq_ex.unwrap()(context, srq_init_attr_ex))
678        } else {
679            *libc::__errno_location() = libc::EOPNOTSUPP;
680            None
681        }
682    }
683}
684
685#[inline]
686pub unsafe fn ibv_get_srq_num(srq: *mut ibv_srq, srq_num: *mut u32) -> c_int {
687    let vcr = verbs_get_ctx_op!((*srq).context, get_srq_num);
688
689    if let Some(vctx) = vcr {
690        (*vctx).get_srq_num.unwrap()(srq, srq_num)
691    } else {
692        libc::EOPNOTSUPP
693    }
694}
695
696#[inline]
697pub unsafe fn ibv_post_srq_recv(
698    srq: *mut ibv_srq,
699    recv_wr: *mut ibv_recv_wr,
700    bad_recv_wr: *mut *mut ibv_recv_wr,
701) -> c_int {
702    (*(*srq).context).ops.post_srq_recv.unwrap()(srq, recv_wr, bad_recv_wr)
703}
704
705#[inline]
706pub unsafe fn ibv_post_srq_ops(
707    srq: *mut ibv_srq,
708    op: *mut ibv_ops_wr,
709    bad_op: *mut *mut ibv_ops_wr,
710) -> c_int {
711    let vcr = verbs_get_ctx_op!((*srq).context, post_srq_ops);
712
713    if let Some(vctx) = vcr {
714        (*vctx).post_srq_ops.unwrap()(srq, op, bad_op)
715    } else {
716        *bad_op = op;
717        libc::EOPNOTSUPP
718    }
719}
720
721// ibv_qp related inline functions
722#[inline]
723pub unsafe fn ibv_create_qp_ex(
724    context: *mut ibv_context,
725    qp_init_attr_ex: *mut ibv_qp_init_attr_ex,
726) -> Option<*mut ibv_qp> {
727    let mask = ibv_qp_init_attr_mask((*qp_init_attr_ex).comp_mask);
728
729    if mask == ibv_qp_init_attr_mask::IBV_QP_INIT_ATTR_PD {
730        Some(ibv_create_qp(
731            (*qp_init_attr_ex).pd,
732            qp_init_attr_ex as *mut ibv_qp_init_attr,
733        ))
734    } else {
735        let vcr = verbs_get_ctx_op!(context, create_qp_ex);
736
737        if let Some(vctx) = vcr {
738            Some((*vctx).create_qp_ex.unwrap()(context, qp_init_attr_ex))
739        } else {
740            *libc::__errno_location() = libc::EOPNOTSUPP;
741            None
742        }
743    }
744}
745
746// ibv_td related inline functions
747#[inline]
748pub unsafe fn ibv_alloc_td(
749    context: *mut ibv_context,
750    init_attr: *mut ibv_td_init_attr,
751) -> Option<*mut ibv_td> {
752    let vcr = verbs_get_ctx_op!(context, alloc_td);
753
754    if let Some(vctx) = vcr {
755        Some((*vctx).alloc_td.unwrap()(context, init_attr))
756    } else {
757        *libc::__errno_location() = libc::EOPNOTSUPP;
758        None
759    }
760}
761
762#[inline]
763pub unsafe fn ibv_dealloc_td(td: *mut ibv_td) -> c_int {
764    let vcr = verbs_get_ctx_op!((*td).context, dealloc_td);
765
766    if let Some(vctx) = vcr {
767        (*vctx).dealloc_td.unwrap()(td)
768    } else {
769        libc::EOPNOTSUPP
770    }
771}
772
773// ibv_pd related inline function
774#[inline]
775pub unsafe fn ibv_alloc_parent_domain(
776    context: *mut ibv_context,
777    attr: *mut ibv_parent_domain_init_attr,
778) -> Option<*mut ibv_pd> {
779    let vcr = verbs_get_ctx_op!(context, alloc_parent_domain);
780
781    if let Some(vctx) = vcr {
782        Some((*vctx).alloc_parent_domain.unwrap()(context, attr))
783    } else {
784        *libc::__errno_location() = libc::EOPNOTSUPP;
785        None
786    }
787}
788
789// device related inline functions
790#[inline]
791pub unsafe fn ibv_query_rt_values_ex(
792    context: *mut ibv_context,
793    values: *mut ibv_values_ex,
794) -> c_int {
795    let vcr = verbs_get_ctx_op!(context, query_rt_values);
796
797    if let Some(vctx) = vcr {
798        (*vctx).query_rt_values.unwrap()(context, values)
799    } else {
800        libc::EOPNOTSUPP
801    }
802}
803
804#[inline]
805pub unsafe fn ibv_query_device_ex(
806    context: *mut ibv_context,
807    input: *const ibv_query_device_ex_input,
808    attr: *mut ibv_device_attr_ex,
809) -> c_int {
810    let vcr = verbs_get_ctx_op!(context, query_device_ex);
811
812    if let Some(vctx) = vcr {
813        let ret = (*vctx).query_device_ex.unwrap()(context, input, attr, mem::size_of_val(&*attr));
814        if ret != libc::EOPNOTSUPP {
815            return ret;
816        }
817    }
818
819    // TODO: memset(attr, 0, sizeof(*attr));
820    ibv_query_device(context, &mut (*attr).orig_attr)
821}
822
823// ibv_qp related inline functions
824#[inline]
825pub unsafe fn ibv_open_qp(
826    context: *mut ibv_context,
827    qp_open_attr: *mut ibv_qp_open_attr,
828) -> Option<*mut ibv_qp> {
829    let vcr = verbs_get_ctx_op!(context, open_qp);
830
831    if let Some(vctx) = vcr {
832        Some((*vctx).open_qp.unwrap()(context, qp_open_attr))
833    } else {
834        *libc::__errno_location() = libc::EOPNOTSUPP;
835        None
836    }
837}
838
839#[inline]
840pub unsafe fn ibv_modify_qp_rate_limit(
841    qp: *mut ibv_qp,
842    attr: *mut ibv_qp_rate_limit_attr,
843) -> c_int {
844    let vcr = verbs_get_ctx_op!((*qp).context, modify_qp_rate_limit);
845
846    if let Some(vctx) = vcr {
847        (*vctx).modify_qp_rate_limit.unwrap()(qp, attr)
848    } else {
849        libc::EOPNOTSUPP
850    }
851}
852
853// ibv_wq related inline functions
854#[inline]
855pub unsafe fn ibv_create_wq(
856    context: *mut ibv_context,
857    wq_init_attr: *mut ibv_wq_init_attr,
858) -> Option<*mut ibv_wq> {
859    let vcr = verbs_get_ctx_op!(context, create_wq);
860
861    if let Some(vctx) = vcr {
862        let wq = (*vctx).create_wq.unwrap()(context, wq_init_attr);
863        if wq != (ptr::null::<ibv_wq>() as *mut _) {
864            (*wq).events_completed = 0;
865            libc::pthread_mutex_init(
866                &mut (*wq).mutex,
867                ptr::null::<libc::pthread_mutexattr_t>() as *mut _,
868            );
869            libc::pthread_cond_init(
870                &mut (*wq).cond,
871                ptr::null::<libc::pthread_condattr_t>() as *mut _,
872            );
873        }
874        Some(wq)
875    } else {
876        *libc::__errno_location() = libc::EOPNOTSUPP;
877        None
878    }
879}
880
881#[inline]
882pub unsafe fn ibv_modify_wq(wq: *mut ibv_wq, wq_attr: *mut ibv_wq_attr) -> c_int {
883    let vcr = verbs_get_ctx_op!((*wq).context, modify_wq);
884
885    if let Some(vctx) = vcr {
886        (*vctx).modify_wq.unwrap()(wq, wq_attr)
887    } else {
888        libc::EOPNOTSUPP
889    }
890}
891
892#[inline]
893pub unsafe fn ibv_destroy_wq(wq: *mut ibv_wq) -> c_int {
894    let vcr = verbs_get_ctx_op!((*wq).context, destroy_wq);
895
896    if let Some(vctx) = vcr {
897        (*vctx).destroy_wq.unwrap()(wq)
898    } else {
899        libc::EOPNOTSUPP
900    }
901}
902
903// ibv_rwq_ind_table related inline functions
904#[inline]
905pub unsafe fn ibv_create_rwq_ind_table(
906    context: *mut ibv_context,
907    init_attr: *mut ibv_rwq_ind_table_init_attr,
908) -> Option<*mut ibv_rwq_ind_table> {
909    let vcr = verbs_get_ctx_op!(context, create_rwq_ind_table);
910
911    if let Some(vctx) = vcr {
912        Some((*vctx).create_rwq_ind_table.unwrap()(context, init_attr))
913    } else {
914        *libc::__errno_location() = libc::EOPNOTSUPP;
915        None
916    }
917}
918
919#[inline]
920pub unsafe fn ibv_destroy_rwq_ind_table(rwq_ind_table: *mut ibv_rwq_ind_table) -> c_int {
921    let vcr = verbs_get_ctx_op!((*rwq_ind_table).context, destroy_rwq_ind_table);
922
923    if let Some(vctx) = vcr {
924        (*vctx).destroy_rwq_ind_table.unwrap()(rwq_ind_table)
925    } else {
926        libc::EOPNOTSUPP
927    }
928}
929
930// If IBV_SEND_INLINE flag is set, the data buffers can be reused
931// immediately after the call returns.
932#[inline]
933pub unsafe fn ibv_post_send(
934    qp: *mut ibv_qp,
935    wr: *mut ibv_send_wr,
936    bad_wr: *mut *mut ibv_send_wr,
937) -> c_int {
938    (*(*qp).context).ops.post_send.unwrap()(qp, wr, bad_wr)
939}
940
941#[inline]
942pub unsafe fn ibv_post_recv(
943    qp: *mut ibv_qp,
944    wr: *mut ibv_recv_wr,
945    bad_wr: *mut *mut ibv_recv_wr,
946) -> c_int {
947    (*(*qp).context).ops.post_recv.unwrap()(qp, wr, bad_wr)
948}
949
950#[inline]
951pub unsafe fn ibv_is_qpt_supported(caps: u32, qpt: ibv_qp_type::Type) -> c_int {
952    !!(caps & (1 << qpt)) as c_int
953}
954
955// ibv_counters related inline functions
956#[inline]
957pub unsafe fn ibv_create_counters(
958    context: *mut ibv_context,
959    init_attr: *mut ibv_counters_init_attr,
960) -> Option<*mut ibv_counters> {
961    let vcr = verbs_get_ctx_op!(context, create_counters);
962
963    if let Some(vctx) = vcr {
964        Some((*vctx).create_counters.unwrap()(context, init_attr))
965    } else {
966        *libc::__errno_location() = libc::EOPNOTSUPP;
967        None
968    }
969}
970
971#[inline]
972pub unsafe fn ibv_destroy_counters(counters: *mut ibv_counters) -> c_int {
973    let vcr = verbs_get_ctx_op!((*counters).context, destroy_counters);
974
975    if let Some(vctx) = vcr {
976        (*vctx).destroy_counters.unwrap()(counters)
977    } else {
978        libc::EOPNOTSUPP
979    }
980}
981
982#[inline]
983pub unsafe fn ibv_attach_counters_point_flow(
984    counters: *mut ibv_counters,
985    attr: *mut ibv_counter_attach_attr,
986    flow: *mut ibv_flow,
987) -> c_int {
988    let vcr = verbs_get_ctx_op!((*counters).context, attach_counters_point_flow);
989
990    if let Some(vctx) = vcr {
991        (*vctx).attach_counters_point_flow.unwrap()(counters, attr, flow)
992    } else {
993        libc::EOPNOTSUPP
994    }
995}
996
997#[inline]
998pub unsafe fn ibv_read_counters(
999    counters: *mut ibv_counters,
1000    counters_value: *mut u64,
1001    ncounters: u32,
1002    flags: u32,
1003) -> c_int {
1004    let vcr = verbs_get_ctx_op!((*counters).context, read_counters);
1005
1006    if let Some(vctx) = vcr {
1007        (*vctx).read_counters.unwrap()(counters, counters_value, ncounters, flags)
1008    } else {
1009        libc::EOPNOTSUPP
1010    }
1011}
1012
1013/// Inline functions from <rdma/rdma_cma.h>
1014
1015pub const RDMA_IB_IP_PS_MASK: u64 = 0xFFFFFFFFFFFF0000;
1016pub const RDMA_IB_IP_PORT_MASK: u64 = 0x000000000000FFFF;
1017pub const RDMA_IB_IP_PS_TCP: u64 = 0x0000000001060000;
1018pub const RDMA_IB_IP_PS_UDP: u64 = 0x0000000001110000;
1019pub const RDMA_IB_PS_IB: u64 = 0x00000000013F0000;
1020
1021pub const RDMA_UDP_QKEY: u32 = 0x01234567;
1022
1023pub const RAI_PASSIVE: u32 = 0x00000001;
1024pub const RAI_NUMERICHOST: u32 = 0x00000002;
1025pub const RAI_NOROUTE: u32 = 0x00000004;
1026pub const RAI_FAMILY: u32 = 0x00000008;
1027
1028#[inline]
1029pub unsafe fn rdma_get_local_addr(id: &rdma_cm_id) -> &libc::sockaddr {
1030    &id.route.addr.src_addr_union.src_addr
1031}
1032
1033#[inline]
1034pub unsafe fn rdma_get_peer_addr(id: &rdma_cm_id) -> &libc::sockaddr {
1035    &id.route.addr.dst_addr_union.dst_addr
1036}
1037
1038/// Inline functions from <rdma/rdma_verbs.h>
1039
1040#[inline]
1041pub unsafe fn rdma_seterrno(ret: c_int) -> c_int {
1042    if ret != 0 {
1043        *libc::__errno_location() = ret;
1044        -1
1045    } else {
1046        ret
1047    }
1048}
1049
1050#[inline]
1051pub unsafe fn rdma_reg_msgs(id: *mut rdma_cm_id, addr: *mut c_void, length: usize) -> *mut ibv_mr {
1052    ibv_reg_mr(
1053        (*id).pd,
1054        addr,
1055        length,
1056        ibv_access_flags::IBV_ACCESS_LOCAL_WRITE.0 as c_int,
1057    )
1058}
1059
1060#[inline]
1061pub unsafe fn rdma_reg_read(id: *mut rdma_cm_id, addr: *mut c_void, length: usize) -> *mut ibv_mr {
1062    ibv_reg_mr(
1063        (*id).pd,
1064        addr,
1065        length,
1066        (ibv_access_flags::IBV_ACCESS_LOCAL_WRITE | ibv_access_flags::IBV_ACCESS_REMOTE_READ).0
1067            as c_int,
1068    )
1069}
1070
1071#[inline]
1072pub unsafe fn rdma_reg_write(id: *mut rdma_cm_id, addr: *mut c_void, length: usize) -> *mut ibv_mr {
1073    ibv_reg_mr(
1074        (*id).pd,
1075        addr,
1076        length,
1077        (ibv_access_flags::IBV_ACCESS_LOCAL_WRITE | ibv_access_flags::IBV_ACCESS_REMOTE_WRITE).0
1078            as c_int,
1079    )
1080}
1081
1082#[inline]
1083pub unsafe fn rdma_dereg_mr(mr: *mut ibv_mr) -> c_int {
1084    rdma_seterrno(ibv_dereg_mr(mr))
1085}
1086
1087#[inline]
1088pub unsafe fn rdma_post_recvv(
1089    id: *mut rdma_cm_id,
1090    context: *mut c_void,
1091    sgl: *mut ibv_sge,
1092    nsge: c_int,
1093) -> c_int {
1094    let mut wr = ibv_recv_wr {
1095        wr_id: context as u64,
1096        next: ptr::null::<ibv_recv_wr>() as *mut _,
1097        sg_list: sgl,
1098        num_sge: nsge,
1099    };
1100    let mut bad = ptr::null::<ibv_recv_wr>() as *mut _;
1101
1102    if (*id).srq as usize != 0 {
1103        rdma_seterrno(ibv_post_srq_recv((*id).srq, &mut wr, &mut bad))
1104    } else {
1105        rdma_seterrno(ibv_post_recv((*id).qp, &mut wr, &mut bad))
1106    }
1107}
1108
1109#[inline]
1110pub unsafe fn rdma_post_sendv(
1111    id: *mut rdma_cm_id,
1112    context: *mut c_void,
1113    sgl: *mut ibv_sge,
1114    nsge: c_int,
1115    flags: c_int,
1116) -> c_int {
1117    let mut wr = std::mem::zeroed::<ibv_send_wr>();
1118    wr.wr_id = context as u64;
1119    wr.next = ptr::null::<ibv_send_wr>() as *mut _;
1120    wr.sg_list = sgl;
1121    wr.num_sge = nsge;
1122    wr.opcode = ibv_wr_opcode::IBV_WR_SEND;
1123    wr.send_flags = flags as c_uint;
1124    let mut bad = ptr::null::<ibv_send_wr>() as *mut _;
1125
1126    rdma_seterrno(ibv_post_send((*id).qp, &mut wr, &mut bad))
1127}
1128
1129#[inline]
1130pub unsafe fn rdma_post_readv(
1131    id: *mut rdma_cm_id,
1132    context: *mut c_void,
1133    sgl: *mut ibv_sge,
1134    nsge: c_int,
1135    flags: c_int,
1136    remote_addr: u64,
1137    rkey: u32,
1138) -> c_int {
1139    let mut wr = std::mem::zeroed::<ibv_send_wr>();
1140    wr.wr_id = context as u64;
1141    wr.next = ptr::null::<ibv_send_wr>() as *mut _;
1142    wr.sg_list = sgl;
1143    wr.num_sge = nsge;
1144    wr.opcode = ibv_wr_opcode::IBV_WR_RDMA_READ;
1145    wr.send_flags = flags as c_uint;
1146    wr.wr = wr_t {
1147        rdma: rdma_t { remote_addr, rkey },
1148    };
1149    let mut bad = ptr::null::<ibv_send_wr>() as *mut _;
1150
1151    rdma_seterrno(ibv_post_send((*id).qp, &mut wr, &mut bad))
1152}
1153
1154#[inline]
1155pub unsafe fn rdma_post_writev(
1156    id: *mut rdma_cm_id,
1157    context: *mut c_void,
1158    sgl: *mut ibv_sge,
1159    nsge: c_int,
1160    flags: c_int,
1161    remote_addr: u64,
1162    rkey: u32,
1163) -> c_int {
1164    let mut wr = std::mem::zeroed::<ibv_send_wr>();
1165    wr.wr_id = context as u64;
1166    wr.next = ptr::null::<ibv_send_wr>() as *mut _;
1167    wr.sg_list = sgl;
1168    wr.num_sge = nsge;
1169    wr.opcode = ibv_wr_opcode::IBV_WR_RDMA_WRITE;
1170    wr.send_flags = flags as c_uint;
1171    wr.wr = wr_t {
1172        rdma: rdma_t { remote_addr, rkey },
1173    };
1174    let mut bad = ptr::null::<ibv_send_wr>() as *mut _;
1175
1176    rdma_seterrno(ibv_post_send((*id).qp, &mut wr, &mut bad))
1177}
1178
1179#[inline]
1180pub unsafe fn rdma_post_recv(
1181    id: *mut rdma_cm_id,
1182    context: *mut c_void,
1183    addr: *mut c_void,
1184    length: usize,
1185    mr: *mut ibv_mr,
1186) -> c_int {
1187    assert!(
1188        addr >= (*mr).addr && (addr as usize + length <= (*mr).addr as usize + (*mr).length),
1189        "invalid addr={} and length={}",
1190        addr as usize,
1191        length,
1192    );
1193    let mut sge = ibv_sge {
1194        addr: addr as u64,
1195        length: length as u32,
1196        lkey: (*mr).lkey,
1197    };
1198    let nsge = 1;
1199    rdma_post_recvv(id, context, &mut sge, nsge)
1200}
1201
1202#[inline]
1203pub unsafe fn rdma_post_send(
1204    id: *mut rdma_cm_id,
1205    context: *mut c_void,
1206    addr: *mut c_void,
1207    length: usize,
1208    mr: *mut ibv_mr,
1209    flags: c_int,
1210) -> c_int {
1211    let mut sge = ibv_sge {
1212        addr: addr as u64,
1213        length: length as u32,
1214        lkey: if !mr.is_null() { (*mr).lkey } else { 0 },
1215    };
1216    let nsge = 1;
1217    rdma_post_sendv(id, context, &mut sge, nsge, flags)
1218}
1219
1220#[inline]
1221pub unsafe fn rdma_post_read(
1222    id: *mut rdma_cm_id,
1223    context: *mut c_void,
1224    addr: *mut c_void,
1225    length: usize,
1226    mr: *mut ibv_mr,
1227    flags: c_int,
1228    remote_addr: u64,
1229    rkey: u32,
1230) -> c_int {
1231    let mut sge = ibv_sge {
1232        addr: addr as u64,
1233        length: length as u32,
1234        lkey: (*mr).lkey,
1235    };
1236    let nsge = 1;
1237    rdma_post_readv(id, context, &mut sge, nsge, flags, remote_addr, rkey)
1238}
1239
1240#[inline]
1241pub unsafe fn rdma_post_write(
1242    id: *mut rdma_cm_id,
1243    context: *mut c_void,
1244    addr: *mut c_void,
1245    length: usize,
1246    mr: *mut ibv_mr,
1247    flags: c_int,
1248    remote_addr: u64,
1249    rkey: u32,
1250) -> c_int {
1251    let mut sge = ibv_sge {
1252        addr: addr as u64,
1253        length: length as u32,
1254        lkey: if !mr.is_null() { (*mr).lkey } else { 0 },
1255    };
1256    let nsge = 1;
1257    rdma_post_writev(id, context, &mut sge, nsge, flags, remote_addr, rkey)
1258}
1259
1260#[inline]
1261pub unsafe fn rdma_post_ud_send(
1262    id: *mut rdma_cm_id,
1263    context: *mut c_void,
1264    addr: *mut c_void,
1265    length: usize,
1266    mr: *mut ibv_mr,
1267    flags: c_int,
1268    ah: *mut ibv_ah,
1269    remote_qpn: u32,
1270) -> c_int {
1271    let mut sge = ibv_sge {
1272        addr: addr as u64,
1273        length: length as u32,
1274        lkey: if !mr.is_null() { (*mr).lkey } else { 0 },
1275    };
1276
1277    let mut wr = std::mem::zeroed::<ibv_send_wr>();
1278    wr.wr_id = context as u64;
1279    wr.next = ptr::null::<ibv_send_wr>() as *mut _;
1280    wr.sg_list = &mut sge;
1281    wr.num_sge = 1;
1282    wr.opcode = ibv_wr_opcode::IBV_WR_SEND;
1283    wr.send_flags = flags as c_uint;
1284    wr.wr = wr_t {
1285        ud: ud_t {
1286            ah,
1287            remote_qpn,
1288            remote_qkey: RDMA_UDP_QKEY,
1289        },
1290    };
1291    let mut bad = ptr::null::<ibv_send_wr>() as *mut _;
1292
1293    rdma_seterrno(ibv_post_send((*id).qp, &mut wr, &mut bad))
1294}
1295
1296#[inline]
1297pub unsafe fn rdma_get_send_comp(id: *mut rdma_cm_id, wc: *mut ibv_wc) -> c_int {
1298    let mut ret: c_int;
1299    let mut cq = ptr::null::<ibv_cq>() as *mut _;
1300    let mut context = ptr::null::<c_void>() as *mut _;
1301    let nevents = 1;
1302    let num_entries = 1;
1303    let solicited_only = 0;
1304
1305    loop {
1306        ret = ibv_poll_cq((*id).send_cq, num_entries, wc);
1307        if ret != 0 {
1308            break;
1309        }
1310        ret = ibv_req_notify_cq((*id).send_cq, solicited_only);
1311        if ret != 0 {
1312            return rdma_seterrno(ret);
1313        }
1314        ret = ibv_poll_cq((*id).send_cq, num_entries, wc);
1315        if ret != 0 {
1316            break;
1317        }
1318        ret = ibv_get_cq_event((*id).send_cq_channel, &mut cq, &mut context);
1319        if ret != 0 {
1320            return ret;
1321        }
1322
1323        assert!(cq == (*id).send_cq && context as *mut rdma_cm_id == id);
1324        ibv_ack_cq_events((*id).send_cq, nevents);
1325    }
1326    if ret < 0 {
1327        rdma_seterrno(ret)
1328    } else {
1329        ret
1330    }
1331}
1332
1333#[inline]
1334pub unsafe fn rdma_get_recv_comp(id: *mut rdma_cm_id, wc: *mut ibv_wc) -> c_int {
1335    let mut ret: c_int;
1336    let mut cq = ptr::null::<ibv_cq>() as *mut _;
1337    let mut context = ptr::null::<c_void>() as *mut _;
1338    let nevents = 1;
1339    let num_entries = 1;
1340    let solicited_only = 0;
1341    loop {
1342        ret = ibv_poll_cq((*id).recv_cq, num_entries, wc);
1343        if ret != 0 {
1344            break;
1345        }
1346        ret = ibv_req_notify_cq((*id).recv_cq, solicited_only);
1347        if ret != 0 {
1348            return rdma_seterrno(ret);
1349        }
1350        ret = ibv_poll_cq((*id).recv_cq, num_entries, wc);
1351        if ret != 0 {
1352            break;
1353        }
1354        ret = ibv_get_cq_event((*id).recv_cq_channel, &mut cq, &mut context);
1355        if ret != 0 {
1356            return ret;
1357        }
1358
1359        assert!(cq == (*id).recv_cq && context as *mut rdma_cm_id == id);
1360        ibv_ack_cq_events((*id).recv_cq, nevents);
1361    }
1362    if ret < 0 {
1363        rdma_seterrno(ret)
1364    } else {
1365        ret
1366    }
1367}