1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2020 Mellanox Technologies Inc. All rights reserved. */ 3 4 #include "mlx5_core.h" 5 #include "eswitch.h" 6 #include "helper.h" 7 #include "lgcy.h" 8 9 static void esw_acl_egress_lgcy_rules_destroy(struct mlx5_vport *vport) 10 { 11 esw_acl_egress_vlan_destroy(vport); 12 if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_rule)) { 13 mlx5_del_flow_rules(vport->egress.legacy.drop_rule); 14 vport->egress.legacy.drop_rule = NULL; 15 } 16 } 17 18 static int esw_acl_egress_lgcy_groups_create(struct mlx5_eswitch *esw, 19 struct mlx5_vport *vport) 20 { 21 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 22 struct mlx5_core_dev *dev = esw->dev; 23 struct mlx5_flow_group *drop_grp; 24 u32 *flow_group_in; 25 int err = 0; 26 27 err = esw_acl_egress_vlan_grp_create(esw, vport); 28 if (err) 29 return err; 30 31 flow_group_in = kvzalloc(inlen, GFP_KERNEL); 32 if (!flow_group_in) { 33 err = -ENOMEM; 34 goto alloc_err; 35 } 36 37 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1); 38 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1); 39 drop_grp = mlx5_create_flow_group(vport->egress.acl, flow_group_in); 40 if (IS_ERR(drop_grp)) { 41 err = PTR_ERR(drop_grp); 42 esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n", 43 vport->vport, err); 44 goto drop_grp_err; 45 } 46 47 vport->egress.legacy.drop_grp = drop_grp; 48 kvfree(flow_group_in); 49 return 0; 50 51 drop_grp_err: 52 kvfree(flow_group_in); 53 alloc_err: 54 esw_acl_egress_vlan_grp_destroy(vport); 55 return err; 56 } 57 58 static void esw_acl_egress_lgcy_groups_destroy(struct mlx5_vport *vport) 59 { 60 if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_grp)) { 61 mlx5_destroy_flow_group(vport->egress.legacy.drop_grp); 62 vport->egress.legacy.drop_grp = NULL; 63 } 64 esw_acl_egress_vlan_grp_destroy(vport); 65 } 66 67 int esw_acl_egress_lgcy_setup(struct mlx5_eswitch *esw, 68 struct mlx5_vport *vport) 69 { 70 struct mlx5_flow_destination drop_ctr_dst = {}; 71 struct mlx5_flow_destination *dst = NULL; 72 struct mlx5_fc *drop_counter = NULL; 73 struct mlx5_flow_act flow_act = {}; 74 /* The egress acl table contains 2 rules: 75 * 1)Allow traffic with vlan_tag=vst_vlan_id 76 * 2)Drop all other traffic. 77 */ 78 int table_size = 2; 79 int dest_num = 0; 80 int err = 0; 81 82 if (MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) { 83 drop_counter = mlx5_fc_create(esw->dev, false); 84 if (IS_ERR(drop_counter)) 85 esw_warn(esw->dev, 86 "vport[%d] configure egress drop rule counter err(%ld)\n", 87 vport->vport, PTR_ERR(drop_counter)); 88 vport->egress.legacy.drop_counter = drop_counter; 89 } 90 91 esw_acl_egress_lgcy_rules_destroy(vport); 92 93 if (!vport->info.vlan && !vport->info.qos) { 94 esw_acl_egress_lgcy_cleanup(esw, vport); 95 return 0; 96 } 97 98 if (!vport->egress.acl) { 99 vport->egress.acl = esw_acl_table_create(esw, vport->vport, 100 MLX5_FLOW_NAMESPACE_ESW_EGRESS, 101 table_size); 102 if (IS_ERR(vport->egress.acl)) { 103 err = PTR_ERR(vport->egress.acl); 104 vport->egress.acl = NULL; 105 goto out; 106 } 107 108 err = esw_acl_egress_lgcy_groups_create(esw, vport); 109 if (err) 110 goto out; 111 } 112 113 esw_debug(esw->dev, 114 "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", 115 vport->vport, vport->info.vlan, vport->info.qos); 116 117 /* Allowed vlan rule */ 118 err = esw_egress_acl_vlan_create(esw, vport, NULL, vport->info.vlan, 119 MLX5_FLOW_CONTEXT_ACTION_ALLOW); 120 if (err) 121 goto out; 122 123 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; 124 125 /* Attach egress drop flow counter */ 126 if (!IS_ERR_OR_NULL(drop_counter)) { 127 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 128 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 129 drop_ctr_dst.counter_id = mlx5_fc_id(drop_counter); 130 dst = &drop_ctr_dst; 131 dest_num++; 132 } 133 vport->egress.legacy.drop_rule = 134 mlx5_add_flow_rules(vport->egress.acl, NULL, 135 &flow_act, dst, dest_num); 136 if (IS_ERR(vport->egress.legacy.drop_rule)) { 137 err = PTR_ERR(vport->egress.legacy.drop_rule); 138 esw_warn(esw->dev, 139 "vport[%d] configure egress drop rule failed, err(%d)\n", 140 vport->vport, err); 141 vport->egress.legacy.drop_rule = NULL; 142 goto out; 143 } 144 145 return err; 146 147 out: 148 esw_acl_egress_lgcy_cleanup(esw, vport); 149 return err; 150 } 151 152 void esw_acl_egress_lgcy_cleanup(struct mlx5_eswitch *esw, 153 struct mlx5_vport *vport) 154 { 155 if (IS_ERR_OR_NULL(vport->egress.acl)) 156 goto clean_drop_counter; 157 158 esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport); 159 160 esw_acl_egress_lgcy_rules_destroy(vport); 161 esw_acl_egress_lgcy_groups_destroy(vport); 162 esw_acl_egress_table_destroy(vport); 163 164 clean_drop_counter: 165 if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_counter)) { 166 mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); 167 vport->egress.legacy.drop_counter = NULL; 168 } 169 } 170