From: Edward Srouji <edwards@xxxxxxxxxxxx> The test creates a client and server sides of RC resources. Then the server resources are imported and used for RDMA write traffic. Reviewed-by: Ido Kalir <idok@xxxxxxxxxxxx> Signed-off-by: Edward Srouji <edwards@xxxxxxxxxxxx> --- tests/CMakeLists.txt | 1 + tests/base.py | 11 ++++-- tests/test_shared_pd.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 tests/test_shared_pd.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1708fb9..33ffc78 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -25,6 +25,7 @@ rdma_python_test(tests test_qpex.py test_rdmacm.py test_relaxed_ordering.py + test_shared_pd.py utils.py ) diff --git a/tests/base.py b/tests/base.py index 5a98d7f..db9a6ec 100755 --- a/tests/base.py +++ b/tests/base.py @@ -244,10 +244,17 @@ class BaseResources(object): :param ib_port: IB port of the device to use (default: 1) :param gid_index: Which GID index to use (default: 0) """ - self.ctx = Context(name=dev_name) + self.dev_name = dev_name self.gid_index = gid_index - self.pd = PD(self.ctx) self.ib_port = ib_port + self.create_context() + self.create_pd() + + def create_context(self): + self.ctx = Context(name=self.dev_name) + + def create_pd(self): + self.pd = PD(self.ctx) class TrafficResources(BaseResources): diff --git a/tests/test_shared_pd.py b/tests/test_shared_pd.py new file mode 100644 index 0000000..e533074 --- /dev/null +++ b/tests/test_shared_pd.py @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) +# Copyright (c) 2020 Mellanox Technologies, Inc. All rights reserved. See COPYING file +""" +Test module for Shared PD. +""" +import unittest +import errno +import os + +from tests.test_qpex import QpExRCRDMAWrite +from tests.base import RDMATestCase +from pyverbs.device import Context +from pyverbs.pd import PD +from pyverbs.mr import MR +import pyverbs.enums as e +import tests.utils as u + + +def get_import_res_class(base_class): + """ + This function creates a class that inherits base_class of any BaseResources + type. Its purpose is to behave exactly as base_class does, except for the + objects creation, which instead of creating context, PD and MR, it imports + them. Hence the returned class must be initialized with (cmd_fd, pd_handle, + mr_handle, mr_addr, **kwargs), while kwargs are the arguments needed + (if any) for base_class. In addition it has unimport_resources() method + which unimprot all the resources and closes the imported PD object. + :param base_class: The base resources class to inherit from + :return: ImportResources(cmd_fd, pd_handle, mr_handle, mr_addr, **kwargs) + class + """ + class ImportResources(base_class): + def __init__(self, cmd_fd, pd_handle, mr_handle, mr_addr=None, **kwargs): + self.cmd_fd = cmd_fd + self.pd_handle = pd_handle + self.mr_handle = mr_handle + self.mr_addr = mr_addr + super(ImportResources, self).__init__(**kwargs) + + def create_context(self): + try: + self.ctx = Context(cmd_fd=self.cmd_fd) + except u.PyverbsRDMAError as ex: + if ex.error_code in [errno.EOPNOTSUPP, errno.EPROTONOSUPPORT]: + raise unittest.SkipTest('Importing a device is not supported') + raise ex + + def create_pd(self): + self.pd = PD(self.ctx, handle=self.pd_handle) + + def create_mr(self): + self.mr = MR(self.pd, handle=self.mr_handle, address=self.mr_addr) + + def unimport_resources(self): + self.mr.unimport() + self.pd.unimport() + self.pd.close() + + return ImportResources + + +class SharedPDTestCase(RDMATestCase): + def setUp(self): + super().setUp() + self.iters = 10 + self.server_res = None + self.imported_res = [] + + def tearDown(self): + for res in self.imported_res: + res.unimport_resources() + super().tearDown() + + def test_imported_rc_ex_rdma_write(self): + setup_params = {'dev_name': self.dev_name, 'ib_port': self.ib_port, + 'gid_index': self.gid_index} + self.server_res = QpExRCRDMAWrite(**setup_params) + cmd_fd_dup = os.dup(self.server_res.ctx.cmd_fd) + import_cls = get_import_res_class(QpExRCRDMAWrite) + server_import = import_cls( + cmd_fd_dup, self.server_res.pd.handle, self.server_res.mr.handle, + # The imported MR's address is NULL, so using the address of the + # "main" MR object to be able to validate the message + self.server_res.mr.buf, + **setup_params) + self.imported_res.append(server_import) + client = QpExRCRDMAWrite(**setup_params) + client.pre_run(server_import.psn, server_import.qpn) + server_import.pre_run(client.psn, client.qpn) + client.rkey = server_import.mr.rkey + server_import.rkey = client.mr.rkey + 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) -- 1.8.3.1