Skip to content

Commit

Permalink
pyverbs: Support WQ creation
Browse files Browse the repository at this point in the history
Add a WQ class that wraps ibv_wq and gives the ability to create,
modify, destroy and post on a WQ by wrapping the C APIs.

Signed-off-by: Shachar Kagan <skagan@nvidia.com>
Signed-off-by: Edward Srouji <edwards@nvidia.com>
  • Loading branch information
ShacharKagan authored and EdwardSro committed Feb 23, 2022
1 parent 8c0caf1 commit 037a175
Show file tree
Hide file tree
Showing 10 changed files with 269 additions and 3 deletions.
1 change: 1 addition & 0 deletions pyverbs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ rdma_cython_module(pyverbs ""
qp.pyx
spec.pyx
srq.pyx
wq.pyx
wr.pyx
xrcd.pyx
)
Expand Down
1 change: 1 addition & 0 deletions pyverbs/cq.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ cdef class CQ(PyverbsCM):
cdef object srqs
cdef object channel
cdef object num_events
cdef object wqs

cdef class CqInitAttrEx(PyverbsObject):
cdef v.ibv_cq_init_attr_ex attr
Expand Down
7 changes: 6 additions & 1 deletion pyverbs/cq.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ cimport pyverbs.libibverbs_enums as e
from pyverbs.device cimport Context
from pyverbs.srq cimport SRQ
from pyverbs.qp cimport QP
from pyverbs.wq cimport WQ


cdef class CompChannel(PyverbsCM):
"""
Expand Down Expand Up @@ -101,6 +103,7 @@ cdef class CQ(PyverbsCM):
context.add_ref(self)
self.qps = weakref.WeakSet()
self.srqs = weakref.WeakSet()
self.wqs = weakref.WeakSet()
self.num_events = 0
self.logger.debug('Created a CQ')

Expand All @@ -109,6 +112,8 @@ cdef class CQ(PyverbsCM):
self.qps.add(obj)
elif isinstance(obj, SRQ):
self.srqs.add(obj)
elif isinstance(obj, WQ):
self.wqs.add(obj)
else:
raise PyverbsError('Unrecognized object type')

Expand All @@ -118,7 +123,7 @@ cdef class CQ(PyverbsCM):
cpdef close(self):
if self.cq != NULL:
self.logger.debug('Closing CQ')
close_weakrefs([self.qps, self.srqs])
close_weakrefs([self.qps, self.srqs, self.wqs])
if self.num_events:
self.ack_events(self.num_events)
rc = v.ibv_destroy_cq(self.cq)
Expand Down
1 change: 1 addition & 0 deletions pyverbs/device.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ cdef class Context(PyverbsCM):
cdef object sched_nodes
cdef object sched_leafs
cdef object dr_domains
cdef object wqs

cdef class DeviceAttr(PyverbsObject):
cdef v.ibv_device_attr dev_attr
Expand Down
6 changes: 5 additions & 1 deletion pyverbs/device.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ from pyverbs.addr cimport GID
from pyverbs.mr import DMMR
from pyverbs.pd cimport PD
from pyverbs.qp cimport QP
from pyverbs.wq cimport WQ
from libc.stdlib cimport free, malloc
from libc.string cimport memset
from libc.stdint cimport uint64_t
Expand Down Expand Up @@ -118,6 +119,7 @@ cdef class Context(PyverbsCM):
self.sched_nodes = weakref.WeakSet()
self.sched_leafs = weakref.WeakSet()
self.dr_domains = weakref.WeakSet()
self.wqs = weakref.WeakSet()

self.name = kwargs.get('name')
provider_attr = kwargs.get('attr')
Expand Down Expand Up @@ -169,7 +171,7 @@ cdef class Context(PyverbsCM):
cpdef close(self):
if self.context != NULL:
self.logger.debug('Closing Context')
close_weakrefs([self.qps, self.ccs, self.cqs, self.dms, self.pds,
close_weakrefs([self.qps, self.wqs, self.ccs, self.cqs, self.dms, self.pds,
self.xrcds, self.vars, self.sched_leafs,
self.sched_nodes, self.dr_domains])
rc = v.ibv_close_device(self.context)
Expand Down Expand Up @@ -328,6 +330,8 @@ cdef class Context(PyverbsCM):
self.qps.add(obj)
elif isinstance(obj, XRCD):
self.xrcds.add(obj)
elif isinstance(obj, WQ):
self.wqs.add(obj)
else:
raise PyverbsError('Unrecognized object type')

Expand Down
33 changes: 33 additions & 0 deletions pyverbs/libibverbs.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,35 @@ cdef extern from 'infiniband/verbs.h':
ibv_async_event_element element
ibv_event_type event_type

cdef struct ibv_wq:
ibv_context *context
void *wq_context
ibv_pd *pd
ibv_cq *cq
uint32_t wq_num
uint32_t handle
ibv_wq_state state
ibv_wq_type wq_type
uint32_t events_completed
uint32_t comp_mask

cdef struct ibv_wq_init_attr:
void *wq_context
ibv_wq_type wq_type
uint32_t max_wr
uint32_t max_sge
ibv_pd *pd
ibv_cq *cq
uint32_t comp_mask
uint32_t create_flags

cdef struct ibv_wq_attr:
uint32_t attr_mask
ibv_wq_state wq_state
ibv_wq_state curr_wq_state
uint32_t flags
uint32_t flags_mask

ibv_device **ibv_get_device_list(int *n)
int ibv_get_device_index(ibv_device *device);
void ibv_free_device_list(ibv_device **list)
Expand Down Expand Up @@ -725,6 +754,10 @@ cdef extern from 'infiniband/verbs.h':
int ibv_query_qp_data_in_order(ibv_qp *qp, ibv_wr_opcode op, uint32_t flags)
int ibv_fork_init()
ibv_fork_status ibv_is_fork_initialized()
ibv_wq *ibv_create_wq(ibv_context *context, ibv_wq_init_attr *wq_init_attr)
int ibv_modify_wq(ibv_wq *wq, ibv_wq_attr *wq_attr)
int ibv_destroy_wq(ibv_wq *wq)
int ibv_post_wq_recv(ibv_wq *wq, ibv_recv_wr *recv_wr, ibv_recv_wr **bad_recv_wr)


cdef extern from 'infiniband/driver.h':
Expand Down
1 change: 1 addition & 0 deletions pyverbs/pd.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ cdef class PD(PyverbsCM):
cdef object ahs
cdef object qps
cdef object parent_domains
cdef object wqs
cdef object mkeys
cdef object deks
cdef object _is_imported
Expand Down
6 changes: 5 additions & 1 deletion pyverbs/pd.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ from pyverbs.srq cimport SRQ
from pyverbs.addr cimport AH
from pyverbs.cq cimport CQEX
from pyverbs.qp cimport QP
from pyverbs.wq cimport WQ


cdef class PD(PyverbsCM):
Expand Down Expand Up @@ -64,6 +65,7 @@ cdef class PD(PyverbsCM):
self.parent_domains = weakref.WeakSet()
self.mkeys = weakref.WeakSet()
self.deks = weakref.WeakSet()
self.wqs = weakref.WeakSet()

def advise_mr(self, advise, uint32_t flags, sg_list not None):
"""
Expand Down Expand Up @@ -106,7 +108,7 @@ cdef class PD(PyverbsCM):
if self.pd != NULL:
self.logger.debug('Closing PD')
close_weakrefs([self.deks, self.mkeys, self.parent_domains, self.qps,
self.ahs, self.mws, self.mrs, self.srqs])
self.wqs, self.ahs, self.mws, self.mrs, self.srqs])
if not self._is_imported:
rc = v.ibv_dealloc_pd(self.pd)
if rc != 0:
Expand All @@ -127,6 +129,8 @@ cdef class PD(PyverbsCM):
self.srqs.add(obj)
elif isinstance(obj, ParentDomain):
self.parent_domains.add(obj)
elif isinstance(obj, WQ):
self.wqs.add(obj)
else:
raise PyverbsError('Unrecognized object type')

