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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
131f1ed317
@ -605,17 +605,6 @@ struct tc_cls_common_offload {
|
||||
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 tcf_exts *exts;
|
||||
struct tc_u32_sel *sel;
|
||||
@ -694,6 +683,18 @@ static inline bool tc_in_hw(u32 flags)
|
||||
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 {
|
||||
TC_CLSFLOWER_REPLACE,
|
||||
TC_CLSFLOWER_DESTROY,
|
||||
@ -736,7 +737,6 @@ struct tc_cls_bpf_offload {
|
||||
struct bpf_prog *oldprog;
|
||||
const char *name;
|
||||
bool exts_integrated;
|
||||
u32 gen_flags;
|
||||
};
|
||||
|
||||
struct tc_mqprio_qopt_offload {
|
||||
|
@ -233,7 +233,8 @@ struct tcf_proto_ops {
|
||||
const struct tcf_proto *,
|
||||
struct tcf_result *);
|
||||
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);
|
||||
int (*change)(struct net *net, struct sk_buff *,
|
||||
|
@ -172,9 +172,10 @@ errout:
|
||||
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);
|
||||
kfree_rcu(tp, rcu);
|
||||
}
|
||||
@ -223,7 +224,7 @@ static void tcf_chain_flush(struct tcf_chain *chain)
|
||||
tcf_chain_head_change(chain, NULL);
|
||||
while (tp) {
|
||||
RCU_INIT_POINTER(chain->filter_chain, tp->next);
|
||||
tcf_proto_destroy(tp);
|
||||
tcf_proto_destroy(tp, NULL);
|
||||
tp = rtnl_dereference(chain->filter_chain);
|
||||
tcf_chain_put(chain);
|
||||
}
|
||||
@ -1182,7 +1183,7 @@ replay:
|
||||
tcf_chain_tp_remove(chain, &chain_info, tp);
|
||||
tfilter_notify(net, skb, n, tp, block, q, parent, fh,
|
||||
RTM_DELTFILTER, false);
|
||||
tcf_proto_destroy(tp);
|
||||
tcf_proto_destroy(tp, extack);
|
||||
err = 0;
|
||||
goto errout;
|
||||
}
|
||||
@ -1200,7 +1201,7 @@ replay:
|
||||
case RTM_NEWTFILTER:
|
||||
if (n->nlmsg_flags & NLM_F_EXCL) {
|
||||
if (tp_created)
|
||||
tcf_proto_destroy(tp);
|
||||
tcf_proto_destroy(tp, NULL);
|
||||
NL_SET_ERR_MSG(extack, "Filter already exists");
|
||||
err = -EEXIST;
|
||||
goto errout;
|
||||
@ -1214,7 +1215,7 @@ replay:
|
||||
goto errout;
|
||||
if (last) {
|
||||
tcf_chain_tp_remove(chain, &chain_info, tp);
|
||||
tcf_proto_destroy(tp);
|
||||
tcf_proto_destroy(tp, extack);
|
||||
}
|
||||
goto errout;
|
||||
case RTM_GETTFILTER:
|
||||
@ -1240,7 +1241,7 @@ replay:
|
||||
RTM_NEWTFILTER, false);
|
||||
} else {
|
||||
if (tp_created)
|
||||
tcf_proto_destroy(tp);
|
||||
tcf_proto_destroy(tp, NULL);
|
||||
}
|
||||
|
||||
errout:
|
||||
|
@ -112,7 +112,7 @@ static void basic_delete_filter(struct rcu_head *head)
|
||||
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_filter *f, *n;
|
||||
|
@ -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);
|
||||
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.exts = &obj->exts;
|
||||
cls_bpf.prog = prog ? prog->filter : NULL;
|
||||
cls_bpf.oldprog = oldprog ? oldprog->filter : NULL;
|
||||
cls_bpf.name = obj->bpf_name;
|
||||
cls_bpf.exts_integrated = obj->exts_integrated;
|
||||
cls_bpf.gen_flags = obj->gen_flags;
|
||||
|
||||
if (oldprog)
|
||||
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,
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
err = cls_bpf_offload_cmd(tp, NULL, prog, NULL);
|
||||
err = cls_bpf_offload_cmd(tp, NULL, prog, extack);
|
||||
if (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,
|
||||
struct tcf_block *block = tp->chain->block;
|
||||
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.exts = &prog->exts;
|
||||
cls_bpf.prog = prog->filter;
|
||||
cls_bpf.name = prog->bpf_name;
|
||||
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);
|
||||
}
|
||||
@ -290,12 +290,13 @@ static void cls_bpf_delete_prog_rcu(struct rcu_head *rcu)
|
||||
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);
|
||||
|
||||
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);
|
||||
tcf_unbind_filter(tp, &prog->res);
|
||||
if (tcf_exts_get_net(&prog->exts))
|
||||
@ -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);
|
||||
|
||||
__cls_bpf_delete(tp, arg);
|
||||
__cls_bpf_delete(tp, arg, extack);
|
||||
*last = list_empty(&head->plist);
|
||||
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_prog *prog, *tmp;
|
||||
|
||||
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);
|
||||
kfree_rcu(head, rcu);
|
||||
|
@ -143,7 +143,8 @@ errout:
|
||||
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);
|
||||
|
||||
|
@ -600,7 +600,7 @@ static int flow_init(struct tcf_proto *tp)
|
||||
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_filter *f, *next;
|
||||
|
@ -218,12 +218,13 @@ static void fl_destroy_filter(struct rcu_head *head)
|
||||
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 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.cookie = (unsigned long) f;
|
||||
|
||||
@ -243,7 +244,7 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
|
||||
bool skip_sw = tc_skip_sw(f->flags);
|
||||
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.cookie = (unsigned long) f;
|
||||
cls_flower.dissector = dissector;
|
||||
@ -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,
|
||||
&cls_flower, skip_sw);
|
||||
if (err < 0) {
|
||||
fl_hw_destroy_filter(tp, f);
|
||||
fl_hw_destroy_filter(tp, f, NULL);
|
||||
return err;
|
||||
} else if (err > 0) {
|
||||
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)
|
||||
struct tc_cls_flower_offload cls_flower = {};
|
||||
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.cookie = (unsigned long) f;
|
||||
cls_flower.exts = &f->exts;
|
||||
@ -282,14 +283,15 @@ static void fl_hw_update_stats(struct tcf_proto *tp, struct cls_fl_filter *f)
|
||||
&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);
|
||||
|
||||
idr_remove_ext(&head->handle_idr, f->handle);
|
||||
list_del_rcu(&f->list);
|
||||
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);
|
||||
if (tcf_exts_get_net(&f->exts))
|
||||
call_rcu(&f->rcu, fl_destroy_filter);
|
||||
@ -315,13 +317,13 @@ static void fl_destroy_rcu(struct rcu_head *rcu)
|
||||
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_filter *f, *next;
|
||||
|
||||
list_for_each_entry_safe(f, next, &head->filters, list)
|
||||
__fl_delete(tp, f);
|
||||
__fl_delete(tp, f, extack);
|
||||
idr_destroy(&head->handle_idr);
|
||||
|
||||
__module_get(THIS_MODULE);
|
||||
@ -958,7 +960,7 @@ static int fl_change(struct net *net, struct sk_buff *in_skb,
|
||||
rhashtable_remove_fast(&head->ht, &fold->ht_node,
|
||||
head->ht_params);
|
||||
if (!tc_skip_hw(fold->flags))
|
||||
fl_hw_destroy_filter(tp, fold);
|
||||
fl_hw_destroy_filter(tp, fold, NULL);
|
||||
}
|
||||
|
||||
*arg = fnew;
|
||||
@ -997,7 +999,7 @@ static int fl_delete(struct tcf_proto *tp, void *arg, bool *last,
|
||||
if (!tc_skip_sw(f->flags))
|
||||
rhashtable_remove_fast(&head->ht, &f->ht_node,
|
||||
head->ht_params);
|
||||
__fl_delete(tp, f);
|
||||
__fl_delete(tp, f, extack);
|
||||
*last = list_empty(&head->filters);
|
||||
return 0;
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ static void fw_delete_filter(struct rcu_head *head)
|
||||
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_filter *f;
|
||||
|
@ -71,12 +71,13 @@ static void mall_destroy_rcu(struct rcu_head *rcu)
|
||||
|
||||
static void mall_destroy_hw_filter(struct tcf_proto *tp,
|
||||
struct cls_mall_head *head,
|
||||
unsigned long cookie)
|
||||
unsigned long cookie,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct tc_cls_matchall_offload cls_mall = {};
|
||||
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.cookie = cookie;
|
||||
|
||||
@ -94,7 +95,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
|
||||
bool skip_sw = tc_skip_sw(head->flags);
|
||||
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.exts = &head->exts;
|
||||
cls_mall.cookie = cookie;
|
||||
@ -102,7 +103,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
|
||||
err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSMATCHALL,
|
||||
&cls_mall, skip_sw);
|
||||
if (err < 0) {
|
||||
mall_destroy_hw_filter(tp, head, cookie);
|
||||
mall_destroy_hw_filter(tp, head, cookie, NULL);
|
||||
return err;
|
||||
} else if (err > 0) {
|
||||
tcf_block_offload_inc(block, &head->flags);
|
||||
@ -114,7 +115,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
|
||||
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);
|
||||
|
||||
@ -122,7 +123,7 @@ static void mall_destroy(struct tcf_proto *tp)
|
||||
return;
|
||||
|
||||
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))
|
||||
call_rcu(&head->rcu, mall_destroy_rcu);
|
||||
|
@ -281,7 +281,7 @@ static void route4_delete_filter(struct rcu_head *head)
|
||||
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);
|
||||
int h1, h2;
|
||||
|
@ -322,7 +322,7 @@ static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_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);
|
||||
int h1, h2;
|
||||
|
@ -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 tcf_walker walker;
|
||||
|
@ -87,6 +87,7 @@ struct tc_u_hnode {
|
||||
unsigned int divisor;
|
||||
struct idr handle_idr;
|
||||
struct rcu_head rcu;
|
||||
u32 flags;
|
||||
/* The 'ht' field MUST be the last field in structure to allow for
|
||||
* 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)
|
||||
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 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.hnode.divisor = h->divisor;
|
||||
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,
|
||||
bool offloaded = false;
|
||||
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.hnode.divisor = h->divisor;
|
||||
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,
|
||||
|
||||
err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw);
|
||||
if (err < 0) {
|
||||
u32_clear_hw_hnode(tp, h);
|
||||
u32_clear_hw_hnode(tp, h, NULL);
|
||||
return err;
|
||||
} else if (err > 0) {
|
||||
offloaded = true;
|
||||
@ -529,12 +531,13 @@ static int u32_replace_hw_hnode(struct tcf_proto *tp, struct tc_u_hnode *h,
|
||||
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 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.knode.handle = n->handle;
|
||||
|
||||
@ -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);
|
||||
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.knode.handle = n->handle;
|
||||
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,
|
||||
|
||||
err = tc_setup_cb_call(block, NULL, TC_SETUP_CLSU32, &cls_u32, skip_sw);
|
||||
if (err < 0) {
|
||||
u32_remove_hw_knode(tp, n);
|
||||
u32_remove_hw_knode(tp, n, NULL);
|
||||
return err;
|
||||
} else if (err > 0) {
|
||||
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,
|
||||
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;
|
||||
unsigned int h;
|
||||
@ -590,7 +594,7 @@ static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
|
||||
RCU_INIT_POINTER(ht->ht[h],
|
||||
rtnl_dereference(n->next));
|
||||
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);
|
||||
if (tcf_exts_get_net(&n->exts))
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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_hnode __rcu **hn;
|
||||
@ -608,14 +613,14 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
|
||||
|
||||
WARN_ON(ht->refcnt);
|
||||
|
||||
u32_clear_hnode(tp, ht);
|
||||
u32_clear_hnode(tp, ht, extack);
|
||||
|
||||
hn = &tp_c->hlist;
|
||||
for (phn = rtnl_dereference(*hn);
|
||||
phn;
|
||||
hn = &phn->next, phn = rtnl_dereference(*hn)) {
|
||||
if (phn == ht) {
|
||||
u32_clear_hw_hnode(tp, ht);
|
||||
u32_clear_hw_hnode(tp, ht, extack);
|
||||
idr_destroy(&ht->handle_idr);
|
||||
idr_remove_ext(&tp_c->handle_idr, ht->handle);
|
||||
RCU_INIT_POINTER(*hn, ht->next);
|
||||
@ -638,7 +643,7 @@ static bool ht_empty(struct tc_u_hnode *ht)
|
||||
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_hnode *root_ht = rtnl_dereference(tp->root);
|
||||
@ -646,7 +651,7 @@ static void u32_destroy(struct tcf_proto *tp)
|
||||
WARN_ON(root_ht == NULL);
|
||||
|
||||
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) {
|
||||
struct tc_u_hnode *ht;
|
||||
@ -657,7 +662,7 @@ static void u32_destroy(struct tcf_proto *tp)
|
||||
ht;
|
||||
ht = rtnl_dereference(ht->next)) {
|
||||
ht->refcnt--;
|
||||
u32_clear_hnode(tp, ht);
|
||||
u32_clear_hnode(tp, ht, extack);
|
||||
}
|
||||
|
||||
while ((ht = rtnl_dereference(tp_c->hlist)) != NULL) {
|
||||
@ -684,7 +689,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last,
|
||||
goto out;
|
||||
|
||||
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);
|
||||
goto out;
|
||||
}
|
||||
@ -696,7 +701,7 @@ static int u32_delete(struct tcf_proto *tp, void *arg, bool *last,
|
||||
|
||||
if (ht->refcnt == 1) {
|
||||
ht->refcnt--;
|
||||
u32_destroy_hnode(tp, ht);
|
||||
u32_destroy_hnode(tp, ht, extack);
|
||||
} else {
|
||||
NL_SET_ERR_MSG_MOD(extack, "Can not delete in-use filter");
|
||||
return -EBUSY;
|
||||
@ -1015,6 +1020,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
|
||||
ht->handle = handle;
|
||||
ht->prio = tp->prio;
|
||||
idr_init(&ht->handle_idr);
|
||||
ht->flags = flags;
|
||||
|
||||
err = u32_replace_hw_hnode(tp, ht, flags, extack);
|
||||
if (err) {
|
||||
|
Loading…
Reference in New Issue
Block a user