blob: fe2e7524d2fefcb6f7d9f9d675027c19a6ea1828 [file]
# 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)