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 8 struct mlx5_flow_table * 9 esw_acl_table_create(struct mlx5_eswitch *esw, u16 vport_num, int ns, int size) 10 { 11 struct mlx5_flow_table_attr ft_attr = {}; 12 struct mlx5_core_dev *dev = esw->dev; 13 struct mlx5_flow_namespace *root_ns; 14 struct mlx5_flow_table *acl; 15 int acl_supported; 16 int vport_index; 17 int err; 18 19 acl_supported = (ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS) ? 20 MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support) : 21 MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support); 22 23 if (!acl_supported) 24 return ERR_PTR(-EOPNOTSUPP); 25 26 esw_debug(dev, "Create vport[%d] %s ACL table\n", vport_num, 27 ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS ? "ingress" : "egress"); 28 29 vport_index = mlx5_eswitch_vport_num_to_index(esw, vport_num); 30 root_ns = mlx5_get_flow_vport_acl_namespace(dev, ns, vport_index); 31 if (!root_ns) { 32 esw_warn(dev, "Failed to get E-Switch root namespace for vport (%d)\n", 33 vport_num); 34 return ERR_PTR(-EOPNOTSUPP); 35 } 36 37 ft_attr.max_fte = size; 38 ft_attr.flags = MLX5_FLOW_TABLE_OTHER_VPORT; 39 acl = mlx5_create_vport_flow_table(root_ns, &ft_attr, vport_num); 40 if (IS_ERR(acl)) { 41 err = PTR_ERR(acl); 42 esw_warn(dev, "vport[%d] create %s ACL table, err(%d)\n", vport_num, 43 ns == MLX5_FLOW_NAMESPACE_ESW_INGRESS ? "ingress" : "egress", err); 44 } 45 return acl; 46 } 47 48 int esw_egress_acl_vlan_create(struct mlx5_eswitch *esw, 49 struct mlx5_vport *vport, 50 struct mlx5_flow_destination *fwd_dest, 51 u16 vlan_id, u32 flow_action) 52 { 53 struct mlx5_flow_act flow_act = {}; 54 struct mlx5_flow_spec *spec; 55 int err = 0; 56 57 if (vport->egress.allowed_vlan) 58 return -EEXIST; 59 60 spec = kvzalloc(sizeof(*spec), GFP_KERNEL); 61 if (!spec) 62 return -ENOMEM; 63 64 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag); 65 MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag); 66 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid); 67 MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id); 68 69 spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; 70 flow_act.action = flow_action; 71 vport->egress.allowed_vlan = 72 mlx5_add_flow_rules(vport->egress.acl, spec, 73 &flow_act, fwd_dest, 0); 74 if (IS_ERR(vport->egress.allowed_vlan)) { 75 err = PTR_ERR(vport->egress.allowed_vlan); 76 esw_warn(esw->dev, 77 "vport[%d] configure egress vlan rule failed, err(%d)\n", 78 vport->vport, err); 79 vport->egress.allowed_vlan = NULL; 80 } 81 82 kvfree(spec); 83 return err; 84 } 85 86 void esw_acl_egress_vlan_destroy(struct mlx5_vport *vport) 87 { 88 if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) { 89 mlx5_del_flow_rules(vport->egress.allowed_vlan); 90 vport->egress.allowed_vlan = NULL; 91 } 92 } 93 94 int esw_acl_egress_vlan_grp_create(struct mlx5_eswitch *esw, struct mlx5_vport *vport) 95 { 96 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in); 97 struct mlx5_flow_group *vlan_grp; 98 void *match_criteria; 99 u32 *flow_group_in; 100 int ret = 0; 101 102 flow_group_in = kvzalloc(inlen, GFP_KERNEL); 103 if (!flow_group_in) 104 return -ENOMEM; 105 106 MLX5_SET(create_flow_group_in, flow_group_in, 107 match_criteria_enable, MLX5_MATCH_OUTER_HEADERS); 108 match_criteria = MLX5_ADDR_OF(create_flow_group_in, 109 flow_group_in, match_criteria); 110 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag); 111 MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid); 112 MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0); 113 MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0); 114 115 vlan_grp = mlx5_create_flow_group(vport->egress.acl, flow_group_in); 116 if (IS_ERR(vlan_grp)) { 117 ret = PTR_ERR(vlan_grp); 118 esw_warn(esw->dev, 119 "Failed to create E-Switch vport[%d] egress pop vlans flow group, err(%d)\n", 120 vport->vport, ret); 121 goto out; 122 } 123 vport->egress.vlan_grp = vlan_grp; 124 125 out: 126 kvfree(flow_group_in); 127 return ret; 128 } 129 130 void esw_acl_egress_vlan_grp_destroy(struct mlx5_vport *vport) 131 { 132 if (!IS_ERR_OR_NULL(vport->egress.vlan_grp)) { 133 mlx5_destroy_flow_group(vport->egress.vlan_grp); 134 vport->egress.vlan_grp = NULL; 135 } 136 } 137 138 void esw_acl_egress_table_destroy(struct mlx5_vport *vport) 139 { 140 if (IS_ERR_OR_NULL(vport->egress.acl)) 141 return; 142 143 mlx5_destroy_flow_table(vport->egress.acl); 144 vport->egress.acl = NULL; 145 } 146 147 void esw_acl_ingress_table_destroy(struct mlx5_vport *vport) 148 { 149 if (!vport->ingress.acl) 150 return; 151 152 mlx5_destroy_flow_table(vport->ingress.acl); 153 vport->ingress.acl = NULL; 154 } 155 156 void esw_acl_ingress_allow_rule_destroy(struct mlx5_vport *vport) 157 { 158 if (!vport->ingress.allow_rule) 159 return; 160 161 mlx5_del_flow_rules(vport->ingress.allow_rule); 162 vport->ingress.allow_rule = NULL; 163 } 164