diff options
Diffstat (limited to 'net/sched/cls_api.c')
| -rw-r--r-- | net/sched/cls_api.c | 41 | 
1 files changed, 41 insertions, 0 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index ca5676b2668e..17d97bbe890f 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -410,12 +410,48 @@ static void tcf_proto_get(struct tcf_proto *tp)  	refcount_inc(&tp->refcnt);  } +static void tcf_maintain_bypass(struct tcf_block *block) +{ +	int filtercnt = atomic_read(&block->filtercnt); +	int skipswcnt = atomic_read(&block->skipswcnt); +	bool bypass_wanted = filtercnt > 0 && filtercnt == skipswcnt; + +	if (bypass_wanted != block->bypass_wanted) { +#ifdef CONFIG_NET_CLS_ACT +		if (bypass_wanted) +			static_branch_inc(&tcf_bypass_check_needed_key); +		else +			static_branch_dec(&tcf_bypass_check_needed_key); +#endif +		block->bypass_wanted = bypass_wanted; +	} +} + +static void tcf_block_filter_cnt_update(struct tcf_block *block, bool *counted, bool add) +{ +	lockdep_assert_not_held(&block->cb_lock); + +	down_write(&block->cb_lock); +	if (*counted != add) { +		if (add) { +			atomic_inc(&block->filtercnt); +			*counted = true; +		} else { +			atomic_dec(&block->filtercnt); +			*counted = false; +		} +	} +	tcf_maintain_bypass(block); +	up_write(&block->cb_lock); +} +  static void tcf_chain_put(struct tcf_chain *chain);  static void tcf_proto_destroy(struct tcf_proto *tp, bool rtnl_held,  			      bool sig_destroy, struct netlink_ext_ack *extack)  {  	tp->ops->destroy(tp, rtnl_held, extack); +	tcf_block_filter_cnt_update(tp->chain->block, &tp->counted, false);  	if (sig_destroy)  		tcf_proto_signal_destroyed(tp->chain, tp);  	tcf_chain_put(tp->chain); @@ -2367,6 +2403,7 @@ replay:  		tfilter_notify(net, skb, n, tp, block, q, parent, fh,  			       RTM_NEWTFILTER, false, rtnl_held, extack);  		tfilter_put(tp, fh); +		tcf_block_filter_cnt_update(block, &tp->counted, true);  		/* q pointer is NULL for shared blocks */  		if (q)  			q->flags &= ~TCQ_F_CAN_BYPASS; @@ -3483,6 +3520,8 @@ static void tcf_block_offload_inc(struct tcf_block *block, u32 *flags)  	if (*flags & TCA_CLS_FLAGS_IN_HW)  		return;  	*flags |= TCA_CLS_FLAGS_IN_HW; +	if (tc_skip_sw(*flags)) +		atomic_inc(&block->skipswcnt);  	atomic_inc(&block->offloadcnt);  } @@ -3491,6 +3530,8 @@ static void tcf_block_offload_dec(struct tcf_block *block, u32 *flags)  	if (!(*flags & TCA_CLS_FLAGS_IN_HW))  		return;  	*flags &= ~TCA_CLS_FLAGS_IN_HW; +	if (tc_skip_sw(*flags)) +		atomic_dec(&block->skipswcnt);  	atomic_dec(&block->offloadcnt);  }  |