Skip to content

Commit cf7221a

Browse files
nirdotandavem330
authored andcommitted
mlxsw: spectrum_router: Add Multicast routing support for Spectrum-2
Add implementation of Spectrum-2 multicast routes for both IPv4 and IPv6 by using ACL module explicitly. In Spectrum-2, multicast routes are set as ACL rules, so initialization takes care of creating dedicated ACL groups and binding them to the appropriate multicast routing protocol IPv4/IPv6, and afterwards routes configuration translates to setting explicit ACL rules. Signed-off-by: Nir Dotan <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: Ido Schimmel <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d7263ab commit cf7221a

File tree

1 file changed

+280
-1
lines changed

1 file changed

+280
-1
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum2_mr_tcam.c

Lines changed: 280 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,257 @@
77
#include "spectrum.h"
88
#include "spectrum_mr.h"
99

10+
struct mlxsw_sp2_mr_tcam {
11+
struct mlxsw_sp *mlxsw_sp;
12+
struct mlxsw_sp_acl_block *acl_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_8_10,
49+
MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
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->acl_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_8_10,
93+
MLXSW_AFK_ELEMENT_VIRT_ROUTER_0_7,
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->acl_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_0_7,
193+
key->vrid, GENMASK(7, 0));
194+
mlxsw_sp_acl_rulei_keymask_u32(rulei,
195+
MLXSW_AFK_ELEMENT_VIRT_ROUTER_8_10,
196+
key->vrid >> 8, GENMASK(2, 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+
10205
static int
11206
mlxsw_sp2_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
12207
void *route_priv,
13208
struct mlxsw_sp_mr_route_key *key,
14209
struct mlxsw_afa_block *afa_block,
15210
enum mlxsw_sp_mr_route_prio prio)
16211
{
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+
17234
return 0;
235+
236+
err_rule_add:
237+
mlxsw_sp_acl_rule_destroy(mlxsw_sp, rule);
238+
return err;
18239
}
19240

20241
static void
21242
mlxsw_sp2_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
22243
void *route_priv,
23244
struct mlxsw_sp_mr_route_key *key)
24245
{
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);
25261
}
26262

27263
static int
@@ -30,21 +266,64 @@ mlxsw_sp2_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
30266
struct mlxsw_sp_mr_route_key *key,
31267
struct mlxsw_afa_block *afa_block)
32268
{
33-
return 0;
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);
34284
}
35285

36286
static int mlxsw_sp2_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
37287
{
288+
struct mlxsw_sp2_mr_tcam *mr_tcam = priv;
289+
int err;
290+
291+
mr_tcam->mlxsw_sp = mlxsw_sp;
292+
mr_tcam->acl_block = mlxsw_sp_acl_block_create(mlxsw_sp, NULL);
293+
if (!mr_tcam->acl_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+
38304
return 0;
305+
306+
err_ipv6_init:
307+
mlxsw_sp2_mr_tcam_ipv4_fini(mr_tcam);
308+
err_ipv4_init:
309+
mlxsw_sp_acl_block_destroy(mr_tcam->acl_block);
310+
return err;
39311
}
40312

41313
static void mlxsw_sp2_mr_tcam_fini(void *priv)
42314
{
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_acl_block_destroy(mr_tcam->acl_block);
43320
}
44321

45322
const struct mlxsw_sp_mr_tcam_ops mlxsw_sp2_mr_tcam_ops = {
323+
.priv_size = sizeof(struct mlxsw_sp2_mr_tcam),
46324
.init = mlxsw_sp2_mr_tcam_init,
47325
.fini = mlxsw_sp2_mr_tcam_fini,
326+
.route_priv_size = sizeof(struct mlxsw_sp2_mr_route),
48327
.route_create = mlxsw_sp2_mr_tcam_route_create,
49328
.route_destroy = mlxsw_sp2_mr_tcam_route_destroy,
50329
.route_update = mlxsw_sp2_mr_tcam_route_update,

0 commit comments

Comments
 (0)