xref: /linux/drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
3 
4 #include <linux/kernel.h>
5 
6 #include "core_acl_flex_actions.h"
7 #include "spectrum.h"
8 #include "spectrum_mr.h"
9 
10 struct mlxsw_sp2_mr_tcam {
11 	struct mlxsw_sp *mlxsw_sp;
12 	struct mlxsw_sp_flow_block *flow_block;
13 	struct mlxsw_sp_acl_ruleset *ruleset4;
14 	struct mlxsw_sp_acl_ruleset *ruleset6;
15 };
16 
17 struct mlxsw_sp2_mr_route {
18 	struct mlxsw_sp2_mr_tcam *mr_tcam;
19 };
20 
21 static struct mlxsw_sp_acl_ruleset *
mlxsw_sp2_mr_tcam_proto_ruleset(struct mlxsw_sp2_mr_tcam * mr_tcam,enum mlxsw_sp_l3proto proto)22 mlxsw_sp2_mr_tcam_proto_ruleset(struct mlxsw_sp2_mr_tcam *mr_tcam,
23 				enum mlxsw_sp_l3proto proto)
24 {
25 	switch (proto) {
26 	case MLXSW_SP_L3_PROTO_IPV4:
27 		return mr_tcam->ruleset4;
28 	case MLXSW_SP_L3_PROTO_IPV6:
29 		return mr_tcam->ruleset6;
30 	}
31 	return NULL;
32 }
33 
mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp * mlxsw_sp,enum mlxsw_reg_pemrbt_protocol protocol,struct mlxsw_sp_acl_ruleset * ruleset)34 static int mlxsw_sp2_mr_tcam_bind_group(struct mlxsw_sp *mlxsw_sp,
35 					enum mlxsw_reg_pemrbt_protocol protocol,
36 					struct mlxsw_sp_acl_ruleset *ruleset)
37 {
38 	char pemrbt_pl[MLXSW_REG_PEMRBT_LEN];
39 	u16 group_id;
40 
41 	group_id = mlxsw_sp_acl_ruleset_group_id(ruleset);
42 
43 	mlxsw_reg_pemrbt_pack(pemrbt_pl, protocol, group_id);
44 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pemrbt), pemrbt_pl);
45 }
46 
47 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv4[] = {
48 		MLXSW_AFK_ELEMENT_VIRT_ROUTER,
49 		MLXSW_AFK_ELEMENT_SRC_IP_0_31,
50 		MLXSW_AFK_ELEMENT_DST_IP_0_31,
51 };
52 
mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam * mr_tcam)53 static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
54 {
55 	struct mlxsw_afk_element_usage elusage;
56 	int err;
57 
58 	/* Initialize IPv4 ACL group. */
59 	mlxsw_afk_element_usage_fill(&elusage,
60 				     mlxsw_sp2_mr_tcam_usage_ipv4,
61 				     ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
62 	mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
63 						     mr_tcam->flow_block,
64 						     MLXSW_SP_L3_PROTO_IPV4,
65 						     MLXSW_SP_ACL_PROFILE_MR,
66 						     &elusage);
67 
68 	if (IS_ERR(mr_tcam->ruleset4))
69 		return PTR_ERR(mr_tcam->ruleset4);
70 
71 	/* MC Router groups should be bound before routes are inserted. */
72 	err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
73 					   MLXSW_REG_PEMRBT_PROTO_IPV4,
74 					   mr_tcam->ruleset4);
75 	if (err)
76 		goto err_bind_group;
77 
78 	return 0;
79 
80 err_bind_group:
81 	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
82 	return err;
83 }
84 
mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam * mr_tcam)85 static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
86 {
87 	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
88 }
89 
90 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
91 		MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
92 		MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
93 		MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
94 		MLXSW_AFK_ELEMENT_SRC_IP_96_127,
95 		MLXSW_AFK_ELEMENT_SRC_IP_64_95,
96 		MLXSW_AFK_ELEMENT_SRC_IP_32_63,
97 		MLXSW_AFK_ELEMENT_SRC_IP_0_31,
98 		MLXSW_AFK_ELEMENT_DST_IP_96_127,
99 		MLXSW_AFK_ELEMENT_DST_IP_64_95,
100 		MLXSW_AFK_ELEMENT_DST_IP_32_63,
101 		MLXSW_AFK_ELEMENT_DST_IP_0_31,
102 };
103 
mlxsw_sp2_mr_tcam_ipv6_init(struct mlxsw_sp2_mr_tcam * mr_tcam)104 static int mlxsw_sp2_mr_tcam_ipv6_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
105 {
106 	struct mlxsw_afk_element_usage elusage;
107 	int err;
108 
109 	/* Initialize IPv6 ACL group */
110 	mlxsw_afk_element_usage_fill(&elusage,
111 				     mlxsw_sp2_mr_tcam_usage_ipv6,
112 				     ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv6));
113 	mr_tcam->ruleset6 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
114 						     mr_tcam->flow_block,
115 						     MLXSW_SP_L3_PROTO_IPV6,
116 						     MLXSW_SP_ACL_PROFILE_MR,
117 						     &elusage);
118 
119 	if (IS_ERR(mr_tcam->ruleset6))
120 		return PTR_ERR(mr_tcam->ruleset6);
121 
122 	/* MC Router groups should be bound before routes are inserted. */
123 	err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
124 					   MLXSW_REG_PEMRBT_PROTO_IPV6,
125 					   mr_tcam->ruleset6);
126 	if (err)
127 		goto err_bind_group;
128 
129 	return 0;
130 
131 err_bind_group:
132 	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
133 	return err;
134 }
135 
mlxsw_sp2_mr_tcam_ipv6_fini(struct mlxsw_sp2_mr_tcam * mr_tcam)136 static void mlxsw_sp2_mr_tcam_ipv6_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
137 {
138 	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset6);
139 }
140 
141 static void
mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info * rulei,struct mlxsw_sp_mr_route_key * key)142 mlxsw_sp2_mr_tcam_rule_parse4(struct mlxsw_sp_acl_rule_info *rulei,
143 			      struct mlxsw_sp_mr_route_key *key)
144 {
145 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER,
146 				       key->vrid, GENMASK(11, 0));
147 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
148 				       (char *) &key->source.addr4,
149 				       (char *) &key->source_mask.addr4, 4);
150 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
151 				       (char *) &key->group.addr4,
152 				       (char *) &key->group_mask.addr4, 4);
153 }
154 
155 static void
mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info * rulei,struct mlxsw_sp_mr_route_key * key)156 mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
157 			      struct mlxsw_sp_mr_route_key *key)
158 {
159 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_3,
160 				       key->vrid, GENMASK(3, 0));
161 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_4_7,
162 				       key->vrid >> 4, GENMASK(3, 0));
163 	mlxsw_sp_acl_rulei_keymask_u32(rulei,
164 				       MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
165 				       key->vrid >> 8, GENMASK(3, 0));
166 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
167 				       &key->source.addr6.s6_addr[0x0],
168 				       &key->source_mask.addr6.s6_addr[0x0], 4);
169 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
170 				       &key->source.addr6.s6_addr[0x4],
171 				       &key->source_mask.addr6.s6_addr[0x4], 4);
172 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
173 				       &key->source.addr6.s6_addr[0x8],
174 				       &key->source_mask.addr6.s6_addr[0x8], 4);
175 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
176 				       &key->source.addr6.s6_addr[0xc],
177 				       &key->source_mask.addr6.s6_addr[0xc], 4);
178 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
179 				       &key->group.addr6.s6_addr[0x0],
180 				       &key->group_mask.addr6.s6_addr[0x0], 4);
181 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
182 				       &key->group.addr6.s6_addr[0x4],
183 				       &key->group_mask.addr6.s6_addr[0x4], 4);
184 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
185 				       &key->group.addr6.s6_addr[0x8],
186 				       &key->group_mask.addr6.s6_addr[0x8], 4);
187 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
188 				       &key->group.addr6.s6_addr[0xc],
189 				       &key->group_mask.addr6.s6_addr[0xc], 4);
190 }
191 
192 static void
mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule * rule,struct mlxsw_sp_mr_route_key * key,unsigned int priority)193 mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
194 			     struct mlxsw_sp_mr_route_key *key,
195 			     unsigned int priority)
196 {
197 	struct mlxsw_sp_acl_rule_info *rulei;
198 
199 	rulei = mlxsw_sp_acl_rule_rulei(rule);
200 	rulei->priority = priority;
201 	switch (key->proto) {
202 	case MLXSW_SP_L3_PROTO_IPV4:
203 		return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
204 	case MLXSW_SP_L3_PROTO_IPV6:
205 		return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
206 	}
207 }
208 
209 static int
mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp * mlxsw_sp,void * priv,void * route_priv,struct mlxsw_sp_mr_route_key * key,struct mlxsw_afa_block * afa_block,enum mlxsw_sp_mr_route_prio prio)210 mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
211 			       void *route_priv,
212 			       struct mlxsw_sp_mr_route_key *key,
213 			       struct mlxsw_afa_block *afa_block,
214 			       enum mlxsw_sp_mr_route_prio prio)
215 {
216 	struct mlxsw_sp2_mr_route *mr_route = route_priv;
217 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
218 	struct mlxsw_sp_acl_ruleset *ruleset;
219 	struct mlxsw_sp_acl_rule *rule;
220 	int err;
221 
222 	mr_route->mr_tcam = mr_tcam;
223 	ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
224 	if (WARN_ON(!ruleset))
225 		return -EINVAL;
226 
227 	rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
228 					(unsigned long) route_priv, afa_block,
229 					NULL);
230 	if (IS_ERR(rule))
231 		return PTR_ERR(rule);
232 
233 	mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
234 	err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
235 	if (err)
236 		goto err_rule_add;
237 
238 	return 0;
239 
240 err_rule_add:
241 	mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
242 	return err;
243 }
244 
245 static void
mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp * mlxsw_sp,void * priv,void * route_priv,struct mlxsw_sp_mr_route_key * key)246 mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
247 				void *route_priv,
248 				struct mlxsw_sp_mr_route_key *key)
249 {
250 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
251 	struct mlxsw_sp_acl_ruleset *ruleset;
252 	struct mlxsw_sp_acl_rule *rule;
253 
254 	ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
255 	if (WARN_ON(!ruleset))
256 		return;
257 
258 	rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
259 					(unsigned long) route_priv);
260 	if (WARN_ON(!rule))
261 		return;
262 
263 	mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
264 	mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
265 }
266 
267 static int
mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp * mlxsw_sp,void * route_priv,struct mlxsw_sp_mr_route_key * key,struct mlxsw_afa_block * afa_block)268 mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
269 			       void *route_priv,
270 			       struct mlxsw_sp_mr_route_key *key,
271 			       struct mlxsw_afa_block *afa_block)
272 {
273 	struct mlxsw_sp2_mr_route *mr_route = route_priv;
274 	struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
275 	struct mlxsw_sp_acl_ruleset *ruleset;
276 	struct mlxsw_sp_acl_rule *rule;
277 
278 	ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
279 	if (WARN_ON(!ruleset))
280 		return -EINVAL;
281 
282 	rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
283 					(unsigned long) route_priv);
284 	if (WARN_ON(!rule))
285 		return -EINVAL;
286 
287 	return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
288 }
289 
mlxsw_sp2_mr_tcam_init(struct mlxsw_sp * mlxsw_sp,void * priv)290 static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
291 {
292 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
293 	int err;
294 
295 	mr_tcam->mlxsw_sp = mlxsw_sp;
296 	mr_tcam->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);
297 	if (!mr_tcam->flow_block)
298 		return -ENOMEM;
299 
300 	err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
301 	if (err)
302 		goto err_ipv4_init;
303 
304 	err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
305 	if (err)
306 		goto err_ipv6_init;
307 
308 	return 0;
309 
310 err_ipv6_init:
311 	mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
312 err_ipv4_init:
313 	mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
314 	return err;
315 }
316 
mlxsw_sp2_mr_tcam_fini(void * priv)317 static void mlxsw_sp2_mr_tcam_fini(void *priv)
318 {
319 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
320 
321 	mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
322 	mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
323 	mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
324 }
325 
326 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
327 	.priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
328 	.init = mlxsw_sp2_mr_tcam_init,
329 	.fini = mlxsw_sp2_mr_tcam_fini,
330 	.route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
331 	.route_create = mlxsw_sp2_mr_tcam_route_create,
332 	.route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
333 	.route_update = mlxsw_sp2_mr_tcam_route_update,
334 };
335