2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <linux/kernel.h>
36 #include <linux/slab.h>
37 #include <linux/errno.h>
38 #include <linux/list.h>
39 #include <linux/string.h>
40 #include <linux/rhashtable.h>
41 #include <linux/netdevice.h>
42 #include <net/net_namespace.h>
43 #include <net/tc_act/tc_vlan.h>
47 #include "resources.h"
49 #include "core_acl_flex_keys.h"
50 #include "core_acl_flex_actions.h"
51 #include "spectrum_acl_flex_keys.h"
54 struct mlxsw_sp
*mlxsw_sp
;
55 struct mlxsw_afk
*afk
;
56 struct mlxsw_sp_fid
*dummy_fid
;
57 const struct mlxsw_sp_acl_ops
*ops
;
58 struct rhashtable ruleset_ht
;
59 struct list_head rules
;
61 struct delayed_work dw
;
62 unsigned long interval
; /* ms */
63 #define MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS 1000
64 } rule_activity_update
;
65 unsigned long priv
[0];
66 /* priv has to be always the last item */
69 struct mlxsw_afk
*mlxsw_sp_acl_afk(struct mlxsw_sp_acl
*acl
)
74 struct mlxsw_sp_acl_block_binding
{
75 struct list_head list
;
76 struct net_device
*dev
;
77 struct mlxsw_sp_port
*mlxsw_sp_port
;
81 struct mlxsw_sp_acl_block
{
82 struct list_head binding_list
;
83 struct mlxsw_sp_acl_ruleset
*ruleset_zero
;
84 struct mlxsw_sp
*mlxsw_sp
;
85 unsigned int rule_count
;
86 unsigned int disable_count
;
89 struct mlxsw_sp_acl_ruleset_ht_key
{
90 struct mlxsw_sp_acl_block
*block
;
92 const struct mlxsw_sp_acl_profile_ops
*ops
;
95 struct mlxsw_sp_acl_ruleset
{
96 struct rhash_head ht_node
; /* Member of acl HT */
97 struct mlxsw_sp_acl_ruleset_ht_key ht_key
;
98 struct rhashtable rule_ht
;
99 unsigned int ref_count
;
100 unsigned long priv
[0];
101 /* priv has to be always the last item */
104 struct mlxsw_sp_acl_rule
{
105 struct rhash_head ht_node
; /* Member of rule HT */
106 struct list_head list
;
107 unsigned long cookie
; /* HT key */
108 struct mlxsw_sp_acl_ruleset
*ruleset
;
109 struct mlxsw_sp_acl_rule_info
*rulei
;
113 unsigned long priv
[0];
114 /* priv has to be always the last item */
117 static const struct rhashtable_params mlxsw_sp_acl_ruleset_ht_params
= {
118 .key_len
= sizeof(struct mlxsw_sp_acl_ruleset_ht_key
),
119 .key_offset
= offsetof(struct mlxsw_sp_acl_ruleset
, ht_key
),
120 .head_offset
= offsetof(struct mlxsw_sp_acl_ruleset
, ht_node
),
121 .automatic_shrinking
= true,
124 static const struct rhashtable_params mlxsw_sp_acl_rule_ht_params
= {
125 .key_len
= sizeof(unsigned long),
126 .key_offset
= offsetof(struct mlxsw_sp_acl_rule
, cookie
),
127 .head_offset
= offsetof(struct mlxsw_sp_acl_rule
, ht_node
),
128 .automatic_shrinking
= true,
131 struct mlxsw_sp_fid
*mlxsw_sp_acl_dummy_fid(struct mlxsw_sp
*mlxsw_sp
)
133 return mlxsw_sp
->acl
->dummy_fid
;
136 struct mlxsw_sp
*mlxsw_sp_acl_block_mlxsw_sp(struct mlxsw_sp_acl_block
*block
)
138 return block
->mlxsw_sp
;
141 unsigned int mlxsw_sp_acl_block_rule_count(struct mlxsw_sp_acl_block
*block
)
143 return block
? block
->rule_count
: 0;
146 void mlxsw_sp_acl_block_disable_inc(struct mlxsw_sp_acl_block
*block
)
149 block
->disable_count
++;
152 void mlxsw_sp_acl_block_disable_dec(struct mlxsw_sp_acl_block
*block
)
155 block
->disable_count
--;
158 bool mlxsw_sp_acl_block_disabled(struct mlxsw_sp_acl_block
*block
)
160 return block
->disable_count
;
164 mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp
*mlxsw_sp
,
165 struct mlxsw_sp_acl_block
*block
,
166 struct mlxsw_sp_acl_block_binding
*binding
)
168 struct mlxsw_sp_acl_ruleset
*ruleset
= block
->ruleset_zero
;
169 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
171 return ops
->ruleset_bind(mlxsw_sp
, ruleset
->priv
,
172 binding
->mlxsw_sp_port
, binding
->ingress
);
176 mlxsw_sp_acl_ruleset_unbind(struct mlxsw_sp
*mlxsw_sp
,
177 struct mlxsw_sp_acl_block
*block
,
178 struct mlxsw_sp_acl_block_binding
*binding
)
180 struct mlxsw_sp_acl_ruleset
*ruleset
= block
->ruleset_zero
;
181 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
183 ops
->ruleset_unbind(mlxsw_sp
, ruleset
->priv
,
184 binding
->mlxsw_sp_port
, binding
->ingress
);
187 static bool mlxsw_sp_acl_ruleset_block_bound(struct mlxsw_sp_acl_block
*block
)
189 return block
->ruleset_zero
;
193 mlxsw_sp_acl_ruleset_block_bind(struct mlxsw_sp
*mlxsw_sp
,
194 struct mlxsw_sp_acl_ruleset
*ruleset
,
195 struct mlxsw_sp_acl_block
*block
)
197 struct mlxsw_sp_acl_block_binding
*binding
;
200 block
->ruleset_zero
= ruleset
;
201 list_for_each_entry(binding
, &block
->binding_list
, list
) {
202 err
= mlxsw_sp_acl_ruleset_bind(mlxsw_sp
, block
, binding
);
209 list_for_each_entry_continue_reverse(binding
, &block
->binding_list
,
211 mlxsw_sp_acl_ruleset_unbind(mlxsw_sp
, block
, binding
);
212 block
->ruleset_zero
= NULL
;
218 mlxsw_sp_acl_ruleset_block_unbind(struct mlxsw_sp
*mlxsw_sp
,
219 struct mlxsw_sp_acl_ruleset
*ruleset
,
220 struct mlxsw_sp_acl_block
*block
)
222 struct mlxsw_sp_acl_block_binding
*binding
;
224 list_for_each_entry(binding
, &block
->binding_list
, list
)
225 mlxsw_sp_acl_ruleset_unbind(mlxsw_sp
, block
, binding
);
226 block
->ruleset_zero
= NULL
;
229 struct mlxsw_sp_acl_block
*mlxsw_sp_acl_block_create(struct mlxsw_sp
*mlxsw_sp
,
232 struct mlxsw_sp_acl_block
*block
;
234 block
= kzalloc(sizeof(*block
), GFP_KERNEL
);
237 INIT_LIST_HEAD(&block
->binding_list
);
238 block
->mlxsw_sp
= mlxsw_sp
;
242 void mlxsw_sp_acl_block_destroy(struct mlxsw_sp_acl_block
*block
)
244 WARN_ON(!list_empty(&block
->binding_list
));
248 static struct mlxsw_sp_acl_block_binding
*
249 mlxsw_sp_acl_block_lookup(struct mlxsw_sp_acl_block
*block
,
250 struct mlxsw_sp_port
*mlxsw_sp_port
, bool ingress
)
252 struct mlxsw_sp_acl_block_binding
*binding
;
254 list_for_each_entry(binding
, &block
->binding_list
, list
)
255 if (binding
->mlxsw_sp_port
== mlxsw_sp_port
&&
256 binding
->ingress
== ingress
)
261 int mlxsw_sp_acl_block_bind(struct mlxsw_sp
*mlxsw_sp
,
262 struct mlxsw_sp_acl_block
*block
,
263 struct mlxsw_sp_port
*mlxsw_sp_port
,
266 struct mlxsw_sp_acl_block_binding
*binding
;
269 if (WARN_ON(mlxsw_sp_acl_block_lookup(block
, mlxsw_sp_port
, ingress
)))
272 binding
= kzalloc(sizeof(*binding
), GFP_KERNEL
);
275 binding
->mlxsw_sp_port
= mlxsw_sp_port
;
276 binding
->ingress
= ingress
;
278 if (mlxsw_sp_acl_ruleset_block_bound(block
)) {
279 err
= mlxsw_sp_acl_ruleset_bind(mlxsw_sp
, block
, binding
);
281 goto err_ruleset_bind
;
284 list_add(&binding
->list
, &block
->binding_list
);
292 int mlxsw_sp_acl_block_unbind(struct mlxsw_sp
*mlxsw_sp
,
293 struct mlxsw_sp_acl_block
*block
,
294 struct mlxsw_sp_port
*mlxsw_sp_port
,
297 struct mlxsw_sp_acl_block_binding
*binding
;
299 binding
= mlxsw_sp_acl_block_lookup(block
, mlxsw_sp_port
, ingress
);
303 list_del(&binding
->list
);
305 if (mlxsw_sp_acl_ruleset_block_bound(block
))
306 mlxsw_sp_acl_ruleset_unbind(mlxsw_sp
, block
, binding
);
312 static struct mlxsw_sp_acl_ruleset
*
313 mlxsw_sp_acl_ruleset_create(struct mlxsw_sp
*mlxsw_sp
,
314 struct mlxsw_sp_acl_block
*block
, u32 chain_index
,
315 const struct mlxsw_sp_acl_profile_ops
*ops
)
317 struct mlxsw_sp_acl
*acl
= mlxsw_sp
->acl
;
318 struct mlxsw_sp_acl_ruleset
*ruleset
;
322 alloc_size
= sizeof(*ruleset
) + ops
->ruleset_priv_size
;
323 ruleset
= kzalloc(alloc_size
, GFP_KERNEL
);
325 return ERR_PTR(-ENOMEM
);
326 ruleset
->ref_count
= 1;
327 ruleset
->ht_key
.block
= block
;
328 ruleset
->ht_key
.chain_index
= chain_index
;
329 ruleset
->ht_key
.ops
= ops
;
331 err
= rhashtable_init(&ruleset
->rule_ht
, &mlxsw_sp_acl_rule_ht_params
);
333 goto err_rhashtable_init
;
335 err
= ops
->ruleset_add(mlxsw_sp
, acl
->priv
, ruleset
->priv
);
337 goto err_ops_ruleset_add
;
339 err
= rhashtable_insert_fast(&acl
->ruleset_ht
, &ruleset
->ht_node
,
340 mlxsw_sp_acl_ruleset_ht_params
);
345 /* We only need ruleset with chain index 0, the implicit one,
346 * to be directly bound to device. The rest of the rulesets
347 * are bound by "Goto action set".
349 err
= mlxsw_sp_acl_ruleset_block_bind(mlxsw_sp
, ruleset
, block
);
351 goto err_ruleset_bind
;
357 rhashtable_remove_fast(&acl
->ruleset_ht
, &ruleset
->ht_node
,
358 mlxsw_sp_acl_ruleset_ht_params
);
360 ops
->ruleset_del(mlxsw_sp
, ruleset
->priv
);
362 rhashtable_destroy(&ruleset
->rule_ht
);
368 static void mlxsw_sp_acl_ruleset_destroy(struct mlxsw_sp
*mlxsw_sp
,
369 struct mlxsw_sp_acl_ruleset
*ruleset
)
371 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
372 struct mlxsw_sp_acl_block
*block
= ruleset
->ht_key
.block
;
373 u32 chain_index
= ruleset
->ht_key
.chain_index
;
374 struct mlxsw_sp_acl
*acl
= mlxsw_sp
->acl
;
377 mlxsw_sp_acl_ruleset_block_unbind(mlxsw_sp
, ruleset
, block
);
378 rhashtable_remove_fast(&acl
->ruleset_ht
, &ruleset
->ht_node
,
379 mlxsw_sp_acl_ruleset_ht_params
);
380 ops
->ruleset_del(mlxsw_sp
, ruleset
->priv
);
381 rhashtable_destroy(&ruleset
->rule_ht
);
385 static void mlxsw_sp_acl_ruleset_ref_inc(struct mlxsw_sp_acl_ruleset
*ruleset
)
387 ruleset
->ref_count
++;
390 static void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp
*mlxsw_sp
,
391 struct mlxsw_sp_acl_ruleset
*ruleset
)
393 if (--ruleset
->ref_count
)
395 mlxsw_sp_acl_ruleset_destroy(mlxsw_sp
, ruleset
);
398 static struct mlxsw_sp_acl_ruleset
*
399 __mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp_acl
*acl
,
400 struct mlxsw_sp_acl_block
*block
, u32 chain_index
,
401 const struct mlxsw_sp_acl_profile_ops
*ops
)
403 struct mlxsw_sp_acl_ruleset_ht_key ht_key
;
405 memset(&ht_key
, 0, sizeof(ht_key
));
406 ht_key
.block
= block
;
407 ht_key
.chain_index
= chain_index
;
409 return rhashtable_lookup_fast(&acl
->ruleset_ht
, &ht_key
,
410 mlxsw_sp_acl_ruleset_ht_params
);
413 struct mlxsw_sp_acl_ruleset
*
414 mlxsw_sp_acl_ruleset_lookup(struct mlxsw_sp
*mlxsw_sp
,
415 struct mlxsw_sp_acl_block
*block
, u32 chain_index
,
416 enum mlxsw_sp_acl_profile profile
)
418 const struct mlxsw_sp_acl_profile_ops
*ops
;
419 struct mlxsw_sp_acl
*acl
= mlxsw_sp
->acl
;
420 struct mlxsw_sp_acl_ruleset
*ruleset
;
422 ops
= acl
->ops
->profile_ops(mlxsw_sp
, profile
);
424 return ERR_PTR(-EINVAL
);
425 ruleset
= __mlxsw_sp_acl_ruleset_lookup(acl
, block
, chain_index
, ops
);
427 return ERR_PTR(-ENOENT
);
431 struct mlxsw_sp_acl_ruleset
*
432 mlxsw_sp_acl_ruleset_get(struct mlxsw_sp
*mlxsw_sp
,
433 struct mlxsw_sp_acl_block
*block
, u32 chain_index
,
434 enum mlxsw_sp_acl_profile profile
)
436 const struct mlxsw_sp_acl_profile_ops
*ops
;
437 struct mlxsw_sp_acl
*acl
= mlxsw_sp
->acl
;
438 struct mlxsw_sp_acl_ruleset
*ruleset
;
440 ops
= acl
->ops
->profile_ops(mlxsw_sp
, profile
);
442 return ERR_PTR(-EINVAL
);
444 ruleset
= __mlxsw_sp_acl_ruleset_lookup(acl
, block
, chain_index
, ops
);
446 mlxsw_sp_acl_ruleset_ref_inc(ruleset
);
449 return mlxsw_sp_acl_ruleset_create(mlxsw_sp
, block
, chain_index
, ops
);
452 void mlxsw_sp_acl_ruleset_put(struct mlxsw_sp
*mlxsw_sp
,
453 struct mlxsw_sp_acl_ruleset
*ruleset
)
455 mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp
, ruleset
);
458 u16
mlxsw_sp_acl_ruleset_group_id(struct mlxsw_sp_acl_ruleset
*ruleset
)
460 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
462 return ops
->ruleset_group_id(ruleset
->priv
);
465 struct mlxsw_sp_acl_rule_info
*
466 mlxsw_sp_acl_rulei_create(struct mlxsw_sp_acl
*acl
)
468 struct mlxsw_sp_acl_rule_info
*rulei
;
471 rulei
= kzalloc(sizeof(*rulei
), GFP_KERNEL
);
474 rulei
->act_block
= mlxsw_afa_block_create(acl
->mlxsw_sp
->afa
);
475 if (IS_ERR(rulei
->act_block
)) {
476 err
= PTR_ERR(rulei
->act_block
);
477 goto err_afa_block_create
;
481 err_afa_block_create
:
486 void mlxsw_sp_acl_rulei_destroy(struct mlxsw_sp_acl_rule_info
*rulei
)
488 mlxsw_afa_block_destroy(rulei
->act_block
);
492 int mlxsw_sp_acl_rulei_commit(struct mlxsw_sp_acl_rule_info
*rulei
)
494 return mlxsw_afa_block_commit(rulei
->act_block
);
497 void mlxsw_sp_acl_rulei_priority(struct mlxsw_sp_acl_rule_info
*rulei
,
498 unsigned int priority
)
500 rulei
->priority
= priority
;
503 void mlxsw_sp_acl_rulei_keymask_u32(struct mlxsw_sp_acl_rule_info
*rulei
,
504 enum mlxsw_afk_element element
,
505 u32 key_value
, u32 mask_value
)
507 mlxsw_afk_values_add_u32(&rulei
->values
, element
,
508 key_value
, mask_value
);
511 void mlxsw_sp_acl_rulei_keymask_buf(struct mlxsw_sp_acl_rule_info
*rulei
,
512 enum mlxsw_afk_element element
,
513 const char *key_value
,
514 const char *mask_value
, unsigned int len
)
516 mlxsw_afk_values_add_buf(&rulei
->values
, element
,
517 key_value
, mask_value
, len
);
520 int mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info
*rulei
)
522 return mlxsw_afa_block_continue(rulei
->act_block
);
525 int mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info
*rulei
,
528 return mlxsw_afa_block_jump(rulei
->act_block
, group_id
);
531 int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info
*rulei
)
533 return mlxsw_afa_block_append_drop(rulei
->act_block
);
536 int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info
*rulei
)
538 return mlxsw_afa_block_append_trap(rulei
->act_block
,
542 int mlxsw_sp_acl_rulei_act_fwd(struct mlxsw_sp
*mlxsw_sp
,
543 struct mlxsw_sp_acl_rule_info
*rulei
,
544 struct net_device
*out_dev
)
546 struct mlxsw_sp_port
*mlxsw_sp_port
;
551 if (!mlxsw_sp_port_dev_check(out_dev
))
553 mlxsw_sp_port
= netdev_priv(out_dev
);
554 if (mlxsw_sp_port
->mlxsw_sp
!= mlxsw_sp
)
556 local_port
= mlxsw_sp_port
->local_port
;
559 /* If out_dev is NULL, the caller wants to
560 * set forward to ingress port.
565 return mlxsw_afa_block_append_fwd(rulei
->act_block
,
566 local_port
, in_port
);
569 int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp
*mlxsw_sp
,
570 struct mlxsw_sp_acl_rule_info
*rulei
,
571 struct mlxsw_sp_acl_block
*block
,
572 struct net_device
*out_dev
)
574 struct mlxsw_sp_acl_block_binding
*binding
;
575 struct mlxsw_sp_port
*out_port
;
576 struct mlxsw_sp_port
*in_port
;
578 if (!list_is_singular(&block
->binding_list
))
581 binding
= list_first_entry(&block
->binding_list
,
582 struct mlxsw_sp_acl_block_binding
, list
);
583 in_port
= binding
->mlxsw_sp_port
;
584 if (!mlxsw_sp_port_dev_check(out_dev
))
587 out_port
= netdev_priv(out_dev
);
588 if (out_port
->mlxsw_sp
!= mlxsw_sp
)
591 return mlxsw_afa_block_append_mirror(rulei
->act_block
,
593 out_port
->local_port
,
597 int mlxsw_sp_acl_rulei_act_vlan(struct mlxsw_sp
*mlxsw_sp
,
598 struct mlxsw_sp_acl_rule_info
*rulei
,
599 u32 action
, u16 vid
, u16 proto
, u8 prio
)
603 if (action
== TCA_VLAN_ACT_MODIFY
) {
612 dev_err(mlxsw_sp
->bus_info
->dev
, "Unsupported VLAN protocol %#04x\n",
617 return mlxsw_afa_block_append_vlan_modify(rulei
->act_block
,
618 vid
, prio
, ethertype
);
620 dev_err(mlxsw_sp
->bus_info
->dev
, "Unsupported VLAN action\n");
625 int mlxsw_sp_acl_rulei_act_count(struct mlxsw_sp
*mlxsw_sp
,
626 struct mlxsw_sp_acl_rule_info
*rulei
)
628 return mlxsw_afa_block_append_counter(rulei
->act_block
,
629 &rulei
->counter_index
);
632 int mlxsw_sp_acl_rulei_act_fid_set(struct mlxsw_sp
*mlxsw_sp
,
633 struct mlxsw_sp_acl_rule_info
*rulei
,
636 return mlxsw_afa_block_append_fid_set(rulei
->act_block
, fid
);
639 struct mlxsw_sp_acl_rule
*
640 mlxsw_sp_acl_rule_create(struct mlxsw_sp
*mlxsw_sp
,
641 struct mlxsw_sp_acl_ruleset
*ruleset
,
642 unsigned long cookie
)
644 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
645 struct mlxsw_sp_acl_rule
*rule
;
648 mlxsw_sp_acl_ruleset_ref_inc(ruleset
);
649 rule
= kzalloc(sizeof(*rule
) + ops
->rule_priv_size
, GFP_KERNEL
);
654 rule
->cookie
= cookie
;
655 rule
->ruleset
= ruleset
;
657 rule
->rulei
= mlxsw_sp_acl_rulei_create(mlxsw_sp
->acl
);
658 if (IS_ERR(rule
->rulei
)) {
659 err
= PTR_ERR(rule
->rulei
);
660 goto err_rulei_create
;
668 mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp
, ruleset
);
672 void mlxsw_sp_acl_rule_destroy(struct mlxsw_sp
*mlxsw_sp
,
673 struct mlxsw_sp_acl_rule
*rule
)
675 struct mlxsw_sp_acl_ruleset
*ruleset
= rule
->ruleset
;
677 mlxsw_sp_acl_rulei_destroy(rule
->rulei
);
679 mlxsw_sp_acl_ruleset_ref_dec(mlxsw_sp
, ruleset
);
682 int mlxsw_sp_acl_rule_add(struct mlxsw_sp
*mlxsw_sp
,
683 struct mlxsw_sp_acl_rule
*rule
)
685 struct mlxsw_sp_acl_ruleset
*ruleset
= rule
->ruleset
;
686 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
689 err
= ops
->rule_add(mlxsw_sp
, ruleset
->priv
, rule
->priv
, rule
->rulei
);
693 err
= rhashtable_insert_fast(&ruleset
->rule_ht
, &rule
->ht_node
,
694 mlxsw_sp_acl_rule_ht_params
);
696 goto err_rhashtable_insert
;
698 list_add_tail(&rule
->list
, &mlxsw_sp
->acl
->rules
);
699 ruleset
->ht_key
.block
->rule_count
++;
702 err_rhashtable_insert
:
703 ops
->rule_del(mlxsw_sp
, rule
->priv
);
707 void mlxsw_sp_acl_rule_del(struct mlxsw_sp
*mlxsw_sp
,
708 struct mlxsw_sp_acl_rule
*rule
)
710 struct mlxsw_sp_acl_ruleset
*ruleset
= rule
->ruleset
;
711 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
713 ruleset
->ht_key
.block
->rule_count
--;
714 list_del(&rule
->list
);
715 rhashtable_remove_fast(&ruleset
->rule_ht
, &rule
->ht_node
,
716 mlxsw_sp_acl_rule_ht_params
);
717 ops
->rule_del(mlxsw_sp
, rule
->priv
);
720 struct mlxsw_sp_acl_rule
*
721 mlxsw_sp_acl_rule_lookup(struct mlxsw_sp
*mlxsw_sp
,
722 struct mlxsw_sp_acl_ruleset
*ruleset
,
723 unsigned long cookie
)
725 return rhashtable_lookup_fast(&ruleset
->rule_ht
, &cookie
,
726 mlxsw_sp_acl_rule_ht_params
);
729 struct mlxsw_sp_acl_rule_info
*
730 mlxsw_sp_acl_rule_rulei(struct mlxsw_sp_acl_rule
*rule
)
735 static int mlxsw_sp_acl_rule_activity_update(struct mlxsw_sp
*mlxsw_sp
,
736 struct mlxsw_sp_acl_rule
*rule
)
738 struct mlxsw_sp_acl_ruleset
*ruleset
= rule
->ruleset
;
739 const struct mlxsw_sp_acl_profile_ops
*ops
= ruleset
->ht_key
.ops
;
743 err
= ops
->rule_activity_get(mlxsw_sp
, rule
->priv
, &active
);
747 rule
->last_used
= jiffies
;
751 static int mlxsw_sp_acl_rules_activity_update(struct mlxsw_sp_acl
*acl
)
753 struct mlxsw_sp_acl_rule
*rule
;
756 /* Protect internal structures from changes */
758 list_for_each_entry(rule
, &acl
->rules
, list
) {
759 err
= mlxsw_sp_acl_rule_activity_update(acl
->mlxsw_sp
,
762 goto err_rule_update
;
772 static void mlxsw_sp_acl_rule_activity_work_schedule(struct mlxsw_sp_acl
*acl
)
774 unsigned long interval
= acl
->rule_activity_update
.interval
;
776 mlxsw_core_schedule_dw(&acl
->rule_activity_update
.dw
,
777 msecs_to_jiffies(interval
));
780 static void mlxsw_sp_acl_rul_activity_update_work(struct work_struct
*work
)
782 struct mlxsw_sp_acl
*acl
= container_of(work
, struct mlxsw_sp_acl
,
783 rule_activity_update
.dw
.work
);
786 err
= mlxsw_sp_acl_rules_activity_update(acl
);
788 dev_err(acl
->mlxsw_sp
->bus_info
->dev
, "Could not update acl activity");
790 mlxsw_sp_acl_rule_activity_work_schedule(acl
);
793 int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp
*mlxsw_sp
,
794 struct mlxsw_sp_acl_rule
*rule
,
795 u64
*packets
, u64
*bytes
, u64
*last_use
)
798 struct mlxsw_sp_acl_rule_info
*rulei
;
803 rulei
= mlxsw_sp_acl_rule_rulei(rule
);
804 err
= mlxsw_sp_flow_counter_get(mlxsw_sp
, rulei
->counter_index
,
805 ¤t_packets
, ¤t_bytes
);
809 *packets
= current_packets
- rule
->last_packets
;
810 *bytes
= current_bytes
- rule
->last_bytes
;
811 *last_use
= rule
->last_used
;
813 rule
->last_bytes
= current_bytes
;
814 rule
->last_packets
= current_packets
;
819 int mlxsw_sp_acl_init(struct mlxsw_sp
*mlxsw_sp
)
821 const struct mlxsw_sp_acl_ops
*acl_ops
= &mlxsw_sp_acl_tcam_ops
;
822 struct mlxsw_sp_fid
*fid
;
823 struct mlxsw_sp_acl
*acl
;
826 acl
= kzalloc(sizeof(*acl
) + acl_ops
->priv_size
, GFP_KERNEL
);
830 acl
->mlxsw_sp
= mlxsw_sp
;
831 acl
->afk
= mlxsw_afk_create(MLXSW_CORE_RES_GET(mlxsw_sp
->core
,
834 MLXSW_SP_AFK_BLOCKS_COUNT
);
840 err
= rhashtable_init(&acl
->ruleset_ht
,
841 &mlxsw_sp_acl_ruleset_ht_params
);
843 goto err_rhashtable_init
;
845 fid
= mlxsw_sp_fid_dummy_get(mlxsw_sp
);
850 acl
->dummy_fid
= fid
;
852 INIT_LIST_HEAD(&acl
->rules
);
853 err
= acl_ops
->init(mlxsw_sp
, acl
->priv
);
855 goto err_acl_ops_init
;
859 /* Create the delayed work for the rule activity_update */
860 INIT_DELAYED_WORK(&acl
->rule_activity_update
.dw
,
861 mlxsw_sp_acl_rul_activity_update_work
);
862 acl
->rule_activity_update
.interval
= MLXSW_SP_ACL_RULE_ACTIVITY_UPDATE_PERIOD_MS
;
863 mlxsw_core_schedule_dw(&acl
->rule_activity_update
.dw
, 0);
867 mlxsw_sp_fid_put(fid
);
869 rhashtable_destroy(&acl
->ruleset_ht
);
871 mlxsw_afk_destroy(acl
->afk
);
877 void mlxsw_sp_acl_fini(struct mlxsw_sp
*mlxsw_sp
)
879 struct mlxsw_sp_acl
*acl
= mlxsw_sp
->acl
;
880 const struct mlxsw_sp_acl_ops
*acl_ops
= acl
->ops
;
882 cancel_delayed_work_sync(&mlxsw_sp
->acl
->rule_activity_update
.dw
);
883 acl_ops
->fini(mlxsw_sp
, acl
->priv
);
884 WARN_ON(!list_empty(&acl
->rules
));
885 mlxsw_sp_fid_put(acl
->dummy_fid
);
886 rhashtable_destroy(&acl
->ruleset_ht
);
887 mlxsw_afk_destroy(acl
->afk
);