| # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) | |
| # Copyright (c) 2018, Mellanox Technologies. All rights reserved. See COPYING file | |
| """ | |
| Device module introduces the Context and DeviceAttr class. | |
| It allows user to open an IB device (using Context(name=<name>) and query it, | |
| which returns a DeviceAttr object. | |
| """ | |
| import weakref | |
| from .pyverbs_error import PyverbsRDMAError, PyverbsError | |
| from pyverbs.comp_cntr cimport CompCntr | |
| from pyverbs.cq cimport CQEX, CQ, CompChannel | |
| from .pyverbs_error import PyverbsUserError | |
| from pyverbs.base import PyverbsRDMAErrno | |
| from pyverbs.base cimport close_weakrefs | |
| from pyverbs.wq cimport WQ, RwqIndTable | |
| cimport pyverbs.libibverbs_enums as e | |
| cimport pyverbs.libibverbs as v | |
| cimport pyverbs.librdmacm as cm | |
| from pyverbs.cmid cimport CMID | |
| from pyverbs.xrcd cimport XRCD | |
| from pyverbs.addr cimport GID | |
| from pyverbs.mr import DMMR, DMAHandle | |
| from pyverbs.pd cimport PD | |
| from pyverbs.qp cimport QP | |
| from libc.stdlib cimport free, malloc | |
| from libc.string cimport memset | |
| from libc.stdint cimport uint64_t | |
| from libc.stdint cimport uint16_t | |
| from libc.stdint cimport uint32_t | |
| from libc.stdint cimport uintptr_t | |
| from pyverbs.utils import gid_str | |
| cdef extern from 'endian.h': | |
| unsigned long be64toh(unsigned long host_64bits); | |
| class Device(PyverbsObject): | |
| """ | |
| Device class represents the C ibv_device. It stores device's properties. | |
| It is not a part of objects creation order - there's no need for the user | |
| to create it for such purposes. | |
| """ | |
| def __init__(self, name, guid, node_type, transport_type, index): | |
| self._node_type = node_type | |
| self._transport_type = transport_type | |
| self._name = name | |
| self._guid = guid | |
| self._index = index | |
| @property | |
| def name(self): | |
| return self._name | |
| @property | |
| def node_type(self): | |
| return self._node_type | |
| @property | |
| def transport_type(self): | |
| return self._transport_type | |
| @property | |
| def guid(self): | |
| return self._guid | |
| @property | |
| def index(self): | |
| return self._index | |
| def __str__(self): | |
| return 'Device {dev}, node type {ntype}, transport type {ttype},' \ | |
| ' guid {guid}, index {index}'.format(dev=self.name.decode(), | |
| ntype=translate_node_type(self.node_type), | |
| ttype=translate_transport_type(self.transport_type), | |
| guid=guid_to_hex(self.guid), index=self._index) | |
| cdef class Context(PyverbsCM): | |
| """ | |
| Context class represents the C ibv_context. | |
| """ | |
| def __init__(self, **kwargs): | |
| """ | |
| Initializes a Context object. The function searches the IB devices list | |
| for a device with the name provided by the user. If such a device is | |
| found, it is opened (unless provider attributes were given). | |
| In case of cmid argument, CMID object already holds an ibv_context | |
| initiated pointer, hence all we have to do is assign this pointer to | |
| Context's object pointer. | |
| :param kwargs: Arguments: | |
| * *name* | |
| The device's name | |
| * *attr* | |
| Provider-specific attributes. If not None, it means that the | |
| device will be opened by the provider and __init__ will return | |
| after locating the requested device. | |
| * *cmid* | |
| A CMID object. If not None, it means that the device was already | |
| opened by a CMID class, and only a pointer assignment is missing. | |
| * *cmd_fd* | |
| A command FD. If passed, the device will be imported from the | |
| given cmd_fd using ibv_import_device. | |
| :return: None | |
| """ | |
| cdef int count | |
| cdef v.ibv_device **dev_list | |
| cdef CMID cmid | |
| super().__init__() | |
| self.pds = weakref.WeakSet() | |
| self.dms = weakref.WeakSet() | |
| self.ccs = weakref.WeakSet() | |
| self.cqs = weakref.WeakSet() | |
| self.qps = weakref.WeakSet() | |
| self.xrcds = weakref.WeakSet() | |
| self.vars = weakref.WeakSet() | |
| self.uars = weakref.WeakSet() | |
| self.pps = weakref.WeakSet() | |
| self.sched_nodes = weakref.WeakSet() | |
| self.sched_leafs = weakref.WeakSet() | |
| self.comp_cntrs = weakref.WeakSet() | |
| self.dr_domains = weakref.WeakSet() | |
| self.wqs = weakref.WeakSet() | |
| self.rwq_ind_tbls = weakref.WeakSet() | |
| self.crypto_logins = weakref.WeakSet() | |
| self.event_channels = weakref.WeakSet() | |
| self.dmahs = weakref.WeakSet() | |
| self.devx_umems = weakref.WeakSet() | |
| self.devx_objs = weakref.WeakSet() | |
| self.name = kwargs.get('name') | |
| provider_attr = kwargs.get('attr') | |
| cmid = kwargs.get('cmid') | |
| cmd_fd = kwargs.get('cmd_fd') | |
| if cmid is not None: | |
| self.context = cmid.id.verbs | |
| self.name = str(v.ibv_get_device_name(self.context.device).decode('utf-8')) | |
| cmid.ctx = self | |
| return | |
| if cmd_fd is not None: | |
| self.context = v.ibv_import_device(cmd_fd) | |
| if self.context == NULL: | |
| raise PyverbsRDMAErrno('Failed to import device') | |
| self.name = str(v.ibv_get_device_name(self.context.device).decode('utf-8')) | |
| return | |
| if self.name is None: | |
| raise PyverbsUserError('Device name must be provided') | |
| dev_list = v.ibv_get_device_list(&count) | |
| if dev_list == NULL: | |
| raise PyverbsRDMAError('Failed to get devices list') | |
| try: | |
| for i in range(count): | |
| if dev_list[i].name.decode() == self.name: | |
| if provider_attr is not None: | |
| # A provider opens its own context, we're just | |
| # setting its IB device | |
| self.device = dev_list[i] | |
| return | |
| self.context = v.ibv_open_device(dev_list[i]) | |
| if self.context == NULL: | |
| raise PyverbsRDMAErrno('Failed to open device {dev}'. | |
| format(dev=self.name)) | |
| self.logger.debug('Context: opened device {dev}'. | |
| format(dev=self.name)) | |
| break | |
| else: | |
| raise PyverbsRDMAError('Failed to find device {dev}'. | |
| format(dev=self.name)) | |
| finally: | |
| v.ibv_free_device_list(dev_list) | |
| def __dealloc__(self): | |
| """ | |
| Closes the inner IB device. | |
| :return: None | |
| """ | |
| self.close() | |
| cpdef close(self): | |
| if self.context != NULL: | |
| if self.logger: | |
| self.logger.debug('Closing Context') | |
| close_weakrefs([self.devx_objs, self.devx_umems, self.qps, | |
| self.crypto_logins, self.rwq_ind_tbls, self.wqs, | |
| self.ccs, self.cqs, self.dms, self.pds, self.xrcds, | |
| self.vars, self.sched_leafs, self.sched_nodes, | |
| self.dr_domains, self.event_channels, self.dmahs, | |
| self.comp_cntrs]) | |
| rc = v.ibv_close_device(self.context) | |
| if rc != 0: | |
| raise PyverbsRDMAErrno(f'Failed to close device {self.name}') | |
| self.context = NULL | |
| @property | |
| def context(self): | |
| return <uintptr_t>self.context | |
| @property | |
| def num_comp_vectors(self): | |
| return self.context.num_comp_vectors | |
| def query_device(self): | |
| """ | |
| Queries the device's attributes. | |
| :return: A DeviceAttr object which holds the device's attributes as | |
| reported by the hardware. | |
| """ | |
| dev_attr = DeviceAttr() | |
| rc = v.ibv_query_device(self.context, &dev_attr.dev_attr) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to query device {name}'. | |
| format(name=self.name), rc) | |
| return dev_attr | |
| def query_device_ex(self, QueryDeviceExInput ex_input = None): | |
| """ | |
| Queries the device's extended attributes. | |
| :param ex_input: An extensible input struct for possible future | |
| extensions | |
| :return: DeviceAttrEx object | |
| """ | |
| dev_attr_ex = DeviceAttrEx() | |
| rc = v.ibv_query_device_ex(self.context, | |
| &ex_input.input if ex_input is not None else NULL, | |
| &dev_attr_ex.dev_attr) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to query EX device {name}'. | |
| format(name=self.name), rc) | |
| return dev_attr_ex | |
| def query_comp_cntr_caps(self): | |
| """ | |
| Query completion counter capabilities. | |
| :return: CompCntrCaps object | |
| """ | |
| caps = CompCntrCaps() | |
| rc = v.ibv_query_comp_cntr_caps(self.context, &caps.caps) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to query comp_cntr caps', rc) | |
| return caps | |
| def query_pkey(self, unsigned int port_num, int index): | |
| cdef uint16_t pkey | |
| rc = v.ibv_query_pkey(self.context, port_num, index, &pkey) | |
| if rc != 0: | |
| raise PyverbsRDMAError(f'Failed to query pkey {index} of port {port_num}') | |
| return pkey | |
| def get_pkey_index(self, unsigned int port_num, int pkey): | |
| idx = v.ibv_get_pkey_index(self.context, port_num, pkey) | |
| if idx == -1: | |
| raise PyverbsRDMAError(f'Failed to get pkey index of pkey = {pkey} of port {port_num}') | |
| return idx | |
| def query_gid(self, unsigned int port_num, int index): | |
| gid = GID() | |
| rc = v.ibv_query_gid(self.context, port_num, index, &gid.gid) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to query gid {idx} of port {port}'. | |
| format(idx=index, port=port_num)) | |
| return gid | |
| def query_gid_type(self, unsigned int port_num, unsigned int index): | |
| cdef v.ibv_gid_type_sysfs gid_type | |
| rc = v.ibv_query_gid_type(self.context, port_num, index, &gid_type) | |
| if rc != 0: | |
| raise PyverbsRDMAErrno('Failed to query gid type of port {p} and gid index {g}' | |
| .format(p=port_num, g=index)) | |
| return gid_type | |
| def query_port(self, unsigned int port_num): | |
| """ | |
| Query port <port_num> of the device and returns its attributes. | |
| :param port_num: Port number to query | |
| :return: PortAttr object on success | |
| """ | |
| port_attrs = PortAttr() | |
| rc = v.ibv_query_port(self.context, port_num, &port_attrs.attr) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to query port {p}'. | |
| format(p=port_num), rc) | |
| return port_attrs | |
| def query_port_speed(self, unsigned int port_num): | |
| """ | |
| Query port <port_num> speed in 100 Mb/s granularity. | |
| :param port_num: Port number to query | |
| :return: Port speed | |
| """ | |
| cdef uint64_t port_speed | |
| rc = v.ibv_query_port_speed(self.context, port_num, &port_speed) | |
| if rc != 0: | |
| raise PyverbsRDMAError(f'Failed to query port speed for port {port_num}', rc) | |
| return port_speed | |
| def query_gid_table(self, size_t max_entries, uint32_t flags=0): | |
| """ | |
| Queries the GID tables of the device for at most <max_entries> entries | |
| and returns them. | |
| :param max_entries: Maximum number of GID entries to retrieve | |
| :param flags: Specifies new extra members of struct ibv_gid_entry to | |
| query | |
| :return: List of GIDEntry objects on success | |
| """ | |
| cdef v.ibv_gid_entry *entries | |
| cdef v.ibv_gid_entry entry | |
| entries = <v.ibv_gid_entry *>malloc(max_entries * | |
| sizeof(v.ibv_gid_entry)) | |
| rc = v.ibv_query_gid_table(self.context, entries, max_entries, flags) | |
| if rc < 0: | |
| raise PyverbsRDMAError('Failed to query gid tables of the device', | |
| rc) | |
| gid_entries = [] | |
| for i in range(rc): | |
| entry = entries[i] | |
| gid_entries.append(GIDEntry(entry.gid._global.subnet_prefix, | |
| entry.gid._global.interface_id, entry.gid_index, | |
| entry.port_num, entry.gid_type, | |
| entry.ndev_ifindex)) | |
| free(entries) | |
| return gid_entries | |
| def query_gid_ex(self, uint32_t port_num, uint32_t gid_index, | |
| uint32_t flags=0): | |
| """ | |
| Queries the GID table of port <port_num> in index <gid_index>, and | |
| returns the GID entry. | |
| :param port_num: The port number to query | |
| :param gid_index: The index in the GID table to query | |
| :param flags: Specifies new extra members of struct ibv_gid_entry to | |
| query | |
| :return: GIDEntry object on success | |
| """ | |
| entry = GIDEntry() | |
| rc = v.ibv_query_gid_ex(self.context, port_num, gid_index, | |
| &entry.entry, flags) | |
| if rc != 0: | |
| raise PyverbsRDMAError(f'Failed to query gid table of port '\ | |
| f'{port_num} in index {gid_index}', rc) | |
| return entry | |
| def query_rt_values_ex(self, comp_mask=v.IBV_VALUES_MASK_RAW_CLOCK): | |
| """ | |
| Query an RDMA device for some real time values. | |
| :return: A tuple of the real time values according to comp_mask (sec, nsec) | |
| """ | |
| cdef v.ibv_values_ex *val | |
| val = <v.ibv_values_ex *>malloc(sizeof(v.ibv_values_ex)) | |
| val.comp_mask = comp_mask | |
| rc = v.ibv_query_rt_values_ex(self.context, val) | |
| if rc != 0: | |
| raise PyverbsRDMAError(f'Failed to query real time values', rc) | |
| if val.comp_mask != comp_mask: | |
| raise PyverbsRDMAError(f'Failed to query real time values with requested comp_mask') | |
| nsec = (<v.ibv_values_ex *>val).raw_clock.tv_nsec | |
| sec = (<v.ibv_values_ex *>val).raw_clock.tv_sec | |
| free(val) | |
| return sec, nsec | |
| cdef add_ref(self, obj): | |
| if isinstance(obj, PD): | |
| self.pds.add(obj) | |
| elif isinstance(obj, DM): | |
| self.dms.add(obj) | |
| elif isinstance(obj, CompChannel): | |
| self.ccs.add(obj) | |
| elif isinstance(obj, CQ) or isinstance(obj, CQEX): | |
| self.cqs.add(obj) | |
| elif isinstance(obj, QP): | |
| self.qps.add(obj) | |
| elif isinstance(obj, XRCD): | |
| self.xrcds.add(obj) | |
| elif isinstance(obj, WQ): | |
| self.wqs.add(obj) | |
| elif isinstance(obj, RwqIndTable): | |
| self.rwq_ind_tbls.add(obj) | |
| elif isinstance(obj, DMAHandle): | |
| self.dmahs.add(obj) | |
| elif isinstance(obj, CompCntr): | |
| self.comp_cntrs.add(obj) | |
| else: | |
| raise PyverbsError('Unrecognized object type') | |
| def get_async_event(self): | |
| event = AsyncEvent() | |
| rc = v.ibv_get_async_event(self.context, &event.event) | |
| if rc != 0: | |
| raise PyverbsRDMAError(f'Failed to get async event', rc) | |
| return event | |
| @property | |
| def cmd_fd(self): | |
| return self.context.cmd_fd | |
| @property | |
| def name(self): | |
| return self.name | |
| cdef class DeviceAttr(PyverbsObject): | |
| """ | |
| DeviceAttr represents ibv_device_attr C class. It exposes the same | |
| properties (read only) and also provides an __str__() function for | |
| readability. | |
| """ | |
| @property | |
| def fw_version(self): | |
| return self.dev_attr.fw_ver.decode() | |
| @property | |
| def node_guid(self): | |
| return self.dev_attr.node_guid | |
| @property | |
| def sys_image_guid(self): | |
| return self.dev_attr.sys_image_guid | |
| @property | |
| def max_mr_size(self): | |
| return self.dev_attr.max_mr_size | |
| @property | |
| def page_size_cap(self): | |
| return self.dev_attr.page_size_cap | |
| @property | |
| def vendor_id(self): | |
| return self.dev_attr.vendor_id | |
| @property | |
| def vendor_part_id(self): | |
| return self.dev_attr.vendor_part_id | |
| @property | |
| def hw_ver(self): | |
| return self.dev_attr.hw_ver | |
| @property | |
| def max_qp(self): | |
| return self.dev_attr.max_qp | |
| @property | |
| def max_qp_wr(self): | |
| return self.dev_attr.max_qp_wr | |
| @property | |
| def device_cap_flags(self): | |
| return self.dev_attr.device_cap_flags | |
| @property | |
| def max_sge(self): | |
| return self.dev_attr.max_sge | |
| @property | |
| def max_sge_rd(self): | |
| return self.dev_attr.max_sge_rd | |
| @property | |
| def max_cq(self): | |
| return self.dev_attr.max_cq | |
| @property | |
| def max_cqe(self): | |
| return self.dev_attr.max_cqe | |
| @property | |
| def max_mr(self): | |
| return self.dev_attr.max_mr | |
| @property | |
| def max_pd(self): | |
| return self.dev_attr.max_pd | |
| @property | |
| def max_qp_rd_atom(self): | |
| return self.dev_attr.max_qp_rd_atom | |
| @property | |
| def max_ee_rd_atom(self): | |
| return self.dev_attr.max_ee_rd_atom | |
| @property | |
| def max_res_rd_atom(self): | |
| return self.dev_attr.max_res_rd_atom | |
| @property | |
| def max_qp_init_rd_atom(self): | |
| return self.dev_attr.max_qp_init_rd_atom | |
| @property | |
| def max_ee_init_rd_atom(self): | |
| return self.dev_attr.max_ee_init_rd_atom | |
| @property | |
| def atomic_caps(self): | |
| return self.dev_attr.atomic_cap | |
| @property | |
| def max_ee(self): | |
| return self.dev_attr.max_ee | |
| @property | |
| def max_rdd(self): | |
| return self.dev_attr.max_rdd | |
| @property | |
| def max_mw(self): | |
| return self.dev_attr.max_mw | |
| @property | |
| def max_raw_ipv6_qps(self): | |
| return self.dev_attr.max_raw_ipv6_qp | |
| @property | |
| def max_raw_ethy_qp(self): | |
| return self.dev_attr.max_raw_ethy_qp | |
| @property | |
| def max_mcast_grp(self): | |
| return self.dev_attr.max_mcast_grp | |
| @property | |
| def max_mcast_qp_attach(self): | |
| return self.dev_attr.max_mcast_qp_attach | |
| @property | |
| def max_ah(self): | |
| return self.dev_attr.max_ah | |
| @property | |
| def max_fmr(self): | |
| return self.dev_attr.max_fmr | |
| @property | |
| def max_map_per_fmr(self): | |
| return self.dev_attr.max_map_per_fmr | |
| @property | |
| def max_srq(self): | |
| return self.dev_attr.max_srq | |
| @property | |
| def max_srq_wr(self): | |
| return self.dev_attr.max_srq_wr | |
| @property | |
| def max_srq_sge(self): | |
| return self.dev_attr.max_srq_sge | |
| @property | |
| def max_pkeys(self): | |
| return self.dev_attr.max_pkeys | |
| @property | |
| def local_ca_ack_delay(self): | |
| return self.dev_attr.local_ca_ack_delay | |
| @property | |
| def phys_port_cnt(self): | |
| return self.dev_attr.phys_port_cnt | |
| def __str__(self): | |
| print_format = '{:<22}: {:<20}\n' | |
| return print_format.format('FW version', self.fw_version) +\ | |
| print_format.format('Node guid', guid_format(self.node_guid)) +\ | |
| print_format.format('Sys image GUID', guid_format(self.sys_image_guid)) +\ | |
| print_format.format('Max MR size', hex(self.max_mr_size).replace('L', '')) +\ | |
| print_format.format('Page size cap', hex(self.page_size_cap).replace('L', '')) +\ | |
| print_format.format('Vendor ID', hex(self.vendor_id)) +\ | |
| print_format.format('Vendor part ID', self.vendor_part_id) +\ | |
| print_format.format('HW version', self.hw_ver) +\ | |
| print_format.format('Max QP', self.max_qp) +\ | |
| print_format.format('Max QP WR', self.max_qp_wr) +\ | |
| print_format.format('Device cap flags', | |
| translate_device_caps(self.device_cap_flags)) +\ | |
| print_format.format('Max SGE', self.max_sge) +\ | |
| print_format.format('Max SGE RD', self.max_sge_rd) +\ | |
| print_format.format('MAX CQ', self.max_cq) +\ | |
| print_format.format('Max CQE', self.max_cqe) +\ | |
| print_format.format('Max MR', self.max_mr) +\ | |
| print_format.format('Max PD', self.max_pd) +\ | |
| print_format.format('Max QP RD atom', self.max_qp_rd_atom) +\ | |
| print_format.format('Max EE RD atom', self.max_ee_rd_atom) +\ | |
| print_format.format('Max res RD atom', self.max_res_rd_atom) +\ | |
| print_format.format('Max QP init RD atom', self.max_qp_init_rd_atom) +\ | |
| print_format.format('Max EE init RD atom', self.max_ee_init_rd_atom) +\ | |
| print_format.format('Atomic caps', self.atomic_caps) +\ | |
| print_format.format('Max EE', self.max_ee) +\ | |
| print_format.format('Max RDD', self.max_rdd) +\ | |
| print_format.format('Max MW', self.max_mw) +\ | |
| print_format.format('Max raw IPv6 QPs', self.max_raw_ipv6_qps) +\ | |
| print_format.format('Max raw ethy QP', self.max_raw_ethy_qp) +\ | |
| print_format.format('Max mcast group', self.max_mcast_grp) +\ | |
| print_format.format('Max mcast QP attach', self.max_mcast_qp_attach) +\ | |
| print_format.format('Max AH', self.max_ah) +\ | |
| print_format.format('Max FMR', self.max_fmr) +\ | |
| print_format.format('Max map per FMR', self.max_map_per_fmr) +\ | |
| print_format.format('Max SRQ', self.max_srq) +\ | |
| print_format.format('Max SRQ WR', self.max_srq_wr) +\ | |
| print_format.format('Max SRQ SGE', self.max_srq_sge) +\ | |
| print_format.format('Max PKeys', self.max_pkeys) +\ | |
| print_format.format('local CA ack delay', self.local_ca_ack_delay) +\ | |
| print_format.format('Phys port count', self.phys_port_cnt) | |
| cdef class QueryDeviceExInput(PyverbsObject): | |
| def __init__(self, comp_mask): | |
| super().__init__() | |
| self.ex_input.comp_mask = comp_mask | |
| cdef class ODPCaps(PyverbsObject): | |
| @property | |
| def general_caps(self): | |
| return self.odp_caps.general_caps | |
| @property | |
| def rc_odp_caps(self): | |
| return self.odp_caps.per_transport_caps.rc_odp_caps | |
| @property | |
| def uc_odp_caps(self): | |
| return self.odp_caps.per_transport_caps.uc_odp_caps | |
| @property | |
| def ud_odp_caps(self): | |
| return self.odp_caps.per_transport_caps.ud_odp_caps | |
| @property | |
| def xrc_odp_caps(self): | |
| return self.xrc_odp_caps | |
| @xrc_odp_caps.setter | |
| def xrc_odp_caps(self, val): | |
| self.xrc_odp_caps = val | |
| def __str__(self): | |
| general_caps = {e.IBV_ODP_SUPPORT: 'IBV_ODP_SUPPORT', | |
| e.IBV_ODP_SUPPORT_IMPLICIT: 'IBV_ODP_SUPPORT_IMPLICIT'} | |
| l = {e.IBV_ODP_SUPPORT_SEND: 'IBV_ODP_SUPPORT_SEND', | |
| e.IBV_ODP_SUPPORT_RECV: 'IBV_ODP_SUPPORT_RECV', | |
| e.IBV_ODP_SUPPORT_WRITE: 'IBV_ODP_SUPPORT_WRITE', | |
| e.IBV_ODP_SUPPORT_READ: 'IBV_ODP_SUPPORT_READ', | |
| e.IBV_ODP_SUPPORT_ATOMIC: 'IBV_ODP_SUPPORT_ATOMIC', | |
| e.IBV_ODP_SUPPORT_SRQ_RECV: 'IBV_ODP_SUPPORT_SRQ_RECV', | |
| e.IBV_ODP_SUPPORT_FLUSH: 'IBV_ODP_SUPPORT_FLUSH', | |
| e.IBV_ODP_SUPPORT_ATOMIC_WRITE: 'IBV_ODP_SUPPORT_ATOMIC_WRITE'} | |
| print_format = '{}: {}\n' | |
| return print_format.format('ODP General caps', str_from_flags(self.general_caps, general_caps)) +\ | |
| print_format.format('RC ODP caps', str_from_flags(self.rc_odp_caps, l)) +\ | |
| print_format.format('UD ODP caps', str_from_flags(self.ud_odp_caps, l)) +\ | |
| print_format.format('UC ODP caps', str_from_flags(self.uc_odp_caps, l)) +\ | |
| print_format.format('XRC ODP caps', str_from_flags(self.xrc_odp_caps, l)) | |
| cdef class PCIAtomicCaps(PyverbsObject): | |
| @property | |
| def fetch_add(self): | |
| return self.caps.fetch_add | |
| @property | |
| def swap(self): | |
| return self.caps.swap | |
| @property | |
| def compare_swap(self): | |
| return self.caps.compare_swap | |
| cdef class TSOCaps(PyverbsObject): | |
| @property | |
| def max_tso(self): | |
| return self.tso_caps.max_tso | |
| @property | |
| def supported_qpts(self): | |
| return self.tso_caps.supported_qpts | |
| cdef class RSSCaps(PyverbsObject): | |
| @property | |
| def supported_qpts(self): | |
| return self.rss_caps.supported_qpts | |
| @property | |
| def max_rwq_indirection_tables(self): | |
| return self.rss_caps.max_rwq_indirection_tables | |
| @property | |
| def rx_hash_fields_mask(self): | |
| return self.rss_caps.rx_hash_fields_mask | |
| @property | |
| def rx_hash_function(self): | |
| return self.rss_caps.rx_hash_function | |
| @property | |
| def max_rwq_indirection_table_size(self): | |
| return self.rss_caps.max_rwq_indirection_table_size | |
| cdef class PacketPacingCaps(PyverbsObject): | |
| @property | |
| def qp_rate_limit_min(self): | |
| return self.packet_pacing_caps.qp_rate_limit_min | |
| @property | |
| def qp_rate_limit_max(self): | |
| return self.packet_pacing_caps.qp_rate_limit_max | |
| @property | |
| def supported_qpts(self): | |
| return self.packet_pacing_caps.supported_qpts | |
| cdef class TMCaps(PyverbsObject): | |
| @property | |
| def max_rndv_hdr_size(self): | |
| return self.tm_caps.max_rndv_hdr_size | |
| @property | |
| def max_num_tags(self): | |
| return self.tm_caps.max_num_tags | |
| @property | |
| def flags(self): | |
| return self.tm_caps.flags | |
| @property | |
| def max_ops(self): | |
| return self.tm_caps.max_ops | |
| @property | |
| def max_sge(self): | |
| return self.tm_caps.max_sge | |
| cdef class CQModerationCaps(PyverbsObject): | |
| @property | |
| def max_cq_count(self): | |
| return self.cq_mod_caps.max_cq_count | |
| @property | |
| def max_cq_period(self): | |
| return self.cq_mod_caps.max_cq_period | |
| cdef class DeviceAttrEx(PyverbsObject): | |
| @property | |
| def orig_attr(self): | |
| attr = DeviceAttr() | |
| attr.dev_attr = self.dev_attr.orig_attr | |
| return attr | |
| @property | |
| def comp_mask(self): | |
| return self.dev_attr.comp_mask | |
| @comp_mask.setter | |
| def comp_mask(self, val): | |
| self.dev_attr.comp_mask = val | |
| @property | |
| def odp_caps(self): | |
| caps = ODPCaps() | |
| caps.odp_caps = self.dev_attr.odp_caps | |
| caps.xrc_odp_caps = self.dev_attr.xrc_odp_caps | |
| return caps | |
| @property | |
| def completion_timestamp_mask(self): | |
| return self.dev_attr.completion_timestamp_mask | |
| @property | |
| def hca_core_clock(self): | |
| return self.dev_attr.hca_core_clock | |
| @property | |
| def device_cap_flags_ex(self): | |
| return self.dev_attr.device_cap_flags_ex | |
| @property | |
| def tso_caps(self): | |
| caps = TSOCaps() | |
| caps.tso_caps = self.dev_attr.tso_caps | |
| return caps | |
| @property | |
| def pci_atomic_caps(self): | |
| caps = PCIAtomicCaps() | |
| caps.caps = self.dev_attr.pci_atomic_caps | |
| return caps | |
| @property | |
| def rss_caps(self): | |
| caps = RSSCaps() | |
| caps.rss_caps = self.dev_attr.rss_caps | |
| return caps | |
| @property | |
| def max_wq_type_rq(self): | |
| return self.dev_attr.max_wq_type_rq | |
| @property | |
| def packet_pacing_caps(self): | |
| caps = PacketPacingCaps() | |
| caps.packet_pacing_caps = self.dev_attr.packet_pacing_caps | |
| return caps | |
| @property | |
| def raw_packet_caps(self): | |
| return self.dev_attr.raw_packet_caps | |
| @property | |
| def tm_caps(self): | |
| caps = TMCaps() | |
| caps.tm_caps = self.dev_attr.tm_caps | |
| return caps | |
| @property | |
| def cq_mod_caps(self): | |
| caps = CQModerationCaps() | |
| caps.cq_mod_caps = self.dev_attr.cq_mod_caps | |
| return caps | |
| @property | |
| def max_dm_size(self): | |
| return self.dev_attr.max_dm_size | |
| @property | |
| def phys_port_cnt_ex(self): | |
| return self.dev_attr.phys_port_cnt_ex | |
| cdef class CompCntrCaps(PyverbsObject): | |
| """Completion counter capabilities.""" | |
| @property | |
| def max_counters(self): | |
| return self.caps.max_counters | |
| @property | |
| def max_value(self): | |
| return self.caps.max_value | |
| @property | |
| def supported_qp_attach_ops(self): | |
| return self.caps.supported_qp_attach_ops | |
| cdef class AllocDmAttr(PyverbsObject): | |
| def __init__(self, length, log_align_req = 0, comp_mask = 0): | |
| """ | |
| Creates an AllocDmAttr object with the given parameters. This object | |
| can than be used to create a DM object. | |
| :param length: Length of the future device memory | |
| :param log_align_req: log2 of address alignment requirement | |
| :param comp_mask: compatibility mask | |
| :return: An AllocDmAttr object | |
| """ | |
| super().__init__() | |
| self.alloc_dm_attr.length = length | |
| self.alloc_dm_attr.log_align_req = log_align_req | |
| self.alloc_dm_attr.comp_mask = comp_mask | |
| @property | |
| def length(self): | |
| return self.alloc_dm_attr.length | |
| @length.setter | |
| def length(self, val): | |
| self.alloc_dm_attr.length = val | |
| @property | |
| def log_align_req(self): | |
| return self.alloc_dm_attr.log_align_req | |
| @log_align_req.setter | |
| def log_align_req(self, val): | |
| self.alloc_dm_attr.log_align_req = val | |
| @property | |
| def comp_mask(self): | |
| return self.alloc_dm_attr.comp_mask | |
| @comp_mask.setter | |
| def comp_mask(self, val): | |
| self.alloc_dm_attr.comp_mask = val | |
| cdef class DM(PyverbsCM): | |
| def __init__(self, Context context, AllocDmAttr dm_attr=None, **kwargs): | |
| """ | |
| Allocate a device (direct) memory. | |
| :param context: The context of the device on which to allocate memory | |
| :param dm_attr: Attributes that define the DM | |
| :param kwargs: Arguments: | |
| * *handle* | |
| A valid kernel handle for a DM object in the given context. | |
| If passed, the DM will be imported and associated with the | |
| given context using ibv_import_dm. | |
| :return: A DM object on success | |
| """ | |
| super().__init__() | |
| self.dm_mrs = weakref.WeakSet() | |
| dm_handle = kwargs.get('handle') | |
| if dm_handle is not None: | |
| self.dm = v.ibv_import_dm(context.context, dm_handle) | |
| if self.dm == NULL: | |
| raise PyverbsRDMAErrno('Failed to import DM') | |
| self._is_imported = True | |
| else: | |
| device_attr = context.query_device_ex() | |
| if device_attr.max_dm_size <= 0: | |
| raise PyverbsUserError('Device doesn\'t support dm allocation') | |
| self.dm = v.ibv_alloc_dm(<v.ibv_context*>context.context, | |
| &dm_attr.alloc_dm_attr) | |
| if self.dm == NULL: | |
| raise PyverbsRDMAErrno('Failed to allocate device memory of size ' | |
| '{size}. Max available size {max}.' | |
| .format(size=dm_attr.length, | |
| max=device_attr.max_dm_size)) | |
| self.context = context | |
| context.add_ref(self) | |
| def unimport(self): | |
| v.ibv_unimport_dm(self.dm) | |
| self.close() | |
| def __dealloc__(self): | |
| self.close() | |
| cpdef close(self): | |
| """ | |
| Closes the underlying C object of the DM. | |
| In case of an imported DM, the DM won't be freed, and it's kept for the | |
| original DM object, in order to prevent double free by Python GC. | |
| """ | |
| if self.dm != NULL: | |
| if self.logger: | |
| self.logger.debug('Closing DM') | |
| close_weakrefs([self.dm_mrs]) | |
| if not self._is_imported: | |
| rc = v.ibv_free_dm(self.dm) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to free dm', rc) | |
| self.dm = NULL | |
| self.context = None | |
| cdef add_ref(self, obj): | |
| if isinstance(obj, DMMR): | |
| self.dm_mrs.add(obj) | |
| def copy_to_dm(self, dm_offset, data, length): | |
| rc = v.ibv_memcpy_to_dm(<v.ibv_dm *>self.dm, <uint64_t>dm_offset, | |
| <char *>data, <size_t>length) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to copy to dm', rc) | |
| def copy_from_dm(self, dm_offset, length): | |
| cdef char *data =<char*>malloc(length) | |
| memset(data, 0, length) | |
| rc = v.ibv_memcpy_from_dm(<void *>data, <v.ibv_dm *>self.dm, | |
| <uint64_t>dm_offset, <size_t>length) | |
| if rc != 0: | |
| raise PyverbsRDMAError('Failed to copy from dm', rc) | |
| res = data[:length] | |
| free(data) | |
| return res | |
| def export_dmabuf_fd(self): | |
| """ | |
| Export a dmabuf FD for this DM object. | |
| :return: A file descriptor (int) for the dmabuf FD | |
| """ | |
| fd = v.ibv_dm_export_dmabuf_fd(self.dm) | |
| if fd < 0: | |
| raise PyverbsRDMAErrno('Failed to export dmabuf FD for DM') | |
| return fd | |
| @property | |
| def handle(self): | |
| return self.dm.handle | |
| cdef class PortAttr(PyverbsObject): | |
| @property | |
| def state(self): | |
| return self.attr.state | |
| @property | |
| def max_mtu(self): | |
| return self.attr.max_mtu | |
| @property | |
| def active_mtu(self): | |
| return self.attr.active_mtu | |
| @property | |
| def gid_tbl_len(self): | |
| return self.attr.gid_tbl_len | |
| @property | |
| def port_cap_flags(self): | |
| return self.attr.port_cap_flags | |
| @property | |
| def max_msg_sz(self): | |
| return self.attr.max_msg_sz | |
| @property | |
| def bad_pkey_cntr(self): | |
| return self.attr.bad_pkey_cntr | |
| @property | |
| def qkey_viol_cntr(self): | |
| return self.attr.qkey_viol_cntr | |
| @property | |
| def pkey_tbl_len(self): | |
| return self.attr.pkey_tbl_len | |
| @property | |
| def lid(self): | |
| return self.attr.lid | |
| @property | |
| def sm_lid(self): | |
| return self.attr.sm_lid | |
| @property | |
| def lmc(self): | |
| return self.attr.lmc | |
| @property | |
| def max_vl_num(self): | |
| return self.attr.max_vl_num | |
| @property | |
| def sm_sl(self): | |
| return self.attr.sm_sl | |
| @property | |
| def subnet_timeout(self): | |
| return self.attr.subnet_timeout | |
| @property | |
| def init_type_reply(self): | |
| return self.attr.init_type_reply | |
| @property | |
| def active_width(self): | |
| return self.attr.active_width | |
| @property | |
| def active_speed(self): | |
| return self.attr.active_speed | |
| @property | |
| def phys_state(self): | |
| return self.attr.phys_state | |
| @property | |
| def link_layer(self): | |
| return self.attr.link_layer | |
| @property | |
| def flags(self): | |
| return self.attr.flags | |
| @property | |
| def port_cap_flags2(self): | |
| return self.attr.port_cap_flags2 | |
| @property | |
| def active_speed_ex(self): | |
| return self.attr.active_speed_ex | |
| def __str__(self): | |
| print_format = '{:<24}: {:<20}\n' | |
| return print_format.format('Port state', port_state_to_str(self.attr.state)) +\ | |
| print_format.format('Max MTU', translate_mtu(self.attr.max_mtu)) +\ | |
| print_format.format('Active MTU', translate_mtu(self.attr.active_mtu)) +\ | |
| print_format.format('SM lid', self.attr.sm_lid) +\ | |
| print_format.format('Port lid', self.attr.lid) +\ | |
| print_format.format('lmc', hex(self.attr.lmc)) +\ | |
| print_format.format('Link layer', translate_link_layer(self.attr.link_layer)) +\ | |
| print_format.format('Max message size', hex(self.attr.max_msg_sz)) +\ | |
| print_format.format('Port cap flags', translate_port_cap_flags(self.attr.port_cap_flags)) +\ | |
| print_format.format('Port cap flags 2', translate_port_cap_flags2(self.attr.port_cap_flags2)) +\ | |
| print_format.format('max VL num', self.attr.max_vl_num) +\ | |
| print_format.format('Bad Pkey counter', self.attr.bad_pkey_cntr) +\ | |
| print_format.format('Qkey violations counter', self.attr.qkey_viol_cntr) +\ | |
| print_format.format('GID table len', self.attr.gid_tbl_len) +\ | |
| print_format.format('Pkey table len', self.attr.pkey_tbl_len) +\ | |
| print_format.format('SM sl', self.attr.sm_sl) +\ | |
| print_format.format('Subnet timeout', self.attr.subnet_timeout) +\ | |
| print_format.format('Init type reply', self.attr.init_type_reply) +\ | |
| print_format.format('Active width', width_to_str(self.attr.active_width)) +\ | |
| print_format.format('Active speed', speed_to_str(self.attr.active_speed, self.attr.active_speed_ex)) +\ | |
| print_format.format('Phys state', phys_state_to_str(self.attr.phys_state)) +\ | |
| print_format.format('Flags', self.attr.flags) | |
| cdef class GIDEntry(PyverbsObject): | |
| def __init__(self, subnet_prefix=0, interface_id=0, gid_index=0, | |
| port_num=0, gid_type=0, ndev_ifindex=0): | |
| super().__init__() | |
| self.entry.gid._global.subnet_prefix = subnet_prefix | |
| self.entry.gid._global.interface_id = interface_id | |
| self.entry.gid_index = gid_index | |
| self.entry.port_num = port_num | |
| self.entry.gid_type = gid_type | |
| self.entry.ndev_ifindex = ndev_ifindex | |
| @property | |
| def gid_subnet_prefix(self): | |
| return self.entry.gid._global.subnet_prefix | |
| @property | |
| def gid_interface_id(self): | |
| return self.entry.gid._global.interface_id | |
| @property | |
| def gid_index(self): | |
| return self.entry.gid_index | |
| @property | |
| def port_num(self): | |
| return self.entry.port_num | |
| @property | |
| def gid_type(self): | |
| return self.entry.gid_type | |
| @property | |
| def ndev_ifindex(self): | |
| return self.entry.ndev_ifindex | |
| def gid_str(self): | |
| return gid_str(self.gid_subnet_prefix, self.gid_interface_id) | |
| def __str__(self): | |
| print_format = '{:<24}: {:<20}\n' | |
| return print_format.format('GID', self.gid_str()) +\ | |
| print_format.format('GID Index', self.gid_index) +\ | |
| print_format.format('Port number', self.port_num) +\ | |
| print_format.format('GID type', translate_gid_type( | |
| self.gid_type)) +\ | |
| print_format.format('Ndev ifindex', self.ndev_ifindex) | |
| cdef class AsyncEvent(PyverbsObject): | |
| def __init__(self, event_type=0): | |
| super().__init__() | |
| self.event.event_type = event_type | |
| def ack(self): | |
| v.ibv_ack_async_event(&self.event) | |
| @property | |
| def event_type(self): | |
| return self.event.event_type | |
| def __str__(self): | |
| print_format = '{:<24}: {:<20}\n' | |
| return print_format.format('Event Type', translate_event_type( | |
| self.event.event_type)) | |
| def translate_gid_type(gid_type): | |
| types = {e.IBV_GID_TYPE_IB: 'IB', e.IBV_GID_TYPE_ROCE_V1: 'RoCEv1', | |
| e.IBV_GID_TYPE_ROCE_V2: 'RoCEv2'} | |
| try: | |
| return types[gid_type] | |
| except KeyError: | |
| return f'Unknown gid_type ({gid_type})' | |
| def guid_format(num): | |
| """ | |
| Get GUID representation of the given number, including change of endianness. | |
| :param num: Number to change to GUID format. | |
| :return: GUID-formatted string. | |
| """ | |
| num = be64toh(num) | |
| hex_str = "%016x" % (num) | |
| hex_array = [hex_str[i:i+2] for i in range(0, len(hex_str), 2)] | |
| hex_array = [''.join(x) for x in zip(hex_array[0::2], hex_array[1::2])] | |
| return ':'.join(hex_array) | |
| def translate_transport_type(transport_type): | |
| l = {0: 'IB', 1: 'IWARP', 2: 'USNIC', 3: 'USNIC UDP'} | |
| try: | |
| return l[transport_type] | |
| except KeyError: | |
| return 'Unknown' | |
| def translate_node_type(node_type): | |
| l = {1: 'CA', 2: 'Switch', 3: 'Router', 4: 'RNIC', 5: 'USNIC', | |
| 6: 'USNIC UDP'} | |
| try: | |
| return l[node_type] | |
| except KeyError: | |
| return 'Unknown' | |
| def guid_to_hex(node_guid): | |
| return hex(node_guid).replace('L', '').replace('0x', '') | |
| def port_state_to_str(port_state): | |
| l = {0: 'NOP', 1: 'Down', 2: 'Init', 3: 'Armed', 4: 'Active', 5: 'Defer'} | |
| try: | |
| return '{s} ({n})'.format(s=l[port_state], n=port_state) | |
| except KeyError: | |
| return 'Invalid state ({s})'.format(s=port_state) | |
| def translate_mtu(mtu): | |
| l = {1: 256, 2: 512, 3: 1024, 4: 2048, 5: 4096} | |
| try: | |
| return '{s} ({n})'.format(s=l[mtu], n=mtu) | |
| except KeyError: | |
| return 'Invalid MTU ({m})'.format(m=mtu) | |
| def translate_link_layer(ll): | |
| l = {0: 'Unspecified', 1:'InfiniBand', 2:'Ethernet'} | |
| try: | |
| return l[ll] | |
| except KeyError: | |
| return 'Invalid link layer ({ll})'.format(ll=ll) | |
| def translate_port_cap_flags(flags): | |
| l = {e.IBV_PORT_SM: 'IBV_PORT_SM', | |
| e.IBV_PORT_NOTICE_SUP: 'IBV_PORT_NOTICE_SUP', | |
| e.IBV_PORT_TRAP_SUP: 'IBV_PORT_TRAP_SUP', | |
| e.IBV_PORT_OPT_IPD_SUP: 'IBV_PORT_OPT_IPD_SUP', | |
| e.IBV_PORT_AUTO_MIGR_SUP: 'IBV_PORT_AUTO_MIGR_SUP', | |
| e.IBV_PORT_SL_MAP_SUP: 'IBV_PORT_SL_MAP_SUP', | |
| e.IBV_PORT_MKEY_NVRAM: 'IBV_PORT_MKEY_NVRAM', | |
| e.IBV_PORT_PKEY_NVRAM: 'IBV_PORT_PKEY_NVRAM', | |
| e.IBV_PORT_LED_INFO_SUP: 'IBV_PORT_LED_INFO_SUP', | |
| e.IBV_PORT_SYS_IMAGE_GUID_SUP: 'IBV_PORT_SYS_IMAGE_GUID_SUP', | |
| e.IBV_PORT_PKEY_SW_EXT_PORT_TRAP_SUP: 'IBV_PORT_PKEY_SW_EXT_PORT_TRAP_SUP', | |
| e.IBV_PORT_EXTENDED_SPEEDS_SUP: 'IBV_PORT_EXTENDED_SPEEDS_SUP', | |
| e.IBV_PORT_CAP_MASK2_SUP: 'IBV_PORT_CAP_MASK2_SUP', | |
| e.IBV_PORT_CM_SUP: 'IBV_PORT_CM_SUP', | |
| e.IBV_PORT_SNMP_TUNNEL_SUP: 'IBV_PORT_SNMP_TUNNEL_SUP', | |
| e.IBV_PORT_REINIT_SUP: 'IBV_PORT_REINIT_SUP', | |
| e.IBV_PORT_DEVICE_MGMT_SUP: 'IBV_PORT_DEVICE_MGMT_SUP', | |
| e.IBV_PORT_VENDOR_CLASS_SUP: 'IBV_PORT_VENDOR_CLASS_SUP', | |
| e.IBV_PORT_DR_NOTICE_SUP: 'IBV_PORT_DR_NOTICE_SUP', | |
| e.IBV_PORT_CAP_MASK_NOTICE_SUP: 'IBV_PORT_CAP_MASK_NOTICE_SUP', | |
| e.IBV_PORT_BOOT_MGMT_SUP: 'IBV_PORT_BOOT_MGMT_SUP', | |
| e.IBV_PORT_LINK_LATENCY_SUP: 'IBV_PORT_LINK_LATENCY_SUP', | |
| e.IBV_PORT_CLIENT_REG_SUP: 'IBV_PORT_CLIENT_REG_SUP', | |
| e.IBV_PORT_IP_BASED_GIDS: 'IBV_PORT_IP_BASED_GIDS'} | |
| return str_from_flags(flags, l) | |
| def translate_port_cap_flags2(flags): | |
| l = {e.IBV_PORT_SET_NODE_DESC_SUP: 'IBV_PORT_SET_NODE_DESC_SUP', | |
| e.IBV_PORT_INFO_EXT_SUP: 'IBV_PORT_INFO_EXT_SUP', | |
| e.IBV_PORT_VIRT_SUP: 'IBV_PORT_VIRT_SUP', | |
| e.IBV_PORT_SWITCH_PORT_STATE_TABLE_SUP: 'IBV_PORT_SWITCH_PORT_STATE_TABLE_SUP', | |
| e.IBV_PORT_LINK_WIDTH_2X_SUP: 'IBV_PORT_LINK_WIDTH_2X_SUP', | |
| e.IBV_PORT_LINK_SPEED_HDR_SUP: 'IBV_PORT_LINK_SPEED_HDR_SUP', | |
| e.IBV_PORT_LINK_SPEED_NDR_SUP: 'IBV_PORT_LINK_SPEED_NDR_SUP'} | |
| return str_from_flags(flags, l) | |
| def translate_device_caps(flags): | |
| l = {e.IBV_DEVICE_RESIZE_MAX_WR: 'IBV_DEVICE_RESIZE_MAX_WR', | |
| e.IBV_DEVICE_BAD_PKEY_CNTR: 'IBV_DEVICE_BAD_PKEY_CNTR', | |
| e.IBV_DEVICE_BAD_QKEY_CNTR: 'IBV_DEVICE_BAD_QKEY_CNTR', | |
| e.IBV_DEVICE_RAW_MULTI: 'IBV_DEVICE_RAW_MULTI', | |
| e.IBV_DEVICE_AUTO_PATH_MIG: 'IBV_DEVICE_AUTO_PATH_MIG', | |
| e.IBV_DEVICE_CHANGE_PHY_PORT: 'IBV_DEVICE_CHANGE_PHY_PORT', | |
| e.IBV_DEVICE_UD_AV_PORT_ENFORCE: 'IBV_DEVICE_UD_AV_PORT_ENFORCE', | |
| e.IBV_DEVICE_CURR_QP_STATE_MOD: 'IBV_DEVICE_CURR_QP_STATE_MOD', | |
| e.IBV_DEVICE_SHUTDOWN_PORT: 'IBV_DEVICE_SHUTDOWN_PORT', | |
| e.IBV_DEVICE_INIT_TYPE: 'IBV_DEVICE_INIT_TYPE', | |
| e.IBV_DEVICE_PORT_ACTIVE_EVENT: 'IBV_DEVICE_PORT_ACTIVE_EVENT', | |
| e.IBV_DEVICE_SYS_IMAGE_GUID: 'IBV_DEVICE_SYS_IMAGE_GUID', | |
| e.IBV_DEVICE_RC_RNR_NAK_GEN: 'IBV_DEVICE_RC_RNR_NAK_GEN', | |
| e.IBV_DEVICE_SRQ_RESIZE: 'IBV_DEVICE_SRQ_RESIZE', | |
| e.IBV_DEVICE_N_NOTIFY_CQ: 'IBV_DEVICE_N_NOTIFY_CQ', | |
| e.IBV_DEVICE_MEM_WINDOW: 'IBV_DEVICE_MEM_WINDOW', | |
| e.IBV_DEVICE_UD_IP_CSUM: 'IBV_DEVICE_UD_IP_CSUM', | |
| e.IBV_DEVICE_XRC: 'IBV_DEVICE_XRC', | |
| e.IBV_DEVICE_MEM_MGT_EXTENSIONS: 'IBV_DEVICE_MEM_MGT_EXTENSIONS', | |
| e.IBV_DEVICE_MEM_WINDOW_TYPE_2A: 'IBV_DEVICE_MEM_WINDOW_TYPE_2A', | |
| e.IBV_DEVICE_MEM_WINDOW_TYPE_2B: 'IBV_DEVICE_MEM_WINDOW_TYPE_2B', | |
| e.IBV_DEVICE_RC_IP_CSUM: 'IBV_DEVICE_RC_IP_CSUM', | |
| e.IBV_DEVICE_RAW_IP_CSUM: 'IBV_DEVICE_RAW_IP_CSUM', | |
| e.IBV_DEVICE_MANAGED_FLOW_STEERING: 'IBV_DEVICE_MANAGED_FLOW_STEERING'} | |
| return str_from_flags(flags, l) | |
| def str_from_flags(flags, dictionary): | |
| str_flags = "\n " | |
| for bit in dictionary: | |
| if flags & bit: | |
| str_flags += dictionary[bit] | |
| str_flags += '\n ' | |
| return str_flags | |
| def phys_state_to_str(phys): | |
| l = {1: 'Sleep', 2: 'Polling', 3: 'Disabled', | |
| 4: 'Port configuration training', 5: 'Link up', | |
| 6: 'Link error recovery', 7: 'Phy test'} | |
| try: | |
| return '{s} ({n})'.format(s=l[phys], n=phys) | |
| except KeyError: | |
| return 'Invalid physical state' | |
| def width_to_str(width): | |
| l = {1: '1X', 2: '4X', 4: '8X', 8: '12X', 16: '2X'} | |
| try: | |
| return '{s} ({n})'.format(s=l[width], n=width) | |
| except KeyError: | |
| return 'Invalid width' | |
| def speed_to_str(active_speed, active_speed_ex): | |
| real_speed = active_speed if not active_speed_ex else active_speed_ex | |
| l = {0: '0.0 Gbps', 1: '2.5 Gbps', 2: '5.0 Gbps', 4: '5.0 Gbps', | |
| 8: '10.0 Gbps', 16: '14.0 Gbps', 32: '25.0 Gbps', 64: '50.0 Gbps', | |
| 128: '100.0 Gbps', 256: '200.0 Gbps'} | |
| try: | |
| return '{s} ({n})'.format(s=l[real_speed], n=real_speed) | |
| except KeyError: | |
| return 'Invalid speed' | |
| def get_device_list(): | |
| """ | |
| :return: list of IB_devices on current node | |
| each list element contains a Device with: | |
| device name | |
| device node type | |
| device transport type | |
| device guid | |
| device index | |
| """ | |
| cdef int count = 0; | |
| cdef v.ibv_device **dev_list; | |
| dev_list = v.ibv_get_device_list(&count) | |
| if dev_list == NULL: | |
| raise PyverbsRDMAError('Failed to get devices list') | |
| devices = [] | |
| try: | |
| for i in range(count): | |
| name = dev_list[i].name | |
| node = dev_list[i].node_type | |
| transport = dev_list[i].transport_type | |
| guid = be64toh(v.ibv_get_device_guid(dev_list[i])) | |
| index = v.ibv_get_device_index(dev_list[i]) | |
| devices.append(Device(name, guid, node, transport, index)) | |
| finally: | |
| v.ibv_free_device_list(dev_list) | |
| return devices | |
| def rdma_get_devices(): | |
| """ | |
| Get the RDMA devices. | |
| :return: list of Device objects. | |
| """ | |
| cdef int count | |
| cdef v.ibv_context **ctx_list | |
| ctx_list = cm.rdma_get_devices(&count) | |
| if ctx_list == NULL: | |
| raise PyverbsRDMAErrno('Failed to get device list') | |
| devices = [] | |
| for i in range(count): | |
| name = ctx_list[i].device.name | |
| node = ctx_list[i].device.node_type | |
| transport = ctx_list[i].device.transport_type | |
| guid = be64toh(v.ibv_get_device_guid(ctx_list[i].device)) | |
| index = v.ibv_get_device_index(ctx_list[i].device) | |
| devices.append(Device(name, guid, node, transport, index)) | |
| cm.rdma_free_devices(ctx_list) | |
| return devices | |
| def translate_event_type(event_type): | |
| types = { | |
| e.IBV_EVENT_CQ_ERR: 'IBV_EVENT_CQ_ERR', | |
| e.IBV_EVENT_QP_FATAL: 'IBV_EVENT_QP_FATAL', | |
| e.IBV_EVENT_QP_REQ_ERR: 'IBV_EVENT_QP_REQ_ERR', | |
| e.IBV_EVENT_QP_ACCESS_ERR: 'IBV_EVENT_QP_ACCESS_ERR', | |
| e.IBV_EVENT_COMM_EST: 'IBV_EVENT_COMM_EST', | |
| e.IBV_EVENT_SQ_DRAINED: 'IBV_EVENT_SQ_DRAINED', | |
| e.IBV_EVENT_PATH_MIG: 'IBV_EVENT_PATH_MIG', | |
| e.IBV_EVENT_PATH_MIG_ERR: 'IBV_EVENT_PATH_MIG_ERR', | |
| e.IBV_EVENT_DEVICE_FATAL: 'IBV_EVENT_DEVICE_FATAL', | |
| e.IBV_EVENT_PORT_ACTIVE: 'IBV_EVENT_PORT_ACTIVE', | |
| e.IBV_EVENT_PORT_ERR: 'IBV_EVENT_PORT_ERR', | |
| e.IBV_EVENT_LID_CHANGE: 'IBV_EVENT_LID_CHANGE', | |
| e.IBV_EVENT_PKEY_CHANGE: 'IBV_EVENT_PKEY_CHANGE', | |
| e.IBV_EVENT_SM_CHANGE: 'IBV_EVENT_SM_CHANGE', | |
| e.IBV_EVENT_SRQ_ERR: 'IBV_EVENT_SRQ_ERR', | |
| e.IBV_EVENT_SRQ_LIMIT_REACHED: 'IBV_EVENT_SRQ_LIMIT_REACHED', | |
| e.IBV_EVENT_QP_LAST_WQE_REACHED: '.IBV_EVENT_QP_LAST_WQE_REACHED', | |
| e.IBV_EVENT_CLIENT_REREGISTER: 'IBV_EVENT_CLIENT_REREGISTER', | |
| e.IBV_EVENT_GID_CHANGE: 'IBV_EVENT_GID_CHANGE', | |
| e.IBV_EVENT_WQ_FATAL: 'IBV_EVENT_WQ_FATAL', | |
| e.IBV_EVENT_DEVICE_SPEED_CHANGE: 'IBV_EVENT_DEVICE_SPEED_CHANGE' | |
| } | |
| try: | |
| return types[event_type] | |
| except KeyError: | |
| return f'Unknown event_type ({event_type})' | |
| cdef class FdArr(PyverbsObject): | |
| """ | |
| Represent ibv_fd_arr struct. This class is used a pointer to the file descriptor array | |
| """ | |
| def __init__(self, arr=[], count=0): | |
| super().__init__() | |
| cdef int *dst | |
| self.attr.arr = <int*>malloc(count * sizeof(int)) | |
| if self.attr.arr == NULL: | |
| raise PyverbsRDMAErrno('Failed to malloc FD list') | |
| dst = self.attr.arr | |
| for i in range(count): | |
| dst[i]= arr[i] | |
| self.attr.count = count | |
| def __dealloc__(self): | |
| self.close() | |
| cpdef close(self): | |
| free(self.attr.arr) | |
| def __str__(self): | |
| print_format = '{:20}: {:<20}\n' | |
| return print_format.format('Number of fd in arr', self.attr.count) +\ | |
| print_format.format('FDs in arr', [self.attr.arr[i] for i in range(self.attr.count)]) | |
| @property | |
| def arr(self): | |
| return [self.attr.arr[i] for i in range(self.attr.count)] | |
| @property | |
| def count(self): | |
| return self.attr.count |