blob: 885855f926709570a290f4e20647c7354fb4623d [file] [log] [blame] [edit]
# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB)
# Copyright (c) 2025 NVIDIA Corporation . All rights reserved. See COPYING file
from pyverbs.libibverbs_enums import ibv_access_flags, ibv_wr_opcode, ibv_odp_transport_cap_bits, \
ibv_tph_mem_type
from tests.base import PyverbsAPITestCase, RCResources, RDMATestCase
from pyverbs.pyverbs_error import PyverbsError, PyverbsRDMAError
import pyverbs.device as d
from pyverbs.pd import PD
from pyverbs.mr import MREx, DMAHandle
from pyverbs.qp import QPAttr
import tests.utils as u
class DMAHandleTest(PyverbsAPITestCase):
@u.skip_unsupported
def test_dmah_with_mrex(self):
"""Verify DMAHandle can be used during MREx registration."""
with d.Context(name=self.dev_name) as ctx:
with PD(ctx) as pd:
attr = u.create_dmah_init_attr()
with DMAHandle(ctx, attr) as dmah:
length = u.get_mr_length()
access = ibv_access_flags.IBV_ACCESS_LOCAL_WRITE
with MREx(pd, length, access, dmah=dmah) as mr:
pass
@u.skip_unsupported
def test_dmah_invalid_ph(self):
"""Verify DMAHandle with invalid PH value, max ph value is 3."""
with d.Context(name=self.dev_name) as ctx:
with PD(ctx) as pd:
attr = u.create_dmah_init_attr(ph=4)
with self.assertRaises(PyverbsError):
DMAHandle(ctx, attr)
@u.skip_unsupported
def test_dmah_persistent_memory(self):
"""Attempt to create DMAHandle targeting persistent memory."""
with d.Context(name=self.dev_name) as ctx:
attr = u.create_dmah_init_attr(tph_mem_type=ibv_tph_mem_type.IBV_TPH_MEM_TYPE_PM)
with DMAHandle(ctx, attr):
pass
@u.skip_unsupported
def test_dmah_invalid_mem_type(self):
"""Pass an unsupported TPH memory-type and verify provider rejects it."""
with d.Context(name=self.dev_name) as ctx:
attr = u.create_dmah_init_attr(tph_mem_type=0xFE)
with self.assertRaises(PyverbsError):
DMAHandle(ctx, attr)
@u.skip_unsupported
def test_dmah_inval_cpu_id(self):
"""Attempt to create DMAHandle with invalid CPU ID (0xffff). Expect failure."""
with d.Context(name=self.dev_name) as ctx:
attr = u.create_dmah_init_attr(cpu_id=0xffff, ph=3)
with self.assertRaises(PyverbsError):
DMAHandle(ctx, attr)
@u.skip_unsupported
def test_dmah_mrex_odp_bad_flow(self):
"""Attempt to register ODP-capable MREx with DMAHandle.
Expect failure since ODP isn't supported with DMAHandle."""
with d.Context(name=self.dev_name) as ctx:
# Check ODP support; skip if not available
odp_cap = (ibv_odp_transport_cap_bits.IBV_ODP_SUPPORT_SEND |
ibv_odp_transport_cap_bits.IBV_ODP_SUPPORT_RECV)
u.odp_supported(ctx, 'rc', odp_cap)
with PD(ctx) as pd:
attr = u.create_dmah_init_attr()
dmah = DMAHandle(ctx, attr)
with self.assertRaises(PyverbsError):
length = u.get_mr_length()
access = (ibv_access_flags.IBV_ACCESS_LOCAL_WRITE |
ibv_access_flags.IBV_ACCESS_ON_DEMAND)
MREx(pd, length, access, dmah=dmah)
class DmaHandleMRExRC(RCResources):
"""RC resource class that registers an MREx with a DMAHandle."""
def __init__(self, dev_name, ib_port, gid_index,
mr_access=ibv_access_flags.IBV_ACCESS_LOCAL_WRITE, msg_size=1024):
self.dmah = None
self.mr_access = mr_access
super().__init__(dev_name=dev_name, ib_port=ib_port, gid_index=gid_index,
msg_size=msg_size)
def create_dmah(self):
"""Allocate a DMAHandle using the existing device Context."""
attr = u.create_dmah_init_attr()
self.dmah = DMAHandle(self.ctx, attr)
@u.skip_unsupported
def create_mr(self):
self.create_dmah()
self.mr = MREx(self.pd, self.msg_size, self.mr_access, dmah=self.dmah)
def create_qp_attr(self):
qp_attr = QPAttr(port_num=self.ib_port)
qp_access = (ibv_access_flags.IBV_ACCESS_LOCAL_WRITE |
ibv_access_flags.IBV_ACCESS_REMOTE_WRITE |
ibv_access_flags.IBV_ACCESS_REMOTE_ATOMIC)
qp_attr.qp_access_flags = qp_access
return qp_attr
class DmaHandleTrafficTest(RDMATestCase):
"""Traffic tests for MREx + DMAHandle combinations."""
def setUp(self):
super().setUp()
self.iters = 10
self.server = None
self.client = None
self.traffic_args = None
def test_dmah_mrex_rc_send(self):
"""Checks basic RC send/recv traffic with DMAHandle-registered MREx."""
access = ibv_access_flags.IBV_ACCESS_LOCAL_WRITE
self.create_players(DmaHandleMRExRC, mr_access=access, msg_size=1024)
u.traffic(**self.traffic_args)
def test_dmah_mrex_rc_rdma_write(self):
"""Validates RC RDMA Write traffic with DMAHandle & MREx."""
access = ibv_access_flags.IBV_ACCESS_LOCAL_WRITE | ibv_access_flags.IBV_ACCESS_REMOTE_WRITE
self.create_players(DmaHandleMRExRC, mr_access=access, msg_size=1024)
u.rdma_traffic(**self.traffic_args, send_op=ibv_wr_opcode.IBV_WR_RDMA_WRITE)
def test_dmah_mrex_rc_atomic(self):
"""Tests RC atomic fetch&add using a DMAHandle-backed MREx."""
access = (ibv_access_flags.IBV_ACCESS_LOCAL_WRITE |
ibv_access_flags.IBV_ACCESS_REMOTE_ATOMIC |
ibv_access_flags.IBV_ACCESS_REMOTE_WRITE)
self.create_players(DmaHandleMRExRC, mr_access=access, msg_size=8)
u.atomic_traffic(**self.traffic_args, send_op=ibv_wr_opcode.IBV_WR_ATOMIC_FETCH_AND_ADD)