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 *
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 
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_MSB,
49 		MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
50 		MLXSW_AFK_ELEMENT_SRC_IP_0_31,
51 		MLXSW_AFK_ELEMENT_DST_IP_0_31,
52 };
53 
54 static int mlxsw_sp2_mr_tcam_ipv4_init(struct mlxsw_sp2_mr_tcam *mr_tcam)
55 {
56 	struct mlxsw_afk_element_usage elusage;
57 	int err;
58 
59 	/* Initialize IPv4 ACL group. */
60 	mlxsw_afk_element_usage_fill(&elusage,
61 				     mlxsw_sp2_mr_tcam_usage_ipv4,
62 				     ARRAY_SIZE(mlxsw_sp2_mr_tcam_usage_ipv4));
63 	mr_tcam->ruleset4 = mlxsw_sp_acl_ruleset_get(mr_tcam->mlxsw_sp,
64 						     mr_tcam->flow_block,
65 						     MLXSW_SP_L3_PROTO_IPV4,
66 						     MLXSW_SP_ACL_PROFILE_MR,
67 						     &elusage);
68 
69 	if (IS_ERR(mr_tcam->ruleset4))
70 		return PTR_ERR(mr_tcam->ruleset4);
71 
72 	/* MC Router groups should be bound before routes are inserted. */
73 	err = mlxsw_sp2_mr_tcam_bind_group(mr_tcam->mlxsw_sp,
74 					   MLXSW_REG_PEMRBT_PROTO_IPV4,
75 					   mr_tcam->ruleset4);
76 	if (err)
77 		goto err_bind_group;
78 
79 	return 0;
80 
81 err_bind_group:
82 	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
83 	return err;
84 }
85 
86 static void mlxsw_sp2_mr_tcam_ipv4_fini(struct mlxsw_sp2_mr_tcam *mr_tcam)
87 {
88 	mlxsw_sp_acl_ruleset_put(mr_tcam->mlxsw_sp, mr_tcam->ruleset4);
89 }
90 
91 static const enum mlxsw_afk_element mlxsw_sp2_mr_tcam_usage_ipv6[] = {
92 		MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
93 		MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
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 
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 
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
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_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
146 				       (char *) &key->source.addr4,
147 				       (char *) &key->source_mask.addr4, 4);
148 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
149 				       (char *) &key->group.addr4,
150 				       (char *) &key->group_mask.addr4, 4);
151 }
152 
153 static void
154 mlxsw_sp2_mr_tcam_rule_parse6(struct mlxsw_sp_acl_rule_info *rulei,
155 			      struct mlxsw_sp_mr_route_key *key)
156 {
157 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_96_127,
158 				       &key->source.addr6.s6_addr[0x0],
159 				       &key->source_mask.addr6.s6_addr[0x0], 4);
160 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_64_95,
161 				       &key->source.addr6.s6_addr[0x4],
162 				       &key->source_mask.addr6.s6_addr[0x4], 4);
163 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_32_63,
164 				       &key->source.addr6.s6_addr[0x8],
165 				       &key->source_mask.addr6.s6_addr[0x8], 4);
166 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_SRC_IP_0_31,
167 				       &key->source.addr6.s6_addr[0xc],
168 				       &key->source_mask.addr6.s6_addr[0xc], 4);
169 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_96_127,
170 				       &key->group.addr6.s6_addr[0x0],
171 				       &key->group_mask.addr6.s6_addr[0x0], 4);
172 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_64_95,
173 				       &key->group.addr6.s6_addr[0x4],
174 				       &key->group_mask.addr6.s6_addr[0x4], 4);
175 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_32_63,
176 				       &key->group.addr6.s6_addr[0x8],
177 				       &key->group_mask.addr6.s6_addr[0x8], 4);
178 	mlxsw_sp_acl_rulei_keymask_buf(rulei, MLXSW_AFK_ELEMENT_DST_IP_0_31,
179 				       &key->group.addr6.s6_addr[0xc],
180 				       &key->group_mask.addr6.s6_addr[0xc], 4);
181 }
182 
183 static void
184 mlxsw_sp2_mr_tcam_rule_parse(struct mlxsw_sp_acl_rule *rule,
185 			     struct mlxsw_sp_mr_route_key *key,
186 			     unsigned int priority)
187 {
188 	struct mlxsw_sp_acl_rule_info *rulei;
189 
190 	rulei = mlxsw_sp_acl_rule_rulei(rule);
191 	rulei->priority = priority;
192 	mlxsw_sp_acl_rulei_keymask_u32(rulei, MLXSW_AFK_ELEMENT_VIRT_ROUTER_LSB,
193 				       key->vrid, GENMASK(7, 0));
194 	mlxsw_sp_acl_rulei_keymask_u32(rulei,
195 				       MLXSW_AFK_ELEMENT_VIRT_ROUTER_MSB,
196 				       key->vrid >> 8, GENMASK(3, 0));
197 	switch (key->proto) {
198 	case MLXSW_SP_L3_PROTO_IPV4:
199 		return mlxsw_sp2_mr_tcam_rule_parse4(rulei, key);
200 	case MLXSW_SP_L3_PROTO_IPV6:
201 		return mlxsw_sp2_mr_tcam_rule_parse6(rulei, key);
202 	}
203 }
204 
205 static int
206 mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
207 			       void *route_priv,
208 			       struct mlxsw_sp_mr_route_key *key,
209 			       struct mlxsw_afa_block *afa_block,
210 			       enum mlxsw_sp_mr_route_prio prio)
211 {
212 	struct mlxsw_sp2_mr_route *mr_route = route_priv;
213 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
214 	struct mlxsw_sp_acl_ruleset *ruleset;
215 	struct mlxsw_sp_acl_rule *rule;
216 	int err;
217 
218 	mr_route->mr_tcam = mr_tcam;
219 	ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
220 	if (WARN_ON(!ruleset))
221 		return -EINVAL;
222 
223 	rule = mlxsw_sp_acl_rule_create(mlxsw_sp, ruleset,
224 					(unsigned long) route_priv, afa_block,
225 					NULL);
226 	if (IS_ERR(rule))
227 		return PTR_ERR(rule);
228 
229 	mlxsw_sp2_mr_tcam_rule_parse(rule, key, prio);
230 	err = mlxsw_sp_acl_rule_add(mlxsw_sp, rule);
231 	if (err)
232 		goto err_rule_add;
233 
234 	return 0;
235 
236 err_rule_add:
237 	mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
238 	return err;
239 }
240 
241 static void
242 mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
243 				void *route_priv,
244 				struct mlxsw_sp_mr_route_key *key)
245 {
246 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
247 	struct mlxsw_sp_acl_ruleset *ruleset;
248 	struct mlxsw_sp_acl_rule *rule;
249 
250 	ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
251 	if (WARN_ON(!ruleset))
252 		return;
253 
254 	rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
255 					(unsigned long) route_priv);
256 	if (WARN_ON(!rule))
257 		return;
258 
259 	mlxsw_sp_acl_rule_del(mlxsw_sp, rule);
260 	mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
261 }
262 
263 static int
264 mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
265 			       void *route_priv,
266 			       struct mlxsw_sp_mr_route_key *key,
267 			       struct mlxsw_afa_block *afa_block)
268 {
269 	struct mlxsw_sp2_mr_route *mr_route = route_priv;
270 	struct mlxsw_sp2_mr_tcam *mr_tcam = mr_route->mr_tcam;
271 	struct mlxsw_sp_acl_ruleset *ruleset;
272 	struct mlxsw_sp_acl_rule *rule;
273 
274 	ruleset = mlxsw_sp2_mr_tcam_proto_ruleset(mr_tcam, key->proto);
275 	if (WARN_ON(!ruleset))
276 		return -EINVAL;
277 
278 	rule = mlxsw_sp_acl_rule_lookup(mlxsw_sp, ruleset,
279 					(unsigned long) route_priv);
280 	if (WARN_ON(!rule))
281 		return -EINVAL;
282 
283 	return mlxsw_sp_acl_rule_action_replace(mlxsw_sp, rule, afa_block);
284 }
285 
286 static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
287 {
288 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
289 	int err;
290 
291 	mr_tcam->mlxsw_sp = mlxsw_sp;
292 	mr_tcam->flow_block = mlxsw_sp_flow_block_create(mlxsw_sp, NULL);
293 	if (!mr_tcam->flow_block)
294 		return -ENOMEM;
295 
296 	err = mlxsw_sp2_mr_tcam_ipv4_init(mr_tcam);
297 	if (err)
298 		goto err_ipv4_init;
299 
300 	err = mlxsw_sp2_mr_tcam_ipv6_init(mr_tcam);
301 	if (err)
302 		goto err_ipv6_init;
303 
304 	return 0;
305 
306 err_ipv6_init:
307 	mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
308 err_ipv4_init:
309 	mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
310 	return err;
311 }
312 
313 static void mlxsw_sp2_mr_tcam_fini(void *priv)
314 {
315 	struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
316 
317 	mlxsw_sp2_mr_tcam_ipv6_fini(mr_tcam);
318 	mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
319 	mlxsw_sp_flow_block_destroy(mr_tcam->flow_block);
320 }
321 
322 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
323 	.priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
324 	.init = mlxsw_sp2_mr_tcam_init,
325 	.fini = mlxsw_sp2_mr_tcam_fini,
326 	.route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
327 	.route_create = mlxsw_sp2_mr_tcam_route_create,
328 	.route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
329 	.route_update = mlxsw_sp2_mr_tcam_route_update,
330 };
331