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 *
esw_acl_table_create(struct mlx5_eswitch * esw,struct mlx5_vport * vport,int ns,int size)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 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
esw_egress_acl_vlan_create(struct mlx5_eswitch * esw,struct mlx5_vport * vport,struct mlx5_flow_destination * fwd_dest,u16 vlan_id,u32 flow_action)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
esw_acl_egress_vlan_destroy(struct mlx5_vport * vport)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
esw_acl_egress_vlan_grp_create(struct mlx5_eswitch * esw,struct mlx5_vport * vport)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
esw_acl_egress_vlan_grp_destroy(struct mlx5_vport * vport)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
esw_acl_egress_table_destroy(struct mlx5_vport * vport)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
esw_acl_ingress_table_destroy(struct mlx5_vport * vport)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
esw_acl_ingress_allow_rule_destroy(struct mlx5_vport * vport)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