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+
10205static int
11206mlxsw_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
20241static void
21242mlxsw_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
27263static 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
36286static 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
41313static 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
45322const 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