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

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: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1ee47330
...@@ -279,7 +279,8 @@ bnxt_tc_parse_pedit(struct bnxt *bp, struct bnxt_tc_actions *actions, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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) ...@@ -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, ...@@ -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)) {
......
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