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