drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c
Extension
.c
Size
4765 bytes
Lines
165
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/* Copyright (c) 2020 Mellanox Technologies Inc. All rights reserved. */

#include "mlx5_core.h"
#include "eswitch.h"
#include "helper.h"

struct mlx5_flow_table *
esw_acl_table_create(struct mlx5_eswitch *esw, struct mlx5_vport *vport, int ns, int size)
{
	struct mlx5_flow_table_attr ft_attr = {};
	struct mlx5_core_dev *dev = esw->dev;
	struct mlx5_flow_namespace *root_ns;
	struct mlx5_flow_table *acl;
	int acl_supported;
	u16 vport_num;
	int err;

	acl_supported = (ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS) ?
			MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support) :
			MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support);

	if (!acl_supported)
		return ERR_PTR(-EOPNOTSUPP);

	vport_num = vport->vport;
	esw_debug(dev, "Create vport[%d] %s ACL table\n", vport_num,
		  ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS ? "ingress" : "egress");

	root_ns = mlx5_get_flow_vport_namespace(dev, ns, vport->index);
	if (!root_ns) {
		esw_warn(dev, "Failed to get E-Switch root namespace for vport (%d)\n",
			 vport_num);
		return ERR_PTR(-EOPNOTSUPP);
	}

	ft_attr.max_fte = size;
	if (vport_num || mlx5_core_is_ecpf(esw->dev))
		ft_attr.flags = MLX5_FLOW_TABLE_OTHER_VPORT;
	acl = mlx5_create_vport_flow_table(root_ns, &ft_attr, vport_num);
	if (IS_ERR(acl)) {
		err = PTR_ERR(acl);
		esw_warn(dev, "vport[%d] create %s ACL table, err(%d)\n", vport_num,
			 ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS ? "ingress" : "egress", err);
	}
	return acl;
}

int esw_egress_acl_vlan_create(struct mlx5_eswitch *esw,
			       struct mlx5_vport *vport,
			       struct mlx5_flow_destination *fwd_dest,
			       u16 vlan_id, u32 flow_action)
{
	struct mlx5_flow_act flow_act = {};
	struct mlx5_flow_spec *spec;
	int err = 0;

	if (vport->egress.allowed_vlan)
		return -EEXIST;

	spec = kvzalloc_obj(*spec);
	if (!spec)
		return -ENOMEM;

	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
	MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
	MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
	MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id);

	spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
	flow_act.action = flow_action;
	vport->egress.allowed_vlan =
		mlx5_add_flow_rules(vport->egress.acl, spec,
				    &flow_act, fwd_dest, 0);
	if (IS_ERR(vport->egress.allowed_vlan)) {
		err = PTR_ERR(vport->egress.allowed_vlan);
		esw_warn(esw->dev,
			 "vport[%d] configure egress vlan rule failed, err(%d)\n",
			 vport->vport, err);
		vport->egress.allowed_vlan = NULL;
	}

	kvfree(spec);
	return err;
}

void esw_acl_egress_vlan_destroy(struct mlx5_vport *vport)
{
	if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) {
		mlx5_del_flow_rules(vport->egress.allowed_vlan);

Annotation

Implementation Notes