Expand Down
25 changes: 25 additions & 0 deletions pyverbs/wq.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB)
# Copyright (c) 2021 Nvidia Inc. All rights reserved. See COPYING file

#cython: language_level=3

from pyverbs.base cimport PyverbsObject, PyverbsCM
from pyverbs.device cimport Context
cimport pyverbs.libibverbs as v
from pyverbs.cq cimport CQ
from pyverbs.pd cimport PD


cdef class WQInitAttr(PyverbsObject):
cdef v.ibv_wq_init_attr attr
cdef PD pd
cdef CQ cq

cdef class WQAttr(PyverbsObject):
cdef v.ibv_wq_attr attr

cdef class WQ(PyverbsCM):
cdef v.ibv_wq *wq
cdef Context context
cdef PD pd
cdef CQ cq
191 changes: 191 additions & 0 deletions pyverbs/wq.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB)
# Copyright (c) 2021 Nvidia Inc. All rights reserved. See COPYING file

from libc.string cimport memcpy

from .pyverbs_error import PyverbsRDMAError
from pyverbs.base import PyverbsRDMAErrno
cimport pyverbs.libibverbs_enums as e
from pyverbs.device cimport Context
from pyverbs.wr cimport RecvWR
from pyverbs.cq cimport CQ
from pyverbs.pd cimport PD
from pyverbs.qp cimport QP


