net: sched: introduce per-block callbacks
Introduce infrastructure that allows drivers to register callbacks that are called whenever tc would offload inserted rule for a specific block. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									6e40cf2d4d
								
							
						
					
					
						commit
						acb674428c
					
				| @ -27,6 +27,8 @@ struct tcf_block_ext_info { | ||||
| 	enum tcf_block_binder_type binder_type; | ||||
| }; | ||||
| 
 | ||||
| struct tcf_block_cb; | ||||
| 
 | ||||
| #ifdef CONFIG_NET_CLS | ||||
| struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, | ||||
| 				bool create); | ||||
| @ -51,6 +53,21 @@ static inline struct net_device *tcf_block_dev(struct tcf_block *block) | ||||
| 	return tcf_block_q(block)->dev_queue->dev; | ||||
| } | ||||
| 
 | ||||
| void *tcf_block_cb_priv(struct tcf_block_cb *block_cb); | ||||
| struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block, | ||||
| 					 tc_setup_cb_t *cb, void *cb_ident); | ||||
| void tcf_block_cb_incref(struct tcf_block_cb *block_cb); | ||||
| unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb); | ||||
| struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block, | ||||
| 					     tc_setup_cb_t *cb, void *cb_ident, | ||||
| 					     void *cb_priv); | ||||
| int tcf_block_cb_register(struct tcf_block *block, | ||||
| 			  tc_setup_cb_t *cb, void *cb_ident, | ||||
| 			  void *cb_priv); | ||||
| void __tcf_block_cb_unregister(struct tcf_block_cb *block_cb); | ||||
| void tcf_block_cb_unregister(struct tcf_block *block, | ||||
| 			     tc_setup_cb_t *cb, void *cb_ident); | ||||
| 
 | ||||
| int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, | ||||
| 		 struct tcf_result *res, bool compat_mode); | ||||
| 
 | ||||
