forked from mirrors/linux
		
	flow_offload: allow user to offload tc action to net device
Use flow_indr_dev_register/flow_indr_dev_setup_offload to offload tc action. We need to call tc_cleanup_flow_action to clean up tc action entry since in tc_setup_action, some actions may hold dev refcnt, especially the mirror action. Signed-off-by: Baowen Zheng <baowen.zheng@corigine.com> Signed-off-by: Louis Peens <louis.peens@corigine.com> Signed-off-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									c54e1d920f
								
							
						
					
					
						commit
						8cbfe939ab
					
				
					 17 changed files with 254 additions and 23 deletions
				
			
		|  | @ -920,6 +920,7 @@ enum tc_setup_type { | ||||||
| 	TC_SETUP_QDISC_TBF, | 	TC_SETUP_QDISC_TBF, | ||||||
| 	TC_SETUP_QDISC_FIFO, | 	TC_SETUP_QDISC_FIFO, | ||||||
| 	TC_SETUP_QDISC_HTB, | 	TC_SETUP_QDISC_HTB, | ||||||
|  | 	TC_SETUP_ACT, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* These structures hold the attributes of bpf state that are being passed
 | /* These structures hold the attributes of bpf state that are being passed
 | ||||||
|  |  | ||||||
|  | @ -551,6 +551,23 @@ struct flow_cls_offload { | ||||||
| 	u32 classid; | 	u32 classid; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | enum offload_act_command  { | ||||||
|  | 	FLOW_ACT_REPLACE, | ||||||
|  | 	FLOW_ACT_DESTROY, | ||||||
|  | 	FLOW_ACT_STATS, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct flow_offload_action { | ||||||
|  | 	struct netlink_ext_ack *extack; /* NULL in FLOW_ACT_STATS process*/ | ||||||
|  | 	enum offload_act_command  command; | ||||||
|  | 	enum flow_action_id id; | ||||||
|  | 	u32 index; | ||||||
|  | 	struct flow_stats stats; | ||||||
|  | 	struct flow_action action; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct flow_offload_action *offload_action_alloc(unsigned int num_actions); | ||||||
|  | 
 | ||||||
| static inline struct flow_rule * | static inline struct flow_rule * | ||||||
| flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd) | flow_cls_offload_flow_rule(struct flow_cls_offload *flow_cmd) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -262,6 +262,9 @@ static inline void tcf_exts_put_net(struct tcf_exts *exts) | ||||||
| 	for (; 0; (void)(i), (void)(a), (void)(exts)) | 	for (; 0; (void)(i), (void)(a), (void)(exts)) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #define tcf_act_for_each_action(i, a, actions) \ | ||||||
|  | 	for (i = 0; i < TCA_ACT_MAX_PRIO && ((a) = actions[i]); i++) | ||||||
|  | 
 | ||||||
