| import weakref | |
| from libc.errno cimport errno | |
| from libc.string cimport memcpy | |
| from libc.stdlib cimport malloc, free | |
| from libc.stdint cimport uintptr_t | |
| 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 = (<CQ>val).cq | |
| self._cq = val | |
| else: | |
| self.attr.cq = (<CQEX>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 = <v.ibv_sge*>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 isinstance(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 = <CQ>init_attr_ex.cq | |
| cq.add_ref(self) | |
| self.cq = cq | |
| if init_attr_ex.xrcd: | |
| xrcd = <XRCD>init_attr_ex.xrcd | |
| xrcd.add_ref(self) | |
| if init_attr_ex.pd: | |
| 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) | |
| @property | |
| def srq(self): | |
| return <uintptr_t>self.srq |