cdef class WQInitAttr(PyverbsObject):
def __init__(self, wq_context=None, PD wq_pd=None, CQ wq_cq=None, wq_type=e.IBV_WQT_RQ,
max_wr=100, max_sge=1, comp_mask=0, create_flags=0):
"""
Initializes a WqInitAttr object representing ibv_wq_init_attr struct.
:param wq_context: Associated WQ context
:param wq_pd: PD to be associated with the WQ
:param wq_cq: CQ to be associated with the WQ
:param wp_type: The desired WQ type
:param max_wr: Requested max number of outstanding WRs in the WQ
:param max_sge: Requested max number of scatter/gather (s/g) elements per WR in the WQ
:param comp_mask: Identifies valid fields
:param create_flags: Creation flags for the WQ
:return: A WqInitAttr object
"""
super().__init__()
self.attr.wq_context = <void*>(wq_context) if wq_context else NULL
self.attr.wq_type = wq_type
self.attr.max_wr = max_wr
self.attr.max_sge = max_sge
self.pd = wq_pd
self.attr.pd = wq_pd.pd if wq_pd else NULL
self.cq = wq_cq
self.attr.cq = wq_cq.cq if wq_cq else NULL
self.attr.comp_mask = comp_mask
self.attr.create_flags = create_flags

@property
def wq_type(self):
return self.attr.wq_type
@wq_type.setter
def wq_type(self, val):
self.attr.wq_type = val

@property
def pd(self):
return self.pd
@pd.setter
def pd(self, PD val):
self.pd = val
self.attr.pd = <v.ibv_pd*>val.pd

@property
def cq(self):
return self.cq
@cq.setter
def cq(self, CQ val):
self.cq = val
self.attr.cq = <v.ibv_cq*>val.cq


cdef class WQAttr(PyverbsObject):
def __init__(self, attr_mask=0, wq_state=0, curr_wq_state=0, flags=0, flags_mask=0):
"""
Initializes a WQAttr object which represents ibv_wq_attr struct. It
can be used to modify a WQ.
:param attr_mask: Identifies valid fields
:param wq_state: Desired WQ state
:param curr_wq_state: Current WQ state
:param flags: Flags values to modify
:param flags_mask: Which flags to modify
:return: An initialized WQAttr object
"""
super().__init__()
self.attr.attr_mask = attr_mask
self.attr.wq_state = wq_state
self.attr.curr_wq_state = curr_wq_state
self.attr.flags = flags
self.attr.flags_mask = flags_mask

@property
def wq_state(self):
return self.attr.wq_state
@wq_state.setter
def wq_state(self, val):
self.attr.wq_state = val

@property
def attr_mask(self):
return self.attr.attr_mask
@attr_mask.setter
def attr_mask(self, val):
self.attr.attr_mask = val

@property
def curr_wq_state(self):
return self.attr.curr_wq_state
@curr_wq_state.setter
def curr_wq_state(self, val):
self.attr.curr_wq_state = val

@property
def flags(self):
return self.attr.flags
@flags.setter
def flags(self, val):
self.attr.flags = val

@property
def flags_mask(self):
return self.attr.flags_mask
@flags_mask.setter
def flags_mask(self, val):
self.attr.flags_mask = val


cdef class WQ(PyverbsCM):
def __init__(self, Context ctx, WQInitAttr attr):
"""
Creates a WQ object.
:param ctx: The context the wq will be associated with.
:param attr: WQ initial attributes of type WQInitAttr.
:return: A WQ object
"""
super().__init__()
self.wq = v.ibv_create_wq(ctx.context, &attr.attr)
if self.wq == NULL:
raise PyverbsRDMAErrno('Failed to create WQ')
self.context = ctx
ctx.add_ref(self)
pd = <PD>attr.pd
pd.add_ref(self)
self.pd = pd
cq = <CQ>attr.cq
cq.add_ref(self)
self.cq = cq

def modify(self, WQAttr wq_attr not None):
"""
Modify the WQ
:param qp_attr: A WQAttr object with updated values to be applied to
the WQ
:return: None
"""
rc = v.ibv_modify_wq(self.wq, &wq_attr.attr)
if rc != 0:
raise PyverbsRDMAError('Failed to modify WQ', rc)

def post_recv(self, RecvWR wr not None, RecvWR bad_wr=None):
"""
Post a receive WR on the WQ.
:param wr: The work request to post
:param bad_wr: A RecvWR object to hold the bad WR if it is available in
case of a failure
:return: None
"""
cdef v.ibv_recv_wr *my_bad_wr
# In order to provide a pointer to a pointer, use a temporary cdef'ed
# variable.
rc = v.ibv_post_wq_recv(self.wq, &wr.recv_wr, &my_bad_wr)
if rc != 0:
if (bad_wr):
memcpy(&bad_wr.recv_wr, my_bad_wr, sizeof(bad_wr.recv_wr))
raise PyverbsRDMAError('Failed to post recv', rc)

def __dealloc__(self):
self.close()

cpdef close(self):
"""
Closes the underlying C object of the WQ.
:return: None
"""
if self.wq != NULL:
self.logger.debug('Closing WQ')
rc = v.ibv_destroy_wq(self.wq)
if rc != 0:
raise PyverbsRDMAError('Failed to dealloc WQ', rc)
self.wq = NULL
self.context = None
self.pd = None
self.cq = None

@property
def wqn(self):
return self.wq.wq_num

0 comments on commit 037a175

Please sign in to comment.