Commit c4eb058e authored by David S. Miller's avatar David S. Miller

Merge branch 'flow_offload-tc-police-parameters'

Jianbo Liu says:

====================
flow_offload: add tc police parameters

As a preparation for more advanced police offload in mlx5 (e.g.,
jumping to another chain when bandwidth is not exceeded), extend the
flow offload API with more tc-police parameters. Adjust existing
drivers to reject unsupported configurations.

Changes since v2:
  * Rename index to extval in exceed and notexceed acts.
  * Add policer validate functions for all drivers.

Changes since v1:
  * Add one more strict validation for the control of drop/ok.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b42a738e d97b4b10
...@@ -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,
......
...@@ -148,6 +148,8 @@ enum flow_action_id { ...@@ -148,6 +148,8 @@ enum flow_action_id {
FLOW_ACTION_MPLS_MANGLE, FLOW_ACTION_MPLS_MANGLE,
FLOW_ACTION_GATE, FLOW_ACTION_GATE,
FLOW_ACTION_PPPOE_PUSH, FLOW_ACTION_PPPOE_PUSH,
FLOW_ACTION_JUMP,
FLOW_ACTION_PIPE,
NUM_FLOW_ACTIONS, NUM_FLOW_ACTIONS,
}; };
...@@ -235,9 +237,16 @@ struct flow_action_entry { ...@@ -235,9 +237,16 @@ struct flow_action_entry {
struct { /* FLOW_ACTION_POLICE */ struct { /* FLOW_ACTION_POLICE */
u32 burst; u32 burst;
u64 rate_bytes_ps; u64 rate_bytes_ps;
u64 peakrate_bytes_ps;
u32 avrate;
u16 overhead;
u64 burst_pkt; u64 burst_pkt;
u64 rate_pkt_ps; u64 rate_pkt_ps;
u32 mtu; u32 mtu;
struct {
enum flow_action_id act_id;
u32 extval;
} exceed, notexceed;
} police; } police;
struct { /* FLOW_ACTION_CT */ struct { /* FLOW_ACTION_CT */
int action; int action;
...@@ -302,6 +311,12 @@ static inline bool flow_offload_has_one_action(const struct flow_action *action) ...@@ -302,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; \
......
...@@ -159,4 +159,34 @@ static inline u32 tcf_police_tcfp_mtu(const struct tc_action *act) ...@@ -159,4 +159,34 @@ static inline u32 tcf_police_tcfp_mtu(const struct tc_action *act)
return params->tcfp_mtu; return params->tcfp_mtu;
} }
static inline u64 tcf_police_peakrate_bytes_ps(const struct tc_action *act)
{
struct tcf_police *police = to_police(act);
struct tcf_police_params *params;
params = rcu_dereference_protected(police->params,
lockdep_is_held(&police->tcf_lock));
return params->peak.rate_bytes_ps;
}
static inline u32 tcf_police_tcfp_ewma_rate(const struct tc_action *act)
{
struct tcf_police *police = to_police(act);
struct tcf_police_params *params;
params = rcu_dereference_protected(police->params,
lockdep_is_held(&police->tcf_lock));
return params->tcfp_ewma_rate;
}
static inline u16 tcf_police_rate_overhead(const struct tc_action *act)
{
struct tcf_police *police = to_police(act);
struct tcf_police_params *params;
params = rcu_dereference_protected(police->params,
lockdep_is_held(&police->tcf_lock));
return params->rate.overhead;
}
#endif /* __NET_TC_POLICE_H */ #endif /* __NET_TC_POLICE_H */
...@@ -419,20 +419,66 @@ static int tcf_police_search(struct net *net, struct tc_action **a, u32 index) ...@@ -419,20 +419,66 @@ static int tcf_police_search(struct net *net, struct tc_action **a, u32 index)
return tcf_idr_search(tn, a, index); return tcf_idr_search(tn, a, index);
} }
static int tcf_police_act_to_flow_act(int tc_act, u32 *extval)
{
int act_id = -EOPNOTSUPP;
if (!TC_ACT_EXT_OPCODE(tc_act)) {
if (tc_act == TC_ACT_OK)
act_id = FLOW_ACTION_ACCEPT;
else if (tc_act == TC_ACT_SHOT)
act_id = FLOW_ACTION_DROP;
else if (tc_act == TC_ACT_PIPE)
act_id = FLOW_ACTION_PIPE;
} else if (TC_ACT_EXT_CMP(tc_act, TC_ACT_GOTO_CHAIN)) {
act_id = FLOW_ACTION_GOTO;
*extval = tc_act & TC_ACT_EXT_VAL_MASK;
} else if (TC_ACT_EXT_CMP(tc_act, TC_ACT_JUMP)) {
act_id = FLOW_ACTION_JUMP;
*extval = tc_act & TC_ACT_EXT_VAL_MASK;
}
return act_id;
}
static int tcf_police_offload_act_setup(struct tc_action *act, void *entry_data, static int tcf_police_offload_act_setup(struct tc_action *act, void *entry_data,
u32 *index_inc, bool bind) u32 *index_inc, bool bind)
{ {
if (bind) { if (bind) {
struct flow_action_entry *entry = entry_data; struct flow_action_entry *entry = entry_data;
struct tcf_police *police = to_police(act);
struct tcf_police_params *p;
int act_id;
p = rcu_dereference_protected(police->params,
lockdep_is_held(&police->tcf_lock));
entry->id = FLOW_ACTION_POLICE; entry->id = FLOW_ACTION_POLICE;
entry->police.burst = tcf_police_burst(act); entry->police.burst = tcf_police_burst(act);
entry->police.rate_bytes_ps = entry->police.rate_bytes_ps =
tcf_police_rate_bytes_ps(act); tcf_police_rate_bytes_ps(act);
entry->police.peakrate_bytes_ps = tcf_police_peakrate_bytes_ps(act);
entry->police.avrate = tcf_police_tcfp_ewma_rate(act);
entry->police.overhead = tcf_police_rate_overhead(act);
entry->police.burst_pkt = tcf_police_burst_pkt(act); entry->police.burst_pkt = tcf_police_burst_pkt(act);
entry->police.rate_pkt_ps = entry->police.rate_pkt_ps =
tcf_police_rate_pkt_ps(act); tcf_police_rate_pkt_ps(act);
entry->police.mtu = tcf_police_tcfp_mtu(act); entry->police.mtu = tcf_police_tcfp_mtu(act);
act_id = tcf_police_act_to_flow_act(police->tcf_action,
&entry->police.exceed.extval);
if (act_id < 0)
return act_id;
entry->police.exceed.act_id = act_id;
act_id = tcf_police_act_to_flow_act(p->tcfp_result,
&entry->police.notexceed.extval);
if (act_id < 0)
return act_id;
entry->police.notexceed.act_id = act_id;
*index_inc = 1; *index_inc = 1;
} else { } else {
struct flow_offload_action *fl_action = entry_data; struct flow_offload_action *fl_action = entry_data;
......
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