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 bool vst_mode_steering = esw_vst_mode_is_steering(esw); 71 struct mlx5_flow_destination drop_ctr_dst = {}; 72 struct mlx5_flow_destination *dst = NULL; 73 struct mlx5_fc *drop_counter = NULL; 74 struct mlx5_flow_act flow_act = {}; 75 /* The egress acl table contains 2 rules: 76 * 1)Allow traffic with vlan_tag=vst_vlan_id 77 * 2)Drop all other traffic. 78 */ 79 int table_size = 2; 80 int dest_num = 0; 81 int actions_flag; 82 int err = 0; 83 84 if (vport->egress.legacy.drop_counter) { 85 drop_counter = vport->egress.legacy.drop_counter; 86 } else if (MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) { 87 drop_counter = mlx5_fc_create(esw->dev, false); 88 if (IS_ERR(drop_counter)) { 89 esw_warn(esw->dev, 90 "vport[%d] configure egress drop rule counter err(%ld)\n", 91 vport->vport, PTR_ERR(drop_counter)); 92 drop_counter = NULL; 93 } 94 vport->egress.legacy.drop_counter = drop_counter; 95 } 96 97 esw_acl_egress_lgcy_rules_destroy(vport); 98 99 if (!vport->info.vlan && !vport->info.qos) { 100 esw_acl_egress_lgcy_cleanup(esw, vport); 101 return 0; 102 } 103 104 if (!vport->egress.acl) { 105 vport->egress.acl = esw_acl_table_create(esw, vport, 106 MLX5_FLOW_NAMESPACE_ESW_EGRESS, 107 table_size); 108 if (IS_ERR(vport->egress.acl)) { 109 err = PTR_ERR(vport->egress.acl); 110 vport->egress.acl = NULL; 111 goto out; 112 } 113 114 err = esw_acl_egress_lgcy_groups_create(esw, vport); 115 if (err) 116 goto out; 117 } 118 119 esw_debug(esw->dev, 120 "vport[%d] configure egress rules, vlan(%d) qos(%d)\n", 121 vport->vport, vport->info.vlan, vport->info.qos); 122 123 /* Allowed vlan rule */ 124 actions_flag = MLX5_FLOW_CONTEXT_ACTION_ALLOW; 125 if (vst_mode_steering) 126 actions_flag |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP; 127 err = esw_egress_acl_vlan_create(esw, vport, NULL, vport->info.vlan, 128 actions_flag); 129 if (err) 130 goto out; 131 132 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; 133 134 /* Attach egress drop flow counter */ 135 if (drop_counter) { 136 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT; 137 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER; 138 drop_ctr_dst.counter_id = mlx5_fc_id(drop_counter); 139 dst = &drop_ctr_dst; 140 dest_num++; 141 } 142 vport->egress.legacy.drop_rule = 143 mlx5_add_flow_rules(vport->egress.acl, NULL, 144 &flow_act, dst, dest_num); 145 if (IS_ERR(vport->egress.legacy.drop_rule)) { 146 err = PTR_ERR(vport->egress.legacy.drop_rule); 147 esw_warn(esw->dev, 148 "vport[%d] configure egress drop rule failed, err(%d)\n", 149 vport->vport, err); 150 vport->egress.legacy.drop_rule = NULL; 151 goto out; 152 } 153 154 return err; 155 156 out: 157 esw_acl_egress_lgcy_cleanup(esw, vport); 158 return err; 159 } 160 161 void esw_acl_egress_lgcy_cleanup(struct mlx5_eswitch *esw, 162 struct mlx5_vport *vport) 163 { 164 if (IS_ERR_OR_NULL(vport->egress.acl)) 165 goto clean_drop_counter; 166 167 esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport); 168 169 esw_acl_egress_lgcy_rules_destroy(vport); 170 esw_acl_egress_lgcy_groups_destroy(vport); 171 esw_acl_egress_table_destroy(vport); 172 173 clean_drop_counter: 174 if (vport->egress.legacy.drop_counter) { 175 mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter); 176 vport->egress.legacy.drop_counter = NULL; 177 } 178 } 179