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