# 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] = 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] = 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] = 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] = 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] = 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] = 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 = kwargs['attr'] self.ah = v.ibv_create_ah(pd.pd, &ah_attr.ah_attr) else: # Create AH from WC wc = kwargs['wc'] grh = 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