# SPDX-License-Identifier: (GPL-2.0 OR Linux-OpenIB) # Copyright (c) 2020 Nvidia, Inc. All rights reserved. See COPYING file from libc.stdlib cimport calloc, free from libc.string cimport memcpy from pyverbs.pyverbs_error import PyverbsRDMAError, PyverbsError, \ PyverbsUserError from pyverbs.device cimport Context from pyverbs.base import PyverbsRDMAErrno from pyverbs.base cimport close_weakrefs from pyverbs.device cimport Context cimport pyverbs.libibverbs as v from pyverbs.qp cimport QP import weakref cdef class Mlx5FlowMatchParameters(PyverbsObject): def __init__(self, size, values): """ Initialize a Mlx5FlowMatchParameters object over an underlying mlx5dv_flow_match_parameters C object that defines match parameters for steering flow. :param size: Length of the mask/value in bytes :param values: Bytes with mask/value to use in format of Flow Table Entry Match Parameters Format table in PRM or instance of FlowTableEntryMatchParam class. """ cdef char *py_bytes_c super().__init__() struct_size = sizeof(size_t) + size self.params = calloc(1, struct_size) if self.params == NULL: raise PyverbsError(f'Failed to allocate buffer of size {struct_size}') self.params.match_sz = size if size: py_bytes = bytes(values) py_bytes_c = py_bytes memcpy(self.params.match_buf, py_bytes_c, len(values)) def __dealloc__(self): self.close() cpdef close(self): if self.params != NULL: if self.logger: self.logger.debug('Closing Mlx5FlowMatchParameters') free(self.params) self.params = NULL cdef class Mlx5FlowMatcherAttr(PyverbsObject): def __init__(self, Mlx5FlowMatchParameters match_mask, attr_type=v.IBV_FLOW_ATTR_NORMAL, flags=0, priority=0, match_criteria_enable=0, comp_mask=0, ft_type=0): """ Initialize a Mlx5FlowMatcherAttr object over an underlying mlx5dv_flow_matcher_attr C object that defines matcher's attributes. :param match_mask: Match parameters to match on :param attr_type: Type of matcher to be created :param flags: Special flags to control rule: Nothing or zero value means matcher will store ingress flow rules. IBV_FLOW_ATTR_FLAGS_EGRESS: Specified this matcher will store egress flow rules. :param priority: Matcher priority :param match_criteria_enable: Bitmask representing which of the headers and parameters in match_criteria are used in defining the Flow. Bit 0: outer_headers Bit 1: misc_parameters Bit 2: inner_headers Bit 3: misc_parameters_2 Bit 4: misc_parameters_3 Bit 5: misc_parameters_4 :param comp_mask: MLX5DV_FLOW_MATCHER_MASK_FT_TYPE for ft_type (the only option that is currently supported) :param ft_type: Specified in which flow table type, the matcher will store the flow rules: MLX5DV_FLOW_TABLE_TYPE_NIC_RX: Specified this matcher will store ingress flow rules. MLX5DV_FLOW_TABLE_TYPE_NIC_TX - matcher will store egress flow rules. MLX5DV_FLOW_TABLE_TYPE_FDB - matcher will store FDB rules. MLX5DV_FLOW_TABLE_TYPE_RDMA_RX - matcher will store ingress RDMA flow rules. MLX5DV_FLOW_TABLE_TYPE_RDMA_TX - matcher will store egress RDMA flow rules. """ super().__init__() self.attr.type = attr_type self.attr.flags = flags self.attr.priority = priority self.attr.match_criteria_enable = match_criteria_enable self.attr.match_mask = match_mask.params self.attr.comp_mask = comp_mask self.attr.ft_type = ft_type cdef class Mlx5FlowMatcher(PyverbsObject): def __init__(self, Context context, Mlx5FlowMatcherAttr attr): """ Initialize a Mlx5FlowMatcher object over an underlying mlx5dv_flow_matcher C object that defines a matcher for steering flow. :param context: Context object :param attr: Flow matcher attributes """ super().__init__() self.flow_matcher = dv.mlx5dv_create_flow_matcher(context.context, &attr.attr) if self.flow_matcher == NULL: raise PyverbsRDMAErrno('Flow matcher creation failed.') self.flows = weakref.WeakSet() cdef add_ref(self, obj): if isinstance(obj, Flow): self.flows.add(obj) else: raise PyverbsError('Unrecognized object type') def __dealloc__(self): self.close() cpdef close(self): if self.flow_matcher != NULL: if self.logger: self.logger.debug('Closing Mlx5FlowMatcher') close_weakrefs([self.flows]) rc = dv.mlx5dv_destroy_flow_matcher(self.flow_matcher) if rc: raise PyverbsRDMAError('Destroy matcher failed.', rc) self.flow_matcher = NULL cdef class Mlx5PacketReformatFlowAction(FlowAction): def __init__(self, Context context, data=None, reformat_type=dv.MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2, ft_type=dv.MLX5DV_FLOW_TABLE_TYPE_NIC_RX): """ Initialize a Mlx5PacketReformatFlowAction object derived from FlowAction class and represents reformat flow steering action that allows adding/removing packet headers. :param context: Context object :param data: Encap headers (if needed) :param reformat_type: L2 or L3 encap or decap :param ft_type: dv.MLX5DV_FLOW_TABLE_TYPE_NIC_RX for ingress or dv.MLX5DV_FLOW_TABLE_TYPE_NIC_TX for egress """ super().__init__() cdef char *buf = NULL data_len = 0 if data is None else len(data) if data: arr = bytearray(data) buf = calloc(1, data_len) for i in range(data_len): buf[i] = arr[i] reformat_data = NULL if data is None else buf self.action = dv.mlx5dv_create_flow_action_packet_reformat( context.context, data_len, reformat_data, reformat_type, ft_type) if data: free(buf) if self.action == NULL: raise PyverbsRDMAErrno('Failed to create flow action packet reformat') cdef class Mlx5FlowActionAttr(PyverbsObject): def __init__(self, action_type=None, QP qp=None, FlowAction flow_action=None): """ Initialize a Mlx5FlowActionAttr object over an underlying mlx5dv_flow_action_attr C object that defines actions attributes for the flow matcher. :param action_type: Type of the action :param qp: A QP target for go to QP action :param flow_action: An action to perform for the flow """ super().__init__() if action_type: self.attr.type = action_type if action_type == dv.MLX5DV_FLOW_ACTION_DEST_IBV_QP: self.attr.qp = qp.qp self.qp = qp elif action_type == dv.MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION: self.attr.action = flow_action.action self.action = flow_action elif action_type: raise PyverbsUserError(f'Unsupported action type: {action_type}.') @property def type(self): return self.attr.type @type.setter def type(self, action_type): if self.attr.type != dv.MLX5DV_FLOW_ACTION_DEST_IBV_QP: raise PyverbsUserError(f'Unsupported action type: {action_type}.') self.attr.type = action_type @property def qp(self): if self.attr.type != dv.MLX5DV_FLOW_ACTION_DEST_IBV_QP: raise PyverbsUserError(f'Action attr of type {self.attr.type} doesn\'t have a qp') return self.qp @qp.setter def qp(self, QP qp): if self.attr.type != dv.MLX5DV_FLOW_ACTION_DEST_IBV_QP: raise PyverbsUserError(f'Action attr of type {self.attr.type} doesn\'t have a qp') self.qp = qp @property def action(self): if self.attr.type != dv.MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION: raise PyverbsUserError(f'Action attr of type {self.attr.type} doesn\'t have an action') return self.action @action.setter def action(self, FlowAction action): if self.attr.type != dv.MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION: raise PyverbsUserError(f'Action attr of type {self.attr.type} doesn\'t have an action') self.action = action self.attr.action = action.action cdef class Mlx5Flow(Flow): def __init__(self, Mlx5FlowMatcher matcher, Mlx5FlowMatchParameters match_value, action_attrs=None, num_actions=0): """ Initialize a Mlx5Flow object derived form Flow class. :param matcher: A matcher with the fields to match on :param match_value: Match parameters with values to match on :param action_attrs: List of actions to perform :param num_actions: Number of actions """ cdef void *tmp_addr cdef void *attr_addr super(Flow, self).__init__() action_attrs = [] if action_attrs is None else action_attrs if len(action_attrs) != num_actions: self.logger.warn('num_actions is different from actions array length.') total_size = num_actions * sizeof(dv.mlx5dv_flow_action_attr) attr_addr = calloc(1, total_size) if attr_addr == NULL: raise PyverbsError(f'Failed to allocate memory of size {total_size}') tmp_addr = attr_addr for attr in action_attrs: if (attr).attr.type == dv.MLX5DV_FLOW_ACTION_DEST_IBV_QP: ((attr.qp)).add_ref(self) self.qp = (attr).qp elif (attr).attr.type not in [dv.MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION]: raise PyverbsUserError(f'Unsupported action type: ' f'{attr).attr.type}.') memcpy(tmp_addr, &(attr).attr, sizeof(dv.mlx5dv_flow_action_attr)) tmp_addr += sizeof(dv.mlx5dv_flow_action_attr) self.flow = dv.mlx5dv_create_flow(matcher.flow_matcher, match_value.params, num_actions, attr_addr) free(attr_addr) if self.flow == NULL: raise PyverbsRDMAErrno('Flow creation failed.') matcher.add_ref(self)