| # SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) | |
| # Copyright (c) 2018, Mellanox Technologies. All rights reserved. See COPYING file | |
| from libc.stdint cimport uint8_t, uintptr_t | |
| from .pyverbs_error import PyverbsUserError, PyverbsRDMAError | |
| from pyverbs.utils import gid_str_to_array, gid_str | |
| from pyverbs.base import PyverbsRDMAErrno | |
| from pyverbs.cmid cimport UDParam | |
| cimport pyverbs.libibverbs as v | |
| from pyverbs.pd cimport PD | |
| from pyverbs.cq cimport WC | |
| cdef extern from 'endian.h': | |
| unsigned long be64toh(unsigned long host_64bits) | |
| cdef class GID(PyverbsObject): | |
| """ | |
| GID class represents ibv_gid. It enables user to query for GIDs values. | |
| """ | |
| def __init__(self, val=None): | |
| super().__init__() | |
| if val is not None: | |
| vals = gid_str_to_array(val) | |
| for i in range(16): | |
| self.gid.raw[i] = <uint8_t>int(vals[i],16) | |
| @property | |
| def gid(self): | |
| """ | |
| Expose the inner GID | |
| :return: A GID string in an 8 words format: | |
| 'xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx' | |
| """ | |
| return self.__str__() | |
| @gid.setter | |
| def gid(self, val): | |
| """ | |
| Sets the inner GID | |
| :param val: A GID string in an 8 words format: | |
| 'xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx' | |
| :return: None | |
| """ | |
| self._set_gid(val) | |
| def _set_gid(self, val): | |
| vals = gid_str_to_array(val) | |
| for i in range(16): | |
| self.gid.raw[i] = <uint8_t>int(vals[i],16) | |
| def __str__(self): | |
| return gid_str(self.gid._global.subnet_prefix, | |
| self.gid._global.interface_id) | |
| cdef class GRH(PyverbsObject): | |
| """ | |
| Represents ibv_grh struct. Used when creating or initializing an | |
| Address Handle from a Work Completion. | |
| """ | |
| def __init__(self, GID sgid=None, GID dgid=None, version_tclass_flow=0, | |
| paylen=0, next_hdr=0, hop_limit=1): | |
| """ | |
| Initializes a GRH object | |
| :param sgid: Source GID | |
| :param dgid: Destination GID | |
| :param version_tclass_flow: A 32b big endian used to communicate | |
| service level e.g. across subnets | |
| :param paylen: A 16b big endian that is the packet length in bytes, | |
| starting from the first byte after the GRH up to and | |
| including the last byte of the ICRC | |
| :param next_hdr: An 8b unsigned integer specifying the next header | |
| For non-raw packets: 0x1B | |
| For raw packets: According to IETF RFC 1700 | |
| :param hop_limit: An 8b unsigned integer specifying the number of hops | |
| (i.e. routers) that the packet is permitted to take | |
| prior to being discarded | |
| :return: A GRH object | |
| """ | |
| super().__init__() | |
| self.grh.dgid = dgid.gid | |
| self.grh.sgid = sgid.gid | |
| self.grh.version_tclass_flow = version_tclass_flow | |
| self.grh.paylen = paylen | |
| self.grh.next_hdr = next_hdr | |
| self.grh.hop_limit = hop_limit | |
| @property | |
| def dgid(self): | |
| return gid_str(self.grh.dgid._global.subnet_prefix, | |
| self.grh.dgid._global.interface_id) | |
| @dgid.setter | |
| def dgid(self, val): | |
| vals = gid_str_to_array(val) | |
| for i in range(16): | |
| self.grh.dgid.raw[i] = <uint8_t>int(vals[i],16) | |
| @property | |
| def sgid(self): | |
| return gid_str(self.grh.sgid._global.subnet_prefix, | |
| self.grh.sgid._global.interface_id) | |
| @sgid.setter | |
| def sgid(self, val): | |
| vals = gid_str_to_array(val) | |
| for i in range(16): | |
| self.grh.sgid.raw[i] = <uint8_t>int(vals[i],16) | |
| @property | |
| def version_tclass_flow(self): | |
| return self.grh.version_tclass_flow | |
| @version_tclass_flow.setter | |
| def version_tclass_flow(self, val): | |
| self.grh.version_tclass_flow = val | |
| @property | |
| def paylen(self): | |
| return self.grh.paylen | |
| @paylen.setter | |
| def paylen(self, val): | |
| self.grh.paylen = val | |
| @property | |
| def next_hdr(self): | |
| return self.grh.next_hdr | |
| @next_hdr.setter | |
| def next_hdr(self, val): | |
| self.grh.next_hdr = val | |
| @property | |
| def hop_limit(self): | |
| return self.grh.hop_limit | |
| @hop_limit.setter | |
| def hop_limit(self, val): | |
| self.grh.hop_limit = val | |
| def __str__(self): | |
| print_format = '{:22}: {:<20}\n' | |
| return print_format.format('DGID', self.dgid) +\ | |
| print_format.format('SGID', self.sgid) +\ | |
| print_format.format('version tclass flow', self.version_tclass_flow) +\ | |
| print_format.format('paylen', self.paylen) +\ | |
| print_format.format('next header', self.next_hdr) +\ | |
| print_format.format('hop limit', self.hop_limit) | |
| cdef class GlobalRoute(PyverbsObject): | |
| """ | |
| Represents ibv_global_route. Used in Address Handle creation and describes | |
| the values to be used in the GRH of the packets that will be sent using | |
| this Address Handle. | |
| """ | |
| def __init__(self, GID dgid=None, flow_label=0, sgid_index=0, hop_limit=1, | |
| traffic_class=0): | |
| """ | |
| Initializes a GlobalRoute object with given parameters. | |
| :param dgid: Destination GID | |
| :param flow_label: A 20b value. If non-zero, gives a hint to switches | |
| and routers that this sequence of packets must be | |
| delivered in order | |
| :param sgid_index: An index in the port's GID table that identifies the | |
| originator of the packet | |
| :param hop_limit: An 8b unsigned integer specifying the number of hops | |
| (i.e. routers) that the packet is permitted to take | |
| prior to being discarded | |
| :param traffic_class: An 8b unsigned integer specifying the required | |
| delivery priority for routers | |
| :return: A GlobalRoute object | |
| """ | |
| super().__init__() | |
| self.gr.dgid=dgid.gid | |
| self.gr.flow_label = flow_label | |
| self.gr.sgid_index = sgid_index | |
| self.gr.hop_limit = hop_limit | |
| self.gr.traffic_class = traffic_class | |
| @property | |
| def dgid(self): | |
| return gid_str(self.gr.dgid._global.subnet_prefix, | |
| self.gr.dgid._global.interface_id) | |
| @dgid.setter | |
| def dgid(self, val): | |
| vals = gid_str_to_array(val) | |
| for i in range(16): | |
| self.gr.dgid.raw[i] = <uint8_t>int(vals[i],16) | |
| @property | |
| def flow_label(self): | |
| return self.gr.flow_label | |
| @flow_label.setter | |
| def flow_label(self, val): | |
| self.gr.flow_label = val | |
| @property | |
| def sgid_index(self): | |
| return self.gr.sgid_index | |
| @sgid_index.setter | |
| def sgid_index(self, val): | |
| self.gr.sgid_index = val | |
| @property | |
| def hop_limit(self): | |
| return self.gr.hop_limit | |
| @hop_limit.setter | |
| def hop_limit(self, val): | |
| self.gr.hop_limit = val | |
| @property | |
| def traffic_class(self): | |
| return self.gr.traffic_class | |
| @traffic_class.setter | |
| def traffic_class(self, val): | |
| self.gr.traffic_class = val | |
| def __str__(self): | |
| print_format = '{:22}: {:<20}\n' | |
| return print_format.format('DGID', self.dgid) +\ | |
| print_format.format('flow label', self.flow_label) +\ | |
| print_format.format('sgid index', self.sgid_index) +\ | |
| print_format.format('hop limit', self.hop_limit) +\ | |
| print_format.format('traffic class', self.traffic_class) | |
| cdef class AHAttr(PyverbsObject): | |
| """ Represents ibv_ah_attr struct """ | |
| def __init__(self, dlid=0, sl=0, src_path_bits=0, static_rate=0, | |
| is_global=0, port_num=1, GlobalRoute gr=None): | |
| """ | |
| Initializes an AHAttr object. | |
| :param dlid: Destination LID, a 16b unsigned integer | |
| :param sl: Service level, an 8b unsigned integer | |
| :param src_path_bits: When LMC (LID mask count) is used in the port, | |
| packets are being sent with the port's base LID, | |
| bitwise ORed with the value of the src_path_bits. | |
| An 8b unsigned integer | |
| :param static_rate: An 8b unsigned integer limiting the rate of packets | |
| that are being sent to the subnet | |
| :param is_global: If non-zero, GRH information exists in the Address | |
| Handle | |
| :param port_num: The local physical port from which the packets will be | |
| sent | |
| :param grh: Attributes of a global routing header. Will only be used if | |
| is_global is non zero. | |
| :return: An AHAttr object | |
| """ | |
| super().__init__() | |
| self.ah_attr.port_num = port_num | |
| self.ah_attr.sl = sl | |
| self.ah_attr.src_path_bits = src_path_bits | |
| self.ah_attr.dlid = dlid | |
| self.ah_attr.static_rate = static_rate | |
| self.ah_attr.is_global = is_global | |
| # Do not set GRH fields for a non-global AH | |
| if is_global: | |
| if gr is None: | |
| raise PyverbsUserError('Global AH Attr is created but gr parameter is None') | |
| self.ah_attr.grh.dgid = gr.gr.dgid | |
| self.ah_attr.grh.flow_label = gr.flow_label | |
| self.ah_attr.grh.sgid_index = gr.sgid_index | |
| self.ah_attr.grh.hop_limit = gr.hop_limit | |
| self.ah_attr.grh.traffic_class = gr.traffic_class | |
| cdef init_from_ud_param(self, UDParam udparam): | |
| """ | |
| Initiate the AHAttr from UDParam's ah_attr. | |
| :param udparam: UDParam that contains the AHAttr. | |
| :return: None | |
| """ | |
| self.ah_attr = udparam.ud_param.ah_attr | |
| @property | |
| def port_num(self): | |
| return self.ah_attr.port_num | |
| @port_num.setter | |
| def port_num(self, val): | |
| self.ah_attr.port_num = val | |
| @property | |
| def sl(self): | |
| return self.ah_attr.sl | |
| @sl.setter | |
| def sl(self, val): | |
| self.ah_attr.sl = val | |
| @property | |
| def src_path_bits(self): | |
| return self.ah_attr.src_path_bits | |
| @src_path_bits.setter | |
| def src_path_bits(self, val): | |
| self.ah_attr.src_path_bits = val | |
| @property | |
| def dlid(self): | |
| return self.ah_attr.dlid | |
| @dlid.setter | |
| def dlid(self, val): | |
| self.ah_attr.dlid = val | |
| @property | |
| def static_rate(self): | |
| return self.ah_attr.static_rate | |
| @static_rate.setter | |
| def static_rate(self, val): | |
| self.ah_attr.static_rate = val | |
| @property | |
| def is_global(self): | |
| return self.ah_attr.is_global | |
| @is_global.setter | |
| def is_global(self, val): | |
| self.ah_attr.is_global = val | |
| @property | |
| def dgid(self): | |
| if self.ah_attr.is_global: | |
| return gid_str(self.ah_attr.grh.dgid._global.subnet_prefix, | |
| self.ah_attr.grh.dgid._global.interface_id) | |
| @dgid.setter | |
| def dgid(self, val): | |
| if self.ah_attr.is_global: | |
| vals = gid_str_to_array(val) | |
| for i in range(16): | |
| self.ah_attr.grh.dgid.raw[i] = <uint8_t>int(vals[i],16) | |
| @property | |
| def flow_label(self): | |
| if self.ah_attr.is_global: | |
| return self.ah_attr.grh.flow_label | |
| @flow_label.setter | |
| def flow_label(self, val): | |
| self.ah_attr.grh.flow_label = val | |
| @property | |
| def sgid_index(self): | |
| if self.ah_attr.is_global: | |
| return self.ah_attr.grh.sgid_index | |
| @sgid_index.setter | |
| def sgid_index(self, val): | |
| self.ah_attr.grh.sgid_index = val | |
| @property | |
| def hop_limit(self): | |
| if self.ah_attr.is_global: | |
| return self.ah_attr.grh.hop_limit | |
| @hop_limit.setter | |
| def hop_limit(self, val): | |
| self.ah_attr.grh.hop_limit = val | |
| @property | |
| def traffic_class(self): | |
| if self.ah_attr.is_global: | |
| return self.ah_attr.grh.traffic_class | |
| @traffic_class.setter | |
| def traffic_class(self, val): | |
| self.ah_attr.grh.traffic_class = val | |
| def __str__(self): | |
| print_format = ' {:22}: {:<20}\n' | |
| if self.is_global: | |
| global_format = print_format.format('dgid', self.dgid) +\ | |
| print_format.format('flow label', self.flow_label) +\ | |
| print_format.format('sgid index', self.sgid_index) +\ | |
| print_format.format('hop limit', self.hop_limit) +\ | |
| print_format.format('traffic_class', self.traffic_class) | |
| else: | |
| global_format = '' | |
| return print_format.format('port num', self.port_num) +\ | |
| print_format.format('sl', self.sl) +\ | |
| print_format.format('source path bits', self.src_path_bits) +\ | |
| print_format.format('dlid', self.dlid) +\ | |
| print_format.format('static rate', self.static_rate) +\ | |
| print_format.format('is global', self.is_global) + global_format | |
| cdef class AH(PyverbsCM): | |
| def __init__(self, PD pd, **kwargs): | |
| """ | |
| Initializes an AH object with the given values. | |
| Two creation methods are supported: | |
| - Creation via AHAttr object (calls ibv_create_ah) | |
| - Creation via a WC object (calls ibv_create_ah_from_wc) | |
| :param pd: PD object this AH belongs to | |
| :param kwargs: Arguments: | |
| * *attr* (AHAttr) | |
| An AHAttr object (represents ibv_ah_attr struct) | |
| * *wc* | |
| A WC object to use for AH initialization | |
| * *grh* | |
| Pointer to GRH object to use for AH initialization (when using | |
| wc) | |
| * *port_num* | |
| Port number to be used for this AH (when using wc) | |
| :return: An AH object on success | |
| """ | |
| super().__init__() | |
| if len(kwargs) == 1: | |
| # Create AH via ib_create_ah | |
| ah_attr = <AHAttr>kwargs['attr'] | |
| self.ah = v.ibv_create_ah(pd.pd, &ah_attr.ah_attr) | |
| else: | |
| # Create AH from WC | |
| wc = <WC>kwargs['wc'] | |
| grh = <v.ibv_grh*><uintptr_t>kwargs['grh'] | |
| port_num = kwargs['port_num'] | |
| self.ah = v.ibv_create_ah_from_wc(pd.pd, &wc.wc, grh, port_num) | |
| if self.ah == NULL: | |
| raise PyverbsRDMAErrno('Failed to create AH') | |
| pd.add_ref(self) | |
| self.pd = pd | |
| def __dealloc__(self): | |
| self.close() | |
| cpdef close(self): | |
| if self.ah != NULL: | |
| if self.logger: | |
| self.logger.debug('Closing AH') | |
| rc = v.ibv_destroy_ah(self.ah) | |
| if rc: | |
| raise PyverbsRDMAError('Failed to destroy AH', rc) | |
| self.ah = NULL | |
| self.pd = None |