| @ -91,6 +108,70 @@ static inline struct net_device *tcf_block_dev(struct tcf_block *block) | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| int tc_setup_cb_block_register(struct tcf_block *block, tc_setup_cb_t *cb, | ||||
| 			       void *cb_priv) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| void tc_setup_cb_block_unregister(struct tcf_block *block, tc_setup_cb_t *cb, | ||||
| 				  void *cb_priv) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| void *tcf_block_cb_priv(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block, | ||||
| 					 tc_setup_cb_t *cb, void *cb_ident) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| void tcf_block_cb_incref(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block, | ||||
| 					     tc_setup_cb_t *cb, void *cb_ident, | ||||
| 					     void *cb_priv) | ||||
| { | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| int tcf_block_cb_register(struct tcf_block *block, | ||||
| 			  tc_setup_cb_t *cb, void *cb_ident, | ||||
| 			  void *cb_priv) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| void __tcf_block_cb_unregister(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| void tcf_block_cb_unregister(struct tcf_block *block, | ||||
| 			     tc_setup_cb_t *cb, void *cb_ident) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| static inline int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp, | ||||
| 			       struct tcf_result *res, bool compat_mode) | ||||
| { | ||||
|  | ||||
| @ -272,6 +272,7 @@ struct tcf_block { | ||||
| 	struct list_head chain_list; | ||||
| 	struct net *net; | ||||
| 	struct Qdisc *q; | ||||
| 	struct list_head cb_list; | ||||
| }; | ||||
| 
 | ||||
| static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) | ||||
|  | ||||
| @ -278,6 +278,8 @@ int tcf_block_get_ext(struct tcf_block **p_block, | ||||
| 	if (!block) | ||||
| 		return -ENOMEM; | ||||
| 	INIT_LIST_HEAD(&block->chain_list); | ||||
| 	INIT_LIST_HEAD(&block->cb_list); | ||||
| 
 | ||||
| 	/* Create chain 0 by default, it has to be always present. */ | ||||
| 	chain = tcf_chain_create(block, 0); | ||||
| 	if (!chain) { | ||||
| @ -354,6 +356,109 @@ void tcf_block_put(struct tcf_block *block) | ||||
| } | ||||
| EXPORT_SYMBOL(tcf_block_put); | ||||
| 
 | ||||
| struct tcf_block_cb { | ||||
| 	struct list_head list; | ||||
| 	tc_setup_cb_t *cb; | ||||
| 	void *cb_ident; | ||||
| 	void *cb_priv; | ||||
| 	unsigned int refcnt; | ||||
| }; | ||||
| 
 | ||||
| void *tcf_block_cb_priv(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| 	return block_cb->cb_priv; | ||||
| } | ||||
| EXPORT_SYMBOL(tcf_block_cb_priv); | ||||
| 
 | ||||
| struct tcf_block_cb *tcf_block_cb_lookup(struct tcf_block *block, | ||||
| 					 tc_setup_cb_t *cb, void *cb_ident) | ||||
| {	struct tcf_block_cb *block_cb; | ||||
| 
 | ||||
| 	list_for_each_entry(block_cb, &block->cb_list, list) | ||||
| 		if (block_cb->cb == cb && block_cb->cb_ident == cb_ident) | ||||
| 			return block_cb; | ||||
| 	return NULL; | ||||
| } | ||||
| EXPORT_SYMBOL(tcf_block_cb_lookup); | ||||
| 
 | ||||
| void tcf_block_cb_incref(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| 	block_cb->refcnt++; | ||||
| } | ||||
| EXPORT_SYMBOL(tcf_block_cb_incref); | ||||
| 
 | ||||
| unsigned int tcf_block_cb_decref(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| 	return --block_cb->refcnt; | ||||
| } | ||||
| EXPORT_SYMBOL(tcf_block_cb_decref); | ||||
| 
 | ||||
| struct tcf_block_cb *__tcf_block_cb_register(struct tcf_block *block, | ||||
| 					     tc_setup_cb_t *cb, void *cb_ident, | ||||
| 					     void *cb_priv) | ||||
| { | ||||
| 	struct tcf_block_cb *block_cb; | ||||
| 
 | ||||
| 	block_cb = kzalloc(sizeof(*block_cb), GFP_KERNEL); | ||||
| 	if (!block_cb) | ||||
| 		return NULL; | ||||
| 	block_cb->cb = cb; | ||||
| 	block_cb->cb_ident = cb_ident; | ||||
| 	block_cb->cb_priv = cb_priv; | ||||
| 	list_add(&block_cb->list, &block->cb_list); | ||||
| 	return block_cb; | ||||
| } | ||||
| EXPORT_SYMBOL(__tcf_block_cb_register); | ||||
| 
 | ||||
| int tcf_block_cb_register(struct tcf_block *block, | ||||
| 			  tc_setup_cb_t *cb, void *cb_ident, | ||||
| 			  void *cb_priv) | ||||
| { | ||||
| 	struct tcf_block_cb *block_cb; | ||||
| 
 | ||||
| 	block_cb = __tcf_block_cb_register(block, cb, cb_ident, cb_priv); | ||||
| 	return block_cb ? 0 : -ENOMEM; | ||||
| } | ||||
| EXPORT_SYMBOL(tcf_block_cb_register); | ||||
| 
 | ||||
| void __tcf_block_cb_unregister(struct tcf_block_cb *block_cb) | ||||
| { | ||||
| 	list_del(&block_cb->list); | ||||
| 	kfree(block_cb); | ||||
| } | ||||
| EXPORT_SYMBOL(__tcf_block_cb_unregister); | ||||
| 
 | ||||
| void tcf_block_cb_unregister(struct tcf_block *block, | ||||
| 			     tc_setup_cb_t *cb, void *cb_ident) | ||||
| { | ||||
| 	struct tcf_block_cb *block_cb; | ||||
| 
 | ||||
| 	block_cb = tcf_block_cb_lookup(block, cb, cb_ident); | ||||
| 	if (!block_cb) | ||||
| 		return; | ||||
| 	__tcf_block_cb_unregister(block_cb); | ||||
| } | ||||
| EXPORT_SYMBOL(tcf_block_cb_unregister); | ||||
| 
 | ||||
| static int tcf_block_cb_call(struct tcf_block *block, enum tc_setup_type type, | ||||
| 			     void *type_data, bool err_stop) | ||||
| { | ||||
| 	struct tcf_block_cb *block_cb; | ||||
| 	int ok_count = 0; | ||||
| 	int err; | ||||
| 
 | ||||
| 	list_for_each_entry(block_cb, &block->cb_list, list) { | ||||
| 		err = block_cb->cb(type, type_data, block_cb->cb_priv); | ||||
| 		if (err) { | ||||
| 			if (err_stop) | ||||
| 				return err; | ||||
| 		} else { | ||||
| 			ok_count++; | ||||
| 		} | ||||
| 	} | ||||
| 	return ok_count; | ||||
| } | ||||
| 
 | ||||
| /* Main classifier routine: scans classifier chain attached
 | ||||
|  * to this qdisc, (optionally) tests for protocol and asks | ||||
|  * specific classifiers. | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user