import weakref from libc.errno cimport errno from libc.string cimport memcpy from libc.stdlib cimport malloc, free from pyverbs.pyverbs_error import PyverbsRDMAError, PyverbsError from pyverbs.wr cimport RecvWR, SGE, copy_sg_array from pyverbs.base import PyverbsRDMAErrno from pyverbs.base cimport close_weakrefs cimport pyverbs.libibverbs_enums as e from pyverbs.device cimport Context from pyverbs.cq cimport CQEX, CQ cimport pyverbs.libibverbs as v from pyverbs.xrcd cimport XRCD from pyverbs.qp cimport QP from pyverbs.pd cimport PD cdef class SrqAttr(PyverbsObject): def __init__(self, max_wr=100, max_sge=1, srq_limit=0): super().__init__() self.attr.max_wr = max_wr self.attr.max_sge = max_sge self.attr.srq_limit = srq_limit @property def max_wr(self): return self.attr.max_wr @max_wr.setter def max_wr(self, val): self.attr.max_wr = val @property def max_sge(self): return self.attr.max_sge @max_sge.setter def max_sge(self, val): self.attr.max_sge = val @property def srq_limit(self): return self.attr.srq_limit @srq_limit.setter def srq_limit(self, val): self.attr.srq_limit = val cdef class SrqInitAttr(PyverbsObject): def __init__(self, SrqAttr attr = None): super().__init__() if attr is not None: self.attr.attr.max_wr = attr.max_wr self.attr.attr.max_sge = attr.max_sge self.attr.attr.srq_limit = attr.srq_limit @property def max_wr(self): return self.attr.attr.max_wr @property def max_sge(self): return self.attr.attr.max_sge @property def srq_limit(self): return self.attr.attr.srq_limit cdef class SrqInitAttrEx(PyverbsObject): def __init__(self, max_wr=100, max_sge=1, srq_limit=0): super().__init__() self.attr.attr.max_wr = max_wr self.attr.attr.max_sge = max_sge self.attr.attr.srq_limit = srq_limit self._cq = None self._pd = None self._xrcd = None @property def max_wr(self): return self.attr.attr.max_wr @property def max_sge(self): return self.attr.attr.max_sge @property def srq_limit(self): return self.attr.attr.srq_limit @property def comp_mask(self): return self.attr.comp_mask @comp_mask.setter def comp_mask(self, val): self.attr.comp_mask = val @property def srq_type(self): return self.attr.srq_type @srq_type.setter def srq_type(self, val): self.attr.srq_type = val @property def pd(self): return self._pd @pd.setter def pd(self, PD val): self._pd = val self.attr.pd = val.pd @property def xrcd(self): return self._xrcd @xrcd.setter def xrcd(self, XRCD val): self._xrcd = val self.attr.xrcd = val.xrcd @property def max_num_tags(self): return self.attr.tm_cap.max_num_tags @max_num_tags.setter def max_num_tags(self, val): self.attr.tm_cap.max_num_tags = val @property def max_ops(self): return self.attr.tm_cap.max_ops @max_ops.setter def max_ops(self, val): self.attr.tm_cap.max_ops = val @property def cq(self): return self._cq @cq.setter def cq(self, val): if type(val) == CQ: self.attr.cq = (val).cq self._cq = val else: self.attr.cq = (val).ibv_cq self._cq = val cdef class OpsWr(PyverbsCM): def __init__(self, wr_id=0, opcode=e.IBV_WR_TAG_ADD, flags=e.IBV_OPS_SIGNALED, OpsWr next_wr=None, unexpected_cnt=0, recv_wr_id=0, num_sge=None, tag=0, mask=0, sg_list=None): self.ops_wr.wr_id = wr_id self.ops_wr.opcode = opcode self.ops_wr.flags = flags self.ops_wr.tm.unexpected_cnt = unexpected_cnt self.ops_wr.tm.add.recv_wr_id = recv_wr_id self.ops_wr.tm.add.tag = tag self.ops_wr.tm.add.mask = mask if next_wr is not None: self.ops_wr.next = &next_wr.ops_wr if num_sge is not None: self.ops_wr.tm.add.num_sge = num_sge cdef v.ibv_sge *dst if sg_list is not None: self.ops_wr.tm.add.sg_list = malloc(num_sge * sizeof(v.ibv_sge)) if self.ops_wr.tm.add.sg_list == NULL: raise MemoryError('Failed to malloc SG buffer') dst = self.ops_wr.tm.add.sg_list copy_sg_array(dst, sg_list, num_sge) def __dealloc__(self): self.close() cpdef close(self): if self.ops_wr.tm.add.sg_list != NULL: free(self.ops_wr.tm.add.sg_list) self.ops_wr.tm.add.sg_list = NULL @property def wr_id(self): return self.ops_wr.wr_id @wr_id.setter def wr_id(self, val): self.ops_wr.wr_id = val @property def next_wr(self): if self.ops_wr.next == NULL: return None val = OpsWr() val.ops_wr = self.ops_wr.next[0] return val @next_wr.setter def next_wr(self, OpsWr val not None): self.ops_wr.next = &val.ops_wr @property def opcode(self): return self.ops_wr.opcode @opcode.setter def opcode(self, val): self.ops_wr.opcode = val @property def flags(self): return self.ops_wr.flags @flags.setter def flags(self, val): self.ops_wr.flags = val @property def unexpected_cnt(self): return self.ops_wr.tm.unexpected_cnt @unexpected_cnt.setter def unexpected_cnt(self, val): self.ops_wr.tm.unexpected_cnt = val @property def recv_wr_id(self): return self.ops_wr.tm.add.recv_wr_id @recv_wr_id.setter def recv_wr_id(self, val): self.ops_wr.tm.add.recv_wr_id = val @property def tag(self): return self.ops_wr.tm.add.tag @tag.setter def tag(self, val): self.ops_wr.tm.add.tag = val @property def handle(self): return self.ops_wr.tm.handle @handle.setter def handle(self, val): self.ops_wr.tm.handle = val @property def mask(self): return self.ops_wr.tm.add.mask @mask.setter def mask(self, val): self.ops_wr.tm.add.mask = val cdef class SRQ(PyverbsCM): def __init__(self, object creator not None, object attr not None): super().__init__() self.srq = NULL self.cq = None self.qps = weakref.WeakSet() if isinstance(creator, PD): self._create_srq(creator, attr) elif type(creator) == Context: self._create_srq_ex(creator, attr) else: raise PyverbsRDMAError('Srq needs either Context or PD for creation') if self.srq == NULL: raise PyverbsRDMAErrno('Failed to create SRQ (errno is {err})'. format(err=errno)) self.logger.debug('SRQ Created') def __dealloc__(self): self.close() cpdef close(self): if self.srq != NULL: if self.logger: self.logger.debug('Closing SRQ') close_weakrefs([self.qps]) rc = v.ibv_destroy_srq(self.srq) if rc != 0: raise PyverbsRDMAError('Failed to destroy SRQ', rc) self.srq = NULL self.cq =None cdef add_ref(self, obj): if isinstance(obj, QP): self.qps.add(obj) else: raise PyverbsError('Unrecognized object type') def _create_srq(self, PD pd, SrqInitAttr init_attr): self.srq = v.ibv_create_srq(pd.pd, &init_attr.attr) pd.add_ref(self) def _create_srq_ex(self, Context context, SrqInitAttrEx init_attr_ex): self.srq = v.ibv_create_srq_ex(context.context, &init_attr_ex.attr) if init_attr_ex.cq: cq = init_attr_ex.cq cq.add_ref(self) self.cq = cq if init_attr_ex.xrcd: xrcd = init_attr_ex.xrcd xrcd.add_ref(self) if init_attr_ex.pd: pd = init_attr_ex.pd pd.add_ref(self) def get_srq_num(self): cdef unsigned int srqn rc = v.ibv_get_srq_num(self.srq, &srqn) if rc != 0: raise PyverbsRDMAError('Failed to retrieve SRQ number', rc) return srqn def modify(self, SrqAttr attr, comp_mask): rc = v.ibv_modify_srq(self.srq, &attr.attr, comp_mask) if rc != 0: raise PyverbsRDMAError('Failed to modify SRQ', rc) def query(self): attr = SrqAttr() rc = v.ibv_query_srq(self.srq, &attr.attr) if rc != 0: raise PyverbsRDMAError('Failed to query SRQ', rc) return attr def post_srq_ops(self, OpsWr wr not None, OpsWr bad_wr=None): """ Perform on a special shared receive queue (SRQ) configuration manipulations :param wr: Ops Work Requests to be posted to the TM-Shared Receive Queue :param bad_wr: A pointer that will be filled with the first Ops Work Request, that its processing failed """ cdef v.ibv_ops_wr *my_bad_wr rc= v.ibv_post_srq_ops(self.srq, &wr.ops_wr, &my_bad_wr) if rc != 0: if bad_wr: memcpy(&bad_wr.ops_wr, my_bad_wr, sizeof(bad_wr.ops_wr)) raise PyverbsRDMAError('post SRQ ops failed.', rc) def post_recv(self, RecvWR wr not None, RecvWR bad_wr=None): cdef v.ibv_recv_wr *my_bad_wr rc = v.ibv_post_srq_recv(self.srq, &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 receive to SRQ.', rc)