From 6085fa27738f9b3adfa5959a948b0e29e5645cec Mon Sep 17 00:00:00 2001 From: Amit Matityahu Date: Tue, 31 Mar 2020 18:26:58 +0300 Subject: [PATCH 1/3] pyverbs: Add the imm_data property to SendWR Added imm_data to the SendWR class with a getter/setter. Signed-off-by: Amit Matityahu Signed-off-by: Edward Srouji --- pyverbs/libibverbs.pxd | 1 + pyverbs/wr.pyx | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pyverbs/libibverbs.pxd b/pyverbs/libibverbs.pxd index dfd4924f7..2f3447aa4 100755 --- a/pyverbs/libibverbs.pxd +++ b/pyverbs/libibverbs.pxd @@ -329,6 +329,7 @@ cdef extern from 'infiniband/verbs.h': ibv_sge *sg_list int num_sge ibv_wr_opcode opcode + uint32_t imm_data unsigned int send_flags wr wr qp_type qp_type diff --git a/pyverbs/wr.pyx b/pyverbs/wr.pyx index 37028c562..3abd6bf68 100644 --- a/pyverbs/wr.pyx +++ b/pyverbs/wr.pyx @@ -143,15 +143,17 @@ cdef class RecvWR(PyverbsCM): cdef class SendWR(PyverbsCM): - def __init__(self, wr_id=0, opcode=e.IBV_WR_SEND, num_sge=0, sg = None, - send_flags=e.IBV_SEND_SIGNALED, SendWR next_wr = None): + def __init__(self, wr_id=0, opcode=e.IBV_WR_SEND, num_sge=0, imm_data=0, + sg = None, send_flags=e.IBV_SEND_SIGNALED, + SendWR next_wr = None): """ Initialize a SendWR object with user-provided or default values. :param wr_id: A user-defined WR ID :param opcode: The WR's opcode :param num_sge: Number of scatter-gather elements in the WR - :param send_flags: Send flags as define in ibv_send_flags enum + :param imm_data: Immediate data :param sg: A SGE element, head of the scatter-gather list + :param send_flags: Send flags as define in ibv_send_flags enum :return: An initialized SendWR object """ cdef v.ibv_sge *dst @@ -170,6 +172,7 @@ cdef class SendWR(PyverbsCM): self.send_wr.next = &next_wr.send_wr self.send_wr.opcode = opcode self.send_wr.send_flags = send_flags + self.send_wr.imm_data = imm_data self.ah = None def __dealloc(self): @@ -184,7 +187,8 @@ cdef class SendWR(PyverbsCM): print_format.format('Num SGE', self.send_wr.num_sge) +\ print_format.format('Opcode', self.send_wr.opcode) +\ print_format.format('Send flags', - send_flags_to_str(self.send_wr.send_flags)) + send_flags_to_str(self.send_wr.send_flags) +\ + print_format.format('Imm Data', self.send_wr.imm_data)) @property def next_wr(self): @@ -211,6 +215,13 @@ cdef class SendWR(PyverbsCM): def num_sge(self, val): self.send_wr.num_sge = val + @property + def imm_data(self): + return self.send_wr.imm_data + @imm_data.setter + def imm_data(self, val): + self.send_wr.imm_data = val + @property def opcode(self): return self.send_wr.opcode From c05fd072e3faf61c0a92d99829bf48478abc9e03 Mon Sep 17 00:00:00 2001 From: Ido Kalir Date: Mon, 25 May 2020 23:48:14 +0300 Subject: [PATCH 2/3] pyverbs: Add memory window support Add support to create and use Memory Window. Supports both types of Memory Window (MW type 1 and 2). Signed-off-by: Ido Kalir Signed-off-by: Edward Srouji --- pyverbs/libibverbs.pxd | 15 +++++++----- pyverbs/mr.pxd | 4 ++++ pyverbs/mr.pyx | 52 ++++++++++++++++++++++++++++++++++++++++++ pyverbs/qp.pyx | 15 ++++++++++-- pyverbs/wr.pyx | 25 ++++++++++++++++++-- 5 files changed, 101 insertions(+), 10 deletions(-) diff --git a/pyverbs/libibverbs.pxd b/pyverbs/libibverbs.pxd index 2f3447aa4..2fb1322fb 100755 --- a/pyverbs/libibverbs.pxd +++ b/pyverbs/libibverbs.pxd @@ -146,7 +146,7 @@ cdef extern from 'infiniband/verbs.h': ibv_pd *pd unsigned int rkey unsigned int handle - ibv_mw_type mw_type + ibv_mw_type type cdef struct ibv_alloc_dm_attr: size_t length @@ -303,6 +303,11 @@ cdef extern from 'infiniband/verbs.h': unsigned long length unsigned int mw_access_flags + cdef struct ibv_mw_bind: + uint64_t wr_id + unsigned int send_flags + ibv_mw_bind_info bind_info + cdef struct bind_mw: ibv_mw *mw unsigned int rkey @@ -313,10 +318,6 @@ cdef extern from 'infiniband/verbs.h': unsigned short hdr_sz unsigned short mss - cdef union unnamed: - bind_mw bind_mw - tso tso - cdef struct xrc: unsigned int remote_srqn @@ -333,7 +334,8 @@ cdef extern from 'infiniband/verbs.h': unsigned int send_flags wr wr qp_type qp_type - unnamed unnamed + bind_mw bind_mw + tso tso cdef struct ibv_qp_cap: unsigned int max_send_wr @@ -557,6 +559,7 @@ cdef extern from 'infiniband/verbs.h': int ibv_destroy_qp(ibv_qp *qp) int ibv_post_recv(ibv_qp *qp, ibv_recv_wr *wr, ibv_recv_wr **bad_wr) int ibv_post_send(ibv_qp *qp, ibv_send_wr *wr, ibv_send_wr **bad_wr) + int ibv_bind_mw(ibv_qp *qp, ibv_mw *mw, ibv_mw_bind *mw_bind) ibv_xrcd *ibv_open_xrcd(ibv_context *context, ibv_xrcd_init_attr *xrcd_init_attr) int ibv_close_xrcd(ibv_xrcd *xrcd) diff --git a/pyverbs/mr.pxd b/pyverbs/mr.pxd index 7c3bb8e28..3adb2ad0f 100644 --- a/pyverbs/mr.pxd +++ b/pyverbs/mr.pxd @@ -21,6 +21,10 @@ cdef class MWBindInfo(PyverbsCM): cdef v.ibv_mw_bind_info info cdef object mr +cdef class MWBind(PyverbsCM): + cdef v.ibv_mw_bind mw_bind + cdef object mr + cdef class MW(PyverbsCM): cdef object pd cdef v.ibv_mw *mw diff --git a/pyverbs/mr.pyx b/pyverbs/mr.pyx index 6838e8427..b9afe0cf0 100644 --- a/pyverbs/mr.pyx +++ b/pyverbs/mr.pyx @@ -204,6 +204,39 @@ cdef class MWBindInfo(PyverbsCM): self.info.length = length self.info.mw_access_flags = mw_access_flags + @property + def mw_access_flags(self): + return self.info.mw_access_flags + + @property + def length(self): + return self.info.length + + @property + def addr(self): + return self.info.addr + + def __str__(self): + print_format = '{:22}: {:<20}\n' + return 'MWBindInfo:\n' +\ + print_format.format('Addr', self.info.addr) +\ + print_format.format('Length', self.info.length) +\ + print_format.format('MW access flags', self.info.mw_access_flags) + + +cdef class MWBind(PyverbsCM): + def __init__(self, MWBindInfo info not None,send_flags, wr_id=0): + super().__init__() + self.mw_bind.wr_id = wr_id + self.mw_bind.send_flags = send_flags + self.mw_bind.bind_info = info.info + + def __str__(self): + print_format = '{:22}: {:<20}\n' + return 'MWBind:\n' +\ + print_format.format('WR id', self.mw_bind.wr_id) +\ + print_format.format('Send flags', self.mw_bind.send_flags) + cdef class MW(PyverbsCM): def __init__(self, PD pd not None, v.ibv_mw_type mw_type): @@ -242,6 +275,25 @@ cdef class MW(PyverbsCM): self.mw = NULL self.pd = None + @property + def handle(self): + return self.mw.handle + + @property + def rkey(self): + return self.mw.rkey + + @property + def type(self): + return self.mw.type + + def __str__(self): + print_format = '{:22}: {:<20}\n' + return 'MW:\n' +\ + print_format.format('Rkey', self.mw.rkey) +\ + print_format.format('Handle', self.mw.handle) +\ + print_format.format('MW Type', mwtype2str(self.mw.type)) + cdef class DMMR(MR): def __init__(self, PD pd not None, length, access, DM dm, offset): diff --git a/pyverbs/qp.pyx b/pyverbs/qp.pyx index d8848add1..c2695a526 100755 --- a/pyverbs/qp.pyx +++ b/pyverbs/qp.pyx @@ -8,11 +8,11 @@ import weakref from pyverbs.pyverbs_error import PyverbsUserError, PyverbsError, PyverbsRDMAError from pyverbs.utils import gid_str, qp_type_to_str, qp_state_to_str, mtu_to_str from pyverbs.utils import access_flags_to_str, mig_state_to_str -from pyverbs.base import PyverbsRDMAErrno +from pyverbs.mr cimport MW, MWBindInfo, MWBind from pyverbs.wr cimport RecvWR, SendWR, SGE +from pyverbs.base import PyverbsRDMAErrno from pyverbs.addr cimport AHAttr, GID, AH from pyverbs.base cimport close_weakrefs -from pyverbs.mr cimport MW, MWBindInfo cimport pyverbs.libibverbs_enums as e from pyverbs.addr cimport GlobalRoute from pyverbs.device cimport Context @@ -1188,6 +1188,17 @@ cdef class QP(PyverbsCM): raise PyverbsRDMAError('Failed to query ECE', rc) return ece + def bind_mw(self, MW mw not None, MWBind mw_bind): + """ + Bind Memory window type 1. + :param mw: The memory window to bind. + :param mw_bind: MWBind object, includes the bind attributes. + :return: None + """ + rc = v.ibv_bind_mw(self.qp, mw.mw, &mw_bind.mw_bind) + if rc != 0: + raise PyverbsRDMAError('Failed to Bind MW', rc) + @property def qp_type(self): return self.qp.qp_type diff --git a/pyverbs/wr.pyx b/pyverbs/wr.pyx index 3abd6bf68..52e9d55c4 100644 --- a/pyverbs/wr.pyx +++ b/pyverbs/wr.pyx @@ -2,8 +2,10 @@ # Copyright (c) 2019 Mellanox Technologies Inc. All rights reserved. See COPYING file from pyverbs.pyverbs_error import PyverbsUserError, PyverbsError -from pyverbs.base import PyverbsRDMAErrno +from pyverbs.base import PyverbsRDMAErrno, inc_rkey +from pyverbs.mr cimport MW, MR, MWBindInfo cimport pyverbs.libibverbs_enums as e +cimport pyverbs.libibverbs as v from pyverbs.addr cimport AH from libc.stdlib cimport free, malloc from libc.string cimport memcpy @@ -159,7 +161,9 @@ cdef class SendWR(PyverbsCM): cdef v.ibv_sge *dst super().__init__() - if num_sge < 1 or sg is None: + mw_opcodes = [e.IBV_WR_LOCAL_INV, e.IBV_WR_BIND_MW, + e.IBV_WR_SEND_WITH_INV] + if opcode not in mw_opcodes and (num_sge < 1 or sg is None): raise PyverbsUserError('A WR needs at least one SGE') self.send_wr.sg_list = malloc(num_sge * sizeof(v.ibv_sge)) if self.send_wr.sg_list == NULL: @@ -284,6 +288,23 @@ cdef class SendWR(PyverbsCM): self.send_wr.wr.atomic.compare_add = compare_add self.send_wr.wr.atomic.swap = swap + def set_bind_wr(self, MW mw, MWBindInfo bind_info): + """ + Set the members of the bind_mw struct in the send_wr. + :param mw: The MW to bind. + :param bind_info: MWBindInfo object, includes the bind attributes. + :return: None + """ + self.send_wr.bind_mw.mw = mw.mw + # Create the new key from the MW rkey. + rkey = inc_rkey(mw.rkey) + self.send_wr.bind_mw.rkey = rkey + self.send_wr.bind_mw.bind_info = bind_info.info + + @property + def rkey(self): + return self.send_wr.bind_mw.rkey + def set_qp_type_xrc(self, remote_srqn): """ Set the members of the xrc struct in the send_wr's qp_type union, used From 7b1ec39e02fe3d0ecee29ba55ad63763ae379d3d Mon Sep 17 00:00:00 2001 From: Ido Kalir Date: Sun, 31 May 2020 22:10:41 +0300 Subject: [PATCH 3/3] tests: Add Memory Window tests Add test cases that create and use Memory Window. This includes both types of Memory Window and invalidate MW as well. Some previous tests were adjusted or removed since they are now covered in the newly added tests. Signed-off-by: Ido Kalir Signed-off-by: Edward Srouji --- Documentation/pyverbs.md | 2 + tests/test_mr.py | 248 ++++++++++++++++++++++++++++++--------- tests/test_qpex.py | 18 +-- tests/test_shared_pd.py | 2 +- tests/utils.py | 46 ++++---- 5 files changed, 231 insertions(+), 85 deletions(-) diff --git a/Documentation/pyverbs.md b/Documentation/pyverbs.md index 2516b10c7..0616d02f5 100755 --- a/Documentation/pyverbs.md +++ b/Documentation/pyverbs.md @@ -175,6 +175,8 @@ with d.Context(name='mlx5_0') as ctx: ##### Memory window The following example shows the equivalent of creating a type 1 memory window. It includes opening a device and allocating the necessary PD. +The user should unbind or close the memory window before being able to +deregister an MR that the MW is bound to. ```python import pyverbs.device as d from pyverbs.pd import PD diff --git a/tests/test_mr.py b/tests/test_mr.py index f53582892..51a7fdd07 100644 --- a/tests/test_mr.py +++ b/tests/test_mr.py @@ -7,9 +7,11 @@ import random import errno +from tests.base import PyverbsAPITestCase, RCResources, RDMATestCase from pyverbs.pyverbs_error import PyverbsRDMAError, PyverbsError -from tests.base import PyverbsAPITestCase -from pyverbs.mr import MR, MW, DMMR +from pyverbs.mr import MR, MW, DMMR, MWBindInfo, MWBind +from pyverbs.qp import QPCap, QPInitAttr, QPAttr, QP +from pyverbs.wr import SendWR import pyverbs.device as d from pyverbs.pd import PD import pyverbs.enums as e @@ -150,74 +152,210 @@ def test_buffer(self): mr.buf -class MWTest(PyverbsAPITestCase): +class MWRC(RCResources): + def __init__(self, dev_name, ib_port, gid_index, mw_type): + """ + Initialize Memory Window resources based on RC resources that include RC + QP. + :param dev_name: Device name to be used + :param ib_port: IB port of the device to use + :param gid_index: Which GID index to use + :param mw_type: The MW type to use + """ + super().__init__(dev_name=dev_name, ib_port=ib_port, + gid_index=gid_index) + self.mw_type = mw_type + access = e.IBV_ACCESS_REMOTE_WRITE | e.IBV_ACCESS_LOCAL_WRITE + self.mw_bind_info = MWBindInfo(self.mr, self.mr.buf, self.msg_size, + access) + self.mw_bind = MWBind(self.mw_bind_info, e.IBV_SEND_SIGNALED) + try: + self.mw = MW(self.pd, self.mw_type) + except PyverbsRDMAError as ex: + if ex.error_code == errno.EOPNOTSUPP: + raise unittest.SkipTest('Create MW is not supported') + raise ex + + def create_mr(self): + access = e.IBV_ACCESS_LOCAL_WRITE | e.IBV_ACCESS_MW_BIND + try: + self.mr = MR(self.pd, self.msg_size, access) + except PyverbsRDMAError as ex: + if ex.error_code == errno.EOPNOTSUPP: + raise unittest.SkipTest('Reg MR with MW access is not supported') + raise ex + + def create_qp(self): + qp_caps = QPCap(max_recv_wr=self.num_msgs) + qp_init_attr = QPInitAttr(qp_type=e.IBV_QPT_RC, scq=self.cq, + rcq=self.cq, cap=qp_caps) + qp_attr = QPAttr(port_num=self.ib_port) + qp_access = e.IBV_ACCESS_LOCAL_WRITE | e.IBV_ACCESS_REMOTE_WRITE + qp_attr.qp_access_flags = qp_access + try: + self.qp = QP(self.pd, qp_init_attr, qp_attr) + except PyverbsRDMAError as ex: + if ex.error_code == errno.EOPNOTSUPP: + raise unittest.SkipTest('Create RC QP is not supported') + raise ex + + + +class MWTest(RDMATestCase): """ Test various functionalities of the MW class. """ - def test_reg_mw_type1(self): - """ - Test ibv_alloc_mw() for type 1 MW - """ - for ctx, attr, attr_ex in self.devices: - with PD(ctx) as pd: - try: - with MW(pd, e.IBV_MW_TYPE_1): - pass - except PyverbsRDMAError as ex: - if ex.error_code == errno.EOPNOTSUPP: - raise unittest.SkipTest('Create memory window of type 1 is not supported') - raise ex + def setUp(self): + super().setUp() + self.iters = 10 + self.server = None + self.client = None - def test_reg_mw_type2(self): - """ - Test ibv_alloc_mw() for type 2 MW - """ - for ctx, attr, attr_ex in self.devices: - with PD(ctx) as pd: - try: - with MW(pd, e.IBV_MW_TYPE_2): - pass - except PyverbsRDMAError as ex: - if ex.error_code == errno.EOPNOTSUPP: - raise unittest.SkipTest('Create memory window of type 2 is not supported') - raise ex + def create_players(self, resource, **resource_arg): + """ + Init memory window tests resources. + :param resource: The RDMA resources to use. + :param resource_arg: Dict of args that specify the resource specific + attributes. + :return: None + """ + self.client = resource(**self.dev_info, **resource_arg) + self.server = resource(**self.dev_info, **resource_arg) + self.client.pre_run(self.server.psn, self.server.qpn) + self.server.pre_run(self.client.psn, self.client.qpn) - def test_dereg_mw_type1(self): - """ - Test ibv_dealloc_mw() for type 1 MW - """ - for ctx, attr, attr_ex in self.devices: - with PD(ctx) as pd: - try: - with MW(pd, e.IBV_MW_TYPE_1) as mw: - mw.close() - except PyverbsRDMAError as ex: - if ex.error_code == errno.EOPNOTSUPP: - raise unittest.SkipTest('Create memory window of type 1 is not supported') - raise ex + def tearDown(self): + if self.server: + self.server.mw.close() + if self.client: + self.client.mw.close() + return super().tearDown() - def test_dereg_mw_type2(self): + def bind_mw_type_1(self): + self.server.qp.bind_mw(self.server.mw, self.server.mw_bind) + self.client.qp.bind_mw(self.client.mw, self.client.mw_bind) + # Poll the bind MW action completion. + u.poll_cq(self.server.cq) + u.poll_cq(self.client.cq) + self.server.rkey = self.client.mw.rkey + self.server.remote_addr = self.client.mr.buf + self.client.rkey = self.server.mw.rkey + self.client.remote_addr = self.server.mr.buf + + def bind_mw_type_2(self): + client_send_wr = SendWR(opcode=e.IBV_WR_BIND_MW) + client_send_wr.set_bind_wr(self.client.mw, self.client.mw_bind_info) + server_send_wr = SendWR(opcode=e.IBV_WR_BIND_MW) + server_send_wr.set_bind_wr(self.server.mw, self.server.mw_bind_info) + self.server.qp.post_send(server_send_wr) + self.client.qp.post_send(client_send_wr) + # Poll the bind MW WR. + u.poll_cq(self.server.cq) + u.poll_cq(self.client.cq) + self.server.rkey = client_send_wr.rkey + self.server.remote_addr = self.client.mr.buf + self.client.rkey = server_send_wr.rkey + self.client.remote_addr = self.server.mr.buf + + def invalidate_mw_type1(self): """ - Test ibv_dealloc_mw() for type 2 MW + Invalidate the MWs by rebind this MW with zero length. + :return: None """ - for ctx, attr, attr_ex in self.devices: - with PD(ctx) as pd: - try: - with MW(pd, e.IBV_MW_TYPE_2) as mw: - mw.close() - except PyverbsRDMAError as ex: - if ex.error_code == errno.EOPNOTSUPP: - raise unittest.SkipTest('Create memory window of type 2 is not supported') - raise ex + for player in [self.server, self.client]: + mw_bind_info = MWBindInfo(player.mr, player.mr.buf, 0, 0) + mw_bind = MWBind(mw_bind_info, e.IBV_SEND_SIGNALED) + player.qp.bind_mw(player.mw, mw_bind) + # Poll the bound MW action request completion. + u.poll_cq(player.cq) + + def invalidate_mw_type2_local(self): + """ + Invalidate the MWs by post invalidation send WR from the local QP. + :return: None + """ + inv_send_wr = SendWR(opcode=e.IBV_WR_LOCAL_INV) + inv_send_wr.imm_data = self.server.rkey + self.client.qp.post_send(inv_send_wr) + inv_send_wr = SendWR(opcode=e.IBV_WR_LOCAL_INV) + inv_send_wr.imm_data = self.client.rkey + self.server.qp.post_send(inv_send_wr) + # Poll the invalidate MW WR. + u.poll_cq(self.server.cq) + u.poll_cq(self.client.cq) + + def invalidate_mw_type2_remote(self): + """ + Invalidate the MWs by sending invalidation send WR from the remote QP. + :return: None + """ + server_recv_wr = u.get_recv_wr(self.server) + client_recv_wr = u.get_recv_wr(self.client) + self.server.qp.post_recv(server_recv_wr) + self.client.qp.post_recv(client_recv_wr) + inv_send_wr = SendWR(opcode=e.IBV_WR_SEND_WITH_INV) + inv_send_wr.imm_data = self.client.rkey + self.client.qp.post_send(inv_send_wr) + inv_send_wr = SendWR(opcode=e.IBV_WR_SEND_WITH_INV) + inv_send_wr.imm_data = self.server.rkey + self.server.qp.post_send(inv_send_wr) + # Poll the invalidate MW send WR. + u.poll_cq(self.server.cq) + u.poll_cq(self.client.cq) + # Poll the invalidate MW recv WR. + u.poll_cq(self.server.cq) + u.poll_cq(self.client.cq) + + def test_mw_type1(self): + self.create_players(MWRC, mw_type=e.IBV_MW_TYPE_1) + self.bind_mw_type_1() + u.rdma_traffic(self.client, self.server, self.iters, self.gid_index, + self.ib_port, send_op=e.IBV_WR_RDMA_WRITE) + + def test_invalidate_mw_type1(self): + self.test_mw_type1() + self.invalidate_mw_type1() + with self.assertRaisesRegex(PyverbsRDMAError, 'Remote access error'): + u.rdma_traffic(self.client, self.server, self.iters, self.gid_index, + self.ib_port, send_op=e.IBV_WR_RDMA_WRITE) + + def test_mw_type2(self): + self.create_players(MWRC, mw_type=e.IBV_MW_TYPE_2) + self.bind_mw_type_2() + u.rdma_traffic(self.client, self.server, self.iters, self.gid_index, + self.ib_port, send_op=e.IBV_WR_RDMA_WRITE) + + def test_mw_type2_invalidate_local(self): + self.test_mw_type2() + self.invalidate_mw_type2_local() + with self.assertRaisesRegex(PyverbsRDMAError, 'Remote access error'): + u.rdma_traffic(self.client, self.server, self.iters, self.gid_index, + self.ib_port, send_op=e.IBV_WR_RDMA_WRITE) + + def test_mw_type2_invalidate_remote(self): + self.test_mw_type2() + self.invalidate_mw_type2_remote() + with self.assertRaisesRegex(PyverbsRDMAError, 'Remote access error'): + u.rdma_traffic(self.client, self.server, self.iters, self.gid_index, + self.ib_port, send_op=e.IBV_WR_RDMA_WRITE) + + def test_mw_type2_invalidate_dealloc(self): + self.test_mw_type2() + # Dealloc the MW by closing the pyverbs objects. + self.server.mw.close() + self.client.mw.close() + with self.assertRaisesRegex(PyverbsRDMAError, 'Remote access error'): + u.rdma_traffic(self.client, self.server, self.iters, self.gid_index, + self.ib_port, send_op=e.IBV_WR_RDMA_WRITE) def test_reg_mw_wrong_type(self): """ Verify that trying to create a MW of a wrong type fails """ - for ctx, attr, attr_ex in self.devices: + with d.Context(name=self.dev_name) as ctx: with PD(ctx) as pd: try: - mw_type = random.randint(3, 100) + mw_type = 3 MW(pd, mw_type) except PyverbsRDMAError as ex: if ex.error_code == errno.EOPNOTSUPP: diff --git a/tests/test_qpex.py b/tests/test_qpex.py index 66ce102f3..ebc0eebf4 100644 --- a/tests/test_qpex.py +++ b/tests/test_qpex.py @@ -183,12 +183,12 @@ def create_players(self, qp_type): def test_qp_ex_ud_send(self): client, server = self.create_players('ud_send') u.traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_SEND) + new_send=True, send_op=e.IBV_QP_EX_WITH_SEND) def test_qp_ex_rc_send(self): client, server = self.create_players('rc_send') u.traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_SEND) + new_send=True, send_op=e.IBV_QP_EX_WITH_SEND) def test_qp_ex_xrc_send(self): client, server = self.create_players('xrc_send') @@ -197,12 +197,12 @@ def test_qp_ex_xrc_send(self): def test_qp_ex_ud_send_imm(self): client, server = self.create_players('ud_send_imm') u.traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_SEND_WITH_IMM) + new_send=True, send_op=e.IBV_QP_EX_WITH_SEND_WITH_IMM) def test_qp_ex_rc_send_imm(self): client, server = self.create_players('rc_send_imm') u.traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_SEND_WITH_IMM) + new_send=True, send_op=e.IBV_QP_EX_WITH_SEND_WITH_IMM) def test_qp_ex_xrc_send_imm(self): client, server = self.create_players('xrc_send_imm') @@ -215,7 +215,7 @@ def test_qp_ex_rc_rdma_write(self): client.raddr = server.mr.buf server.raddr = client.mr.buf u.rdma_traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_RDMA_WRITE) + new_send=True, send_op=e.IBV_QP_EX_WITH_RDMA_WRITE) def test_qp_ex_rc_rdma_write_imm(self): client, server = self.create_players('rc_write_imm') @@ -224,7 +224,7 @@ def test_qp_ex_rc_rdma_write_imm(self): client.raddr = server.mr.buf server.raddr = client.mr.buf u.traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_RDMA_WRITE_WITH_IMM) + new_send=True, send_op=e.IBV_QP_EX_WITH_RDMA_WRITE_WITH_IMM) def test_qp_ex_rc_rdma_read(self): client, server = self.create_players('rc_read') @@ -234,7 +234,7 @@ def test_qp_ex_rc_rdma_read(self): server.raddr = client.mr.buf server.mr.write('s' * server.msg_size, server.msg_size) u.rdma_traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_RDMA_READ) + new_send=True, send_op=e.IBV_QP_EX_WITH_RDMA_READ) def test_qp_ex_rc_atomic_cmp_swp(self): client, server = self.create_players('rc_cmp_swp') @@ -246,7 +246,7 @@ def test_qp_ex_rc_atomic_cmp_swp(self): server.raddr = client.mr.buf server.mr.write('s' * 8, 8) u.rdma_traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_ATOMIC_CMP_AND_SWP) + new_send=True, send_op=e.IBV_QP_EX_WITH_ATOMIC_CMP_AND_SWP) def test_qp_ex_rc_atomic_fetch_add(self): client, server = self.create_players('rc_fetch_add') @@ -258,7 +258,7 @@ def test_qp_ex_rc_atomic_fetch_add(self): server.raddr = client.mr.buf server.mr.write('s' * 8, 8) u.rdma_traffic(client, server, self.iters, self.gid_index, self.ib_port, - is_cq_ex=False, send_op=e.IBV_QP_EX_WITH_ATOMIC_FETCH_AND_ADD) + new_send=True, send_op=e.IBV_QP_EX_WITH_ATOMIC_FETCH_AND_ADD) def test_qp_ex_rc_bind_mw(self): """ diff --git a/tests/test_shared_pd.py b/tests/test_shared_pd.py index e533074b4..b4cf190c3 100644 --- a/tests/test_shared_pd.py +++ b/tests/test_shared_pd.py @@ -92,4 +92,4 @@ def test_imported_rc_ex_rdma_write(self): client.raddr = server_import.mr.buf server_import.raddr = client.mr.buf u.rdma_traffic(client, server_import, self.iters, self.gid_index, - self.ib_port, send_op=e.IBV_QP_EX_WITH_RDMA_WRITE) + self.ib_port, send_op=e.IBV_QP_EX_WITH_RDMA_WRITE, new_send=True) diff --git a/tests/utils.py b/tests/utils.py index 36793a367..92152190d 100755 --- a/tests/utils.py +++ b/tests/utils.py @@ -278,7 +278,7 @@ def create_custom_mr(agr_obj, additional_access_flags=0, size=None): # Traffic helpers -def get_send_elements(agr_obj, is_server): +def get_send_elements(agr_obj, is_server, opcode=e.IBV_WR_SEND): """ Creates a single SGE and a single Send WR for agr_obj's QP type. The content of the message is either 's' for server side or 'c' for client side. @@ -293,8 +293,10 @@ def get_send_elements(agr_obj, is_server): msg = (agr_obj.msg_size + offset) * ('s' if is_server else 'c') mr.write(msg, agr_obj.msg_size + offset) sge = SGE(mr.buf + offset, agr_obj.msg_size, mr.lkey) - return SendWR(num_sge=1, sg=[sge]), sge - + send_wr = SendWR(opcode=opcode, num_sge=1, sg=[sge]) + if opcode in [e.IBV_WR_RDMA_WRITE, e.IBV_WR_RDMA_READ]: + send_wr.set_wr_rdma(int(agr_obj.rkey), int(agr_obj.remote_addr)) + return send_wr, sge def get_recv_wr(agr_obj): """ @@ -490,13 +492,14 @@ def validate(received_str, is_server, msg_size): format(exp=expected_str, rcv=received_str)) -def send(agr_obj, send_object, gid_index, port, send_op=None): - if send_op: +def send(agr_obj, send_object, gid_index, port, send_op=None, new_send=False): + if new_send: return post_send_ex(agr_obj, send_object, gid_index, port, send_op) return post_send(agr_obj, send_object, gid_index, port) -def traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=None): +def traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=None, + new_send=False): """ Runs basic traffic between two sides :param client: client side, clients base class is BaseTraffic @@ -505,7 +508,8 @@ def traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=None): :param gid_idx: local gid index :param port: IB port :param is_cq_ex: If True, use poll_cq_ex() rather than poll_cq() - :param send_op: If not None, new post send API is assumed. + :param send_op: The send_wr opcode. + :param new_send: If True use new post send API. :return: """ poll = poll_cq_ex if is_cq_ex else poll_cq @@ -524,7 +528,7 @@ def traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=None): if client.use_mr_prefetch: prefetch_mrs(client, [c_sg]) c_send_object = c_sg if send_op else c_send_wr - send(client, c_send_object, gid_idx, port, send_op) + send(client, c_send_object, gid_idx, port, send_op, new_send) poll(client.cq) poll(server.cq, data=imm_data) post_recv(server.qp, s_recv_wr) @@ -534,7 +538,7 @@ def traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=None): if server.use_mr_prefetch: prefetch_mrs(server, [s_sg]) s_send_object = s_sg if send_op else s_send_wr - send(server, s_send_object, gid_idx, port, send_op) + send(server, s_send_object, gid_idx, port, send_op, new_send) poll(server.cq) poll(client.cq, data=imm_data) post_recv(client.qp, c_recv_wr) @@ -542,7 +546,8 @@ def traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=None): validate(msg_received, False, client.msg_size) -def rdma_traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=None): +def rdma_traffic(client, server, iters, gid_idx, port, new_send=False, + send_op=None): """ Runs basic RDMA traffic between two sides. No receive WQEs are posted. For RDMA send with immediate, use traffic(). @@ -551,18 +556,19 @@ def rdma_traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=N :param iters: number of traffic iterations :param gid_idx: local gid index :param port: IB port - :param is_cq_ex: If True, use poll_cq_ex() rather than poll_cq() - :param send_op: If not None, new post send API is assumed. + :param new_send: If True use new post send API. + :param send_op: The send_wr opcode. :return: """ # Using the new post send API, we need the SGE, not the SendWR - send_element_idx = 1 if send_op else 0 - same_side_check = (send_op == e.IBV_QP_EX_WITH_RDMA_READ or - send_op == e.IBV_QP_EX_WITH_ATOMIC_CMP_AND_SWP or - send_op == e.IBV_QP_EX_WITH_ATOMIC_FETCH_AND_ADD) + send_element_idx = 1 if new_send else 0 + same_side_check = send_op in [e.IBV_QP_EX_WITH_RDMA_READ, + e.IBV_QP_EX_WITH_ATOMIC_CMP_AND_SWP, + e.IBV_QP_EX_WITH_ATOMIC_FETCH_AND_ADD, + e.IBV_WR_RDMA_READ] for _ in range(iters): - c_send_wr = get_send_elements(client, False)[send_element_idx] - send(client, c_send_wr, gid_idx, port, send_op) + c_send_wr = get_send_elements(client, False, send_op)[send_element_idx] + send(client, c_send_wr, gid_idx, port, send_op, new_send) poll_cq(client.cq) if same_side_check: msg_received = client.mr.read(client.msg_size, 0) @@ -570,10 +576,10 @@ def rdma_traffic(client, server, iters, gid_idx, port, is_cq_ex=False, send_op=N msg_received = server.mr.read(server.msg_size, 0) validate(msg_received, False if same_side_check else True, server.msg_size) - s_send_wr = get_send_elements(server, True)[send_element_idx] + s_send_wr = get_send_elements(server, True, send_op)[send_element_idx] if same_side_check: client.mr.write('c' * client.msg_size, client.msg_size) - send(server, s_send_wr, gid_idx, port, send_op) + send(server, s_send_wr, gid_idx, port, send_op, new_send) poll_cq(server.cq) if same_side_check: msg_received = server.mr.read(client.msg_size, 0)