// 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" #include "lgcy.h" static void esw_acl_egress_lgcy_rules_destroy(struct mlx5_vport *vport) { esw_acl_egress_vlan_destroy(vport); if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_rule)) { mlx5_del_flow_rules(vport->egress.legacy.drop_rule); vport->egress.legacy.drop_rule = NULL; } } static int esw_acl_egress_lgcy_groups_create(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); struct mlx5_core_dev *dev = esw->dev; struct mlx5_flow_group *drop_grp; u32 *flow_group_in; int err = 0; err = esw_acl_egress_vlan_grp_create(esw, vport); if (err) return err; flow_group_in = kvzalloc(inlen, GFP_KERNEL); if (!flow_group_in) { err = -ENOMEM; goto alloc_err; } MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1); MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1); drop_grp = mlx5_create_flow_group(vport->egress.acl, flow_group_in); if (IS_ERR(drop_grp)) { err = PTR_ERR(drop_grp); esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n", vport->vport, err); goto drop_grp_err; } vport->egress.legacy.drop_grp = drop_grp; kvfree(flow_group_in); return 0; drop_grp_err: kvfree(flow_group_in); alloc_err: esw_acl_egress_vlan_grp_destroy(vport); return err; } static void esw_acl_egress_lgcy_groups_destroy(struct mlx5_vport *vport) { if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_grp)) { mlx5_destroy_flow_group(vport->egress.legacy.drop_grp); vport->egress.legacy.drop_grp = NULL; } esw_acl_egress_vlan_grp_destroy(vport); } int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { struct mlx5_flow_destination drop_ctr_dst = {}; struct mlx5_flow_destination *dst = NULL; struct mlx5_fc *drop_counter = NULL; struct mlx5_flow_act flow_act = {}; /* The egress acl table contains 2 rules: * 1)Allow traffic with vlan_tag=vst_vlan_id * 2)Drop all other traffic. */ int table_size = 2; int dest_num = 0; int err = 0; if (MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) { drop_counter = mlx5_fc_create(esw->dev, false); if (IS_ERR(drop_counter)) esw_warn(esw->dev, "vport[%d] configure egress drop rule counter err(%ld)\n", vport->vport, PTR_ERR(drop_counter)); vport->egress.legacy.drop_counter = drop_counter; } esw_acl_egress_lgcy_rules_destroy(vport); if (!vport->info.vlan && !vport->info.qos) { esw_acl_egress_lgcy_cleanup(esw, vport); return 0; } if (!IS_ERR_OR_NULL(vport->egress.acl)) return 0; vport->egress.acl = esw_acl_table_create(esw, vport->vport, MLX5_FLOW_NAMESPACE_ESW_EGRESS, table_size); if (IS_ERR(vport->egress.acl)) { err = PTR_ERR(vport->egress.acl); vport->egress.acl = NULL; goto out; } err = esw_acl_egress_lgcy_groups_create(esw, vport); if (err) goto out; esw_debug(esw->dev, "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", vport->vport, vport->info.vlan, vport->info.qos); /* Allowed vlan rule */ err = esw_egress_acl_vlan_create(esw, vport, NULL, vport->info.vlan, MLX5_FLOW_CONTEXT_ACTION_ALLOW); if (err) goto out; flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; /* Attach egress drop flow counter */ if (!IS_ERR_OR_NULL(drop_counter)) { flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; drop_ctr_dst.counter_id = mlx5_fc_id(drop_counter); dst = &drop_ctr_dst; dest_num++; } vport->egress.legacy.drop_rule = mlx5_add_flow_rules(vport->egress.acl, NULL, &flow_act, dst, dest_num); if (IS_ERR(vport->egress.legacy.drop_rule)) { err = PTR_ERR(vport->egress.legacy.drop_rule); esw_warn(esw->dev, "vport[%d] configure egress drop rule failed, err(%d)\n", vport->vport, err); vport->egress.legacy.drop_rule = NULL; goto out; } return err; out: esw_acl_egress_lgcy_cleanup(esw, vport); return err; } void esw_acl_egress_lgcy_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport) { if (IS_ERR_OR_NULL(vport->egress.acl)) goto clean_drop_counter; esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport); esw_acl_egress_lgcy_rules_destroy(vport); esw_acl_egress_lgcy_groups_destroy(vport); esw_acl_egress_table_destroy(vport); clean_drop_counter: if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_counter)) { mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); vport->egress.legacy.drop_counter = NULL; } }