net: sched: notify classifier on successful offload add/delete
To remove dependency on rtnl lock, extend classifier ops with new ops->hw_add() and ops->hw_del() callbacks. Call them from cls API while holding cb_lock every time filter if successfully added to or deleted from hardware. Implement the new API in flower classifier. Use it to manage hw_filters list under cb_lock protection, instead of relying on rtnl lock to synchronize with concurrent fl_reoffload() call. Signed-off-by: Vlad Buslov <vladbu@mellanox.com> Acked-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
4011921137
commit
a449a3e77a
@@ -421,9 +421,6 @@ static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
|
||||
|
||||
tc_setup_cb_destroy(block, tp, TC_SETUP_CLSFLOWER, &cls_flower, false,
|
||||
&f->flags, &f->in_hw_count, true);
|
||||
spin_lock(&tp->lock);
|
||||
list_del_init(&f->hw_list);
|
||||
spin_unlock(&tp->lock);
|
||||
|
||||
if (!rtnl_held)
|
||||
rtnl_unlock();
|
||||
@@ -433,7 +430,6 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
|
||||
struct cls_fl_filter *f, bool rtnl_held,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
struct tcf_block *block = tp->chain->block;
|
||||
struct flow_cls_offload cls_flower = {};
|
||||
bool skip_sw = tc_skip_sw(f->flags);
|
||||
@@ -480,9 +476,6 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
|
||||
goto errout;
|
||||
}
|
||||
|
||||
spin_lock(&tp->lock);
|
||||
list_add(&f->hw_list, &head->hw_filters);
|
||||
spin_unlock(&tp->lock);
|
||||
errout:
|
||||
if (!rtnl_held)
|
||||
rtnl_unlock();
|
||||
@@ -1856,6 +1849,30 @@ next_flow:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fl_hw_add(struct tcf_proto *tp, void *type_data)
|
||||
{
|
||||
struct flow_cls_offload *cls_flower = type_data;
|
||||
struct cls_fl_filter *f =
|
||||
(struct cls_fl_filter *) cls_flower->cookie;
|
||||
struct cls_fl_head *head = fl_head_dereference(tp);
|
||||
|
||||
spin_lock(&tp->lock);
|
||||
list_add(&f->hw_list, &head->hw_filters);
|
||||
spin_unlock(&tp->lock);
|
||||
}
|
||||
|
||||
static void fl_hw_del(struct tcf_proto *tp, void *type_data)
|
||||
{
|
||||
struct flow_cls_offload *cls_flower = type_data;
|
||||
struct cls_fl_filter *f =
|
||||
(struct cls_fl_filter *) cls_flower->cookie;
|
||||
|
||||
spin_lock(&tp->lock);
|
||||
if (!list_empty(&f->hw_list))
|
||||
list_del_init(&f->hw_list);
|
||||
spin_unlock(&tp->lock);
|
||||
}
|
||||
|
||||
static int fl_hw_create_tmplt(struct tcf_chain *chain,
|
||||
struct fl_flow_tmplt *tmplt)
|
||||
{
|
||||
@@ -2516,6 +2533,8 @@ static struct tcf_proto_ops cls_fl_ops __read_mostly = {
|
||||
.delete = fl_delete,
|
||||
.walk = fl_walk,
|
||||
.reoffload = fl_reoffload,
|
||||
.hw_add = fl_hw_add,
|
||||
.hw_del = fl_hw_del,
|
||||
.dump = fl_dump,
|
||||
.bind_class = fl_bind_class,
|
||||
.tmplt_create = fl_tmplt_create,
|
||||
|
Reference in New Issue
Block a user