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