@@ -438,6 +438,10 @@ cdef extern from 'infiniband/verbs.h':
unsigned int handle
unsigned int events_completed
+ cdef struct ibv_data_buf:
+ void *addr
+ size_t length
+
cdef struct ibv_qp:
ibv_context *context;
void *qp_context;
@@ -460,6 +464,12 @@ cdef extern from 'infiniband/verbs.h':
uint64_t resource_type);
void *pd_context;
+ cdef struct ibv_qp_ex:
+ ibv_qp qp_base
+ uint64_t comp_mask
+ uint64_t wr_id
+ unsigned int wr_flags
+
ibv_device **ibv_get_device_list(int *n)
void ibv_free_device_list(ibv_device **list)
ibv_context *ibv_open_device(ibv_device *device)
@@ -549,3 +559,33 @@ cdef extern from 'infiniband/verbs.h':
ibv_pd *ibv_alloc_parent_domain(ibv_context *context,
ibv_parent_domain_init_attr *attr)
uint32_t ibv_inc_rkey(uint32_t rkey)
+ ibv_qp_ex *ibv_qp_to_qp_ex(ibv_qp *qp)
+ void ibv_wr_atomic_cmp_swp(ibv_qp_ex *qp, uint32_t rkey,
+ uint64_t remote_addr, uint64_t compare,
+ uint64_t swap)
+ void ibv_wr_atomic_fetch_add(ibv_qp_ex *qp, uint32_t rkey,
+ uint64_t remote_addr, uint64_t add)
+ void ibv_wr_bind_mw(ibv_qp_ex *qp, ibv_mw *mw, uint32_t rkey,
+ ibv_mw_bind_info *bind_info)
+ void ibv_wr_local_inv(ibv_qp_ex *qp, uint32_t invalidate_rkey)
+ void ibv_wr_rdma_read(ibv_qp_ex *qp, uint32_t rkey, uint64_t remote_addr)
+ void ibv_wr_rdma_write(ibv_qp_ex *qp, uint32_t rkey, uint64_t remote_addr)
+ void ibv_wr_rdma_write_imm(ibv_qp_ex *qp, uint32_t rkey,
+ uint64_t remote_addr, uint32_t imm_data)
+ void ibv_wr_send(ibv_qp_ex *qp)
+ void ibv_wr_send_imm(ibv_qp_ex *qp, uint32_t imm_data)
+ void ibv_wr_send_inv(ibv_qp_ex *qp, uint32_t invalidate_rkey)
+ void ibv_wr_send_tso(ibv_qp_ex *qp, void *hdr, uint16_t hdr_sz,
+ uint16_t mss)
+ void ibv_wr_set_ud_addr(ibv_qp_ex *qp, ibv_ah *ah, uint32_t remote_qpn,
+ uint32_t remote_qkey)
+ void ibv_wr_set_xrc_srqn(ibv_qp_ex *qp, uint32_t remote_srqn)
+ void ibv_wr_set_inline_data(ibv_qp_ex *qp, void *addr, size_t length)
+ void ibv_wr_set_inline_data_list(ibv_qp_ex *qp, size_t num_buf,
+ ibv_data_buf *buf_list)
+ void ibv_wr_set_sge(ibv_qp_ex *qp, uint32_t lkey, uint64_t addr,
+ uint32_t length)
+ void ibv_wr_set_sge_list(ibv_qp_ex *qp, size_t num_sge, ibv_sge *sg_list)
+ void ibv_wr_start(ibv_qp_ex *qp)
+ int ibv_wr_complete(ibv_qp_ex *qp)
+ void ibv_wr_abort(ibv_qp_ex *qp)
@@ -236,6 +236,7 @@ cdef extern from '<infiniband/verbs.h>':
IBV_QP_INIT_ATTR_MAX_TSO_HEADER
IBV_QP_INIT_ATTR_IND_TABLE
IBV_QP_INIT_ATTR_RX_HASH
+ IBV_QP_INIT_ATTR_SEND_OPS_FLAGS
cpdef enum ibv_qp_create_flags:
IBV_QP_CREATE_BLOCK_SELF_MCAST_LB
@@ -401,6 +402,19 @@ cdef extern from '<infiniband/verbs.h>':
cpdef enum:
IBV_WC_STANDARD_FLAGS
+ cpdef enum ibv_qp_create_send_ops_flags:
+ IBV_QP_EX_WITH_RDMA_WRITE
+ IBV_QP_EX_WITH_RDMA_WRITE_WITH_IMM
+ IBV_QP_EX_WITH_SEND
+ IBV_QP_EX_WITH_SEND_WITH_IMM
+ IBV_QP_EX_WITH_RDMA_READ
+ IBV_QP_EX_WITH_ATOMIC_CMP_AND_SWP
+ IBV_QP_EX_WITH_ATOMIC_FETCH_AND_ADD
+ IBV_QP_EX_WITH_LOCAL_INV
+ IBV_QP_EX_WITH_BIND_MW
+ IBV_QP_EX_WITH_SEND_WITH_INV
+ IBV_QP_EX_WITH_TSO
+
cdef unsigned long long IBV_DEVICE_RAW_SCATTER_FCS
cdef unsigned long long IBV_DEVICE_PCI_WRITE_END_PADDING
@@ -37,3 +37,9 @@ cdef class QP(PyverbsCM):
cdef update_cqs(self, init_attr)
cdef object scq
cdef object rcq
+
+cdef class DataBuffer(PyverbsCM):
+ cdef v.ibv_data_buf data
+
+cdef class QPEx(QP):
+ cdef v.ibv_qp_ex *qp_ex
@@ -1,20 +1,30 @@
# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB)
# Copyright (c) 2019 Mellanox Technologies, Inc. All rights reserved.
+
+from libc.stdlib cimport malloc, free
+from libc.string cimport memcpy
+
from pyverbs.utils import gid_str, qp_type_to_str, qp_state_to_str, mtu_to_str
+from pyverbs.pyverbs_error import PyverbsUserError, PyverbsError
from pyverbs.utils import access_flags_to_str, mig_state_to_str
-from pyverbs.pyverbs_error import PyverbsUserError
+from pyverbs.wr cimport RecvWR, SendWR, SGE
from pyverbs.base import PyverbsRDMAErrno
-from pyverbs.wr cimport RecvWR, SendWR
+from pyverbs.addr cimport AHAttr, GID, AH
+from pyverbs.mr cimport MW, MWBindInfo
cimport pyverbs.libibverbs_enums as e
-from pyverbs.addr cimport AHAttr, GID
from pyverbs.addr cimport GlobalRoute
from pyverbs.device cimport Context
+from cpython.ref cimport PyObject
from pyverbs.cq cimport CQ, CQEX
cimport pyverbs.libibverbs as v
from pyverbs.xrcd cimport XRCD
from pyverbs.srq cimport SRQ
from pyverbs.pd cimport PD
-from libc.string cimport memcpy
+
+cdef extern from 'Python.h':
+ void* PyLong_AsVoidPtr(object)
+cdef extern from 'endian.h':
+ unsigned long htobe32(unsigned long host_32bits)
cdef class QPCap(PyverbsObject):
@@ -240,7 +250,7 @@ cdef class QPInitAttrEx(PyverbsObject):
SRQ srq=None, QPCap cap=None, sq_sig_all=0, comp_mask=0,
PD pd=None, XRCD xrcd=None, create_flags=0,
max_tso_header=0, source_qpn=0, object hash_conf=None,
- object ind_table=None):
+ object ind_table=None, send_ops_flags=0):
"""
Initialize a QPInitAttrEx object with user-defined or default values.
:param qp_type: QP type to be created
@@ -261,6 +271,8 @@ cdef class QPInitAttrEx(PyverbsObject):
set in create_flags)
:param hash_conf: Not yet supported
:param ind_table: Not yet supported
+ :param send_ops_flags: Send opcodes to be supported by the extended QP.
+ Use ibv_qp_create_send_ops_flags enum
:return: An initialized QPInitAttrEx object
"""
super().__init__()
@@ -302,6 +314,7 @@ cdef class QPInitAttrEx(PyverbsObject):
self.attr.create_flags = create_flags
self.attr.max_tso_header = max_tso_header
self.attr.source_qpn = source_qpn
+ self.attr.send_ops_flags = send_ops_flags
@property
def send_cq(self):
@@ -1141,6 +1154,137 @@ cdef class QP(PyverbsCM):
print_format.format(' state', qp_state_to_str(self.qp_state))
+cdef class DataBuffer(PyverbsCM):
+ def __init__(self, addr, length):
+ super().__init__()
+ self.data.addr = PyLong_AsVoidPtr(addr)
+ self.data.length = length
+
+
+cdef class QPEx(QP):
+ def __init__(self, object creator not None, object init_attr not None,
+ QPAttr qp_attr=None):
+ """
+ Initializes a QPEx object. Since this is an extension of a QP, QP
+ creation is done in the parent class. The extended QP is retrieved by
+ casting the ibv_qp to ibv_qp_ex.
+ :return: An initialized QPEx object
+ """
+ super().__init__(creator, init_attr, qp_attr)
+ self.qp_ex = v.ibv_qp_to_qp_ex(self.qp)
+ if self.qp_ex == NULL:
+ raise PyverbsRDMAErrno('Failed to create extended QP')
+
+ @property
+ def comp_mask(self):
+ return self.qp_ex.comp_mask
+ @comp_mask.setter
+ def comp_mask(self, val):
+ self.qp_ex.comp_mask = val
+
+ @property
+ def wr_id(self):
+ return self.qp_ex.wr_id
+ @wr_id.setter
+ def wr_id(self, val):
+ self.qp_ex.wr_id = val
+
+ @property
+ def wr_flags(self):
+ return self.qp_ex.wr_flags
+ @wr_flags.setter
+ def wr_flags(self, val):
+ self.qp_ex.wr_flags = val
+
+ def wr_atomic_cmp_swp(self, rkey, remote_addr, compare, swap):
+ v.ibv_wr_atomic_cmp_swp(self.qp_ex, rkey, remote_addr, compare, swap)
+
+ def wr_atomic_fetch_add(self, rkey, remote_addr, add):
+ v.ibv_wr_atomic_fetch_add(self.qp_ex, rkey, remote_addr, add)
+
+ def wr_bind_mw(self, MW mw, rkey, MWBindInfo bind_info):
+ cdef v.ibv_mw_bind_info *info
+ info = &bind_info.info
+ v.ibv_wr_bind_mw(self.qp_ex, <v.ibv_mw*>mw.mw, rkey,
+ <v.ibv_mw_bind_info*>info)
+
+ def wr_local_inv(self, invalidate_rkey):
+ v.ibv_wr_local_inv(self.qp_ex, invalidate_rkey)
+
+ def wr_rdma_read(self, rkey, remote_addr):
+ v.ibv_wr_rdma_read(self.qp_ex, rkey, remote_addr)
+
+ def wr_rdma_write(self, rkey, remote_addr):
+ v.ibv_wr_rdma_write(self.qp_ex, rkey, remote_addr)
+
+ def wr_rdma_write_imm(self, rkey, remote_addr, data):
+ cdef unsigned int imm_data = htobe32(data)
+ v.ibv_wr_rdma_write_imm(self.qp_ex, rkey, remote_addr, imm_data)
+
+ def wr_send(self):
+ v.ibv_wr_send(self.qp_ex)
+
+ def wr_send_imm(self, data):
+ cdef unsigned int imm_data = htobe32(data)
+ return v.ibv_wr_send_imm(self.qp_ex, imm_data)
+
+ def wr_send_inv(self, invalidate_rkey):
+ v.ibv_wr_send_inv(self.qp_ex, invalidate_rkey)
+
+ def wr_send_tso(self, hdr, hdr_sz, mss):
+ ptr = PyLong_AsVoidPtr(hdr)
+ v.ibv_wr_send_tso(self.qp_ex, ptr, hdr_sz, mss)
+
+ def wr_set_ud_addr(self, AH ah, remote_qpn, remote_rkey):
+ v.ibv_wr_set_ud_addr(self.qp_ex, ah.ah, remote_qpn, remote_rkey)
+
+ def wr_set_xrc_srqn(self, remote_srqn):
+ v.ibv_wr_set_xrc_srqn(self.qp_ex, remote_srqn)
+
+ def wr_set_inline_data(self, addr, length):
+ ptr = PyLong_AsVoidPtr(addr)
+ v.ibv_wr_set_inline_data(self.qp_ex, ptr, length)
+
+ def wr_set_inline_data_list(self, num_buf, buf_list):
+ cdef v.ibv_data_buf *data = NULL
+ data = <v.ibv_data_buf*>malloc(num_buf * sizeof(v.ibv_data_buf))
+ if data == NULL:
+ raise PyverbsError('Failed to allocate data buffer')
+ for i in range(num_buf):
+ data_buf = <DataBuffer>buf_list[i]
+ data[i].addr = data_buf.data.addr
+ data[i].length = data_buf.data.length
+ v.ibv_wr_set_inline_data_list(self.qp_ex, num_buf, data)
+ free(data)
+
+ def wr_set_sge(self, SGE sge not None):
+ v.ibv_wr_set_sge(self.qp_ex, sge.lkey, sge.addr, sge.length)
+
+ def wr_set_sge_list(self, num_sge, sg_list):
+ cdef v.ibv_sge *sge = NULL
+ sge = <v.ibv_sge*>malloc(num_sge * sizeof(v.ibv_sge))
+ if sge == NULL:
+ raise PyverbsError('Failed to allocate SGE buffer')
+ for i in range(num_sge):
+ sge[i].addr = sg_list[i].addr
+ sge[i].length = sg_list[i].length
+ sge[i].lkey = sg_list[i].lkey
+ v.ibv_wr_set_sge_list(self.qp_ex, num_sge, sge)
+ free(sge)
+
+ def wr_start(self):
+ v.ibv_wr_start(self.qp_ex)
+
+ def wr_complete(self):
+ rc = v.ibv_wr_complete(self.qp_ex)
+ if rc != 0:
+ raise PyverbsRDMAErrno('ibv_wr_complete failed , returned {}'.
+ format(rc))
+
+ def wr_abort(self):
+ v.ibv_wr_abort(self.qp_ex)
+
+
def _copy_caps(QPCap src, dst):
"""
Copy the QPCaps values of src into the inner ibv_qp_cap struct of dst.