Commit f36fe1c4 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

net: sched: introduce block mechanism to handle netif_keep_dst calls

Couple of classifiers call netif_keep_dst directly on q->dev. That is
not possible to do directly for shared blocke where multiple qdiscs are
owning the block. So introduce a infrastructure to keep track of the
block owners in list and use this list to implement block variant of
netif_keep_dst.
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Acked-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Acked-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9d3aaff3
...@@ -39,6 +39,7 @@ bool tcf_queue_work(struct work_struct *work); ...@@ -39,6 +39,7 @@ bool tcf_queue_work(struct work_struct *work);
struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
bool create); bool create);
void tcf_chain_put(struct tcf_chain *chain); void tcf_chain_put(struct tcf_chain *chain);
void tcf_block_netif_keep_dst(struct tcf_block *block);
int tcf_block_get(struct tcf_block **p_block, int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q, struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
......
...@@ -289,6 +289,8 @@ struct tcf_block { ...@@ -289,6 +289,8 @@ struct tcf_block {
struct net *net; struct net *net;
struct Qdisc *q; struct Qdisc *q;
struct list_head cb_list; struct list_head cb_list;
struct list_head owner_list;
bool keep_dst;
}; };
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
......
...@@ -375,6 +375,7 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q, ...@@ -375,6 +375,7 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
} }
INIT_LIST_HEAD(&block->chain_list); INIT_LIST_HEAD(&block->chain_list);
INIT_LIST_HEAD(&block->cb_list); INIT_LIST_HEAD(&block->cb_list);
INIT_LIST_HEAD(&block->owner_list);
/* Create chain 0 by default, it has to be always present. */ /* Create chain 0 by default, it has to be always present. */
chain = tcf_chain_create(block, 0); chain = tcf_chain_create(block, 0);
...@@ -406,6 +407,65 @@ static struct tcf_chain *tcf_block_chain_zero(struct tcf_block *block) ...@@ -406,6 +407,65 @@ static struct tcf_chain *tcf_block_chain_zero(struct tcf_block *block)
return list_first_entry(&block->chain_list, struct tcf_chain, list); return list_first_entry(&block->chain_list, struct tcf_chain, list);
} }
struct tcf_block_owner_item {
struct list_head list;
struct Qdisc *q;
enum tcf_block_binder_type binder_type;
};
static void
tcf_block_owner_netif_keep_dst(struct tcf_block *block,
struct Qdisc *q,
enum tcf_block_binder_type binder_type)
{
if (block->keep_dst &&
binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS &&
binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_EGRESS)
netif_keep_dst(qdisc_dev(q));
}
void tcf_block_netif_keep_dst(struct tcf_block *block)
{
struct tcf_block_owner_item *item;
block->keep_dst = true;
list_for_each_entry(item, &block->owner_list, list)
tcf_block_owner_netif_keep_dst(block, item->q,
item->binder_type);
}
EXPORT_SYMBOL(tcf_block_netif_keep_dst);
static int tcf_block_owner_add(struct tcf_block *block,
struct Qdisc *q,
enum tcf_block_binder_type binder_type)
{
struct tcf_block_owner_item *item;
item = kmalloc(sizeof(*item), GFP_KERNEL);
if (!item)
return -ENOMEM;
item->q = q;
item->binder_type = binder_type;
list_add(&item->list, &block->owner_list);
return 0;
}
static void tcf_block_owner_del(struct tcf_block *block,
struct Qdisc *q,
enum tcf_block_binder_type binder_type)
{
struct tcf_block_owner_item *item;
list_for_each_entry(item, &block->owner_list, list) {
if (item->q == q && item->binder_type == binder_type) {
list_del(&item->list);
kfree(item);
return;
}
}
WARN_ON(1);
}
int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
struct tcf_block_ext_info *ei, struct tcf_block_ext_info *ei,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
...@@ -435,6 +495,12 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, ...@@ -435,6 +495,12 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
} }
} }
err = tcf_block_owner_add(block, q, ei->binder_type);
if (err)
goto err_block_owner_add;
tcf_block_owner_netif_keep_dst(block, q, ei->binder_type);
err = tcf_chain_head_change_cb_add(tcf_block_chain_zero(block), err = tcf_chain_head_change_cb_add(tcf_block_chain_zero(block),
ei, extack); ei, extack);
if (err) if (err)
...@@ -444,6 +510,8 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, ...@@ -444,6 +510,8 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
return 0; return 0;
err_chain_head_change_cb_add: err_chain_head_change_cb_add:
tcf_block_owner_del(block, q, ei->binder_type);
err_block_owner_add:
if (created) { if (created) {
if (tcf_block_shared(block)) if (tcf_block_shared(block))
tcf_block_remove(block, net); tcf_block_remove(block, net);
...@@ -489,6 +557,7 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, ...@@ -489,6 +557,7 @@ void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q,
if (!block) if (!block)
return; return;
tcf_chain_head_change_cb_del(tcf_block_chain_zero(block), ei); tcf_chain_head_change_cb_del(tcf_block_chain_zero(block), ei);
tcf_block_owner_del(block, q, ei->binder_type);
if (--block->refcnt == 0) { if (--block->refcnt == 0) {
if (tcf_block_shared(block)) if (tcf_block_shared(block))
......
...@@ -392,8 +392,8 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog, ...@@ -392,8 +392,8 @@ static int cls_bpf_prog_from_efd(struct nlattr **tb, struct cls_bpf_prog *prog,
prog->bpf_name = name; prog->bpf_name = name;
prog->filter = fp; prog->filter = fp;
if (fp->dst_needed && !(tp->q->flags & TCQ_F_INGRESS)) if (fp->dst_needed)
netif_keep_dst(qdisc_dev(tp->q)); tcf_block_netif_keep_dst(tp->chain->block);
return 0; return 0;
} }
......
...@@ -526,7 +526,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb, ...@@ -526,7 +526,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
timer_setup(&fnew->perturb_timer, flow_perturbation, TIMER_DEFERRABLE); timer_setup(&fnew->perturb_timer, flow_perturbation, TIMER_DEFERRABLE);
netif_keep_dst(qdisc_dev(tp->q)); tcf_block_netif_keep_dst(tp->chain->block);
if (tb[TCA_FLOW_KEYS]) { if (tb[TCA_FLOW_KEYS]) {
fnew->keymask = keymask; fnew->keymask = keymask;
......
...@@ -527,7 +527,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, ...@@ -527,7 +527,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
if (f->handle < f1->handle) if (f->handle < f1->handle)
break; break;
netif_keep_dst(qdisc_dev(tp->q)); tcf_block_netif_keep_dst(tp->chain->block);
rcu_assign_pointer(f->next, f1); rcu_assign_pointer(f->next, f1);
rcu_assign_pointer(*fp, f); rcu_assign_pointer(*fp, f);
......
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