| # 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 = <dv.mlx5dv_flow_match_parameters *>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 = <char *>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 (<Mlx5FlowActionAttr>attr).attr.type == dv.MLX5DV_FLOW_ACTION_DEST_IBV_QP: |
| (<QP>(attr.qp)).add_ref(self) |
| self.qp = (<Mlx5FlowActionAttr>attr).qp |
| elif (<Mlx5FlowActionAttr>attr).attr.type not in [dv.MLX5DV_FLOW_ACTION_IBV_FLOW_ACTION]: |
| raise PyverbsUserError(f'Unsupported action type: ' |
| f'{<Mlx5FlowActionAttr>attr).attr.type}.') |
| memcpy(tmp_addr, &(<Mlx5FlowActionAttr>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, |
| <dv.mlx5dv_flow_action_attr *>attr_addr) |
| free(attr_addr) |
| if self.flow == NULL: |
| raise PyverbsRDMAErrno('Flow creation failed.') |
| matcher.add_ref(self) |