@@ -745,3 +745,37 @@ Below is the output when printing the spec.
Dst mac : de:de:de:00:de:de mask: ff:ff:ff:ff:ff:ff
Ether type : 8451 mask: 65535
Vlan tag : 8961 mask: 65535
+
+
+##### MLX5 DevX Objects
+A DevX object represents some underlay firmware object, the input command to
+create it is some raw data given by the user application which should match the
+device specification.
+Upon successful creation, the output buffer includes the raw data from the device
+according to its specification and is stored in the Mlx5DevxObj instance. This
+data can be used as part of related firmware commands to this object.
+In addition to creation, the user can query/modify and destroy the object.
+
+Although weakrefs and DevX objects closure are added and handled by
+Pyverbs, the users must manually close these objects when finished, and
+should not let them be handled by the GC, or by closing the Mlx5Context directly,
+since there's no guarantee that the DevX objects are closed in the correct order,
+because Mlx5DevxObj is a general class that can be any of the device's available
+objects.
+But Pyverbs does guarantee to close DevX UARs and UMEMs in order, and after
+closing the other DevX objects.
+
+The following code snippet shows how to allocate and destroy a PD object over DevX.
+```python
+from pyverbs.providers.mlx5.mlx5dv import Mlx5Context, Mlx5DVContextAttr, Mlx5DevxObj
+import pyverbs.providers.mlx5.mlx5_enums as dve
+import struct
+
+attr = Mlx5DVContextAttr(dve.MLX5DV_CONTEXT_FLAGS_DEVX)
+ctx = Mlx5Context(attr, 'rocep8s0f0')
+MLX5_CMD_OP_ALLOC_PD = 0x800
+MLX5_CMD_OP_ALLOC_PD_OUTLEN = 0x10
+cmd_in = struct.pack('!H14s', MLX5_CMD_OP_ALLOC_PD, bytes(0))
+pd = Mlx5DevxObj(ctx, cmd_in, MLX5_CMD_OP_ALLOC_PD_OUTLEN)
+pd.close()
+```
@@ -319,6 +319,13 @@ cdef extern from 'infiniband/mlx5dv.h':
mlx5dv_devx_umem_in *umem_in)
int mlx5dv_devx_umem_dereg(mlx5dv_devx_umem *umem)
int mlx5dv_devx_query_eqn(v.ibv_context *context, uint32_t vector, uint32_t *eqn)
+ mlx5dv_devx_obj *mlx5dv_devx_obj_create(v.ibv_context *context, const void *_in,
+ size_t inlen, void *out, size_t outlen)
+ int mlx5dv_devx_obj_query(mlx5dv_devx_obj *obj, const void *in_,
+ size_t inlen, void *out, size_t outlen)
+ int mlx5dv_devx_obj_modify(mlx5dv_devx_obj *obj, const void *in_,
+ size_t inlen, void *out, size_t outlen)
+ int mlx5dv_devx_obj_destroy(mlx5dv_devx_obj *obj)
# Mkey setters
void mlx5dv_wr_mkey_configure(mlx5dv_qp_ex *mqp, mlx5dv_mkey *mkey,
@@ -12,6 +12,7 @@ from pyverbs.cq cimport CQEX
cdef class Mlx5Context(Context):
cdef object devx_umems
+ cdef object devx_objs
cdef add_ref(self, obj)
cpdef close(self)
@@ -77,3 +78,8 @@ cdef class Mlx5UMEM(PyverbsCM):
cdef Context context
cdef void *addr
cdef object is_user_addr
+
+cdef class Mlx5DevxObj(PyverbsCM):
+ cdef dv.mlx5dv_devx_obj *obj
+ cdef Context context
+ cdef object out_view
@@ -140,6 +140,104 @@ cdef class Mlx5DVContextAttr(PyverbsObject):
self.attr.comp_mask = val
+cdef class Mlx5DevxObj(PyverbsCM):
+ """
+ Represents mlx5dv_devx_obj C struct.
+ """
+ def __init__(self, Context context, in_, outlen):
+ """
+ Creates a DevX object.
+ If the object was successfully created, the command's output would be
+ stored as a memoryview in self.out_view.
+ :param in_: Bytes of the obj_create command's input data provided in a
+ device specification format.
+ (Stream of bytes or __bytes__ is implemented)
+ :param outlen: Expected output length in bytes
+ """
+ super().__init__()
+ in_bytes = bytes(in_)
+ cdef char *in_mailbox = _prepare_devx_inbox(in_bytes)
+ cdef char *out_mailbox = _prepare_devx_outbox(outlen)
+ self.obj = dv.mlx5dv_devx_obj_create(context.context, in_mailbox,
+ len(in_bytes), out_mailbox, outlen)
+ try:
+ if self.obj == NULL:
+ raise PyverbsRDMAErrno('Failed to create DevX object')
+ self.out_view = memoryview(out_mailbox[:outlen])
+ status = hex(self.out_view[0])
+ syndrome = self.out_view[4:8].hex()
+ if status != hex(0):
+ raise PyverbsRDMAError('Failed to create DevX object with status'
+ f'({status}) and syndrome (0x{syndrome})')
+ finally:
+ free(in_mailbox)
+ free(out_mailbox)
+ self.context = context
+ self.context.add_ref(self)
+
+ def query(self, in_, outlen):
+ """
+ Queries the DevX object.
+ :param in_: Bytes of the obj_query command's input data provided in a
+ device specification format.
+ (Stream of bytes or __bytes__ is implemented)
+ :param outlen: Expected output length in bytes
+ :return: Bytes of the command's output
+ """
+ in_bytes = bytes(in_)
+ cdef char *in_mailbox = _prepare_devx_inbox(in_bytes)
+ cdef char *out_mailbox = _prepare_devx_outbox(outlen)
+ rc = dv.mlx5dv_devx_obj_query(self.obj, in_mailbox, len(in_bytes),
+ out_mailbox, outlen)
+ try:
+ if rc:
+ raise PyverbsRDMAError('Failed to query DevX object', rc)
+ out = <bytes>out_mailbox[:outlen]
+ finally:
+ free(in_mailbox)
+ free(out_mailbox)
+ return out
+
+ def modify(self, in_, outlen):
+ """
+ Modifies the DevX object.
+ :param in_: Bytes of the obj_modify command's input data provided in a
+ device specification format.
+ (Stream of bytes or __bytes__ is implemented)
+ :param outlen: Expected output length in bytes
+ :return: Bytes of the command's output
+ """
+ in_bytes = bytes(in_)
+ cdef char *in_mailbox = _prepare_devx_inbox(in_bytes)
+ cdef char *out_mailbox = _prepare_devx_outbox(outlen)
+ rc = dv.mlx5dv_devx_obj_modify(self.obj, in_mailbox, len(in_bytes),
+ out_mailbox, outlen)
+ try:
+ if rc:
+ raise PyverbsRDMAError('Failed to modify DevX object', rc)
+ out = <bytes>out_mailbox[:outlen]
+ finally:
+ free(in_mailbox)
+ free(out_mailbox)
+ return out
+
+ @property
+ def out_view(self):
+ return self.out_view
+
+ def __dealloc__(self):
+ self.close()
+
+ cpdef close(self):
+ if self.obj != NULL:
+ self.logger.debug('Closing Mlx5DvexObj')
+ rc = dv.mlx5dv_devx_obj_destroy(self.obj)
+ if rc:
+ raise PyverbsRDMAError('Failed to destroy a DevX object', rc)
+ self.obj = NULL
+ self.context = None
+
+
cdef class Mlx5Context(Context):
"""
Represent mlx5 context, which extends Context.
@@ -159,6 +257,7 @@ cdef class Mlx5Context(Context):
raise PyverbsRDMAErrno('Failed to open mlx5 context on {dev}'
.format(dev=self.name))
self.devx_umems = weakref.WeakSet()
+ self.devx_objs = weakref.WeakSet()
def query_mlx5_device(self, comp_mask=-1):
"""
@@ -280,6 +379,8 @@ cdef class Mlx5Context(Context):
except PyverbsError:
if isinstance(obj, Mlx5UMEM):
self.devx_umems.add(obj)
+ elif isinstance(obj, Mlx5DevxObj):
+ self.devx_objs.add(obj)
else:
raise PyverbsError('Unrecognized object type')
@@ -288,7 +389,7 @@ cdef class Mlx5Context(Context):
cpdef close(self):
if self.context != NULL:
- close_weakrefs([self.pps, self.devx_umems])
+ close_weakrefs([self.pps, self.devx_objs, self.devx_umems])
super(Mlx5Context, self).close()