Commit 131f1ed3 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-sched-propagate-extack-to-cls-offloads-on-destroy-and-only-with-skip_sw'

Jakub Kicinski says:

====================
net: sched: propagate extack to cls offloads on destroy and only with skip_sw

This series some of Jiri's comments and the fact that today drivers
may produce extack even if there is no skip_sw flag (meaning the
driver failure is not really a problem), and warning messages will
only confuse the users.

First patch propagates extack to destroy as requested by Jiri, extack
is then propagated to the driver callback for each classifier.  I chose
not to provide the extack on error paths.  As a rule of thumb it seems
best to keep the extack of the condition which caused the error.  E.g.

     err = this_will_fail(arg, extack);
     if (err) {
        undo_things(arg, NULL /* don't pass extack */);
	return err;
     }

Note that NL_SET_ERR_MSG() will ignore the message if extack is NULL.
I was pondering whether we should make NL_SET_ERR_MSG() refuse to
overwrite the msg, but there seem to be cases in the tree where extack
is set like this:

     err = this_will_fail(arg, extack);
     if (err) {
        undo_things(arg, NULL /* don't pass extack */);
	NL_SET_ERR_MSG(extack, "extack is set after undo call :/");
	return err;
     }

I think not passing extack to undo calls is reasonable.

v2:
 - rename the temporary tc_cls_common_offload_init().
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 46410c2e c846adb6
...@@ -605,17 +605,6 @@ struct tc_cls_common_offload { ...@@ -605,17 +605,6 @@ struct tc_cls_common_offload {
struct netlink_ext_ack *extack; struct netlink_ext_ack *extack;
}; };
static inline void
tc_cls_common_offload_init(struct tc_cls_common_offload *cls_common,
const struct tcf_proto *tp,
struct netlink_ext_ack *extack)
{
cls_common->chain_index = tp->chain->index;
cls_common->protocol = tp->protocol;
cls_common->prio = tp->prio;
cls_common->extack = extack;
}
struct tc_cls_u32_knode { struct tc_cls_u32_knode {
struct tcf_exts *exts; struct tcf_exts *exts;
struct tc_u32_sel *sel; struct tc_u32_sel *sel;
...@@ -694,6 +683,18 @@ static inline bool tc_in_hw(u32 flags) ...@@ -694,6 +683,18 @@ static inline bool tc_in_hw(u32 flags)
return (flags & TCA_CLS_FLAGS_IN_HW) ? true : false; return (flags & TCA_CLS_FLAGS_IN_HW) ? true : false;
} }
static inline void
tc_cls_common_offload_init(struct tc_cls_common_offload *cls_common,
const struct tcf_proto *tp, u32 flags,
struct netlink_ext_ack *extack)
{
cls_common->chain_index = tp->chain->index;
cls_common->protocol = tp->protocol;
cls_common->prio = tp->prio;
if (tc_skip_sw(flags))
cls_common->extack = extack;
}
enum tc_fl_command { enum tc_fl_command {
TC_CLSFLOWER_REPLACE, TC_CLSFLOWER_REPLACE,
TC_CLSFLOWER_DESTROY, TC_CLSFLOWER_DESTROY,
...@@ -736,7 +737,6 @@ struct tc_cls_bpf_offload { ...@@ -736,7 +737,6 @@ struct tc_cls_bpf_offload {
struct bpf_prog *oldprog; struct bpf_prog *oldprog;
const char *name; const char *name;
bool exts_integrated; bool exts_integrated;
u32 gen_flags;
}; };
struct tc_mqprio_qopt_offload { struct tc_mqprio_qopt_offload {
......
...@@ -233,7 +233,8 @@ struct tcf_proto_ops { ...@@ -233,7 +233,8 @@ struct tcf_proto_ops {
const struct tcf_proto *, const struct tcf_proto *,
struct tcf_result *); struct tcf_result *);
int (*init)(struct tcf_proto*); int (*init)(struct tcf_proto*);
void (*destroy)(struct tcf_proto*); void (*destroy)(struct tcf_proto *tp,
struct netlink_ext_ack *extack);
void* (*get)(struct tcf_proto*, u32 handle); void* (*get)(struct tcf_proto*, u32 handle);
int (*change)(struct net *net, struct sk_buff *, int (*change)(struct net *net, struct sk_buff *,
......
...@@ -172,9 +172,10 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol, ...@@ -172,9 +172,10 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
return ERR_PTR(err); return ERR_PTR(err);
} }
static void tcf_proto_destroy(struct tcf_proto *tp) static void tcf_proto_destroy(struct tcf_proto *tp,
struct netlink_ext_ack *extack)
{ {
tp->ops->destroy(tp); tp->ops->destroy(tp, extack);
module_put(tp->ops->owner); module_put(tp->ops->owner);
kfree_rcu(tp, rcu); kfree_rcu(tp, rcu);
} }
...@@ -223,7 +224,7 @@ static void tcf_chain_flush(struct tcf_chain *chain) ...@@ -223,7 +224,7 @@ static void tcf_chain_flush(struct tcf_chain *chain)
tcf_chain_head_change(chain, NULL); tcf_chain_head_change(chain, NULL);
while (tp) { while (tp) {
RCU_INIT_POINTER(chain->filter_chain, tp->next); RCU_INIT_POINTER(chain->filter_chain, tp->next);
tcf_proto_destroy(tp); tcf_proto_destroy(tp, NULL);
tp = rtnl_dereference(chain->filter_chain); tp = rtnl_dereference(chain->filter_chain);
tcf_chain_put(chain); tcf_chain_put(chain);
} }
...@@ -1182,7 +1183,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, ...@@ -1182,7 +1183,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
tcf_chain_tp_remove(chain, &chain_info, tp); tcf_chain_tp_remove(chain, &chain_info, tp);
tfilter_notify(net, skb, n, tp, block, q, parent, fh, tfilter_notify(net, skb, n, tp, block, q, parent, fh,
RTM_DELTFILTER, false); RTM_DELTFILTER, false);
tcf_proto_destroy(tp); tcf_proto_destroy(tp, extack);
err = 0; err = 0;
goto errout; goto errout;
} }
...@@ -1200,7 +1201,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, ...@@ -1200,7 +1201,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
case RTM_NEWTFILTER: case RTM_NEWTFILTER:
if (n->nlmsg_flags & NLM_F_EXCL) { if (n->nlmsg_flags & NLM_F_EXCL) {
if (tp_created) if (tp_created)
tcf_proto_destroy(tp); tcf_proto_destroy(tp, NULL);
NL_SET_ERR_MSG(extack, "Filter already exists"); NL_SET_ERR_MSG(extack, "Filter already exists");
err = -EEXIST; err = -EEXIST;
goto errout; goto errout;
...@@ -1214,7 +1215,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, ...@@ -1214,7 +1215,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
goto errout; goto errout;
if (last) { if (last) {
tcf_chain_tp_remove(chain, &chain_info, tp); tcf_chain_tp_remove(chain, &chain_info, tp);
tcf_proto_destroy(tp); tcf_proto_destroy(tp, extack);
} }
goto errout; goto errout;
case RTM_GETTFILTER: case RTM_GETTFILTER:
...@@ -1240,7 +1241,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, ...@@ -1240,7 +1241,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
RTM_NEWTFILTER, false); RTM_NEWTFILTER, false);
} else { } else {
if (tp_created) if (tp_created)
tcf_proto_destroy(tp); tcf_proto_destroy(tp, NULL);
} }
errout: errout:
......
...@@ -112,7 +112,7 @@ static void basic_delete_filter(struct rcu_head *head) ...@@ -112,7 +112,7 @@ static void basic_delete_filter(struct rcu_head *head)
tcf_queue_work(&f->work); tcf_queue_work(&f->work);
} }
static void basic_destroy(struct tcf_proto *tp) static void basic_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct basic_head *head = rtnl_dereference(tp->root); struct basic_head *head = rtnl_dereference(tp->root);
struct basic_filter *f, *n; struct basic_filter *f, *n;
......
...@@ -159,14 +159,14 @@ static int cls_bpf_offload_cmd(struct tcf_proto *tp, struct cls_bpf_prog *prog, ...@@ -159,14 +159,14 @@ static int cls_bpf_offload_cmd(struct tcf_proto *tp, struct cls_bpf_prog *prog,
skip_sw = prog && tc_skip_sw(prog->gen_flags); skip_sw = prog && tc_skip_sw(prog->gen_flags);
obj = prog ?: oldprog; obj = prog ?: oldprog;
tc_cls_common_offload_init(&cls_bpf.common, tp, extack); tc_cls_common_offload_init(&cls_bpf.common, tp, obj->gen_flags,
extack);
cls_bpf.command = TC_CLSBPF_OFFLOAD; cls_bpf.command = TC_CLSBPF_OFFLOAD;
cls_bpf.exts = &obj->exts; cls_bpf.exts = &obj->exts;
cls_bpf.prog = prog ? prog->filter : NULL; cls_bpf.prog = prog ? prog->filter : NULL;
cls_bpf.oldprog = oldprog ? oldprog->filter : NULL; cls_bpf.oldprog = oldprog ? oldprog->filter : NULL;
cls_bpf.name = obj->bpf_name; cls_bpf.name = obj->bpf_name;
cls_bpf.exts_integrated = obj->exts_integrated; cls_bpf.exts_integrated = obj->exts_integrated;
cls_bpf.gen_flags = obj->gen_flags;
if (oldprog) if (oldprog)
tcf_block_offload_dec(block, &oldprog->gen_flags); tcf_block_offload_dec(block, &oldprog->gen_flags);
...@@ -212,11 +212,12 @@ static int cls_bpf_offload(struct tcf_proto *tp, struct cls_bpf_prog *prog, ...@@ -212,11 +212,12 @@ static int cls_bpf_offload(struct tcf_proto *tp, struct cls_bpf_prog *prog,
} }
static void cls_bpf_stop_offload(struct tcf_proto *tp, static void cls_bpf_stop_offload(struct tcf_proto *tp,
struct cls_bpf_prog *prog) struct cls_bpf_prog *prog,
struct netlink_ext_ack *extack)
{ {
int err; int err;
err = cls_bpf_offload_cmd(tp, NULL, prog, NULL); err = cls_bpf_offload_cmd(tp, NULL, prog, extack);
if (err) if (err)
pr_err("Stopping hardware offload failed: %d\n", err); pr_err("Stopping hardware offload failed: %d\n", err);
} }
...@@ -227,13 +228,12 @@ static void cls_bpf_offload_update_stats(struct tcf_proto *tp, ...@@ -227,13 +228,12 @@ static void cls_bpf_offload_update_stats(struct tcf_proto *tp,
struct tcf_block *block = tp->chain->block; struct tcf_block *block = tp->chain->block;
struct tc_cls_bpf_offload cls_bpf = {}; struct tc_cls_bpf_offload cls_bpf = {};
tc_cls_common_offload_init(&cls_bpf.common, tp, NULL); tc_cls_common_offload_init(&cls_bpf.common, tp, prog->gen_flags, NULL);
cls_bpf.command = TC_CLSBPF_STATS; cls_bpf.command = TC_CLSBPF_STATS;
cls_bpf.exts = &prog->exts; cls_bpf.exts = &prog->exts;
cls_bpf.prog = prog->filter; cls_bpf.prog = prog->filter;
cls_bpf.name = prog->bpf_name; cls_bpf.name = prog->bpf_name;
cls_bpf.exts_integrated = prog->exts_integrated; cls_bpf.exts_integrated = prog->exts_integrated;
cls_bpf.gen_flags = prog->gen_flags;
tc_setup_cb_call(block, NULL, TC_SETUP_CLSBPF, &cls_bpf, false); tc_setup_cb_call(block, NULL, TC_SETUP_CLSBPF, &cls_bpf, false);
} }
...@@ -290,12 +290,13 @@ static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu) ...@@ -290,12 +290,13 @@ static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu)
tcf_queue_work(&prog->work); tcf_queue_work(&prog->work);
} }
static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog) static void __cls_bpf_delete(struct tcf_proto *tp, struct cls_bpf_prog *prog,
struct netlink_ext_ack *extack)
{ {
struct cls_bpf_head *head = rtnl_dereference(tp->root); struct cls_bpf_head *head = rtnl_dereference(tp->root);
idr_remove_ext(&head->handle_idr, prog->handle); idr_remove_ext(&head->handle_idr, prog->handle);
cls_bpf_stop_offload(tp, prog); cls_bpf_stop_offload(tp, prog, extack);
list_del_rcu(&prog->link); list_del_rcu(&prog->link);
tcf_unbind_filter(tp, &prog->res); tcf_unbind_filter(tp, &prog->res);
if (tcf_exts_get_net(&prog->exts)) if (tcf_exts_get_net(&prog->exts))
...@@ -309,18 +310,19 @@ static int cls_bpf_delete(struct tcf_proto *tp, void *arg, bool *last, ...@@ -309,18 +310,19 @@ static int cls_bpf_delete(struct tcf_proto *tp, void *arg, bool *last,
{ {
struct cls_bpf_head *head = rtnl_dereference(tp->root); struct cls_bpf_head *head = rtnl_dereference(tp->root);
__cls_bpf_delete(tp, arg); __cls_bpf_delete(tp, arg, extack);
*last = list_empty(&head->plist); *last = list_empty(&head->plist);
return 0; return 0;
} }
static void cls_bpf_destroy(struct tcf_proto *tp) static void cls_bpf_destroy(struct tcf_proto *tp,
struct netlink_ext_ack *extack)
{ {
struct cls_bpf_head *head = rtnl_dereference(tp->root); struct cls_bpf_head *head = rtnl_dereference(tp->root);
struct cls_bpf_prog *prog, *tmp; struct cls_bpf_prog *prog, *tmp;
list_for_each_entry_safe(prog, tmp, &head->plist, link) list_for_each_entry_safe(prog, tmp, &head->plist, link)
__cls_bpf_delete(tp, prog); __cls_bpf_delete(tp, prog, extack);
idr_destroy(&head->handle_idr); idr_destroy(&head->handle_idr);
kfree_rcu(head, rcu); kfree_rcu(head, rcu);
......
...@@ -143,7 +143,8 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, ...@@ -143,7 +143,8 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
return err; return err;
} }
static void cls_cgroup_destroy(struct tcf_proto *tp) static void cls_cgroup_destroy(struct tcf_proto *tp,
struct netlink_ext_ack *extack)
{ {
struct cls_cgroup_head *head = rtnl_dereference(tp->root); struct cls_cgroup_head *head = rtnl_dereference(tp->root);
......
...@@ -600,7 +600,7 @@ static int flow_init(struct tcf_proto *tp) ...@@ -600,7 +600,7 @@ static int flow_init(struct tcf_proto *tp)
return 0; return 0;
} }
static void flow_destroy(struct tcf_proto *tp) static void flow_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct flow_head *head = rtnl_dereference(tp->root); struct flow_head *head = rtnl_dereference(tp->root);
struct flow_filter *f, *next; struct flow_filter *f, *next;
......
...@@ -218,12 +218,13 @@ static void fl_destroy_filter(struct rcu_head *head) ...@@ -218,12 +218,13 @@ static void fl_destroy_filter(struct rcu_head *head)
tcf_queue_work(&f->work); tcf_queue_work(&f->work);
} }
static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f) static void fl_hw_destroy_filter(struct tcf_proto *tp, struct cls_fl_filter *f,
struct netlink_ext_ack *extack)
{ {
struct tc_cls_flower_offload cls_flower = {}; struct tc_cls_flower_offload cls_flower = {};
struct tcf_block *block = tp->chain->block; struct tcf_block *block = tp->chain->block;
tc_cls_common_offload_init(&cls_flower.common, tp, NULL); tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
cls_flower.command = TC_CLSFLOWER_DESTROY; cls_flower.command = TC_CLSFLOWER_DESTROY;
cls_flower.cookie = (unsigned long) f; cls_flower.cookie = (unsigned long) f;
...@@ -243,7 +244,7 @@ static int fl_hw_replace_filter(struct tcf_proto *tp, ...@@ -243,7 +244,7 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
bool skip_sw = tc_skip_sw(f->flags); bool skip_sw = tc_skip_sw(f->flags);
int err; int err;
tc_cls_common_offload_init(&cls_flower.common, tp, extack); tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
cls_flower.command = TC_CLSFLOWER_REPLACE; cls_flower.command = TC_CLSFLOWER_REPLACE;
cls_flower.cookie = (unsigned long) f; cls_flower.cookie = (unsigned long) f;
cls_flower.dissector = dissector; cls_flower.dissector = dissector;
...@@ -255,7 +256,7 @@ static int fl_hw_replace_filter(struct tcf_proto *tp, ...@@ -255,7 +256,7 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER, err = tc_setup_cb_call(block, &f->exts, TC_SETUP_CLSFLOWER,
&cls_flower, skip_sw); &cls_flower, skip_sw);
if (err < 0) { if (err < 0) {
fl_hw_destroy_filter(tp, f); fl_hw_destroy_filter(tp, f, NULL);
return err; return err;
} else if (err > 0) { } else if (err > 0) {
tcf_block_offload_inc(block, &f->flags); tcf_block_offload_inc(block, &f->flags);
...@@ -272,7 +273,7 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) ...@@ -272,7 +273,7 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
struct tc_cls_flower_offload cls_flower = {}; struct tc_cls_flower_offload cls_flower = {};
struct tcf_block *block = tp->chain->block; struct tcf_block *block = tp->chain->block;
tc_cls_common_offload_init(&cls_flower.common, tp, NULL); tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, NULL);
cls_flower.command = TC_CLSFLOWER_STATS; cls_flower.command = TC_CLSFLOWER_STATS;
cls_flower.cookie = (unsigned long) f; cls_flower.cookie = (unsigned long) f;
cls_flower.exts = &f->exts; cls_flower.exts = &f->exts;
...@@ -282,14 +283,15 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f) ...@@ -282,14 +283,15 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
&cls_flower, false); &cls_flower, false);
} }
static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f) static void __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,
struct netlink_ext_ack *extack)
{ {
struct cls_fl_head *head = rtnl_dereference(tp->root); struct cls_fl_head *head = rtnl_dereference(tp->root);
idr_remove_ext(&head->handle_idr, f->handle); idr_remove_ext(&head->handle_idr, f->handle);
list_del_rcu(&f->list); list_del_rcu(&f->list);
if (!tc_skip_hw(f->flags)) if (!tc_skip_hw(f->flags))
fl_hw_destroy_filter(tp, f); fl_hw_destroy_filter(tp, f, extack);
tcf_unbind_filter(tp, &f->res); tcf_unbind_filter(tp, &f->res);
if (tcf_exts_get_net(&f->exts)) if (tcf_exts_get_net(&f->exts))
call_rcu(&f->rcu, fl_destroy_filter); call_rcu(&f->rcu, fl_destroy_filter);
...@@ -315,13 +317,13 @@ static void fl_destroy_rcu(struct rcu_head *rcu) ...@@ -315,13 +317,13 @@ static void fl_destroy_rcu(struct rcu_head *rcu)
schedule_work(&head->work); schedule_work(&head->work);
} }
static void fl_destroy(struct tcf_proto *tp) static void fl_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct cls_fl_head *head = rtnl_dereference(tp->root); struct cls_fl_head *head = rtnl_dereference(tp->root);
struct cls_fl_filter *f, *next; struct cls_fl_filter *f, *next;
list_for_each_entry_safe(f, next, &head->filters, list) list_for_each_entry_safe(f, next, &head->filters, list)
__fl_delete(tp, f); __fl_delete(tp, f, extack);
idr_destroy(&head->handle_idr); idr_destroy(&head->handle_idr);
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
...@@ -958,7 +960,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb, ...@@ -958,7 +960,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
rhashtable_remove_fast(&head->ht, &fold->ht_node, rhashtable_remove_fast(&head->ht, &fold->ht_node,
head->ht_params); head->ht_params);
if (!tc_skip_hw(fold->flags)) if (!tc_skip_hw(fold->flags))
fl_hw_destroy_filter(tp, fold); fl_hw_destroy_filter(tp, fold, NULL);
} }
*arg = fnew; *arg = fnew;
...@@ -997,7 +999,7 @@ static int fl_delete(struct tcf_proto *tp, void *arg, bool *last, ...@@ -997,7 +999,7 @@ static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
if (!tc_skip_sw(f->flags)) if (!tc_skip_sw(f->flags))
rhashtable_remove_fast(&head->ht, &f->ht_node, rhashtable_remove_fast(&head->ht, &f->ht_node,
head->ht_params); head->ht_params);
__fl_delete(tp, f); __fl_delete(tp, f, extack);
*last = list_empty(&head->filters); *last = list_empty(&head->filters);
return 0; return 0;
} }
......
...@@ -149,7 +149,7 @@ static void fw_delete_filter(struct rcu_head *head) ...@@ -149,7 +149,7 @@ static void fw_delete_filter(struct rcu_head *head)
tcf_queue_work(&f->work); tcf_queue_work(&f->work);
} }
static void fw_destroy(struct tcf_proto *tp) static void fw_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct fw_head *head = rtnl_dereference(tp->root); struct fw_head *head = rtnl_dereference(tp->root);
struct fw_filter *f; struct fw_filter *f;
......
...@@ -71,12 +71,13 @@ static void mall_destroy_rcu(struct rcu_head *rcu) ...@@ -71,12 +71,13 @@ static void mall_destroy_rcu(struct rcu_head *rcu)
static void mall_destroy_hw_filter(struct tcf_proto *tp, static void mall_destroy_hw_filter(struct tcf_proto *tp,
struct cls_mall_head *head, struct cls_mall_head *head,
unsigned long cookie) unsigned long cookie,
struct netlink_ext_ack *extack)
{ {
struct tc_cls_matchall_offload cls_mall = {}; struct tc_cls_matchall_offload cls_mall = {};
struct tcf_block *block = tp->chain->block; struct tcf_block *block = tp->chain->block;
tc_cls_common_offload_init(&cls_mall.common, tp, NULL); tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack);
cls_mall.command = TC_CLSMATCHALL_DESTROY; cls_mall.command = TC_CLSMATCHALL_DESTROY;
cls_mall.cookie = cookie; cls_mall.cookie = cookie;
...@@ -94,7 +95,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp, ...@@ -94,7 +95,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
bool skip_sw = tc_skip_sw(head->flags); bool skip_sw = tc_skip_sw(head->flags);
int err; int err;
tc_cls_common_offload_init(&cls_mall.common, tp, extack); tc_cls_common_offload_init(&cls_mall.common, tp, head->flags, extack);
cls_mall.command = TC_CLSMATCHALL_REPLACE; cls_mall.command = TC_CLSMATCHALL_REPLACE;
cls_mall.exts = &head->exts; cls_mall.exts = &head->exts;
cls_mall.cookie = cookie; cls_mall.cookie = cookie;
...@@ -102,7 +103,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp, ...@@ -102,7 +103,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSMATCHALL, err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSMATCHALL,
&cls_mall, skip_sw); &cls_mall, skip_sw);
if (err < 0) { if (err < 0) {
mall_destroy_hw_filter(tp, head, cookie); mall_destroy_hw_filter(tp, head, cookie, NULL);
return err; return err;
} else if (err > 0) { } else if (err > 0) {
tcf_block_offload_inc(block, &head->flags); tcf_block_offload_inc(block, &head->flags);
...@@ -114,7 +115,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp, ...@@ -114,7 +115,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
return 0; return 0;
} }
static void mall_destroy(struct tcf_proto *tp) static void mall_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct cls_mall_head *head = rtnl_dereference(tp->root); struct cls_mall_head *head = rtnl_dereference(tp->root);
...@@ -122,7 +123,7 @@ static void mall_destroy(struct tcf_proto *tp) ...@@ -122,7 +123,7 @@ static void mall_destroy(struct tcf_proto *tp)
return; return;
if (!tc_skip_hw(head->flags)) if (!tc_skip_hw(head->flags))
mall_destroy_hw_filter(tp, head, (unsigned long) head); mall_destroy_hw_filter(tp, head, (unsigned long) head, extack);
if (tcf_exts_get_net(&head->exts)) if (tcf_exts_get_net(&head->exts))
call_rcu(&head->rcu, mall_destroy_rcu); call_rcu(&head->rcu, mall_destroy_rcu);
......
...@@ -281,7 +281,7 @@ static void route4_delete_filter(struct rcu_head *head) ...@@ -281,7 +281,7 @@ static void route4_delete_filter(struct rcu_head *head)
tcf_queue_work(&f->work); tcf_queue_work(&f->work);
} }
static void route4_destroy(struct tcf_proto *tp) static void route4_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct route4_head *head = rtnl_dereference(tp->root); struct route4_head *head = rtnl_dereference(tp->root);
int h1, h2; int h1, h2;
......
...@@ -322,7 +322,7 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) ...@@ -322,7 +322,7 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f)
__rsvp_delete_filter(f); __rsvp_delete_filter(f);
} }
static void rsvp_destroy(struct tcf_proto *tp) static void rsvp_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct rsvp_head *data = rtnl_dereference(tp->root); struct rsvp_head *data = rtnl_dereference(tp->root);
int h1, h2; int h1, h2;
......
...@@ -581,7 +581,8 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker) ...@@ -581,7 +581,8 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
} }
} }
static void tcindex_destroy(struct tcf_proto *tp) static void tcindex_destroy(struct tcf_proto *tp,
struct netlink_ext_ack *extack)
{ {
struct tcindex_data *p = rtnl_dereference(tp->root); struct tcindex_data *p = rtnl_dereference(tp->root);
struct tcf_walker walker; struct tcf_walker walker;
......
...@@ -87,6 +87,7 @@ struct tc_u_hnode { ...@@ -87,6 +87,7 @@ struct tc_u_hnode {
unsigned int divisor; unsigned int divisor;
struct idr handle_idr; struct idr handle_idr;
struct rcu_head rcu; struct rcu_head rcu;
u32 flags;
/* The 'ht' field MUST be the last field in structure to allow for /* The 'ht' field MUST be the last field in structure to allow for
* more entries allocated at end of structure. * more entries allocated at end of structure.
*/ */
...@@ -486,12 +487,13 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key) ...@@ -486,12 +487,13 @@ static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode *key)
return 0; return 0;
} }
static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h) static void u32_clear_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h,
struct netlink_ext_ack *extack)
{ {
struct tcf_block *block = tp->chain->block; struct tcf_block *block = tp->chain->block;
struct tc_cls_u32_offload cls_u32 = {}; struct tc_cls_u32_offload cls_u32 = {};
tc_cls_common_offload_init(&cls_u32.common, tp, NULL); tc_cls_common_offload_init(&cls_u32.common, tp, h->flags, extack);
cls_u32.command = TC_CLSU32_DELETE_HNODE; cls_u32.command = TC_CLSU32_DELETE_HNODE;
cls_u32.hnode.divisor = h->divisor; cls_u32.hnode.divisor = h->divisor;
cls_u32.hnode.handle = h->handle; cls_u32.hnode.handle = h->handle;
...@@ -509,7 +511,7 @@ static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h, ...@@ -509,7 +511,7 @@ static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h,
bool offloaded = false; bool offloaded = false;
int err; int err;
tc_cls_common_offload_init(&cls_u32.common, tp, extack); tc_cls_common_offload_init(&cls_u32.common, tp, flags, extack);
cls_u32.command = TC_CLSU32_NEW_HNODE; cls_u32.command = TC_CLSU32_NEW_HNODE;
cls_u32.hnode.divisor = h->divisor; cls_u32.hnode.divisor = h->divisor;
cls_u32.hnode.handle = h->handle; cls_u32.hnode.handle = h->handle;
...@@ -517,7 +519,7 @@ static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h, ...@@ -517,7 +519,7 @@ static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h,
err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw); err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw);
if (err < 0) { if (err < 0) {
u32_clear_hw_hnode(tp, h); u32_clear_hw_hnode(tp, h, NULL);
return err; return err;
} else if (err > 0) { } else if (err > 0) {
offloaded = true; offloaded = true;
...@@ -529,12 +531,13 @@ static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h, ...@@ -529,12 +531,13 @@ static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h,
return 0; return 0;
} }
static void u32_remove_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n) static void u32_remove_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
struct netlink_ext_ack *extack)
{ {
struct tcf_block *block = tp->chain->block; struct tcf_block *block = tp->chain->block;
struct tc_cls_u32_offload cls_u32 = {}; struct tc_cls_u32_offload cls_u32 = {};
tc_cls_common_offload_init(&cls_u32.common, tp, NULL); tc_cls_common_offload_init(&cls_u32.common, tp, n->flags, extack);
cls_u32.command = TC_CLSU32_DELETE_KNODE; cls_u32.command = TC_CLSU32_DELETE_KNODE;
cls_u32.knode.handle = n->handle; cls_u32.knode.handle = n->handle;
...@@ -550,7 +553,7 @@ static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n, ...@@ -550,7 +553,7 @@ static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
bool skip_sw = tc_skip_sw(flags); bool skip_sw = tc_skip_sw(flags);
int err; int err;
tc_cls_common_offload_init(&cls_u32.common, tp, extack); tc_cls_common_offload_init(&cls_u32.common, tp, flags, extack);
cls_u32.command = TC_CLSU32_REPLACE_KNODE; cls_u32.command = TC_CLSU32_REPLACE_KNODE;
cls_u32.knode.handle = n->handle; cls_u32.knode.handle = n->handle;
cls_u32.knode.fshift = n->fshift; cls_u32.knode.fshift = n->fshift;
...@@ -568,7 +571,7 @@ static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n, ...@@ -568,7 +571,7 @@ static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw); err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw);
if (err < 0) { if (err < 0) {
u32_remove_hw_knode(tp, n); u32_remove_hw_knode(tp, n, NULL);
return err; return err;
} else if (err > 0) { } else if (err > 0) {
tcf_block_offload_inc(block, &n->flags); tcf_block_offload_inc(block, &n->flags);
...@@ -580,7 +583,8 @@ static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n, ...@@ -580,7 +583,8 @@ static int u32_replace_hw_knode(struct tcf_proto *tp, struct tc_u_knode *n,
return 0; return 0;
} }
static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
struct netlink_ext_ack *extack)
{ {
struct tc_u_knode *n; struct tc_u_knode *n;
unsigned int h; unsigned int h;
...@@ -590,7 +594,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) ...@@ -590,7 +594,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
RCU_INIT_POINTER(ht->ht[h], RCU_INIT_POINTER(ht->ht[h],
rtnl_dereference(n->next)); rtnl_dereference(n->next));
tcf_unbind_filter(tp, &n->res); tcf_unbind_filter(tp, &n->res);
u32_remove_hw_knode(tp, n); u32_remove_hw_knode(tp, n, extack);
idr_remove_ext(&ht->handle_idr, n->handle); idr_remove_ext(&ht->handle_idr, n->handle);
if (tcf_exts_get_net(&n->exts)) if (tcf_exts_get_net(&n->exts))
call_rcu(&n->rcu, u32_delete_key_freepf_rcu); call_rcu(&n->rcu, u32_delete_key_freepf_rcu);
...@@ -600,7 +604,8 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) ...@@ -600,7 +604,8 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
} }
} }
static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht,
struct netlink_ext_ack *extack)
{ {
struct tc_u_common *tp_c = tp->data; struct tc_u_common *tp_c = tp->data;
struct tc_u_hnode __rcu **hn; struct tc_u_hnode __rcu **hn;
...@@ -608,14 +613,14 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) ...@@ -608,14 +613,14 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
WARN_ON(ht->refcnt); WARN_ON(ht->refcnt);
u32_clear_hnode(tp, ht); u32_clear_hnode(tp, ht, extack);
hn = &tp_c->hlist; hn = &tp_c->hlist;
for (phn = rtnl_dereference(*hn); for (phn = rtnl_dereference(*hn);
phn; phn;
hn = &phn->next, phn = rtnl_dereference(*hn)) { hn = &phn->next, phn = rtnl_dereference(*hn)) {
if (phn == ht) { if (phn == ht) {
u32_clear_hw_hnode(tp, ht); u32_clear_hw_hnode(tp, ht, extack);
idr_destroy(&ht->handle_idr); idr_destroy(&ht->handle_idr);
idr_remove_ext(&tp_c->handle_idr, ht->handle); idr_remove_ext(&tp_c->handle_idr, ht->handle);
RCU_INIT_POINTER(*hn, ht->next); RCU_INIT_POINTER(*hn, ht->next);
...@@ -638,7 +643,7 @@ static bool ht_empty(struct tc_u_hnode *ht) ...@@ -638,7 +643,7 @@ static bool ht_empty(struct tc_u_hnode *ht)
return true; return true;
} }
static void u32_destroy(struct tcf_proto *tp) static void u32_destroy(struct tcf_proto *tp, struct netlink_ext_ack *extack)
{ {
struct tc_u_common *tp_c = tp->data; struct tc_u_common *tp_c = tp->data;
struct tc_u_hnode *root_ht = rtnl_dereference(tp->root); struct tc_u_hnode *root_ht = rtnl_dereference(tp->root);
...@@ -646,7 +651,7 @@ static void u32_destroy(struct tcf_proto *tp) ...@@ -646,7 +651,7 @@ static void u32_destroy(struct tcf_proto *tp)
WARN_ON(root_ht == NULL); WARN_ON(root_ht == NULL);
if (root_ht && --root_ht->refcnt == 0) if (root_ht && --root_ht->refcnt == 0)
u32_destroy_hnode(tp, root_ht); u32_destroy_hnode(tp, root_ht, extack);
if (--tp_c->refcnt == 0) { if (--tp_c->refcnt == 0) {
struct tc_u_hnode *ht; struct tc_u_hnode *ht;
...@@ -657,7 +662,7 @@ static void u32_destroy(struct tcf_proto *tp) ...@@ -657,7 +662,7 @@ static void u32_destroy(struct tcf_proto *tp)
ht; ht;
ht = rtnl_dereference(ht->next)) { ht = rtnl_dereference(ht->next)) {
ht->refcnt--; ht->refcnt--;
u32_clear_hnode(tp, ht); u32_clear_hnode(tp, ht, extack);
} }
while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) { while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) {
...@@ -684,7 +689,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, ...@@ -684,7 +689,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last,
goto out; goto out;
if (TC_U32_KEY(ht->handle)) { if (TC_U32_KEY(ht->handle)) {
u32_remove_hw_knode(tp, (struct tc_u_knode *)ht); u32_remove_hw_knode(tp, (struct tc_u_knode *)ht, extack);
ret = u32_delete_key(tp, (struct tc_u_knode *)ht); ret = u32_delete_key(tp, (struct tc_u_knode *)ht);
goto out; goto out;
} }
...@@ -696,7 +701,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last, ...@@ -696,7 +701,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last,
if (ht->refcnt == 1) { if (ht->refcnt == 1) {
ht->refcnt--; ht->refcnt--;
u32_destroy_hnode(tp, ht); u32_destroy_hnode(tp, ht, extack);
} else { } else {
NL_SET_ERR_MSG_MOD(extack, "Can not delete in-use filter"); NL_SET_ERR_MSG_MOD(extack, "Can not delete in-use filter");
return -EBUSY; return -EBUSY;
...@@ -1015,6 +1020,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -1015,6 +1020,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
ht->handle = handle; ht->handle = handle;
ht->prio = tp->prio; ht->prio = tp->prio;
idr_init(&ht->handle_idr); idr_init(&ht->handle_idr);
ht->flags = flags;
err = u32_replace_hw_hnode(tp, ht, flags, extack); err = u32_replace_hw_hnode(tp, ht, flags, extack);
if (err) { if (err) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment