net/mlx5e: TC, add support for meter mtu offload
authorOz Shlomo <ozsh@nvidia.com>
Wed, 2 Nov 2022 14:36:51 +0000 (14:36 +0000)
committerSaeed Mahameed <saeedm@nvidia.com>
Fri, 9 Dec 2022 00:10:55 +0000 (16:10 -0800)
Initialize the meter object with the TC police mtu parameter.
Use the hardware range destination to compare the pkt len to the mtu setting.
Assign the range destination hit/miss ft to the police conform/exceed
attributes.

Signed-off-by: Oz Shlomo <ozsh@nvidia.com>
Reviewed-by: Roi Dayan <roid@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/police.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/post_meter.h
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.h
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c

index 898fe16a4384cb11dae0a75131733ea27acba9b9..512d431489228eba07e4e333632f28ff2807ba6e 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "act.h"
 #include "en/tc_priv.h"
+#include "fs_core.h"
 
 static bool police_act_validate_control(enum flow_action_id act_id,
                                        struct netlink_ext_ack *extack)
@@ -71,6 +72,8 @@ fill_meter_params_from_act(const struct flow_action_entry *act,
                params->mode = MLX5_RATE_LIMIT_PPS;
                params->rate = act->police.rate_pkt_ps;
                params->burst = act->police.burst_pkt;
+       } else if (act->police.mtu) {
+               params->mtu = act->police.mtu;
        } else {
                return -EOPNOTSUPP;
        }
@@ -84,14 +87,25 @@ tc_act_parse_police(struct mlx5e_tc_act_parse_state *parse_state,
                    struct mlx5e_priv *priv,
                    struct mlx5_flow_attr *attr)
 {
+       enum mlx5_flow_namespace_type ns =  mlx5e_get_flow_namespace(parse_state->flow);
+       struct mlx5e_flow_meter_params *params = &attr->meter_attr.params;
        int err;
 
-       err = fill_meter_params_from_act(act, &attr->meter_attr.params);
+       err = fill_meter_params_from_act(act, params);
        if (err)
                return err;
 
-       attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
-       attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
+       if (params->mtu) {
+               if (!(mlx5_fs_get_capabilities(priv->mdev, ns) &
+                     MLX5_FLOW_STEERING_CAP_MATCH_RANGES))
+                       return -EOPNOTSUPP;
+
+               attr->action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+               attr->flags |= MLX5_ATTR_FLAG_MTU;
+       } else {
+               attr->action |= MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO;
+               attr->exe_aso_type = MLX5_EXE_ASO_FLOW_METER;
+       }
 
        return 0;
 }
index 4e5f4aa44724e97dded4aaecf2e24c9202cd9c90..9c1c24da94530b0892c307be11701505bf11f9eb 100644 (file)
@@ -241,7 +241,7 @@ mlx5e_flow_meter_destroy_aso_obj(struct mlx5_core_dev *mdev, u32 obj_id)
 }
 
 static struct mlx5e_flow_meter_handle *
-__mlx5e_flow_meter_alloc(struct mlx5e_flow_meters *flow_meters)
+__mlx5e_flow_meter_alloc(struct mlx5e_flow_meters *flow_meters, bool alloc_aso)
 {
        struct mlx5_core_dev *mdev = flow_meters->mdev;
        struct mlx5e_flow_meter_aso_obj *meters_obj;
@@ -268,6 +268,9 @@ __mlx5e_flow_meter_alloc(struct mlx5e_flow_meters *flow_meters)
        }
        meter->act_counter = counter;
 
+       if (!alloc_aso)
+               goto no_aso;
+
        meters_obj = list_first_entry_or_null(&flow_meters->partial_list,
                                              struct mlx5e_flow_meter_aso_obj,
                                              entry);
@@ -300,11 +303,12 @@ __mlx5e_flow_meter_alloc(struct mlx5e_flow_meters *flow_meters)
        }
 
        bitmap_set(meters_obj->meters_map, pos, 1);
-       meter->flow_meters = flow_meters;
        meter->meters_obj = meters_obj;
        meter->obj_id = meters_obj->base_id + pos / 2;
        meter->idx = pos % 2;
 
+no_aso:
+       meter->flow_meters = flow_meters;
        mlx5_core_dbg(mdev, "flow meter allocated, obj_id=0x%x, index=%d\n",
                      meter->obj_id, meter->idx);
 
@@ -332,6 +336,9 @@ __mlx5e_flow_meter_free(struct mlx5e_flow_meter_handle *meter)
        mlx5_fc_destroy(mdev, meter->act_counter);
        mlx5_fc_destroy(mdev, meter->drop_counter);
 
+       if (meter->params.mtu)
+               goto out_no_aso;
+
        meters_obj = meter->meters_obj;
        pos = (meter->obj_id - meters_obj->base_id) * 2 + meter->idx;
        bitmap_clear(meters_obj->meters_map, pos, 1);
@@ -345,6 +352,7 @@ __mlx5e_flow_meter_free(struct mlx5e_flow_meter_handle *meter)
                list_add(&meters_obj->entry, &flow_meters->partial_list);
        }
 
+out_no_aso:
        mlx5_core_dbg(mdev, "flow meter freed, obj_id=0x%x, index=%d\n",
                      meter->obj_id, meter->idx);
        kfree(meter);
@@ -409,12 +417,13 @@ mlx5e_tc_meter_alloc(struct mlx5e_flow_meters *flow_meters,
 {
        struct mlx5e_flow_meter_handle *meter;
 
-       meter = __mlx5e_flow_meter_alloc(flow_meters);
+       meter = __mlx5e_flow_meter_alloc(flow_meters, !params->mtu);
        if (IS_ERR(meter))
                return meter;
 
        hash_add(flow_meters->hashtbl, &meter->hlist, params->index);
        meter->params.index = params->index;
+       meter->params.mtu = params->mtu;
        meter->refcnt++;
 
        return meter;
index f16abf33bb515e26b0217d32b8eabb2a34067cfc..9b795cd106bbe4aa7608e76ba9c2c799cf1dcfd0 100644 (file)
@@ -20,6 +20,7 @@ struct mlx5e_flow_meter_params {
        u32 index;
        u64 rate;
        u64 burst;
+       u32 mtu;
 };
 
 struct mlx5e_flow_meter_handle {
index ffed3af7d01ec343464f968e520be5a962ad4670..8d7d761482d272bae10a3b75c080955ef564ba5d 100644 (file)
@@ -43,6 +43,18 @@ mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter)
        return post_meter->rate_steering_table.ft;
 }
 
+struct mlx5_flow_table *
+mlx5e_post_meter_get_mtu_true_ft(struct mlx5e_post_meter_priv *post_meter)
+{
+       return post_meter->mtu_tables.green_table.ft;
+}
+
+struct mlx5_flow_table *
+mlx5e_post_meter_get_mtu_false_ft(struct mlx5e_post_meter_priv *post_meter)
+{
+       return post_meter->mtu_tables.red_table.ft;
+}
+
 static struct mlx5_flow_table *
 mlx5e_post_meter_table_create(struct mlx5e_priv *priv,
                              enum mlx5_flow_namespace_type ns_type)
index 0a3dbf5ed86dc4fcddb41f56aeec57ee21ee5a77..e013b77186b2f6b5fe97f83431918865c1a88a1a 100644 (file)
@@ -19,9 +19,17 @@ enum mlx5e_post_meter_type {
        MLX5E_POST_METER_MTU
 };
 
+#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
+
 struct mlx5_flow_table *
 mlx5e_post_meter_get_ft(struct mlx5e_post_meter_priv *post_meter);
 
+struct mlx5_flow_table *
+mlx5e_post_meter_get_mtu_true_ft(struct mlx5e_post_meter_priv *post_meter);
+
+struct mlx5_flow_table *
+mlx5e_post_meter_get_mtu_false_ft(struct mlx5e_post_meter_priv *post_meter);
+
 struct mlx5e_post_meter_priv *
 mlx5e_post_meter_init(struct mlx5e_priv *priv,
                      enum mlx5_flow_namespace_type ns_type,
@@ -35,4 +43,20 @@ mlx5e_post_meter_init(struct mlx5e_priv *priv,
 void
 mlx5e_post_meter_cleanup(struct mlx5_eswitch *esw, struct mlx5e_post_meter_priv *post_meter);
 
+#else /* CONFIG_MLX5_CLS_ACT */
+
+static inline struct mlx5_flow_table *
+mlx5e_post_meter_get_mtu_true_ft(struct mlx5e_post_meter_priv *post_meter)
+{
+       return NULL;
+}
+
+static inline struct mlx5_flow_table *
+mlx5e_post_meter_get_mtu_false_ft(struct mlx5e_post_meter_priv *post_meter)
+{
+       return NULL;
+}
+
+#endif
+
 #endif /* __MLX5_EN_POST_METER_H__ */
index f66a2546003e36290d52ace5558ed2e5fa5314f7..9af2aa2922f5da605d3001e81abb8fd04074f004 100644 (file)
@@ -402,8 +402,9 @@ mlx5_tc_rule_delete(struct mlx5e_priv *priv,
 static bool
 is_flow_meter_action(struct mlx5_flow_attr *attr)
 {
-       return ((attr->action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) &&
-               (attr->exe_aso_type == MLX5_EXE_ASO_FLOW_METER));
+       return (((attr->action & MLX5_FLOW_CONTEXT_ACTION_EXECUTE_ASO) &&
+                (attr->exe_aso_type == MLX5_EXE_ASO_FLOW_METER)) ||
+               attr->flags & MLX5_ATTR_FLAG_MTU);
 }
 
 static int
@@ -414,6 +415,7 @@ mlx5e_tc_add_flow_meter(struct mlx5e_priv *priv,
        struct mlx5e_post_meter_priv *post_meter;
        enum mlx5_flow_namespace_type ns_type;
        struct mlx5e_flow_meter_handle *meter;
+       enum mlx5e_post_meter_type type;
 
        meter = mlx5e_tc_meter_replace(priv->mdev, &attr->meter_attr.params);
        if (IS_ERR(meter)) {
@@ -422,8 +424,9 @@ mlx5e_tc_add_flow_meter(struct mlx5e_priv *priv,
        }
 
        ns_type = mlx5e_tc_meter_get_namespace(meter->flow_meters);
+       type = meter->params.mtu ? MLX5E_POST_METER_MTU : MLX5E_POST_METER_RATE;
        post_meter = mlx5e_post_meter_init(priv, ns_type, post_act,
-                                          MLX5E_POST_METER_RATE,
+                                          type,
                                           meter->act_counter, meter->drop_counter,
                                           attr->branch_true, attr->branch_false);
        if (IS_ERR(post_meter)) {
index f2677d9ca0b467f8fa63b0884aa9f1eb02aab41e..50af70ef22f3c4e5cdbd2f21abdd42d33ac3926c 100644 (file)
@@ -114,6 +114,7 @@ enum {
        MLX5_ATTR_FLAG_ACCEPT        = BIT(5),
        MLX5_ATTR_FLAG_CT            = BIT(6),
        MLX5_ATTR_FLAG_TERMINATING   = BIT(7),
+       MLX5_ATTR_FLAG_MTU           = BIT(8),
 };
 
 /* Returns true if any of the flags that require skipping further TC/NF processing are set. */
index 1987a9d9d40cf9eb98c5eaf74a34ce0e54fafa7b..e455b215c70885a93b34cc68579669297c39c667 100644 (file)
@@ -50,6 +50,7 @@
 #include "en/mapping.h"
 #include "devlink.h"
 #include "lag/lag.h"
+#include "en/tc/post_meter.h"
 
 #define mlx5_esw_for_each_rep(esw, i, rep) \
        xa_for_each(&((esw)->offloads.vport_reps), i, rep)
@@ -201,6 +202,21 @@ esw_cleanup_decap_indir(struct mlx5_eswitch *esw,
                                         true);
 }
 
+static int
+esw_setup_mtu_dest(struct mlx5_flow_destination *dest,
+                  struct mlx5e_meter_attr *meter,
+                  int i)
+{
+       dest[i].type = MLX5_FLOW_DESTINATION_TYPE_RANGE;
+       dest[i].range.field = MLX5_FLOW_DEST_RANGE_FIELD_PKT_LEN;
+       dest[i].range.min = 0;
+       dest[i].range.max = meter->params.mtu;
+       dest[i].range.hit_ft = mlx5e_post_meter_get_mtu_true_ft(meter->post_meter);
+       dest[i].range.miss_ft = mlx5e_post_meter_get_mtu_false_ft(meter->post_meter);
+
+       return 0;
+}
+
 static int
 esw_setup_sampler_dest(struct mlx5_flow_destination *dest,
                       struct mlx5_flow_act *flow_act,
@@ -491,6 +507,9 @@ esw_setup_dests(struct mlx5_flow_destination *dest,
        } else if (attr->flags & MLX5_ATTR_FLAG_ACCEPT) {
                esw_setup_accept_dest(dest, flow_act, chains, *i);
                (*i)++;
+       } else if (attr->flags & MLX5_ATTR_FLAG_MTU) {
+               err = esw_setup_mtu_dest(dest, &attr->meter_attr, *i);
+               (*i)++;
        } else if (esw_is_indir_table(esw, attr)) {
                err = esw_setup_indir_table(dest, flow_act, esw, attr, spec, true, i);
        } else if (esw_is_chain_src_port_rewrite(esw, esw_attr)) {