IBV_WR_FLUSH(3)
β¨ IBV_WR API(3) β¨
ok so this is the libibverbs Programmer's Manual, page IBV_WR API(3) β and bestie, it's literally the group chat of work-request functions π
πΈ NAME πΈ
Get comfy, there's a whole squad here:
ibv_wr_abort,ibv_wr_complete,ibv_wr_startβ manage regions allowed to post workibv_wr_atomic_cmp_swp,ibv_wr_atomic_fetch_addβ post remote atomic operation work requestsibv_wr_bind_mw,ibv_wr_local_invβ post work requests for memory windowsibv_wr_rdma_read,ibv_wr_rdma_write,ibv_wr_rdma_write_imm,ibv_wr_flushβ post RDMA work requestsibv_wr_send,ibv_wr_send_imm,ibv_wr_send_invβ post send work requestsibv_wr_send_tsoβ post segmentation offload work requestsibv_wr_set_inline_data,ibv_wr_set_inline_data_listβ attach inline data to the last work requestibv_wr_set_sge,ibv_wr_set_sge_listβ attach data to the last work requestibv_wr_set_ud_addrβ attach UD addressing info to the last work requestibv_wr_set_xrc_srqnβ attach an XRC SRQN to the last work request
π SYNOPSIS π
#include <infiniband/verbs.h>
void ibv_wr_abort(struct ibv_qp_ex *qp);
int ibv_wr_complete(struct ibv_qp_ex *qp);
void ibv_wr_start(struct ibv_qp_ex *qp);
void ibv_wr_atomic_cmp_swp(struct ibv_qp_ex *qp, uint32_t rkey,
uint64_t remote_addr, uint64_t compare,
uint64_t swap);
void ibv_wr_atomic_fetch_add(struct ibv_qp_ex *qp, uint32_t rkey,
uint64_t remote_addr, uint64_t add);
void ibv_wr_bind_mw(struct ibv_qp_ex *qp, struct ibv_mw *mw, uint32_t rkey,
const struct ibv_mw_bind_info *bind_info);
void ibv_wr_local_inv(struct ibv_qp_ex *qp, uint32_t invalidate_rkey);
void ibv_wr_rdma_read(struct ibv_qp_ex *qp, uint32_t rkey,
uint64_t remote_addr);
void ibv_wr_rdma_write(struct ibv_qp_ex *qp, uint32_t rkey,
uint64_t remote_addr);
void ibv_wr_rdma_write_imm(struct ibv_qp_ex *qp, uint32_t rkey,
uint64_t remote_addr, __be32 imm_data);
void ibv_wr_send(struct ibv_qp_ex *qp);
void ibv_wr_send_imm(struct ibv_qp_ex *qp, __be32 imm_data);
void ibv_wr_send_inv(struct ibv_qp_ex *qp, uint32_t invalidate_rkey);
void ibv_wr_send_tso(struct ibv_qp_ex *qp, void *hdr, uint16_t hdr_sz,
uint16_t mss);
void ibv_wr_set_inline_data(struct ibv_qp_ex *qp, void *addr, size_t length);
void ibv_wr_set_inline_data_list(struct ibv_qp_ex *qp, size_t num_buf,
const struct ibv_data_buf *buf_list);
void ibv_wr_set_sge(struct ibv_qp_ex *qp, uint32_t lkey, uint64_t addr,
uint32_t length);
void ibv_wr_set_sge_list(struct ibv_qp_ex *qp, size_t num_sge,
const struct ibv_sge *sg_list);
void ibv_wr_set_ud_addr(struct ibv_qp_ex *qp, struct ibv_ah *ah,
uint32_t remote_qpn, uint32_t remote_qkey);
void ibv_wr_set_xrc_srqn(struct ibv_qp_ex *qp, uint32_t remote_srqn);
void ibv_wr_flush(struct ibv_qp_ex *qp, uint32_t rkey, uint64_t remote_addr,
size_t len, uint8_t type, uint8_t level);
π¦ DESCRIPTION π¦
ok so picture this: the verbs work request API (the whole ibv_wr_* family) lets you post work to a send queue efficiently β using function calls instead of that struct-based ibv_post_send() scheme. It's giving glow-up β¨ The whole design is about minimizing CPU branching and locking while you're posting. No cap, that's the entire point.
This API is intended to be used to access additional functionality beyond what ibv_post_send() gives you π₯
WRs batches from ibv_post_send() and WRs batches from this API can interleave together β but only if they are not posted within the critical region of each other. (A critical region in this API is formed by ibv_wr_start() and ibv_wr_complete()/ibv_wr_abort().) So like, respect the boundaries, bestie π
π USAGE π
To use these APIs the QP must be created using ibv_create_qp_ex() β that's the one that lets you set the IBV_QP_INIT_ATTR_SEND_OPS_FLAGS in comp_mask. The send_ops_flags should be set to the OR of the work request types that will be posted to the QP. Yes, the OR of them, all of them, together π«Ά
If the QP does not support all the requested work request types then QP creation will fail. π no partial credit, sorry.
Posting work requests to the QP is done within the critical region formed by ibv_wr_start() and ibv_wr_complete()/ibv_wr_abort() (see CONCURRENCY below).
Each work request is created by calling a WR builder function (see the table column WR builder below) to start creating the work request, followed by the allowed/required setter functions described below. Builder first, setters after β that's the order, don't fight it π
The WR builder and setter combination can be called multiple times to efficiently post multiple work requests within a single critical region. Iconic behaviour, honestly π
Each WR builder will use the wr_id member of struct ibv_qp_ex to set the value to be returned in the completion. Some operations will also use the wr_flags member to influence operation (see Flags below). These values should be set before invoking the WR builder function. Set it first, then build. Periodt.
For example a simple send could be formed as follows:
qpx->wr_id = 1;
ibv_wr_send(qpx);
ibv_wr_set_sge(qpx, lkey, &data, sizeof(data));
The section WORK REQUESTS describes the various WR builders and setters in detail.
Posting work is completed by calling ibv_wr_complete() or ibv_wr_abort(). No work is executed to the queue until ibv_wr_complete() returns success. And ibv_wr_abort() will discard all work prepared since ibv_wr_start() β like, poof, gone, never happened π
π WORK REQUESTS π
Okay bestie, so like β a bunch of these operations literally match the opcodes available for ibv_post_send(). Each operation has its own WR builder function, a list of allowed setters, and a flag bit to request it with send_ops_flags in struct ibv_qp_init_attr_ex (peep the EXAMPLE below, iykyk).
Here's the full operation table translated into snackable bullets, so your brain doesn't ghost you:
ATOMIC_CMP_AND_SWPβ WR builder:ibv_wr_atomic_cmp_swp(); QP types supported:RC,XRC_SEND; setters:DATA,QP.ATOMIC_FETCH_AND_ADDβ WR builder:ibv_wr_atomic_fetch_add(); QP types supported:RC,XRC_SEND; setters:DATA,QP.BIND_MWβ WR builder:ibv_wr_bind_mw(); QP types supported:UC,RC,XRC_SEND; setters:NONE.LOCAL_INVβ WR builder:ibv_wr_local_inv(); QP types supported:UC,RC,XRC_SEND; setters:NONE.RDMA_READβ WR builder:ibv_wr_rdma_read(); QP types supported:RC,XRC_SEND; setters:DATA,QP.RDMA_WRITEβ WR builder:ibv_wr_rdma_write(); QP types supported:UC,RC,XRC_SEND; setters:DATA,QP.FLUSHβ WR builder:ibv_wr_flush(); QP types supported:RC,RD,XRC_SEND; setters:DATA,QP.RDMA_WRITE_WITH_IMMβ WR builder:ibv_wr_rdma_write_imm(); QP types supported:UC,RC,XRC_SEND; setters:DATA,QP.SENDβ WR builder:ibv_wr_send(); QP types supported:UD,UC,RC,XRC_SEND,RAW_PACKET; setters:DATA,QP.SEND_WITH_IMMβ WR builder:ibv_wr_send_imm(); QP types supported:UD,UC,RC,XRC_SEND; setters:DATA,QP.SEND_WITH_INVβ WR builder:ibv_wr_send_inv(); QP types supported:UC,RC,XRC_SEND; setters:DATA,QP.TSOβ WR builder:ibv_wr_send_tso(); QP types supported:UD,RAW_PACKET; setters:DATA,QP.
βοΈ Atomic operations βοΈ
β οΈ Important vibe check: atomic operations are only atomic so long as all writes to memory go only through the same RDMA hardware. They are not atomic with writes performed by the CPU, or by other RDMA hardware in the system. No cap.
ibv_wr_atomic_cmp_swp()β if the remote 64-bit memory location specified byrkeyandremote_addrequalscompare, then set it toswap.ibv_wr_atomic_fetch_add()β addaddto the 64-bit memory location specified byrkeyandremote_addr.
π§ Memory Windows π§
These are memory window type 2 operations (see the man page for ibv_alloc_mw).
ibv_wr_bind_mw()β bind a MW type 2 specified bymw, set a newrkey, and set its properties bybind_info.ibv_wr_local_inv()β invalidate a MW type 2 which is associated withrkey.
π RDMA π
ibv_wr_rdma_read()β read from the remote memory location specified byrkeyandremote_addr. The number of bytes to read, and the local location to store the data, is determined by theDATAbuffers set after this call.ibv_wr_rdma_write(),ibv_wr_rdma_write_imm()β write to the remote memory location specified byrkeyandremote_addr. The number of bytes to read, and the local location to get the data, is determined by theDATAbuffers set after this call.
The _imm version causes the remote side to get a IBV_WC_RECV_RDMA_WITH_IMM containing the 32 bits of immediate data.
βοΈ Message Send βοΈ
ibv_wr_send(),ibv_wr_send_imm()β send a message. The number of bytes to send, and the local location to get the data, is determined by theDATAbuffers set after this call.
The _imm version causes the remote side to get a IBV_WC_RECV_RDMA_WITH_IMM containing the 32 bits of immediate data.
ibv_wr_send_inv()β the data transfer is the same as foribv_wr_send(), however the remote side will invalidate the MR specified byinvalidate_rkeybefore delivering a completion.ibv_wr_send_tso()β produce multiple SEND messages using TCP Segmentation Offload. The SGE points to a TCP Stream buffer which will be segmented into MSS size SENDs. Thehdrincludes the entire network headers up to and including the TCP header and is prefixed before each segment.
π― QP Specific setters π―
Certain QP types require each post to be accompanied by additional setters β these setters are mandatory for any operation that lists a QP setter in the above table.
- UD QPs β
ibv_wr_set_ud_addr()must be called to set the destination address of the work. - XRC_SEND QPs β
ibv_wr_set_xrc_srqn()must be called to set the destination SRQN field.
π¦ DATA transfer setters π¦
For work that requires transferring data, one of the following setters should be called once after the WR builder:
ibv_wr_set_sge()β transfer data to/from a single buffer given by thelkey,addr, andlength. This is equivalent toibv_wr_set_sge_list()with a single element.ibv_wr_set_sge_list()β transfer data to/from a list of buffers, logically concatenated together. Each buffer is specified by an element in an array ofstruct ibv_sge.
Inline setters will copy the send data during the setter and allow the caller to immediately re-use the buffer. This behavior is identical to the IBV_SEND_INLINE flag. Generally this copy is done in a way that optimizes SEND latency and is suitable for small messages. The provider will limit the amount of data it can support in a single operation. This limit is requested in the max_inline_data member of struct ibv_qp_init_attr. Valid only for SEND and RDMA_WRITE.
ibv_wr_set_inline_data()β copy send data from a single buffer given by theaddrandlength. This is equivalent toibv_wr_set_inline_data_list()with a single element.ibv_wr_set_inline_data_list()β copy send data from a list of buffers, logically concatenated together. Each buffer is specified by an element in an array ofstruct ibv_inl_data.
π© Flags π©
A bit mask of flags may be specified in wr_flags to control the behavior of the work request.
IBV_SEND_FENCEβ do not start this work request until prior work has completed.IBV_SEND_IP_CSUMβ offload the IPv4 and TCP/UDP checksum calculation.IBV_SEND_SIGNALEDβ a completion will be generated in the completion queue for the operation.IBV_SEND_SOLICITEDβ set the solicited bit in the RDMA packet. This informs the other side to generate a completion event upon receiving the RDMA operation.
π CONCURRENCY π
The provider will provide locking to ensure that ibv_wr_start() and ibv_wr_complete()/abort() form a per-QP critical section where no other threads can enter.
If an ibv_td is provided during QP creation then no locking will be performed and it is up to the caller to ensure that only one thread can be within the critical region at a time.
π«Ά RETURN VALUE π«Ά
Applications should use this API in a way that does not create failures. The individual APIs do not return a failure indication to avoid branching.
If a failure is detected during operation, for instance due to an invalid argument, then ibv_wr_complete() will return failure and the entire posting will be aborted.
π EXAMPLE π
/* create RC QP type and specify the required send opcodes */
qp_init_attr_ex.qp_type = IBV_QPT_RC;
qp_init_attr_ex.comp_mask |= IBV_QP_INIT_ATTR_SEND_OPS_FLAGS;
qp_init_attr_ex.send_ops_flags |= IBV_QP_EX_WITH_RDMA_WRITE;
qp_init_attr_ex.send_ops_flags |= IBV_QP_EX_WITH_RDMA_WRITE_WITH_IMM;
ibv_qp *qp = ibv_create_qp_ex(ctx, qp_init_attr_ex);
ibv_qp_ex *qpx = ibv_qp_to_qp_ex(qp);
ibv_wr_start(qpx);
/* create 1st WRITE WR entry */
qpx->wr_id = my_wr_id_1;
ibv_wr_rdma_write(qpx, rkey, remote_addr_1);
ibv_wr_set_sge(qpx, lkey, local_addr_1, length_1);
/* create 2nd WRITE_WITH_IMM WR entry */
qpx->wr_id = my_wr_id_2;
qpx->wr_flags = IBV_SEND_SIGNALED;
ibv_wr_rdma_write_imm(qpx, rkey, remote_addr_2, htonl(0x1234));
ibv_set_wr_sge(qpx, lkey, local_addr_2, length_2);
/* Begin processing WRs */
ret = ibv_wr_complete(qpx);
π SEE ALSO π
π AUTHOR π
- Jason Gunthorpe
<jgg@mellanox.com> - Guy Levi
<guyle@mellanox.com>
That's the whole page, bestie π β source is libibverbs, dated 2018-11-27, and the title is IBV_WR API(3). Stay iconic. π
β¨
π¦ where this page comes from
- alpine 3.24: rdma-core-doc 61.0-r0 Β· GPL-2.0-only OR BSD-2-Clause
- centos-stream 10: rdma-core-devel 62.0-3.el10 Β· GPLv2 or BSD
- centos-stream 9: rdma-core-devel 61.0-3.el9 Β· GPLv2 or BSD
- centos-stream 9: rdma-core-devel 61.0-3.el9 Β· GPLv2 or BSD
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms