flow_offload: reject offload for all drivers with invalid police parameters
authorJianbo Liu <jianbol@nvidia.com>
Thu, 24 Feb 2022 10:29:08 +0000 (10:29 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Feb 2022 11:12:20 +0000 (11:12 +0000)
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: Jianbo Liu <jianbol@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
12 files changed:
drivers/net/dsa/sja1105/sja1105_flower.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_tc_matchall.c
drivers/net/ethernet/freescale/enetc/enetc_qos.c
drivers/net/ethernet/marvell/octeontx2/nic/otx2_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
drivers/net/ethernet/mscc/ocelot_flower.c
drivers/net/ethernet/mscc/ocelot_net.c
drivers/net/ethernet/mscc/ocelot_police.c
drivers/net/ethernet/mscc/ocelot_police.h
drivers/net/ethernet/netronome/nfp/flower/qos_conf.c
include/net/flow_offload.h

index 7dcdd78..fad5afe 100644 (file)
@@ -300,6 +300,46 @@ static int sja1105_flower_parse_key(struct sja1105_private *priv,
        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,
                           struct flow_cls_offload *cls, bool ingress)
 {
@@ -321,12 +361,9 @@ int sja1105_cls_flower_add(struct dsa_switch *ds, int port,
        flow_action_for_each(i, act, &rule->action) {
                switch (act->id) {
                case FLOW_ACTION_POLICE:
-                       if (act->police.rate_pkt_ps) {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "QoS offload not support packets per second");
-                               rc = -EOPNOTSUPP;
+                       rc = sja1105_policer_validate(&rule->action, act, extack);
+                       if (rc)
                                goto out;
-                       }
 
                        rc = sja1105_flower_policer(priv, port, extack, cookie,
                                                    &key,
index 28fd2de..1672d3a 100644 (file)
@@ -8,6 +8,46 @@
 #include "cxgb4_filter.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,
                                          struct tc_cls_matchall_offload *cls)
 {
@@ -48,11 +88,10 @@ static int cxgb4_matchall_egress_validate(struct net_device *dev,
        flow_action_for_each(i, entry, actions) {
                switch (entry->id) {
                case FLOW_ACTION_POLICE:
-                       if (entry->police.rate_pkt_ps) {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "QoS offload not support packets per second");
-                               return -EOPNOTSUPP;
-                       }
+                       ret = cxgb4_policer_validate(actions, entry, extack);
+                       if (ret)
+                               return ret;
+
                        /* Convert bytes per second to bits per second */
                        if (entry->police.rate_bytes_ps * 8 > max_link_rate) {
                                NL_SET_ERR_MSG_MOD(extack,
@@ -150,11 +189,11 @@ static int cxgb4_matchall_alloc_tc(struct net_device *dev,
        flow_action_for_each(i, entry, &cls->rule->action)
                if (entry->id == FLOW_ACTION_POLICE)
                        break;
-       if (entry->police.rate_pkt_ps) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "QoS offload not support packets per second");
-               return -EOPNOTSUPP;
-       }
+
+       ret = cxgb4_policer_validate(&cls->rule->action, entry, extack);
+       if (ret)
+               return ret;
+
        /* Convert from bytes per second to Kbps */
        p.u.params.maxrate = div_u64(entry->police.rate_bytes_ps * 8, 1000);
        p.u.params.channel = pi->tx_chan;
index 5a3eea1..79afb1d 100644 (file)
@@ -1021,6 +1021,46 @@ static struct actions_fwd *enetc_check_flow_actions(u64 acts,
        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,
                                      struct flow_cls_offload *f)
 {
@@ -1177,11 +1217,10 @@ static int enetc_psfp_parse_clsflower(struct enetc_ndev_priv *priv,
 
        /* Flow meter and max frame size */
        if (entryp) {
-               if (entryp->police.rate_pkt_ps) {
-                       NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second");
-                       err = -EOPNOTSUPP;
+               err = enetc_psfp_policer_validate(&rule->action, entryp, extack);
+               if (err)
                        goto free_sfi;
-               }
+
                if (entryp->police.burst) {
                        fmi = kzalloc(sizeof(*fmi), GFP_KERNEL);
                        if (!fmi) {
index 0593106..28b1994 100644 (file)
@@ -190,6 +190,40 @@ static int otx2_tc_validate_flow(struct otx2_nic *nic,
        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,
                                           struct tc_cls_matchall_offload *cls)
 {
@@ -212,6 +246,10 @@ static int otx2_tc_egress_matchall_install(struct otx2_nic *nic,
        entry = &cls->rule->action.entries[0];
        switch (entry->id) {
        case FLOW_ACTION_POLICE:
+               err = otx2_policer_validate(&cls->rule->action, entry, extack);
+               if (err)
+                       return err;
+
                if (entry->police.rate_pkt_ps) {
                        NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second");
                        return -EOPNOTSUPP;
@@ -315,6 +353,7 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
        u8 nr_police = 0;
        bool pps = false;
        u64 rate;
+       int err;
        int i;
 
        if (!flow_action_has_entries(flow_action)) {
@@ -355,6 +394,10 @@ static int otx2_tc_parse_actions(struct otx2_nic *nic,
                                return -EOPNOTSUPP;
                        }
 
+                       err = otx2_policer_validate(flow_action, act, extack);
+                       if (err)
+                               return err;
+
                        if (act->police.rate_bytes_ps > 0) {
                                rate = act->police.rate_bytes_ps * 8;
                                burst = act->police.burst;
index 1e7e931..40416e0 100644 (file)
@@ -4482,6 +4482,46 @@ static int apply_police_params(struct mlx5e_priv *priv, u64 rate,
        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,
                                        struct flow_action *flow_action,
                                        struct netlink_ext_ack *extack)
@@ -4509,10 +4549,10 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_POLICE:
-                       if (act->police.rate_pkt_ps) {
-                               NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second");
-                               return -EOPNOTSUPP;
-                       }
+                       err = mlx5e_policer_validate(flow_action, act, extack);
+                       if (err)
+                               return err;
+
                        err = apply_police_params(priv, act->police.rate_bytes_ps, extack);
                        if (err)
                                return err;
index f54af3d..e91fb20 100644 (file)
 #include "spectrum.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,
                                         struct mlxsw_sp_flow_block *block,
                                         struct mlxsw_sp_acl_rule_info *rulei,
@@ -191,10 +231,9 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
                                return -EOPNOTSUPP;
                        }
 
-                       if (act->police.rate_pkt_ps) {
-                               NL_SET_ERR_MSG_MOD(extack, "QoS offload not support packets per second");
-                               return -EOPNOTSUPP;
-                       }
+                       err = mlxsw_sp_policer_validate(flow_action, act, extack);
+                       if (err)
+                               return err;
 
                        /* The kernel might adjust the requested burst size so
                         * that it is not exactly a power of two. Re-adjust it
index 7106137..b3f5418 100644 (file)
@@ -6,6 +6,7 @@
 #include <net/pkt_cls.h>
 #include <net/tc_act/tc_gact.h>
 #include <soc/mscc/ocelot_vcap.h>
+#include "ocelot_police.h"
 #include "ocelot_vcap.h"
 
 /* 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,
                                      bool ingress, struct flow_cls_offload *f,
                                      struct ocelot_vcap_filter *filter)
 {
+       const struct flow_action *action = &f->rule->action;
        struct netlink_ext_ack *extack = f->common.extack;
        bool allow_missing_goto_target = false;
        const struct flow_action_entry *a;
@@ -244,7 +246,7 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
        filter->goto_target = -1;
        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) {
                case FLOW_ACTION_DROP:
                        if (filter->block_id != VCAP_IS2) {
@@ -297,11 +299,11 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
                                                   "Last action must be GOTO");
                                return -EOPNOTSUPP;
                        }
-                       if (a->police.rate_pkt_ps) {
-                               NL_SET_ERR_MSG_MOD(extack,
-                                                  "QoS offload not support packets per second");
-                               return -EOPNOTSUPP;
-                       }
+
+                       err = ocelot_policer_validate(action, a, extack);
+                       if (err)
+                               return err;
+
                        filter->action.police_ena = true;
 
                        pol_ix = a->hw_index + ocelot->vcap_pol.base;
index cfe767d..5767e38 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/phy/phy.h>
 #include <net/pkt_cls.h>
 #include "ocelot.h"
+#include "ocelot_police.h"
 #include "ocelot_vcap.h"
 #include "ocelot_fdma.h"
 
@@ -258,11 +259,10 @@ static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private *priv,
                        return -EEXIST;
                }
 
-               if (action->police.rate_pkt_ps) {
-                       NL_SET_ERR_MSG_MOD(extack,
-                                          "QoS offload not support packets per second");
-                       return -EOPNOTSUPP;
-               }
+               err = ocelot_policer_validate(&f->rule->action, action,
+                                             extack);
+               if (err)
+                       return err;
 
                pol.rate = (u32)div_u64(action->police.rate_bytes_ps, 1000) * 8;
                pol.burst = action->police.burst;
index 6f5068c..a65606b 100644 (file)
@@ -154,6 +154,47 @@ int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
        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,
                            struct ocelot_policer *pol)
 {
index 7adb05f..7552995 100644 (file)
@@ -8,6 +8,7 @@
 #define _MSCC_OCELOT_POLICE_H_
 
 #include "ocelot.h"
+#include <net/flow_offload.h>
 
 enum mscc_qos_rate_mode {
        MSCC_QOS_RATE_MODE_DISABLED, /* Policer/shaper disabled */
@@ -33,4 +34,8 @@ struct qos_policer_conf {
 int qos_policer_conf_set(struct ocelot *ocelot, int port, u32 pol_ix,
                         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_ */
index 6f2f3c7..cd3fdb9 100644 (file)
@@ -117,6 +117,40 @@ int nfp_flower_offload_one_police(struct nfp_app *app, bool ingress,
        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
 nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
                                struct tc_cls_matchall_offload *flow,
@@ -135,6 +169,7 @@ nfp_flower_install_rate_limiter(struct nfp_app *app, struct net_device *netdev,
        u32 burst;
        bool pps;
        u64 rate;
+       int err;
 
        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");
@@ -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");
                        return -EOPNOTSUPP;
                }
+
+               err = nfp_policer_validate(&flow->rule->action, action, extack);
+               if (err)
+                       return err;
+
                if (action->police.rate_bytes_ps > 0) {
                        if (bps_num++) {
                                NL_SET_ERR_MSG_MOD(extack,
index 74f44d4..92267d2 100644 (file)
@@ -311,6 +311,12 @@ static inline bool flow_offload_has_one_action(const struct flow_action *action)
        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)                    \
         for (__i = 0, __act = &(__actions)->entries[0];                        \
             __i < (__actions)->num_entries;                            \