// 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, u16 vport_num, int ns, int size) { struct mlx5_core_dev *dev = esw->dev; struct mlx5_flow_namespace *root_ns; struct mlx5_flow_table *acl; int acl_supported; int vport_index; 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); esw_debug(dev, "Create vport[%d] %s ACL table\n", vport_num, ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS ? "ingress" : "egress"); vport_index = mlx5_eswitch_vport_num_to_index(esw, vport_num); root_ns = mlx5_get_flow_vport_acl_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); } acl = mlx5_create_vport_flow_table(root_ns, 0, size, 0, 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(sizeof(*spec), GFP_KERNEL); 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); vport->egress.allowed_vlan = NULL; } } int esw_acl_egress_vlan_grp_create(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_flow_group *vlan_grp; void *match_criteria; u32 *flow_group_in; int ret = 0; flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) return -ENOMEM; MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria); MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag); MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid); MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0); vlan_grp = mlx5_create_flow_group(vport->egress.acl, flow_group_in); if (IS_ERR(vlan_grp)) { ret = PTR_ERR(vlan_grp); esw_warn(esw->dev, "Failed to create E-Switch vport[%d] egress pop vlans flow group, err(%d)\n", vport->vport, ret); goto out; } vport->egress.vlan_grp = vlan_grp; out: kvfree(flow_group_in); return ret; } void esw_acl_egress_vlan_grp_destroy(struct mlx5_vport *vport) { if (!IS_ERR_OR_NULL(vport->egress.vlan_grp)) { mlx5_destroy_flow_group(vport->egress.vlan_grp); vport->egress.vlan_grp = NULL; } } void esw_acl_egress_table_destroy(struct mlx5_vport *vport) { if (IS_ERR_OR_NULL(vport->egress.acl)) return; mlx5_destroy_flow_table(vport->egress.acl); vport->egress.acl = NULL; } void esw_acl_ingress_table_destroy(struct mlx5_vport *vport) { if (!vport->ingress.acl) return; mlx5_destroy_flow_table(vport->ingress.acl); vport->ingress.acl = NULL; } void esw_acl_ingress_allow_rule_destroy(struct mlx5_vport *vport) { if (!vport->ingress.allow_rule) return; mlx5_del_flow_rules(vport->ingress.allow_rule); vport->ingress.allow_rule = NULL; }