| static inline void | static inline void | ||||||
| tcf_exts_stats_update(const struct tcf_exts *exts, | tcf_exts_stats_update(const struct tcf_exts *exts, | ||||||
| 		      u64 bytes, u64 packets, u64 drops, u64 lastuse, | 		      u64 bytes, u64 packets, u64 drops, u64 lastuse, | ||||||
|  | @ -539,6 +542,8 @@ tcf_match_indev(struct sk_buff *skb, int ifindex) | ||||||
| int tc_setup_offload_action(struct flow_action *flow_action, | int tc_setup_offload_action(struct flow_action *flow_action, | ||||||
| 			    const struct tcf_exts *exts); | 			    const struct tcf_exts *exts); | ||||||
| void tc_cleanup_offload_action(struct flow_action *flow_action); | void tc_cleanup_offload_action(struct flow_action *flow_action); | ||||||
|  | int tc_setup_action(struct flow_action *flow_action, | ||||||
|  | 		    struct tc_action *actions[]); | ||||||
| 
 | 
 | ||||||
| int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, | int tc_setup_cb_call(struct tcf_block *block, enum tc_setup_type type, | ||||||
| 		     void *type_data, bool err_stop, bool rtnl_held); | 		     void *type_data, bool err_stop, bool rtnl_held); | ||||||
|  |  | ||||||
|  | @ -27,6 +27,26 @@ struct flow_rule *flow_rule_alloc(unsigned int num_actions) | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(flow_rule_alloc); | EXPORT_SYMBOL(flow_rule_alloc); | ||||||
| 
 | 
 | ||||||
|  | struct flow_offload_action *offload_action_alloc(unsigned int num_actions) | ||||||
|  | { | ||||||
|  | 	struct flow_offload_action *fl_action; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	fl_action = kzalloc(struct_size(fl_action, action.entries, num_actions), | ||||||
|  | 			    GFP_KERNEL); | ||||||
|  | 	if (!fl_action) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	fl_action->action.num_entries = num_actions; | ||||||
|  | 	/* Pre-fill each action hw_stats with DONT_CARE.
 | ||||||
|  | 	 * Caller can override this if it wants stats for a given action. | ||||||
|  | 	 */ | ||||||
|  | 	for (i = 0; i < num_actions; i++) | ||||||
|  | 		fl_action->action.entries[i].hw_stats = FLOW_ACTION_HW_STATS_DONT_CARE; | ||||||
|  | 
 | ||||||
|  | 	return fl_action; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #define FLOW_DISSECTOR_MATCH(__rule, __type, __out)				\ | #define FLOW_DISSECTOR_MATCH(__rule, __type, __out)				\ | ||||||
| 	const struct flow_match *__m = &(__rule)->match;			\ | 	const struct flow_match *__m = &(__rule)->match;			\ | ||||||
| 	struct flow_dissector *__d = (__m)->dissector;				\ | 	struct flow_dissector *__d = (__m)->dissector;				\ | ||||||
|  | @ -549,19 +569,25 @@ int flow_indr_dev_setup_offload(struct net_device *dev,	struct Qdisc *sch, | ||||||
| 				void (*cleanup)(struct flow_block_cb *block_cb)) | 				void (*cleanup)(struct flow_block_cb *block_cb)) | ||||||
| { | { | ||||||
| 	struct flow_indr_dev *this; | 	struct flow_indr_dev *this; | ||||||
|  | 	u32 count = 0; | ||||||
|  | 	int err; | ||||||
| 
 | 
 | ||||||
| 	mutex_lock(&flow_indr_block_lock); | 	mutex_lock(&flow_indr_block_lock); | ||||||
|  | 	if (bo) { | ||||||
|  | 		if (bo->command == FLOW_BLOCK_BIND) | ||||||
|  | 			indir_dev_add(data, dev, sch, type, cleanup, bo); | ||||||
|  | 		else if (bo->command == FLOW_BLOCK_UNBIND) | ||||||
|  | 			indir_dev_remove(data); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	if (bo->command == FLOW_BLOCK_BIND) | 	list_for_each_entry(this, &flow_block_indr_dev_list, list) { | ||||||
| 		indir_dev_add(data, dev, sch, type, cleanup, bo); | 		err = this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup); | ||||||
| 	else if (bo->command == FLOW_BLOCK_UNBIND) | 		if (!err) | ||||||
| 		indir_dev_remove(data); | 			count++; | ||||||
| 
 | 	} | ||||||
| 	list_for_each_entry(this, &flow_block_indr_dev_list, list) |  | ||||||
| 		this->cb(dev, sch, this->cb_priv, type, bo, data, cleanup); |  | ||||||
| 
 | 
 | ||||||
| 	mutex_unlock(&flow_indr_block_lock); | 	mutex_unlock(&flow_indr_block_lock); | ||||||
| 
 | 
 | ||||||
| 	return list_empty(&bo->cb_list) ? -EOPNOTSUPP : 0; | 	return (bo && list_empty(&bo->cb_list)) ? -EOPNOTSUPP : count; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL(flow_indr_dev_setup_offload); | EXPORT_SYMBOL(flow_indr_dev_setup_offload); | ||||||
|  |  | ||||||
|  | @ -19,8 +19,10 @@ | ||||||
| #include <net/sock.h> | #include <net/sock.h> | ||||||
| #include <net/sch_generic.h> | #include <net/sch_generic.h> | ||||||
| #include <net/pkt_cls.h> | #include <net/pkt_cls.h> | ||||||
|  | #include <net/tc_act/tc_pedit.h> | ||||||
| #include <net/act_api.h> | #include <net/act_api.h> | ||||||
| #include <net/netlink.h> | #include <net/netlink.h> | ||||||
|  | #include <net/flow_offload.h> | ||||||
| 
 | 
 | ||||||
| #ifdef CONFIG_INET | #ifdef CONFIG_INET | ||||||
| DEFINE_STATIC_KEY_FALSE(tcf_frag_xmit_count); | DEFINE_STATIC_KEY_FALSE(tcf_frag_xmit_count); | ||||||
|  | @ -129,8 +131,92 @@ static void free_tcf(struct tc_action *p) | ||||||
| 	kfree(p); | 	kfree(p); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static unsigned int tcf_offload_act_num_actions_single(struct tc_action *act) | ||||||
|  | { | ||||||
|  | 	if (is_tcf_pedit(act)) | ||||||
|  | 		return tcf_pedit_nkeys(act); | ||||||
|  | 	else | ||||||
|  | 		return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int offload_action_init(struct flow_offload_action *fl_action, | ||||||
|  | 			       struct tc_action *act, | ||||||
|  | 			       enum offload_act_command  cmd, | ||||||
|  | 			       struct netlink_ext_ack *extack) | ||||||
|  | { | ||||||
|  | 	fl_action->extack = extack; | ||||||
|  | 	fl_action->command = cmd; | ||||||
|  | 	fl_action->index = act->tcfa_index; | ||||||
|  | 
 | ||||||
|  | 	if (act->ops->offload_act_setup) | ||||||
|  | 		return act->ops->offload_act_setup(act, fl_action, NULL, false); | ||||||
|  | 
 | ||||||
|  | 	return -EOPNOTSUPP; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tcf_action_offload_cmd(struct flow_offload_action *fl_act, | ||||||
|  | 				  struct netlink_ext_ack *extack) | ||||||
|  | { | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	err = flow_indr_dev_setup_offload(NULL, NULL, TC_SETUP_ACT, | ||||||
|  | 					  fl_act, NULL, NULL); | ||||||
|  | 	if (err < 0) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* offload the tc action after it is inserted */ | ||||||
|  | static int tcf_action_offload_add(struct tc_action *action, | ||||||
|  | 				  struct netlink_ext_ack *extack) | ||||||
|  | { | ||||||
|  | 	struct tc_action *actions[TCA_ACT_MAX_PRIO] = { | ||||||
|  | 		[0] = action, | ||||||
|  | 	}; | ||||||
|  | 	struct flow_offload_action *fl_action; | ||||||
|  | 	int num, err = 0; | ||||||
|  | 
 | ||||||
|  | 	num = tcf_offload_act_num_actions_single(action); | ||||||
|  | 	fl_action = offload_action_alloc(num); | ||||||
|  | 	if (!fl_action) | ||||||
|  | 		return -ENOMEM; | ||||||
|  | 
 | ||||||
|  | 	err = offload_action_init(fl_action, action, FLOW_ACT_REPLACE, extack); | ||||||
|  | 	if (err) | ||||||
|  | 		goto fl_err; | ||||||
|  | 
 | ||||||
|  | 	err = tc_setup_action(&fl_action->action, actions); | ||||||
|  | 	if (err) { | ||||||
|  | 		NL_SET_ERR_MSG_MOD(extack, | ||||||
|  | 				   "Failed to setup tc actions for offload\n"); | ||||||
|  | 		goto fl_err; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = tcf_action_offload_cmd(fl_action, extack); | ||||||
|  | 	tc_cleanup_offload_action(&fl_action->action); | ||||||
|  | 
 | ||||||
|  | fl_err: | ||||||
|  | 	kfree(fl_action); | ||||||
|  | 
 | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int tcf_action_offload_del(struct tc_action *action) | ||||||
|  | { | ||||||
|  | 	struct flow_offload_action fl_act = {}; | ||||||
|  | 	int err = 0; | ||||||
|  | 
 | ||||||
|  | 	err = offload_action_init(&fl_act, action, FLOW_ACT_DESTROY, NULL); | ||||||
|  | 	if (err) | ||||||
|  | 		return err; | ||||||
|  | 
 | ||||||
|  | 	return tcf_action_offload_cmd(&fl_act, NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void tcf_action_cleanup(struct tc_action *p) | static void tcf_action_cleanup(struct tc_action *p) | ||||||
| { | { | ||||||
|  | 	tcf_action_offload_del(p); | ||||||
| 	if (p->ops->cleanup) | 	if (p->ops->cleanup) | ||||||
| 		p->ops->cleanup(p); | 		p->ops->cleanup(p); | ||||||
| 
 | 
 | ||||||
|  | @ -1061,6 +1147,11 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp, | ||||||
| 	return ERR_PTR(err); | 	return ERR_PTR(err); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool tc_act_bind(u32 flags) | ||||||
|  | { | ||||||
|  | 	return !!(flags & TCA_ACT_FLAGS_BIND); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Returns numbers of initialized actions or negative error. */ | /* Returns numbers of initialized actions or negative error. */ | ||||||
| 
 | 
 | ||||||
| int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, | int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, | ||||||
|  | @ -1103,6 +1194,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla, | ||||||
| 		sz += tcf_action_fill_size(act); | 		sz += tcf_action_fill_size(act); | ||||||
| 		/* Start from index 0 */ | 		/* Start from index 0 */ | ||||||
| 		actions[i - 1] = act; | 		actions[i - 1] = act; | ||||||
|  | 		if (!tc_act_bind(flags)) | ||||||
|  | 			tcf_action_offload_add(act, extack); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* We have to commit them all together, because if any error happened in
 | 	/* We have to commit them all together, because if any error happened in
 | ||||||
|  |  | ||||||
|  | @ -705,7 +705,9 @@ static int tcf_csum_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		entry->csum_flags = tcf_csum_update_flags(act); | 		entry->csum_flags = tcf_csum_update_flags(act); | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		fl_action->id = FLOW_ACTION_CSUM; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -1505,7 +1505,9 @@ static int tcf_ct_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		entry->ct.flow_table = tcf_ct_ft(act); | 		entry->ct.flow_table = tcf_ct_ft(act); | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		fl_action->id = FLOW_ACTION_CT; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -272,7 +272,18 @@ static int tcf_gact_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		} | 		} | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		if (is_tcf_gact_ok(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_ACCEPT; | ||||||
|  | 		else if (is_tcf_gact_shot(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_DROP; | ||||||
|  | 		else if (is_tcf_gact_trap(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_TRAP; | ||||||
|  | 		else if (is_tcf_gact_goto_chain(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_GOTO; | ||||||
|  | 		else | ||||||
|  | 			return -EOPNOTSUPP; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -637,7 +637,9 @@ static int tcf_gate_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 			return err; | 			return err; | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		fl_action->id = FLOW_ACTION_GATE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -482,7 +482,18 @@ static int tcf_mirred_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		} | 		} | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		if (is_tcf_mirred_egress_redirect(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_REDIRECT; | ||||||
|  | 		else if (is_tcf_mirred_egress_mirror(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_MIRRED; | ||||||
|  | 		else if (is_tcf_mirred_ingress_redirect(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_REDIRECT_INGRESS; | ||||||
|  | 		else if (is_tcf_mirred_ingress_mirror(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_MIRRED_INGRESS; | ||||||
|  | 		else | ||||||
|  | 			return -EOPNOTSUPP; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -415,7 +415,21 @@ static int tcf_mpls_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		} | 		} | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		switch (tcf_mpls_action(act)) { | ||||||
|  | 		case TCA_MPLS_ACT_PUSH: | ||||||
|  | 			fl_action->id = FLOW_ACTION_MPLS_PUSH; | ||||||
|  | 			break; | ||||||
|  | 		case TCA_MPLS_ACT_POP: | ||||||
|  | 			fl_action->id = FLOW_ACTION_MPLS_POP; | ||||||
|  | 			break; | ||||||
|  | 		case TCA_MPLS_ACT_MODIFY: | ||||||
|  | 			fl_action->id = FLOW_ACTION_MPLS_MANGLE; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			return -EOPNOTSUPP; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -421,7 +421,9 @@ static int tcf_police_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		entry->police.mtu = tcf_police_tcfp_mtu(act); | 		entry->police.mtu = tcf_police_tcfp_mtu(act); | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		fl_action->id = FLOW_ACTION_POLICE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -303,7 +303,9 @@ static int tcf_sample_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		tcf_offload_sample_get_group(entry, act); | 		tcf_offload_sample_get_group(entry, act); | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		fl_action->id = FLOW_ACTION_SAMPLE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -347,7 +347,16 @@ static int tcf_skbedit_offload_act_setup(struct tc_action *act, void *entry_data | ||||||
| 		} | 		} | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		if (is_tcf_skbedit_mark(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_MARK; | ||||||
|  | 		else if (is_tcf_skbedit_ptype(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_PTYPE; | ||||||
|  | 		else if (is_tcf_skbedit_priority(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_PRIORITY; | ||||||
|  | 		else | ||||||
|  | 			return -EOPNOTSUPP; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -827,7 +827,14 @@ static int tcf_tunnel_key_offload_act_setup(struct tc_action *act, | ||||||
| 		} | 		} | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		if (is_tcf_tunnel_set(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_TUNNEL_ENCAP; | ||||||
|  | 		else if (is_tcf_tunnel_release(act)) | ||||||
|  | 			fl_action->id = FLOW_ACTION_TUNNEL_DECAP; | ||||||
|  | 		else | ||||||
|  | 			return -EOPNOTSUPP; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -395,7 +395,21 @@ static int tcf_vlan_offload_act_setup(struct tc_action *act, void *entry_data, | ||||||
| 		} | 		} | ||||||
| 		*index_inc = 1; | 		*index_inc = 1; | ||||||
| 	} else { | 	} else { | ||||||
| 		return -EOPNOTSUPP; | 		struct flow_offload_action *fl_action = entry_data; | ||||||
|  | 
 | ||||||
|  | 		switch (tcf_vlan_action(act)) { | ||||||
|  | 		case TCA_VLAN_ACT_PUSH: | ||||||
|  | 			fl_action->id = FLOW_ACTION_VLAN_PUSH; | ||||||
|  | 			break; | ||||||
|  | 		case TCA_VLAN_ACT_POP: | ||||||
|  | 			fl_action->id = FLOW_ACTION_VLAN_POP; | ||||||
|  | 			break; | ||||||
|  | 		case TCA_VLAN_ACT_MODIFY: | ||||||
|  | 			fl_action->id = FLOW_ACTION_VLAN_MANGLE; | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			return -EOPNOTSUPP; | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -3488,8 +3488,8 @@ static int tc_setup_offload_act(struct tc_action *act, | ||||||
| #endif | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int tc_setup_offload_action(struct flow_action *flow_action, | int tc_setup_action(struct flow_action *flow_action, | ||||||
| 			    const struct tcf_exts *exts) | 		    struct tc_action *actions[]) | ||||||
| { | { | ||||||
| 	int i, j, index, err = 0; | 	int i, j, index, err = 0; | ||||||
| 	struct tc_action *act; | 	struct tc_action *act; | ||||||
|  | @ -3498,11 +3498,11 @@ int tc_setup_offload_action(struct flow_action *flow_action, | ||||||
| 	BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE); | 	BUILD_BUG_ON(TCA_ACT_HW_STATS_IMMEDIATE != FLOW_ACTION_HW_STATS_IMMEDIATE); | ||||||
| 	BUILD_BUG_ON(TCA_ACT_HW_STATS_DELAYED != FLOW_ACTION_HW_STATS_DELAYED); | 	BUILD_BUG_ON(TCA_ACT_HW_STATS_DELAYED != FLOW_ACTION_HW_STATS_DELAYED); | ||||||
| 
 | 
 | ||||||
| 	if (!exts) | 	if (!actions) | ||||||
| 		return 0; | 		return 0; | ||||||
| 
 | 
 | ||||||
| 	j = 0; | 	j = 0; | ||||||
| 	tcf_exts_for_each_action(i, act, exts) { | 	tcf_act_for_each_action(i, act, actions) { | ||||||
| 		struct flow_action_entry *entry; | 		struct flow_action_entry *entry; | ||||||
| 
 | 
 | ||||||
| 		entry = &flow_action->entries[j]; | 		entry = &flow_action->entries[j]; | ||||||
|  | @ -3531,6 +3531,19 @@ int tc_setup_offload_action(struct flow_action *flow_action, | ||||||
| 	spin_unlock_bh(&act->tcfa_lock); | 	spin_unlock_bh(&act->tcfa_lock); | ||||||
| 	goto err_out; | 	goto err_out; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | int tc_setup_offload_action(struct flow_action *flow_action, | ||||||
|  | 			    const struct tcf_exts *exts) | ||||||
|  | { | ||||||
|  | #ifdef CONFIG_NET_CLS_ACT | ||||||
|  | 	if (!exts) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	return tc_setup_action(flow_action, exts->actions); | ||||||
|  | #else | ||||||
|  | 	return 0; | ||||||
|  | #endif | ||||||
|  | } | ||||||
| EXPORT_SYMBOL(tc_setup_offload_action); | EXPORT_SYMBOL(tc_setup_offload_action); | ||||||
| 
 | 
 | ||||||
| unsigned int tcf_exts_num_actions(struct tcf_exts *exts) | unsigned int tcf_exts_num_actions(struct tcf_exts *exts) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Baowen Zheng
						Baowen Zheng