Commit d97b4b10 authored by Jianbo Liu's avatar Jianbo Liu Committed by David S. Miller

flow_offload: reject offload for all drivers with invalid police parameters

As more police parameters are passed to flow_offload, driver can check
them to make sure hardware handles packets in the way indicated by tc.
The conform-exceed control should be drop/pipe or drop/ok. Besides,
for drop/ok, the police should be the last action. As hardware can't
configure peakrate/avrate/overhead, offload should not be supported if
any of them is configured.
Signed-off-by: default avatarJianbo Liu <jianbol@nvidia.com>
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b8cd5831
...@@ -300,6 +300,46 @@ static int sja1105_flower_parse_key(struct sja1105_private *priv, ...@@ -300,6 +300,46 @@ static int sja1105_flower_parse_key(struct sja1105_private *priv,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int sja1105_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (act->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"QoS offload not support packets per second");
return -EOPNOTSUPP;
}
return 0;
}
int sja1105_cls_flower_add(struct dsa_switch *ds, int port, int sja1105_cls_flower_add(struct dsa_switch *ds, int port,
struct flow_cls_offload *cls, bool ingress) struct flow_cls_offload *cls, bool ingress)
{ {
...@@ -321,12 +361,9 @@ int sja1105_cls_flower_add(struct dsa_switch *ds, int port, ...@@ -321,12 +361,9 @@ int sja1105_cls_flower_add(struct dsa_switch *ds, int port,
flow_action_for_each(i, act, &rule->action) { flow_action_for_each(i, act, &rule->action) {
switch (act->id) { switch (act->id) {
case FLOW_ACTION_POLICE: case FLOW_ACTION_POLICE:
if (act->police.rate_pkt_ps) { rc = sja1105_policer_validate(&rule->action, act, extack);
NL_SET_ERR_MSG_MOD(extack, if (rc)
"QoS offload not support packets per second");
rc = -EOPNOTSUPP;
goto out; goto out;
}
rc = sja1105_flower_policer(priv, port, extack, cookie, rc = sja1105_flower_policer(priv, port, extack, cookie,
&key, &key,
......
...@@ -8,6 +8,46 @@ ...@@ -8,6 +8,46 @@
#include "cxgb4_filter.h" #include "cxgb4_filter.h"
#include "cxgb4_tc_flower.h" #include "cxgb4_tc_flower.h"
static int cxgb4_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (act->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"QoS offload not support packets per second");
return -EOPNOTSUPP;
}
return 0;
}
static int cxgb4_matchall_egress_validate(struct net_device *dev, static int cxgb4_matchall_egress_validate(struct net_device *dev,
struct tc_cls_matchall_offload *cls) struct tc_cls_matchall_offload *cls)
{ {
...@@ -48,11 +88,10 @@ static int cxgb4_matchall_egress_validate(struct net_device *dev, ...@@ -48,11 +88,10 @@ static int cxgb4_matchall_egress_validate(struct net_device *dev,
flow_action_for_each(i, entry, actions) { flow_action_for_each(i, entry, actions) {
switch (entry->id) { switch (entry->id) {
case FLOW_ACTION_POLICE: case FLOW_ACTION_POLICE:
if (entry->police.rate_pkt_ps) { ret = cxgb4_policer_validate(actions, entry, extack);
NL_SET_ERR_MSG_MOD(extack, if (ret)
"QoS offload not support packets per second"); return ret;
return -EOPNOTSUPP;
}
/* Convert bytes per second to bits per second */ /* Convert bytes per second to bits per second */
if (entry->police.rate_bytes_ps * 8 > max_link_rate) { if (entry->police.rate_bytes_ps * 8 > max_link_rate) {
NL_SET_ERR_MSG_MOD(extack, NL_SET_ERR_MSG_MOD(extack,
...@@ -150,11 +189,11 @@ static int cxgb4_matchall_alloc_tc(struct net_device *dev, ...@@ -150,11 +189,11 @@ static int cxgb4_matchall_alloc_tc(struct net_device *dev,
flow_action_for_each(i, entry, &cls->rule->action) flow_action_for_each(i, entry, &cls->rule->action)
if (entry->id == FLOW_ACTION_POLICE) if (entry->id == FLOW_ACTION_POLICE)
break; break;
if (entry->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack, ret = cxgb4_policer_validate(&cls->rule->action, entry, extack);
"QoS offload not support packets per second"); if (ret)
return -EOPNOTSUPP; return ret;
}
/* Convert from bytes per second to Kbps */ /* Convert from bytes per second to Kbps */
p.u.params.maxrate = div_u64(entry->police.rate_bytes_ps * 8, 1000); p.u.params.maxrate = div_u64(entry->police.rate_bytes_ps * 8, 1000);
p.u.params.channel = pi->tx_chan; p.u.params.channel = pi->tx_chan;
......
...@@ -1021,6 +1021,46 @@ static struct actions_fwd *enetc_check_flow_actions(u64 acts, ...@@ -1021,6 +1021,46 @@ static struct actions_fwd *enetc_check_flow_actions(u64 acts,
return NULL; return NULL;
} }
static int enetc_psfp_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (act->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"QoS offload not support packets per second");
return -EOPNOTSUPP;
}
return 0;
}
static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv, static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv,
struct flow_cls_offload *f) struct flow_cls_offload *f)
{ {
...@@ -1177,11 +1217,10 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv, ...@@ -1177,11 +1217,10 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv,
/* Flow meter and max frame size */ /* Flow meter and max frame size */
if (entryp) { if (entryp) {
if (entryp->police.rate_pkt_ps) { err = enetc_psfp_policer_validate(&rule->action, entryp, extack);
NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); if (err)
err = -EOPNOTSUPP;
goto free_sfi; goto free_sfi;
}
if (entryp->police.burst) { if (entryp->police.burst) {
fmi = kzalloc(sizeof(*fmi), GFP_KERNEL); fmi = kzalloc(sizeof(*fmi), GFP_KERNEL);
if (!fmi) { if (!fmi) {
......
...@@ -190,6 +190,40 @@ static int otx2_tc_validate_flow(struct otx2_nic *nic, ...@@ -190,6 +190,40 @@ static int otx2_tc_validate_flow(struct otx2_nic *nic,
return 0; return 0;
} }
static int otx2_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
return 0;
}
static int otx2_tc_egress_matchall_install(struct otx2_nic *nic, static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,
struct tc_cls_matchall_offload *cls) struct tc_cls_matchall_offload *cls)
{ {
...@@ -212,6 +246,10 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic, ...@@ -212,6 +246,10 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,
entry = &cls->rule->action.entries[0]; entry = &cls->rule->action.entries[0];
switch (entry->id) { switch (entry->id) {
case FLOW_ACTION_POLICE: case FLOW_ACTION_POLICE:
err = otx2_policer_validate(&cls->rule->action, entry, extack);
if (err)
return err;
if (entry->police.rate_pkt_ps) { if (entry->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second");
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -315,6 +353,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, ...@@ -315,6 +353,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
u8 nr_police = 0; u8 nr_police = 0;
bool pps = false; bool pps = false;
u64 rate; u64 rate;
int err;
int i; int i;
if (!flow_action_has_entries(flow_action)) { if (!flow_action_has_entries(flow_action)) {
...@@ -355,6 +394,10 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic, ...@@ -355,6 +394,10 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
err = otx2_policer_validate(flow_action, act, extack);
if (err)
return err;
if (act->police.rate_bytes_ps > 0) { if (act->police.rate_bytes_ps > 0) {
rate = act->police.rate_bytes_ps * 8; rate = act->police.rate_bytes_ps * 8;
burst = act->police.burst; burst = act->police.burst;
......
...@@ -4482,6 +4482,46 @@ static int apply_police_params(struct mlx5e_priv *priv, u64 rate, ...@@ -4482,6 +4482,46 @@ static int apply_police_params(struct mlx5e_priv *priv, u64 rate,
return err; return err;
} }
static int mlx5e_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (act->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"QoS offload not support packets per second");
return -EOPNOTSUPP;
}
return 0;
}
static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv, static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
struct flow_action *flow_action, struct flow_action *flow_action,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
...@@ -4509,10 +4549,10 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv, ...@@ -4509,10 +4549,10 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
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:
if (act->police.rate_pkt_ps) { err = mlx5e_policer_validate(flow_action, act, extack);
NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); if (err)
return -EOPNOTSUPP; return err;
}
err = apply_police_params(priv, act->police.rate_bytes_ps, extack); err = apply_police_params(priv, act->police.rate_bytes_ps, extack);
if (err) if (err)
return err; return err;
......
...@@ -15,6 +15,46 @@ ...@@ -15,6 +15,46 @@
#include "spectrum.h" #include "spectrum.h"
#include "core_acl_flex_keys.h" #include "core_acl_flex_keys.h"
static int mlxsw_sp_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (act->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"QoS offload not support packets per second");
return -EOPNOTSUPP;
}
return 0;
}
static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_flow_block *block, struct mlxsw_sp_flow_block *block,
struct mlxsw_sp_acl_rule_info *rulei, struct mlxsw_sp_acl_rule_info *rulei,
...@@ -191,10 +231,9 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, ...@@ -191,10 +231,9 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (act->police.rate_pkt_ps) { err = mlxsw_sp_policer_validate(flow_action, act, extack);
NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second"); if (err)
return -EOPNOTSUPP; return err;
}
/* The kernel might adjust the requested burst size so /* The kernel might adjust the requested burst size so
* that it is not exactly a power of two. Re-adjust it * that it is not exactly a power of two. Re-adjust it
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include <net/tc_act/tc_gact.h> #include <net/tc_act/tc_gact.h>
#include <soc/mscc/ocelot_vcap.h> #include <soc/mscc/ocelot_vcap.h>
#include "ocelot_police.h"
#include "ocelot_vcap.h" #include "ocelot_vcap.h"
/* Arbitrarily chosen constants for encoding the VCAP block and lookup number /* Arbitrarily chosen constants for encoding the VCAP block and lookup number
...@@ -217,6 +218,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -217,6 +218,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
bool ingress, struct flow_cls_offload *f, bool ingress, struct flow_cls_offload *f,
struct ocelot_vcap_filter *filter) struct ocelot_vcap_filter *filter)
{ {
const struct flow_action *action = &f->rule->action;
struct netlink_ext_ack *extack = f->common.extack; struct netlink_ext_ack *extack = f->common.extack;
bool allow_missing_goto_target = false; bool allow_missing_goto_target = false;
const struct flow_action_entry *a; const struct flow_action_entry *a;
...@@ -244,7 +246,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -244,7 +246,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
filter->goto_target = -1; filter->goto_target = -1;
filter->type = OCELOT_VCAP_FILTER_DUMMY; filter->type = OCELOT_VCAP_FILTER_DUMMY;
flow_action_for_each(i, a, &f->rule->action) { flow_action_for_each(i, a, action) {
switch (a->id) { switch (a->id) {
case FLOW_ACTION_DROP: case FLOW_ACTION_DROP:
if (filter->block_id != VCAP_IS2) { if (filter->block_id != VCAP_IS2) {
...@@ -297,11 +299,11 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port, ...@@ -297,11 +299,11 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
"Last action must be GOTO"); "Last action must be GOTO");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
if (a->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack, err = ocelot_policer_validate(action, a, extack);
"QoS offload not support packets per second"); if (err)
return -EOPNOTSUPP; return err;
}
filter->action.police_ena = true; filter->action.police_ena = true;
pol_ix = a->hw_index + ocelot->vcap_pol.base; pol_ix = a->hw_index + ocelot->vcap_pol.base;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <net/pkt_cls.h> #include <net/pkt_cls.h>
#include "ocelot.h" #include "ocelot.h"
#include "ocelot_police.h"
#include "ocelot_vcap.h" #include "ocelot_vcap.h"
#include "ocelot_fdma.h" #include "ocelot_fdma.h"
...@@ -258,11 +259,10 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv, ...@@ -258,11 +259,10 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
return -EEXIST; return -EEXIST;
} }
if (action->police.rate_pkt_ps) { err = ocelot_policer_validate(&f->rule->action, action,
NL_SET_ERR_MSG_MOD(extack, extack);
"QoS offload not support packets per second"); if (err)
return -EOPNOTSUPP; return err;
}
pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8; pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
pol.burst = action->police.burst; pol.burst = action->police.burst;
......
...@@ -154,6 +154,47 @@ int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, ...@@ -154,6 +154,47 @@ int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
return 0; return 0;
} }
int ocelot_policer_validate(const struct flow_action *action,
const struct flow_action_entry *a,
struct netlink_ext_ack *extack)
{
if (a->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (a->police.notexceed.act_id != FLOW_ACTION_PIPE &&
a->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (a->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, a)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but police action is not last");
return -EOPNOTSUPP;
}
if (a->police.peakrate_bytes_ps ||
a->police.avrate || a->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
if (a->police.rate_pkt_ps) {
NL_SET_ERR_MSG_MOD(extack,
"Offload does not support packets per second");
return -EOPNOTSUPP;
}
return 0;
}
EXPORT_SYMBOL(ocelot_policer_validate);
int ocelot_port_policer_add(struct ocelot *ocelot, int port, int ocelot_port_policer_add(struct ocelot *ocelot, int port,
struct ocelot_policer *pol) struct ocelot_policer *pol)
{ {
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define _MSCC_OCELOT_POLICE_H_ #define _MSCC_OCELOT_POLICE_H_
#include "ocelot.h" #include "ocelot.h"
#include <net/flow_offload.h>
enum mscc_qos_rate_mode { enum mscc_qos_rate_mode {
MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */ MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
...@@ -33,4 +34,8 @@ struct qos_policer_conf { ...@@ -33,4 +34,8 @@ struct qos_policer_conf {
int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix, int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
struct qos_policer_conf *conf); struct qos_policer_conf *conf);
int ocelot_policer_validate(const struct flow_action *action,
const struct flow_action_entry *a,
struct netlink_ext_ack *extack);
#endif /* _MSCC_OCELOT_POLICE_H_ */ #endif /* _MSCC_OCELOT_POLICE_H_ */
...@@ -117,6 +117,40 @@ int nfp_flower_offload_one_police(struct nfp_app *app, bool ingress, ...@@ -117,6 +117,40 @@ int nfp_flower_offload_one_police(struct nfp_app *app, bool ingress,
return 0; return 0;
} }
static int nfp_policer_validate(const struct flow_action *action,
const struct flow_action_entry *act,
struct netlink_ext_ack *extack)
{
if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when exceed action is not drop");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is not pipe or ok");
return -EOPNOTSUPP;
}
if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
!flow_action_is_last_entry(action, act)) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when conform action is ok, but action is not last");
return -EOPNOTSUPP;
}
if (act->police.peakrate_bytes_ps ||
act->police.avrate || act->police.overhead) {
NL_SET_ERR_MSG_MOD(extack,
"Offload not supported when peakrate/avrate/overhead is configured");
return -EOPNOTSUPP;
}
return 0;
}
static int static int
nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev, nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
struct tc_cls_matchall_offload *flow, struct tc_cls_matchall_offload *flow,
...@@ -135,6 +169,7 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev, ...@@ -135,6 +169,7 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
u32 burst; u32 burst;
bool pps; bool pps;
u64 rate; u64 rate;
int err;
if (!nfp_netdev_is_nfp_repr(netdev)) { if (!nfp_netdev_is_nfp_repr(netdev)) {
NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port"); NL_SET_ERR_MSG_MOD(extack, "unsupported offload: qos rate limit offload not supported on higher level port");
...@@ -181,6 +216,11 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev, ...@@ -181,6 +216,11 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
"unsupported offload: qos rate limit offload requires police action"); "unsupported offload: qos rate limit offload requires police action");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
err = nfp_policer_validate(&flow->rule->action, action, extack);
if (err)
return err;
if (action->police.rate_bytes_ps > 0) { if (action->police.rate_bytes_ps > 0) {
if (bps_num++) { if (bps_num++) {
NL_SET_ERR_MSG_MOD(extack, NL_SET_ERR_MSG_MOD(extack,
......
...@@ -311,6 +311,12 @@ static inline bool flow_offload_has_one_action(const struct flow_action *action) ...@@ -311,6 +311,12 @@ 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_is_last_entry(const struct flow_action *action,
const struct flow_action_entry *entry)
{
return entry == &action->entries[action->num_entries - 1];
}
#define flow_action_for_each(__i, __act, __actions) \ #define flow_action_for_each(__i, __act, __actions) \
for (__i = 0, __act = &(__actions)->entries[0]; \ for (__i = 0, __act = &(__actions)->entries[0]; \
__i < (__actions)->num_entries; \ __i < (__actions)->num_entries; \
......
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