| # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) | |
| # Copyright (c) 2020 NVIDIA Corporation . All rights reserved. See COPYING file | |
| import unittest | |
| import errno | |
| import pyverbs.providers.mlx5.mlx5_enums as me | |
| from tests.mlx5_base import Mlx5DcResources, Mlx5RDMATestCase, Mlx5DcStreamsRes,\ | |
| DCI_TEST_GOOD_FLOW, DCI_TEST_BAD_FLOW_WITH_RESET,\ | |
| DCI_TEST_BAD_FLOW_WITHOUT_RESET | |
| from pyverbs.pyverbs_error import PyverbsRDMAError | |
| from pyverbs.providers.mlx5.mlx5dv import Mlx5QP | |
| import pyverbs.enums as e | |
| import tests.utils as u | |
| class OdpDc(Mlx5DcResources): | |
| def create_mr(self): | |
| try: | |
| self.mr = u.create_custom_mr(self, e.IBV_ACCESS_ON_DEMAND) | |
| except PyverbsRDMAError as ex: | |
| if ex.error_code == errno.EOPNOTSUPP: | |
| raise unittest.SkipTest('Reg ODP MR is not supported') | |
| raise ex | |
| class DCTest(Mlx5RDMATestCase): | |
| def setUp(self): | |
| super().setUp() | |
| self.iters = 10 | |
| self.server = None | |
| self.client = None | |
| self.traffic_args = None | |
| def sync_remote_attr(self): | |
| """ | |
| Exchange the remote attributes between the server and the client. | |
| """ | |
| super().sync_remote_attr() | |
| self.client.remote_dct_num = self.server.dct_qp.qp_num | |
| self.server.remote_dct_num = self.client.dct_qp.qp_num | |
| def test_dc_rdma_write(self): | |
| self.create_players(Mlx5DcResources, qp_count=2, | |
| send_ops_flags=e.IBV_QP_EX_WITH_RDMA_WRITE) | |
| u.rdma_traffic(**self.traffic_args, new_send=True, | |
| send_op=e.IBV_WR_RDMA_WRITE) | |
| def test_dc_send(self): | |
| self.create_players(Mlx5DcResources, qp_count=2, | |
| send_ops_flags=e.IBV_QP_EX_WITH_SEND) | |
| u.traffic(**self.traffic_args, new_send=True, | |
| send_op=e.IBV_WR_SEND) | |
| def test_dc_atomic(self): | |
| self.create_players(Mlx5DcResources, qp_count=2, | |
| send_ops_flags=e.IBV_QP_EX_WITH_ATOMIC_FETCH_AND_ADD) | |
| client_max_log = self.client.ctx.query_mlx5_device().max_dc_rd_atom | |
| server_max_log = self.server.ctx.query_mlx5_device().max_dc_rd_atom | |
| u.atomic_traffic(**self.traffic_args, new_send=True, | |
| send_op=e.IBV_WR_ATOMIC_FETCH_AND_ADD, | |
| client_wr=client_max_log, server_wr=server_max_log) | |
| def test_dc_ah_to_qp_mapping(self): | |
| self.create_players(Mlx5DcResources, qp_count=2, | |
| send_ops_flags=e.IBV_QP_EX_WITH_SEND) | |
| client_ah = u.get_global_ah(self.client, self.gid_index, self.ib_port) | |
| try: | |
| Mlx5QP.map_ah_to_qp(client_ah, self.server.qps[0].qp_num) | |
| except PyverbsRDMAError as ex: | |
| if ex.error_code == errno.EOPNOTSUPP: | |
| raise unittest.SkipTest('Mapping AH to QP is not supported') | |
| raise ex | |
| u.traffic(**self.traffic_args, new_send=True, | |
| send_op=e.IBV_WR_SEND) | |
| def check_odp_dc_support(self): | |
| """ | |
| Check if the device supports ODP with DC. | |
| :raises SkipTest: In case ODP is not supported with DC | |
| """ | |
| dc_odp_caps = self.server.ctx.query_mlx5_device().dc_odp_caps | |
| required_odp_caps = e.IBV_ODP_SUPPORT_SEND | e.IBV_ODP_SUPPORT_SRQ_RECV | |
| if required_odp_caps & dc_odp_caps != required_odp_caps: | |
| raise unittest.SkipTest('ODP is not supported using DC') | |
| def test_odp_dc_traffic(self): | |
| send_ops_flag = e.IBV_QP_EX_WITH_SEND | |
| self.create_players(OdpDc, qp_count=2, send_ops_flags=send_ops_flag) | |
| self.check_odp_dc_support() | |
| u.traffic(**self.traffic_args, new_send=True, | |
| send_op=e.IBV_WR_SEND) | |
| def test_dc_rdma_write_stream(self): | |
| """ | |
| Check good flow of DCS. | |
| Calculate stream_id for DCS test by setting same stream id | |
| twice for WR and after increase it. Setting goes by loop | |
| and after stream_id is more than number of concurrent | |
| streams + 1 then stream_id returns to 1. | |
| :raises SkipTest: In case DCI is not supported with HW | |
| """ | |
| self.create_players(Mlx5DcStreamsRes, qp_count=2, | |
| send_ops_flags=e.IBV_QP_EX_WITH_RDMA_WRITE) | |
| u.rdma_traffic(**self.traffic_args, new_send=True, | |
| send_op=e.IBV_WR_RDMA_WRITE) | |
| def test_dc_send_stream_bad_flow(self): | |
| """ | |
| Check bad flow of DCS with reset stream id. | |
| Create error in dci stream by setting invalid PD so dci stream goes to error. | |
| In the end, the test verifies that the number of errors is as expected. | |
| :raises SkipTest: In case DCI is not supported with HW | |
| """ | |
| self.create_players(Mlx5DcStreamsRes, | |
| qp_count=1, send_ops_flags=e.IBV_QP_EX_WITH_SEND) | |
| self.client.set_bad_flow(DCI_TEST_BAD_FLOW_WITH_RESET) | |
| self.client.traffic_with_bad_flow(**self.traffic_args) | |
| def test_dc_send_stream_bad_flow_qp(self): | |
| """ | |
| Check bad flow of DCS with reset qp. | |
| Checked if resetting of wrong dci stream id produces an exception. | |
| This bad flow creates enough errors without resetting the streams, | |
| enforcing the QP to get into ERR state. Then the checking is stopped. | |
| Also has feature that after QP goes in ERR state test will | |
| reset QP to RTS state. | |
| :raises SkipTest: In case DCI is not supported with HW | |
| """ | |
| self.iters = 20 | |
| self.create_players(Mlx5DcStreamsRes, | |
| qp_count=1, send_ops_flags=e.IBV_QP_EX_WITH_SEND) | |
| self.client.set_bad_flow(DCI_TEST_BAD_FLOW_WITHOUT_RESET) | |
| self.client.traffic_with_bad_flow(**self.traffic_args) |