forked from mirrors/linux
		
	flow_offload: check for basic action hw stats type
Introduce flow_action_basic_hw_stats_types_check() helper and use it in drivers. That sanitizes the drivers which do not have support for action HW stats types. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									1ee473306a
								
							
						
					
					
						commit
						319a1d1947
					
				
					 12 changed files with 119 additions and 11 deletions
				
			
		| 
						 | 
					@ -279,7 +279,8 @@ bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bnxt_tc_parse_actions(struct bnxt *bp,
 | 
					static int bnxt_tc_parse_actions(struct bnxt *bp,
 | 
				
			||||||
				 struct bnxt_tc_actions *actions,
 | 
									 struct bnxt_tc_actions *actions,
 | 
				
			||||||
				 struct flow_action *flow_action)
 | 
									 struct flow_action *flow_action,
 | 
				
			||||||
 | 
									 struct netlink_ext_ack *extack)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Used to store the L2 rewrite mask for dmac (6 bytes) followed by
 | 
						/* Used to store the L2 rewrite mask for dmac (6 bytes) followed by
 | 
				
			||||||
	 * smac (6 bytes) if rewrite of both is specified, otherwise either
 | 
						 * smac (6 bytes) if rewrite of both is specified, otherwise either
 | 
				
			||||||
| 
						 | 
					@ -299,6 +300,9 @@ static int bnxt_tc_parse_actions(struct bnxt *bp,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, act, flow_action) {
 | 
						flow_action_for_each(i, act, flow_action) {
 | 
				
			||||||
		switch (act->id) {
 | 
							switch (act->id) {
 | 
				
			||||||
		case FLOW_ACTION_DROP:
 | 
							case FLOW_ACTION_DROP:
 | 
				
			||||||
| 
						 | 
					@ -491,7 +495,8 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
 | 
				
			||||||
		flow->tun_mask.tp_src = match.mask->src;
 | 
							flow->tun_mask.tp_src = match.mask->src;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return bnxt_tc_parse_actions(bp, &flow->actions, &rule->action);
 | 
						return bnxt_tc_parse_actions(bp, &flow->actions, &rule->action,
 | 
				
			||||||
 | 
									     tc_flow_cmd->common.extack);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int bnxt_hwrm_cfa_flow_free(struct bnxt *bp,
 | 
					static int bnxt_hwrm_cfa_flow_free(struct bnxt *bp,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -544,7 +544,8 @@ static bool valid_pedit_action(struct net_device *dev,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int cxgb4_validate_flow_actions(struct net_device *dev,
 | 
					int cxgb4_validate_flow_actions(struct net_device *dev,
 | 
				
			||||||
				struct flow_action *actions)
 | 
									struct flow_action *actions,
 | 
				
			||||||
 | 
									struct netlink_ext_ack *extack)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct flow_action_entry *act;
 | 
						struct flow_action_entry *act;
 | 
				
			||||||
	bool act_redir = false;
 | 
						bool act_redir = false;
 | 
				
			||||||
| 
						 | 
					@ -552,6 +553,9 @@ int cxgb4_validate_flow_actions(struct net_device *dev,
 | 
				
			||||||
	bool act_vlan = false;
 | 
						bool act_vlan = false;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(actions, extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, act, actions) {
 | 
						flow_action_for_each(i, act, actions) {
 | 
				
			||||||
		switch (act->id) {
 | 
							switch (act->id) {
 | 
				
			||||||
		case FLOW_ACTION_ACCEPT:
 | 
							case FLOW_ACTION_ACCEPT:
 | 
				
			||||||
| 
						 | 
					@ -642,7 +646,7 @@ int cxgb4_tc_flower_replace(struct net_device *dev,
 | 
				
			||||||
	struct filter_ctx ctx;
 | 
						struct filter_ctx ctx;
 | 
				
			||||||
	int fidx, ret;
 | 
						int fidx, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cxgb4_validate_flow_actions(dev, &rule->action))
 | 
						if (cxgb4_validate_flow_actions(dev, &rule->action, extack))
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cxgb4_validate_flow_match(dev, cls))
 | 
						if (cxgb4_validate_flow_match(dev, cls))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,7 +112,8 @@ void cxgb4_process_flow_actions(struct net_device *in,
 | 
				
			||||||
				struct flow_action *actions,
 | 
									struct flow_action *actions,
 | 
				
			||||||
				struct ch_filter_specification *fs);
 | 
									struct ch_filter_specification *fs);
 | 
				
			||||||
int cxgb4_validate_flow_actions(struct net_device *dev,
 | 
					int cxgb4_validate_flow_actions(struct net_device *dev,
 | 
				
			||||||
				struct flow_action *actions);
 | 
									struct flow_action *actions,
 | 
				
			||||||
 | 
									struct netlink_ext_ack *extack);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int cxgb4_tc_flower_replace(struct net_device *dev,
 | 
					int cxgb4_tc_flower_replace(struct net_device *dev,
 | 
				
			||||||
			    struct flow_cls_offload *cls);
 | 
								    struct flow_cls_offload *cls);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,7 +286,8 @@ int cxgb4_tc_matchall_replace(struct net_device *dev,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = cxgb4_validate_flow_actions(dev,
 | 
							ret = cxgb4_validate_flow_actions(dev,
 | 
				
			||||||
						  &cls_matchall->rule->action);
 | 
											  &cls_matchall->rule->action,
 | 
				
			||||||
 | 
											  extack);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1082,6 +1082,9 @@ static int mvpp2_port_c2_tcam_rule_add(struct mvpp2_port *port,
 | 
				
			||||||
	u8 qh, ql, pmap;
 | 
						u8 qh, ql, pmap;
 | 
				
			||||||
	int index, ctx;
 | 
						int index, ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(&rule->flow->action, NULL))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&c2, 0, sizeof(c2));
 | 
						memset(&c2, 0, sizeof(c2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	index = mvpp2_cls_c2_port_flow_index(port, rule->loc);
 | 
						index = mvpp2_cls_c2_port_flow_index(port, rule->loc);
 | 
				
			||||||
| 
						 | 
					@ -1305,6 +1308,9 @@ static int mvpp2_cls_rfs_parse_rule(struct mvpp2_rfs_rule *rule)
 | 
				
			||||||
	struct flow_rule *flow = rule->flow;
 | 
						struct flow_rule *flow = rule->flow;
 | 
				
			||||||
	struct flow_action_entry *act;
 | 
						struct flow_action_entry *act;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(&rule->flow->action, NULL))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	act = &flow->action.entries[0];
 | 
						act = &flow->action.entries[0];
 | 
				
			||||||
	if (act->id != FLOW_ACTION_QUEUE && act->id != FLOW_ACTION_DROP)
 | 
						if (act->id != FLOW_ACTION_QUEUE && act->id != FLOW_ACTION_DROP)
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2878,6 +2878,9 @@ static int parse_tc_nic_actions(struct mlx5e_priv *priv,
 | 
				
			||||||
	if (!flow_action_has_entries(flow_action))
 | 
						if (!flow_action_has_entries(flow_action))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
 | 
						attr->flow_tag = MLX5_FS_DEFAULT_FLOW_TAG;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, act, flow_action) {
 | 
						flow_action_for_each(i, act, flow_action) {
 | 
				
			||||||
| 
						 | 
					@ -3330,6 +3333,9 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv,
 | 
				
			||||||
	if (!flow_action_has_entries(flow_action))
 | 
						if (!flow_action_has_entries(flow_action))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, act, flow_action) {
 | 
						flow_action_for_each(i, act, flow_action) {
 | 
				
			||||||
		switch (act->id) {
 | 
							switch (act->id) {
 | 
				
			||||||
		case FLOW_ACTION_DROP:
 | 
							case FLOW_ACTION_DROP:
 | 
				
			||||||
| 
						 | 
					@ -4148,6 +4154,9 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, act, flow_action) {
 | 
						flow_action_for_each(i, act, flow_action) {
 | 
				
			||||||
		switch (act->id) {
 | 
							switch (act->id) {
 | 
				
			||||||
		case FLOW_ACTION_POLICE:
 | 
							case FLOW_ACTION_POLICE:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,10 @@ static int ocelot_flower_parse_action(struct flow_cls_offload *f,
 | 
				
			||||||
	if (!flow_offload_has_one_action(&f->rule->action))
 | 
						if (!flow_offload_has_one_action(&f->rule->action))
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(&f->rule->action,
 | 
				
			||||||
 | 
											    f->common.extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, a, &f->rule->action) {
 | 
						flow_action_for_each(i, a, &f->rule->action) {
 | 
				
			||||||
		switch (a->id) {
 | 
							switch (a->id) {
 | 
				
			||||||
		case FLOW_ACTION_DROP:
 | 
							case FLOW_ACTION_DROP:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1207,6 +1207,10 @@ int nfp_flower_compile_action(struct nfp_app *app,
 | 
				
			||||||
	bool pkt_host = false;
 | 
						bool pkt_host = false;
 | 
				
			||||||
	u32 csum_updated = 0;
 | 
						u32 csum_updated = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(&flow->rule->action,
 | 
				
			||||||
 | 
											    extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ);
 | 
						memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ);
 | 
				
			||||||
	nfp_flow->meta.act_len = 0;
 | 
						nfp_flow->meta.act_len = 0;
 | 
				
			||||||
	tun_type = NFP_FL_TUNNEL_NONE;
 | 
						tun_type = NFP_FL_TUNNEL_NONE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1746,7 +1746,8 @@ int qede_get_arfs_filter_count(struct qede_dev *edev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int qede_parse_actions(struct qede_dev *edev,
 | 
					static int qede_parse_actions(struct qede_dev *edev,
 | 
				
			||||||
			      struct flow_action *flow_action)
 | 
								      struct flow_action *flow_action,
 | 
				
			||||||
 | 
								      struct netlink_ext_ack *extack)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct flow_action_entry *act;
 | 
						const struct flow_action_entry *act;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
| 
						 | 
					@ -1756,6 +1757,9 @@ static int qede_parse_actions(struct qede_dev *edev,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(flow_action, extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, act, flow_action) {
 | 
						flow_action_for_each(i, act, flow_action) {
 | 
				
			||||||
		switch (act->id) {
 | 
							switch (act->id) {
 | 
				
			||||||
		case FLOW_ACTION_DROP:
 | 
							case FLOW_ACTION_DROP:
 | 
				
			||||||
| 
						 | 
					@ -1970,7 +1974,7 @@ int qede_add_tc_flower_fltr(struct qede_dev *edev, __be16 proto,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* parse tc actions and get the vf_id */
 | 
						/* parse tc actions and get the vf_id */
 | 
				
			||||||
	if (qede_parse_actions(edev, &f->rule->action))
 | 
						if (qede_parse_actions(edev, &f->rule->action, f->common.extack))
 | 
				
			||||||
		goto unlock;
 | 
							goto unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (qede_flow_find_fltr(edev, &t)) {
 | 
						if (qede_flow_find_fltr(edev, &t)) {
 | 
				
			||||||
| 
						 | 
					@ -2038,7 +2042,7 @@ static int qede_flow_spec_validate(struct qede_dev *edev,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (qede_parse_actions(edev, flow_action))
 | 
						if (qede_parse_actions(edev, flow_action, NULL))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -367,7 +367,8 @@ static int tc_setup_cbs(struct stmmac_priv *priv,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tc_parse_flow_actions(struct stmmac_priv *priv,
 | 
					static int tc_parse_flow_actions(struct stmmac_priv *priv,
 | 
				
			||||||
				 struct flow_action *action,
 | 
									 struct flow_action *action,
 | 
				
			||||||
				 struct stmmac_flow_entry *entry)
 | 
									 struct stmmac_flow_entry *entry,
 | 
				
			||||||
 | 
									 struct netlink_ext_ack *extack)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct flow_action_entry *act;
 | 
						struct flow_action_entry *act;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
| 
						 | 
					@ -375,6 +376,9 @@ static int tc_parse_flow_actions(struct stmmac_priv *priv,
 | 
				
			||||||
	if (!flow_action_has_entries(action))
 | 
						if (!flow_action_has_entries(action))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(action, extack))
 | 
				
			||||||
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow_action_for_each(i, act, action) {
 | 
						flow_action_for_each(i, act, action) {
 | 
				
			||||||
		switch (act->id) {
 | 
							switch (act->id) {
 | 
				
			||||||
		case FLOW_ACTION_DROP:
 | 
							case FLOW_ACTION_DROP:
 | 
				
			||||||
| 
						 | 
					@ -530,7 +534,8 @@ static int tc_add_flow(struct stmmac_priv *priv,
 | 
				
			||||||
			return -ENOENT;
 | 
								return -ENOENT;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = tc_parse_flow_actions(priv, &rule->action, entry);
 | 
						ret = tc_parse_flow_actions(priv, &rule->action, entry,
 | 
				
			||||||
 | 
									    cls->common.extack);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/kernel.h>
 | 
					#include <linux/kernel.h>
 | 
				
			||||||
#include <linux/list.h>
 | 
					#include <linux/list.h>
 | 
				
			||||||
 | 
					#include <linux/netlink.h>
 | 
				
			||||||
#include <net/flow_dissector.h>
 | 
					#include <net/flow_dissector.h>
 | 
				
			||||||
#include <linux/rhashtable.h>
 | 
					#include <linux/rhashtable.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -251,6 +252,66 @@ static inline bool flow_offload_has_one_action(const struct flow_action *action)
 | 
				
			||||||
	return action->num_entries == 1;
 | 
						return action->num_entries == 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					flow_action_mixed_hw_stats_types_check(const struct flow_action *action,
 | 
				
			||||||
 | 
									       struct netlink_ext_ack *extack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct flow_action_entry *action_entry;
 | 
				
			||||||
 | 
						u8 uninitialized_var(last_hw_stats_type);
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (flow_offload_has_one_action(action))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < action->num_entries; i++) {
 | 
				
			||||||
 | 
							action_entry = &action->entries[i];
 | 
				
			||||||
 | 
							if (i && action_entry->hw_stats_type != last_hw_stats_type) {
 | 
				
			||||||
 | 
								NL_SET_ERR_MSG_MOD(extack, "Mixing HW stats types for actions is not supported");
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							last_hw_stats_type = action_entry->hw_stats_type;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline const struct flow_action_entry *
 | 
				
			||||||
 | 
					flow_action_first_entry_get(const struct flow_action *action)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						WARN_ON(!flow_action_has_entries(action));
 | 
				
			||||||
 | 
						return &action->entries[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					flow_action_hw_stats_types_check(const struct flow_action *action,
 | 
				
			||||||
 | 
									 struct netlink_ext_ack *extack,
 | 
				
			||||||
 | 
									 u8 allowed_hw_stats_type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct flow_action_entry *action_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_has_entries(action))
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						if (!flow_action_mixed_hw_stats_types_check(action, extack))
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						action_entry = flow_action_first_entry_get(action);
 | 
				
			||||||
 | 
						if (allowed_hw_stats_type == 0 &&
 | 
				
			||||||
 | 
						    action_entry->hw_stats_type != FLOW_ACTION_HW_STATS_TYPE_ANY) {
 | 
				
			||||||
 | 
							NL_SET_ERR_MSG_MOD(extack, "Driver supports only default HW stats type \"any\"");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						} else if (allowed_hw_stats_type != 0 &&
 | 
				
			||||||
 | 
							   action_entry->hw_stats_type != allowed_hw_stats_type) {
 | 
				
			||||||
 | 
							NL_SET_ERR_MSG_MOD(extack, "Driver does not support selected HW stats type");
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool
 | 
				
			||||||
 | 
					flow_action_basic_hw_stats_types_check(const struct flow_action *action,
 | 
				
			||||||
 | 
									       struct netlink_ext_ack *extack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return flow_action_hw_stats_types_check(action, extack, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define flow_action_for_each(__i, __act, __actions)			\
 | 
					#define flow_action_for_each(__i, __act, __actions)			\
 | 
				
			||||||
        for (__i = 0, __act = &(__actions)->entries[0]; __i < (__actions)->num_entries; __act = &(__actions)->entries[++__i])
 | 
					        for (__i = 0, __act = &(__actions)->entries[0]; __i < (__actions)->num_entries; __act = &(__actions)->entries[++__i])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -865,6 +865,10 @@ static int dsa_slave_add_cls_matchall(struct net_device *dev,
 | 
				
			||||||
	if (!flow_offload_has_one_action(&cls->rule->action))
 | 
						if (!flow_offload_has_one_action(&cls->rule->action))
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!flow_action_basic_hw_stats_types_check(&cls->rule->action,
 | 
				
			||||||
 | 
											    cls->common.extack))
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	act = &cls->rule->action.entries[0];
 | 
						act = &cls->rule->action.entries[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) {
 | 
						if (act->id == FLOW_ACTION_MIRRED && protocol == htons(ETH_P_ALL)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue