This source file includes following definitions.
- mlxsw_sp_acl_afk
- mlxsw_sp_acl_dummy_fid
- mlxsw_sp_acl_block_mlxsw_sp
- mlxsw_sp_acl_block_rule_count
- mlxsw_sp_acl_block_disable_inc
- mlxsw_sp_acl_block_disable_dec
- mlxsw_sp_acl_block_disabled
- mlxsw_sp_acl_block_is_egress_bound
- mlxsw_sp_acl_ruleset_is_singular
- mlxsw_sp_acl_ruleset_bind
- mlxsw_sp_acl_ruleset_unbind
- mlxsw_sp_acl_ruleset_block_bound
- mlxsw_sp_acl_ruleset_block_bind
- mlxsw_sp_acl_ruleset_block_unbind
- mlxsw_sp_acl_block_create
- mlxsw_sp_acl_block_destroy
- mlxsw_sp_acl_block_lookup
- mlxsw_sp_acl_block_bind
- mlxsw_sp_acl_block_unbind
- mlxsw_sp_acl_ruleset_create
- mlxsw_sp_acl_ruleset_destroy
- mlxsw_sp_acl_ruleset_ref_inc
- mlxsw_sp_acl_ruleset_ref_dec
- __mlxsw_sp_acl_ruleset_lookup
- mlxsw_sp_acl_ruleset_lookup
- mlxsw_sp_acl_ruleset_get
- mlxsw_sp_acl_ruleset_put
- mlxsw_sp_acl_ruleset_group_id
- mlxsw_sp_acl_rulei_create
- mlxsw_sp_acl_rulei_destroy
- mlxsw_sp_acl_rulei_commit
- mlxsw_sp_acl_rulei_priority
- mlxsw_sp_acl_rulei_keymask_u32
- mlxsw_sp_acl_rulei_keymask_buf
- mlxsw_sp_acl_rulei_act_continue
- mlxsw_sp_acl_rulei_act_jump
- mlxsw_sp_acl_rulei_act_terminate
- mlxsw_sp_acl_rulei_act_drop
- mlxsw_sp_acl_rulei_act_trap
- mlxsw_sp_acl_rulei_act_fwd
- mlxsw_sp_acl_rulei_act_mirror
- mlxsw_sp_acl_rulei_act_vlan
- mlxsw_sp_acl_rulei_act_count
- mlxsw_sp_acl_rulei_act_fid_set
- mlxsw_sp_acl_rule_create
- mlxsw_sp_acl_rule_destroy
- mlxsw_sp_acl_rule_add
- mlxsw_sp_acl_rule_del
- mlxsw_sp_acl_rule_action_replace
- mlxsw_sp_acl_rule_lookup
- mlxsw_sp_acl_rule_rulei
- mlxsw_sp_acl_rule_activity_update
- mlxsw_sp_acl_rules_activity_update
- mlxsw_sp_acl_rule_activity_work_schedule
- mlxsw_sp_acl_rule_activity_update_work
- mlxsw_sp_acl_rule_get_stats
- mlxsw_sp_acl_init
- mlxsw_sp_acl_fini
- mlxsw_sp_acl_region_rehash_intrvl_get
- mlxsw_sp_acl_region_rehash_intrvl_set
1
2
3
4 #include <linux/kernel.h>
5 #include <linux/slab.h>
6 #include <linux/errno.h>
7 #include <linux/list.h>
8 #include <linux/string.h>
9 #include <linux/rhashtable.h>
10 #include <linux/netdevice.h>
11 #include <linux/mutex.h>
12 #include <net/net_namespace.h>
13 #include <net/tc_act/tc_vlan.h>
14
15 #include "reg.h"
16 #include "core.h"
17 #include "resources.h"
18 #include "spectrum.h"
19 #include "core_acl_flex_keys.h"
20 #include "core_acl_flex_actions.h"
21 #include "spectrum_acl_tcam.h"
22
23 struct mlxsw_sp_acl {
24 struct mlxsw_sp *mlxsw_sp;
25 struct mlxsw_afk *afk;
26 struct mlxsw_sp_fid *dummy_fid;
27 struct rhashtable ruleset_ht;
28 struct list_head rules;
29 struct mutex rules_lock;
30 struct {
31 struct delayed_work dw;
32 unsigned long interval;
33 #define MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS 1000
34 } rule_activity_update;
35 struct mlxsw_sp_acl_tcam tcam;
36 };
37
38 struct mlxsw_afk *mlxsw_sp_acl_afk(struct mlxsw_sp_acl *acl)
39 {
40 return acl->afk;
41 }
42
43 struct mlxsw_sp_acl_block_binding {
44 struct list_head list;
45 struct net_device *dev;
46 struct mlxsw_sp_port *mlxsw_sp_port;
47 bool ingress;
48 };
49
50 struct mlxsw_sp_acl_ruleset_ht_key {
51 struct mlxsw_sp_acl_block *block;
52 u32 chain_index;
53 const struct mlxsw_sp_acl_profile_ops *ops;
54 };
55
56 struct mlxsw_sp_acl_ruleset {
57 struct rhash_head ht_node;
58 struct mlxsw_sp_acl_ruleset_ht_key ht_key;
59 struct rhashtable rule_ht;
60 unsigned int ref_count;
61 unsigned long priv[0];
62
63 };
64
65 struct mlxsw_sp_acl_rule {
66 struct rhash_head ht_node;
67 struct list_head list;
68 unsigned long cookie;
69 struct mlxsw_sp_acl_ruleset *ruleset;
70 struct mlxsw_sp_acl_rule_info *rulei;
71 u64 last_used;
72 u64 last_packets;
73 u64 last_bytes;
74 unsigned long priv[0];
75
76 };
77
78 static const struct rhashtable_params mlxsw_sp_acl_ruleset_ht_params = {
79 .key_len = sizeof(struct mlxsw_sp_acl_ruleset_ht_key),
80 .key_offset = offsetof(struct mlxsw_sp_acl_ruleset, ht_key),
81 .head_offset = offsetof(struct mlxsw_sp_acl_ruleset, ht_node),
82 .automatic_shrinking = true,
83 };
84
85 static const struct rhashtable_params mlxsw_sp_acl_rule_ht_params = {
86 .key_len = sizeof(unsigned long),
87 .key_offset = offsetof(struct mlxsw_sp_acl_rule, cookie),
88 .head_offset = offsetof(struct mlxsw_sp_acl_rule, ht_node),
89 .automatic_shrinking = true,
90 };
91
92 struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp)
93 {
94 return mlxsw_sp->acl->dummy_fid;
95 }
96
97 struct mlxsw_sp *mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block *block)
98 {
99 return block->mlxsw_sp;
100 }
101
102 unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block *block)
103 {
104 return block ? block->rule_count : 0;
105 }
106
107 void mlxsw_sp_acl_block_disable_inc(struct mlxsw_sp_acl_block *block)
108 {
109 if (block)
110 block->disable_count++;
111 }
112
113 void mlxsw_sp_acl_block_disable_dec(struct mlxsw_sp_acl_block *block)
114 {
115 if (block)
116 block->disable_count--;
117 }
118
119 bool mlxsw_sp_acl_block_disabled(struct mlxsw_sp_acl_block *block)
120 {
121 return block->disable_count;
122 }
123
124 bool mlxsw_sp_acl_block_is_egress_bound(struct mlxsw_sp_acl_block *block)
125 {
126 struct mlxsw_sp_acl_block_binding *binding;
127
128 list_for_each_entry(binding, &block->binding_list, list) {
129 if (!binding->ingress)
130 return true;
131 }
132 return false;
133 }
134
135 static bool
136 mlxsw_sp_acl_ruleset_is_singular(const struct mlxsw_sp_acl_ruleset *ruleset)
137 {
138
139 return ruleset->ref_count == 2;
140 }
141
142 static int
143 mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp,
144 struct mlxsw_sp_acl_block *block,
145 struct mlxsw_sp_acl_block_binding *binding)
146 {
147 struct mlxsw_sp_acl_ruleset *ruleset = block->ruleset_zero;
148 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
149
150 return ops->ruleset_bind(mlxsw_sp, ruleset->priv,
151 binding->mlxsw_sp_port, binding->ingress);
152 }
153
154 static void
155 mlxsw_sp_acl_ruleset_unbind(struct mlxsw_sp *mlxsw_sp,
156 struct mlxsw_sp_acl_block *block,
157 struct mlxsw_sp_acl_block_binding *binding)
158 {
159 struct mlxsw_sp_acl_ruleset *ruleset = block->ruleset_zero;
160 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
161
162 ops->ruleset_unbind(mlxsw_sp, ruleset->priv,
163 binding->mlxsw_sp_port, binding->ingress);
164 }
165
166 static bool mlxsw_sp_acl_ruleset_block_bound(struct mlxsw_sp_acl_block *block)
167 {
168 return block->ruleset_zero;
169 }
170
171 static int
172 mlxsw_sp_acl_ruleset_block_bind(struct mlxsw_sp *mlxsw_sp,
173 struct mlxsw_sp_acl_ruleset *ruleset,
174 struct mlxsw_sp_acl_block *block)
175 {
176 struct mlxsw_sp_acl_block_binding *binding;
177 int err;
178
179 block->ruleset_zero = ruleset;
180 list_for_each_entry(binding, &block->binding_list, list) {
181 err = mlxsw_sp_acl_ruleset_bind(mlxsw_sp, block, binding);
182 if (err)
183 goto rollback;
184 }
185 return 0;
186
187 rollback:
188 list_for_each_entry_continue_reverse(binding, &block->binding_list,
189 list)
190 mlxsw_sp_acl_ruleset_unbind(mlxsw_sp, block, binding);
191 block->ruleset_zero = NULL;
192
193 return err;
194 }
195
196 static void
197 mlxsw_sp_acl_ruleset_block_unbind(struct mlxsw_sp *mlxsw_sp,
198 struct mlxsw_sp_acl_ruleset *ruleset,
199 struct mlxsw_sp_acl_block *block)
200 {
201 struct mlxsw_sp_acl_block_binding *binding;
202
203 list_for_each_entry(binding, &block->binding_list, list)
204 mlxsw_sp_acl_ruleset_unbind(mlxsw_sp, block, binding);
205 block->ruleset_zero = NULL;
206 }
207
208 struct mlxsw_sp_acl_block *mlxsw_sp_acl_block_create(struct mlxsw_sp *mlxsw_sp,
209 struct net *net)
210 {
211 struct mlxsw_sp_acl_block *block;
212
213 block = kzalloc(sizeof(*block), GFP_KERNEL);
214 if (!block)
215 return NULL;
216 INIT_LIST_HEAD(&block->binding_list);
217 block->mlxsw_sp = mlxsw_sp;
218 block->net = net;
219 return block;
220 }
221
222 void mlxsw_sp_acl_block_destroy(struct mlxsw_sp_acl_block *block)
223 {
224 WARN_ON(!list_empty(&block->binding_list));
225 kfree(block);
226 }
227
228 static struct mlxsw_sp_acl_block_binding *
229 mlxsw_sp_acl_block_lookup(struct mlxsw_sp_acl_block *block,
230 struct mlxsw_sp_port *mlxsw_sp_port, bool ingress)
231 {
232 struct mlxsw_sp_acl_block_binding *binding;
233
234 list_for_each_entry(binding, &block->binding_list, list)
235 if (binding->mlxsw_sp_port == mlxsw_sp_port &&
236 binding->ingress == ingress)
237 return binding;
238 return NULL;
239 }
240
241 int mlxsw_sp_acl_block_bind(struct mlxsw_sp *mlxsw_sp,
242 struct mlxsw_sp_acl_block *block,
243 struct mlxsw_sp_port *mlxsw_sp_port,
244 bool ingress,
245 struct netlink_ext_ack *extack)
246 {
247 struct mlxsw_sp_acl_block_binding *binding;
248 int err;
249
250 if (WARN_ON(mlxsw_sp_acl_block_lookup(block, mlxsw_sp_port, ingress)))
251 return -EEXIST;
252
253 if (!ingress && block->egress_blocker_rule_count) {
254 NL_SET_ERR_MSG_MOD(extack, "Block cannot be bound to egress because it contains unsupported rules");
255 return -EOPNOTSUPP;
256 }
257
258 binding = kzalloc(sizeof(*binding), GFP_KERNEL);
259 if (!binding)
260 return -ENOMEM;
261 binding->mlxsw_sp_port = mlxsw_sp_port;
262 binding->ingress = ingress;
263
264 if (mlxsw_sp_acl_ruleset_block_bound(block)) {
265 err = mlxsw_sp_acl_ruleset_bind(mlxsw_sp, block, binding);
266 if (err)
267 goto err_ruleset_bind;
268 }
269
270 list_add(&binding->list, &block->binding_list);
271 return 0;
272
273 err_ruleset_bind:
274 kfree(binding);
275 return err;
276 }
277
278 int mlxsw_sp_acl_block_unbind(struct mlxsw_sp *mlxsw_sp,
279 struct mlxsw_sp_acl_block *block,
280 struct mlxsw_sp_port *mlxsw_sp_port,
281 bool ingress)
282 {
283 struct mlxsw_sp_acl_block_binding *binding;
284
285 binding = mlxsw_sp_acl_block_lookup(block, mlxsw_sp_port, ingress);
286 if (!binding)
287 return -ENOENT;
288
289 list_del(&binding->list);
290
291 if (mlxsw_sp_acl_ruleset_block_bound(block))
292 mlxsw_sp_acl_ruleset_unbind(mlxsw_sp, block, binding);
293
294 kfree(binding);
295 return 0;
296 }
297
298 static struct mlxsw_sp_acl_ruleset *
299 mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp,
300 struct mlxsw_sp_acl_block *block, u32 chain_index,
301 const struct mlxsw_sp_acl_profile_ops *ops,
302 struct mlxsw_afk_element_usage *tmplt_elusage)
303 {
304 struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
305 struct mlxsw_sp_acl_ruleset *ruleset;
306 size_t alloc_size;
307 int err;
308
309 alloc_size = sizeof(*ruleset) + ops->ruleset_priv_size;
310 ruleset = kzalloc(alloc_size, GFP_KERNEL);
311 if (!ruleset)
312 return ERR_PTR(-ENOMEM);
313 ruleset->ref_count = 1;
314 ruleset->ht_key.block = block;
315 ruleset->ht_key.chain_index = chain_index;
316 ruleset->ht_key.ops = ops;
317
318 err = rhashtable_init(&ruleset->rule_ht, &mlxsw_sp_acl_rule_ht_params);
319 if (err)
320 goto err_rhashtable_init;
321
322 err = ops->ruleset_add(mlxsw_sp, &acl->tcam, ruleset->priv,
323 tmplt_elusage);
324 if (err)
325 goto err_ops_ruleset_add;
326
327 err = rhashtable_insert_fast(&acl->ruleset_ht, &ruleset->ht_node,
328 mlxsw_sp_acl_ruleset_ht_params);
329 if (err)
330 goto err_ht_insert;
331
332 return ruleset;
333
334 err_ht_insert:
335 ops->ruleset_del(mlxsw_sp, ruleset->priv);
336 err_ops_ruleset_add:
337 rhashtable_destroy(&ruleset->rule_ht);
338 err_rhashtable_init:
339 kfree(ruleset);
340 return ERR_PTR(err);
341 }
342
343 static void mlxsw_sp_acl_ruleset_destroy(struct mlxsw_sp *mlxsw_sp,
344 struct mlxsw_sp_acl_ruleset *ruleset)
345 {
346 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
347 struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
348
349 rhashtable_remove_fast(&acl->ruleset_ht, &ruleset->ht_node,
350 mlxsw_sp_acl_ruleset_ht_params);
351 ops->ruleset_del(mlxsw_sp, ruleset->priv);
352 rhashtable_destroy(&ruleset->rule_ht);
353 kfree(ruleset);
354 }
355
356 static void mlxsw_sp_acl_ruleset_ref_inc(struct mlxsw_sp_acl_ruleset *ruleset)
357 {
358 ruleset->ref_count++;
359 }
360
361 static void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp *mlxsw_sp,
362 struct mlxsw_sp_acl_ruleset *ruleset)
363 {
364 if (--ruleset->ref_count)
365 return;
366 mlxsw_sp_acl_ruleset_destroy(mlxsw_sp, ruleset);
367 }
368
369 static struct mlxsw_sp_acl_ruleset *
370 __mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp_acl *acl,
371 struct mlxsw_sp_acl_block *block, u32 chain_index,
372 const struct mlxsw_sp_acl_profile_ops *ops)
373 {
374 struct mlxsw_sp_acl_ruleset_ht_key ht_key;
375
376 memset(&ht_key, 0, sizeof(ht_key));
377 ht_key.block = block;
378 ht_key.chain_index = chain_index;
379 ht_key.ops = ops;
380 return rhashtable_lookup_fast(&acl->ruleset_ht, &ht_key,
381 mlxsw_sp_acl_ruleset_ht_params);
382 }
383
384 struct mlxsw_sp_acl_ruleset *
385 mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp *mlxsw_sp,
386 struct mlxsw_sp_acl_block *block, u32 chain_index,
387 enum mlxsw_sp_acl_profile profile)
388 {
389 const struct mlxsw_sp_acl_profile_ops *ops;
390 struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
391 struct mlxsw_sp_acl_ruleset *ruleset;
392
393 ops = mlxsw_sp_acl_tcam_profile_ops(mlxsw_sp, profile);
394 if (!ops)
395 return ERR_PTR(-EINVAL);
396 ruleset = __mlxsw_sp_acl_ruleset_lookup(acl, block, chain_index, ops);
397 if (!ruleset)
398 return ERR_PTR(-ENOENT);
399 return ruleset;
400 }
401
402 struct mlxsw_sp_acl_ruleset *
403 mlxsw_sp_acl_ruleset_get(struct mlxsw_sp *mlxsw_sp,
404 struct mlxsw_sp_acl_block *block, u32 chain_index,
405 enum mlxsw_sp_acl_profile profile,
406 struct mlxsw_afk_element_usage *tmplt_elusage)
407 {
408 const struct mlxsw_sp_acl_profile_ops *ops;
409 struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
410 struct mlxsw_sp_acl_ruleset *ruleset;
411
412 ops = mlxsw_sp_acl_tcam_profile_ops(mlxsw_sp, profile);
413 if (!ops)
414 return ERR_PTR(-EINVAL);
415
416 ruleset = __mlxsw_sp_acl_ruleset_lookup(acl, block, chain_index, ops);
417 if (ruleset) {
418 mlxsw_sp_acl_ruleset_ref_inc(ruleset);
419 return ruleset;
420 }
421 return mlxsw_sp_acl_ruleset_create(mlxsw_sp, block, chain_index, ops,
422 tmplt_elusage);
423 }
424
425 void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp *mlxsw_sp,
426 struct mlxsw_sp_acl_ruleset *ruleset)
427 {
428 mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
429 }
430
431 u16 mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset *ruleset)
432 {
433 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
434
435 return ops->ruleset_group_id(ruleset->priv);
436 }
437
438 struct mlxsw_sp_acl_rule_info *
439 mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl *acl,
440 struct mlxsw_afa_block *afa_block)
441 {
442 struct mlxsw_sp_acl_rule_info *rulei;
443 int err;
444
445 rulei = kzalloc(sizeof(*rulei), GFP_KERNEL);
446 if (!rulei)
447 return ERR_PTR(-ENOMEM);
448
449 if (afa_block) {
450 rulei->act_block = afa_block;
451 return rulei;
452 }
453
454 rulei->act_block = mlxsw_afa_block_create(acl->mlxsw_sp->afa);
455 if (IS_ERR(rulei->act_block)) {
456 err = PTR_ERR(rulei->act_block);
457 goto err_afa_block_create;
458 }
459 rulei->action_created = 1;
460 return rulei;
461
462 err_afa_block_create:
463 kfree(rulei);
464 return ERR_PTR(err);
465 }
466
467 void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp_acl_rule_info *rulei)
468 {
469 if (rulei->action_created)
470 mlxsw_afa_block_destroy(rulei->act_block);
471 kfree(rulei);
472 }
473
474 int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info *rulei)
475 {
476 return mlxsw_afa_block_commit(rulei->act_block);
477 }
478
479 void mlxsw_sp_acl_rulei_priority(struct mlxsw_sp_acl_rule_info *rulei,
480 unsigned int priority)
481 {
482 rulei->priority = priority;
483 }
484
485 void mlxsw_sp_acl_rulei_keymask_u32(struct mlxsw_sp_acl_rule_info *rulei,
486 enum mlxsw_afk_element element,
487 u32 key_value, u32 mask_value)
488 {
489 mlxsw_afk_values_add_u32(&rulei->values, element,
490 key_value, mask_value);
491 }
492
493 void mlxsw_sp_acl_rulei_keymask_buf(struct mlxsw_sp_acl_rule_info *rulei,
494 enum mlxsw_afk_element element,
495 const char *key_value,
496 const char *mask_value, unsigned int len)
497 {
498 mlxsw_afk_values_add_buf(&rulei->values, element,
499 key_value, mask_value, len);
500 }
501
502 int mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info *rulei)
503 {
504 return mlxsw_afa_block_continue(rulei->act_block);
505 }
506
507 int mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei,
508 u16 group_id)
509 {
510 return mlxsw_afa_block_jump(rulei->act_block, group_id);
511 }
512
513 int mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei)
514 {
515 return mlxsw_afa_block_terminate(rulei->act_block);
516 }
517
518 int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei)
519 {
520 return mlxsw_afa_block_append_drop(rulei->act_block);
521 }
522
523 int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei)
524 {
525 return mlxsw_afa_block_append_trap(rulei->act_block,
526 MLXSW_TRAP_ID_ACL0);
527 }
528
529 int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp *mlxsw_sp,
530 struct mlxsw_sp_acl_rule_info *rulei,
531 struct net_device *out_dev,
532 struct netlink_ext_ack *extack)
533 {
534 struct mlxsw_sp_port *mlxsw_sp_port;
535 u8 local_port;
536 bool in_port;
537
538 if (out_dev) {
539 if (!mlxsw_sp_port_dev_check(out_dev)) {
540 NL_SET_ERR_MSG_MOD(extack, "Invalid output device");
541 return -EINVAL;
542 }
543 mlxsw_sp_port = netdev_priv(out_dev);
544 if (mlxsw_sp_port->mlxsw_sp != mlxsw_sp) {
545 NL_SET_ERR_MSG_MOD(extack, "Invalid output device");
546 return -EINVAL;
547 }
548 local_port = mlxsw_sp_port->local_port;
549 in_port = false;
550 } else {
551
552
553
554 local_port = 0;
555 in_port = true;
556 }
557 return mlxsw_afa_block_append_fwd(rulei->act_block,
558 local_port, in_port, extack);
559 }
560
561 int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp,
562 struct mlxsw_sp_acl_rule_info *rulei,
563 struct mlxsw_sp_acl_block *block,
564 struct net_device *out_dev,
565 struct netlink_ext_ack *extack)
566 {
567 struct mlxsw_sp_acl_block_binding *binding;
568 struct mlxsw_sp_port *in_port;
569
570 if (!list_is_singular(&block->binding_list)) {
571 NL_SET_ERR_MSG_MOD(extack, "Only a single mirror source is allowed");
572 return -EOPNOTSUPP;
573 }
574 binding = list_first_entry(&block->binding_list,
575 struct mlxsw_sp_acl_block_binding, list);
576 in_port = binding->mlxsw_sp_port;
577
578 return mlxsw_afa_block_append_mirror(rulei->act_block,
579 in_port->local_port,
580 out_dev,
581 binding->ingress,
582 extack);
583 }
584
585 int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp *mlxsw_sp,
586 struct mlxsw_sp_acl_rule_info *rulei,
587 u32 action, u16 vid, u16 proto, u8 prio,
588 struct netlink_ext_ack *extack)
589 {
590 u8 ethertype;
591
592 if (action == FLOW_ACTION_VLAN_MANGLE) {
593 switch (proto) {
594 case ETH_P_8021Q:
595 ethertype = 0;
596 break;
597 case ETH_P_8021AD:
598 ethertype = 1;
599 break;
600 default:
601 NL_SET_ERR_MSG_MOD(extack, "Unsupported VLAN protocol");
602 dev_err(mlxsw_sp->bus_info->dev, "Unsupported VLAN protocol %#04x\n",
603 proto);
604 return -EINVAL;
605 }
606
607 return mlxsw_afa_block_append_vlan_modify(rulei->act_block,
608 vid, prio, ethertype,
609 extack);
610 } else {
611 NL_SET_ERR_MSG_MOD(extack, "Unsupported VLAN action");
612 dev_err(mlxsw_sp->bus_info->dev, "Unsupported VLAN action\n");
613 return -EINVAL;
614 }
615 }
616
617 int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp *mlxsw_sp,
618 struct mlxsw_sp_acl_rule_info *rulei,
619 struct netlink_ext_ack *extack)
620 {
621 return mlxsw_afa_block_append_counter(rulei->act_block,
622 &rulei->counter_index, extack);
623 }
624
625 int mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp *mlxsw_sp,
626 struct mlxsw_sp_acl_rule_info *rulei,
627 u16 fid, struct netlink_ext_ack *extack)
628 {
629 return mlxsw_afa_block_append_fid_set(rulei->act_block, fid, extack);
630 }
631
632 struct mlxsw_sp_acl_rule *
633 mlxsw_sp_acl_rule_create(struct mlxsw_sp *mlxsw_sp,
634 struct mlxsw_sp_acl_ruleset *ruleset,
635 unsigned long cookie,
636 struct mlxsw_afa_block *afa_block,
637 struct netlink_ext_ack *extack)
638 {
639 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
640 struct mlxsw_sp_acl_rule *rule;
641 int err;
642
643 mlxsw_sp_acl_ruleset_ref_inc(ruleset);
644 rule = kzalloc(sizeof(*rule) + ops->rule_priv_size,
645 GFP_KERNEL);
646 if (!rule) {
647 err = -ENOMEM;
648 goto err_alloc;
649 }
650 rule->cookie = cookie;
651 rule->ruleset = ruleset;
652
653 rule->rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl, afa_block);
654 if (IS_ERR(rule->rulei)) {
655 err = PTR_ERR(rule->rulei);
656 goto err_rulei_create;
657 }
658
659 return rule;
660
661 err_rulei_create:
662 kfree(rule);
663 err_alloc:
664 mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
665 return ERR_PTR(err);
666 }
667
668 void mlxsw_sp_acl_rule_destroy(struct mlxsw_sp *mlxsw_sp,
669 struct mlxsw_sp_acl_rule *rule)
670 {
671 struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
672
673 mlxsw_sp_acl_rulei_destroy(rule->rulei);
674 kfree(rule);
675 mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp, ruleset);
676 }
677
678 int mlxsw_sp_acl_rule_add(struct mlxsw_sp *mlxsw_sp,
679 struct mlxsw_sp_acl_rule *rule)
680 {
681 struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
682 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
683 struct mlxsw_sp_acl_block *block = ruleset->ht_key.block;
684 int err;
685
686 err = ops->rule_add(mlxsw_sp, ruleset->priv, rule->priv, rule->rulei);
687 if (err)
688 return err;
689
690 err = rhashtable_insert_fast(&ruleset->rule_ht, &rule->ht_node,
691 mlxsw_sp_acl_rule_ht_params);
692 if (err)
693 goto err_rhashtable_insert;
694
695 if (!ruleset->ht_key.chain_index &&
696 mlxsw_sp_acl_ruleset_is_singular(ruleset)) {
697
698
699
700
701 err = mlxsw_sp_acl_ruleset_block_bind(mlxsw_sp, ruleset, block);
702 if (err)
703 goto err_ruleset_block_bind;
704 }
705
706 mutex_lock(&mlxsw_sp->acl->rules_lock);
707 list_add_tail(&rule->list, &mlxsw_sp->acl->rules);
708 mutex_unlock(&mlxsw_sp->acl->rules_lock);
709 block->rule_count++;
710 block->egress_blocker_rule_count += rule->rulei->egress_bind_blocker;
711 return 0;
712
713 err_ruleset_block_bind:
714 rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node,
715 mlxsw_sp_acl_rule_ht_params);
716 err_rhashtable_insert:
717 ops->rule_del(mlxsw_sp, rule->priv);
718 return err;
719 }
720
721 void mlxsw_sp_acl_rule_del(struct mlxsw_sp *mlxsw_sp,
722 struct mlxsw_sp_acl_rule *rule)
723 {
724 struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
725 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
726 struct mlxsw_sp_acl_block *block = ruleset->ht_key.block;
727
728 block->egress_blocker_rule_count -= rule->rulei->egress_bind_blocker;
729 ruleset->ht_key.block->rule_count--;
730 mutex_lock(&mlxsw_sp->acl->rules_lock);
731 list_del(&rule->list);
732 mutex_unlock(&mlxsw_sp->acl->rules_lock);
733 if (!ruleset->ht_key.chain_index &&
734 mlxsw_sp_acl_ruleset_is_singular(ruleset))
735 mlxsw_sp_acl_ruleset_block_unbind(mlxsw_sp, ruleset,
736 ruleset->ht_key.block);
737 rhashtable_remove_fast(&ruleset->rule_ht, &rule->ht_node,
738 mlxsw_sp_acl_rule_ht_params);
739 ops->rule_del(mlxsw_sp, rule->priv);
740 }
741
742 int mlxsw_sp_acl_rule_action_replace(struct mlxsw_sp *mlxsw_sp,
743 struct mlxsw_sp_acl_rule *rule,
744 struct mlxsw_afa_block *afa_block)
745 {
746 struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
747 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
748 struct mlxsw_sp_acl_rule_info *rulei;
749
750 rulei = mlxsw_sp_acl_rule_rulei(rule);
751 rulei->act_block = afa_block;
752
753 return ops->rule_action_replace(mlxsw_sp, rule->priv, rule->rulei);
754 }
755
756 struct mlxsw_sp_acl_rule *
757 mlxsw_sp_acl_rule_lookup(struct mlxsw_sp *mlxsw_sp,
758 struct mlxsw_sp_acl_ruleset *ruleset,
759 unsigned long cookie)
760 {
761 return rhashtable_lookup_fast(&ruleset->rule_ht, &cookie,
762 mlxsw_sp_acl_rule_ht_params);
763 }
764
765 struct mlxsw_sp_acl_rule_info *
766 mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule *rule)
767 {
768 return rule->rulei;
769 }
770
771 static int mlxsw_sp_acl_rule_activity_update(struct mlxsw_sp *mlxsw_sp,
772 struct mlxsw_sp_acl_rule *rule)
773 {
774 struct mlxsw_sp_acl_ruleset *ruleset = rule->ruleset;
775 const struct mlxsw_sp_acl_profile_ops *ops = ruleset->ht_key.ops;
776 bool active;
777 int err;
778
779 err = ops->rule_activity_get(mlxsw_sp, rule->priv, &active);
780 if (err)
781 return err;
782 if (active)
783 rule->last_used = jiffies;
784 return 0;
785 }
786
787 static int mlxsw_sp_acl_rules_activity_update(struct mlxsw_sp_acl *acl)
788 {
789 struct mlxsw_sp_acl_rule *rule;
790 int err;
791
792 mutex_lock(&acl->rules_lock);
793 list_for_each_entry(rule, &acl->rules, list) {
794 err = mlxsw_sp_acl_rule_activity_update(acl->mlxsw_sp,
795 rule);
796 if (err)
797 goto err_rule_update;
798 }
799 mutex_unlock(&acl->rules_lock);
800 return 0;
801
802 err_rule_update:
803 mutex_unlock(&acl->rules_lock);
804 return err;
805 }
806
807 static void mlxsw_sp_acl_rule_activity_work_schedule(struct mlxsw_sp_acl *acl)
808 {
809 unsigned long interval = acl->rule_activity_update.interval;
810
811 mlxsw_core_schedule_dw(&acl->rule_activity_update.dw,
812 msecs_to_jiffies(interval));
813 }
814
815 static void mlxsw_sp_acl_rule_activity_update_work(struct work_struct *work)
816 {
817 struct mlxsw_sp_acl *acl = container_of(work, struct mlxsw_sp_acl,
818 rule_activity_update.dw.work);
819 int err;
820
821 err = mlxsw_sp_acl_rules_activity_update(acl);
822 if (err)
823 dev_err(acl->mlxsw_sp->bus_info->dev, "Could not update acl activity");
824
825 mlxsw_sp_acl_rule_activity_work_schedule(acl);
826 }
827
828 int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp,
829 struct mlxsw_sp_acl_rule *rule,
830 u64 *packets, u64 *bytes, u64 *last_use)
831
832 {
833 struct mlxsw_sp_acl_rule_info *rulei;
834 u64 current_packets;
835 u64 current_bytes;
836 int err;
837
838 rulei = mlxsw_sp_acl_rule_rulei(rule);
839 err = mlxsw_sp_flow_counter_get(mlxsw_sp, rulei->counter_index,
840 ¤t_packets, ¤t_bytes);
841 if (err)
842 return err;
843
844 *packets = current_packets - rule->last_packets;
845 *bytes = current_bytes - rule->last_bytes;
846 *last_use = rule->last_used;
847
848 rule->last_bytes = current_bytes;
849 rule->last_packets = current_packets;
850
851 return 0;
852 }
853
854 int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp)
855 {
856 struct mlxsw_sp_fid *fid;
857 struct mlxsw_sp_acl *acl;
858 size_t alloc_size;
859 int err;
860
861 alloc_size = sizeof(*acl) + mlxsw_sp_acl_tcam_priv_size(mlxsw_sp);
862 acl = kzalloc(alloc_size, GFP_KERNEL);
863 if (!acl)
864 return -ENOMEM;
865 mlxsw_sp->acl = acl;
866 acl->mlxsw_sp = mlxsw_sp;
867 acl->afk = mlxsw_afk_create(MLXSW_CORE_RES_GET(mlxsw_sp->core,
868 ACL_FLEX_KEYS),
869 mlxsw_sp->afk_ops);
870 if (!acl->afk) {
871 err = -ENOMEM;
872 goto err_afk_create;
873 }
874
875 err = rhashtable_init(&acl->ruleset_ht,
876 &mlxsw_sp_acl_ruleset_ht_params);
877 if (err)
878 goto err_rhashtable_init;
879
880 fid = mlxsw_sp_fid_dummy_get(mlxsw_sp);
881 if (IS_ERR(fid)) {
882 err = PTR_ERR(fid);
883 goto err_fid_get;
884 }
885 acl->dummy_fid = fid;
886
887 INIT_LIST_HEAD(&acl->rules);
888 mutex_init(&acl->rules_lock);
889 err = mlxsw_sp_acl_tcam_init(mlxsw_sp, &acl->tcam);
890 if (err)
891 goto err_acl_ops_init;
892
893
894 INIT_DELAYED_WORK(&acl->rule_activity_update.dw,
895 mlxsw_sp_acl_rule_activity_update_work);
896 acl->rule_activity_update.interval = MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS;
897 mlxsw_core_schedule_dw(&acl->rule_activity_update.dw, 0);
898 return 0;
899
900 err_acl_ops_init:
901 mutex_destroy(&acl->rules_lock);
902 mlxsw_sp_fid_put(fid);
903 err_fid_get:
904 rhashtable_destroy(&acl->ruleset_ht);
905 err_rhashtable_init:
906 mlxsw_afk_destroy(acl->afk);
907 err_afk_create:
908 kfree(acl);
909 return err;
910 }
911
912 void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp)
913 {
914 struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
915
916 cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw);
917 mlxsw_sp_acl_tcam_fini(mlxsw_sp, &acl->tcam);
918 mutex_destroy(&acl->rules_lock);
919 WARN_ON(!list_empty(&acl->rules));
920 mlxsw_sp_fid_put(acl->dummy_fid);
921 rhashtable_destroy(&acl->ruleset_ht);
922 mlxsw_afk_destroy(acl->afk);
923 kfree(acl);
924 }
925
926 u32 mlxsw_sp_acl_region_rehash_intrvl_get(struct mlxsw_sp *mlxsw_sp)
927 {
928 struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
929
930 return mlxsw_sp_acl_tcam_vregion_rehash_intrvl_get(mlxsw_sp,
931 &acl->tcam);
932 }
933
934 int mlxsw_sp_acl_region_rehash_intrvl_set(struct mlxsw_sp *mlxsw_sp, u32 val)
935 {
936 struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
937
938 return mlxsw_sp_acl_tcam_vregion_rehash_intrvl_set(mlxsw_sp,
939 &acl->tcam, val);
940 }