]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net/mlx5: HWS, Fix matcher action template attach
authorVlad Dogaru <vdogaru@nvidia.com>
Thu, 10 Apr 2025 19:17:31 +0000 (22:17 +0300)
committerJakub Kicinski <kuba@kernel.org>
Tue, 15 Apr 2025 00:29:15 +0000 (17:29 -0700)
The procedure of attaching an action template to an existing matcher had
a few issues:

1. Attaching accidentally overran the `at` array in bwc_matcher, which
   would result in memory corruption. This bug wasn't triggered, but it
   is possible to trigger it by attaching action templates beyond the
   initial buffer size of 8. Fix this by converting to a dynamically
   sized buffer and reallocating if needed.

2. Similarly, the `at` array inside the native matcher was never
   reallocated. Fix this the same as above.

3. The bwc layer treated any error in action template attach as a signal
   that the matcher should be rehashed to account for a larger number of
   action STEs. In reality, there are other unrelated errors that can
   arise and they should be propagated upstack. Fix this by adding a
   `need_rehash` output parameter that's orthogonal to error codes.

Fixes: 2111bb970c78 ("net/mlx5: HWS, added backward-compatible API handling")
Signed-off-by: Vlad Dogaru <vdogaru@nvidia.com>
Reviewed-by: Yevgeny Kliteynik <kliteyn@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Michal Kubiak <michal.kubiak@intel.com>
Link: https://patch.msgid.link/1744312662-356571-2-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/mlx5hws.h

index 19dce1ba512d42d8403f77fa4211c67900d6ffbc..32de8bfc7644f5b8f5c739ddfd244d274afb1007 100644 (file)
@@ -90,13 +90,19 @@ int mlx5hws_bwc_matcher_create_simple(struct mlx5hws_bwc_matcher *bwc_matcher,
        bwc_matcher->priority = priority;
        bwc_matcher->size_log = MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG;
 
+       bwc_matcher->size_of_at_array = MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM;
+       bwc_matcher->at = kcalloc(bwc_matcher->size_of_at_array,
+                                 sizeof(*bwc_matcher->at), GFP_KERNEL);
+       if (!bwc_matcher->at)
+               goto free_bwc_matcher_rules;
+
        /* create dummy action template */
        bwc_matcher->at[0] =
                mlx5hws_action_template_create(action_types ?
                                               action_types : init_action_types);
        if (!bwc_matcher->at[0]) {
                mlx5hws_err(table->ctx, "BWC matcher: failed creating action template\n");
-               goto free_bwc_matcher_rules;
+               goto free_bwc_matcher_at_array;
        }
 
        bwc_matcher->num_of_at = 1;
@@ -126,6 +132,8 @@ free_mt:
        mlx5hws_match_template_destroy(bwc_matcher->mt);
 free_at:
        mlx5hws_action_template_destroy(bwc_matcher->at[0]);
+free_bwc_matcher_at_array:
+       kfree(bwc_matcher->at);
 free_bwc_matcher_rules:
        kfree(bwc_matcher->rules);
 err:
@@ -192,6 +200,7 @@ int mlx5hws_bwc_matcher_destroy_simple(struct mlx5hws_bwc_matcher *bwc_matcher)
 
        for (i = 0; i < bwc_matcher->num_of_at; i++)
                mlx5hws_action_template_destroy(bwc_matcher->at[i]);
+       kfree(bwc_matcher->at);
 
        mlx5hws_match_template_destroy(bwc_matcher->mt);
        kfree(bwc_matcher->rules);
@@ -520,6 +529,23 @@ hws_bwc_matcher_extend_at(struct mlx5hws_bwc_matcher *bwc_matcher,
                          struct mlx5hws_rule_action rule_actions[])
 {
        enum mlx5hws_action_type action_types[MLX5HWS_BWC_MAX_ACTS];
+       void *p;
+
+       if (unlikely(bwc_matcher->num_of_at >= bwc_matcher->size_of_at_array)) {
+               if (bwc_matcher->size_of_at_array >= MLX5HWS_MATCHER_MAX_AT)
+                       return -ENOMEM;
+               bwc_matcher->size_of_at_array *= 2;
+               p = krealloc(bwc_matcher->at,
+                            bwc_matcher->size_of_at_array *
+                                    sizeof(*bwc_matcher->at),
+                            __GFP_ZERO | GFP_KERNEL);
+               if (!p) {
+                       bwc_matcher->size_of_at_array /= 2;
+                       return -ENOMEM;
+               }
+
+               bwc_matcher->at = p;
+       }
 
        hws_bwc_rule_actions_to_action_types(rule_actions, action_types);
 
@@ -777,6 +803,7 @@ int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule,
        struct mlx5hws_rule_attr rule_attr;
        struct mutex *queue_lock; /* Protect the queue */
        u32 num_of_rules;
+       bool need_rehash;
        int ret = 0;
        int at_idx;
 
@@ -803,10 +830,14 @@ int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule,
                at_idx = bwc_matcher->num_of_at - 1;
 
                ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher,
-                                               bwc_matcher->at[at_idx]);
+                                               bwc_matcher->at[at_idx],
+                                               &need_rehash);
                if (unlikely(ret)) {
-                       /* Action template attach failed, possibly due to
-                        * requiring more action STEs.
+                       hws_bwc_unlock_all_queues(ctx);
+                       return ret;
+               }
+               if (unlikely(need_rehash)) {
+                       /* The new action template requires more action STEs.
                         * Need to attempt creating new matcher with all
                         * the action templates, including the new one.
                         */
@@ -942,6 +973,7 @@ hws_bwc_rule_action_update(struct mlx5hws_bwc_rule *bwc_rule,
        struct mlx5hws_context *ctx = bwc_matcher->matcher->tbl->ctx;
        struct mlx5hws_rule_attr rule_attr;
        struct mutex *queue_lock; /* Protect the queue */
+       bool need_rehash;
        int at_idx, ret;
        u16 idx;
 
@@ -973,12 +1005,17 @@ hws_bwc_rule_action_update(struct mlx5hws_bwc_rule *bwc_rule,
                        at_idx = bwc_matcher->num_of_at - 1;
 
                        ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher,
-                                                       bwc_matcher->at[at_idx]);
+                                                       bwc_matcher->at[at_idx],
+                                                       &need_rehash);
                        if (unlikely(ret)) {
-                               /* Action template attach failed, possibly due to
-                                * requiring more action STEs.
-                                * Need to attempt creating new matcher with all
-                                * the action templates, including the new one.
+                               hws_bwc_unlock_all_queues(ctx);
+                               return ret;
+                       }
+                       if (unlikely(need_rehash)) {
+                               /* The new action template requires more action
+                                * STEs. Need to attempt creating new matcher
+                                * with all the action templates, including the
+                                * new one.
                                 */
                                ret = hws_bwc_matcher_rehash_at(bwc_matcher);
                                if (unlikely(ret)) {
index 47f7ed1415535fb97bd8584b5e4df4ef851664da..bb0cf4b922ceba21c623b63e13d70abf01595763 100644 (file)
@@ -10,9 +10,7 @@
 #define MLX5HWS_BWC_MATCHER_REHASH_BURST_TH 32
 
 /* Max number of AT attach operations for the same matcher.
- * When the limit is reached, next attempt to attach new AT
- * will result in creation of a new matcher and moving all
- * the rules to this matcher.
+ * When the limit is reached, a larger buffer is allocated for the ATs.
  */
 #define MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM 8
 
 struct mlx5hws_bwc_matcher {
        struct mlx5hws_matcher *matcher;
        struct mlx5hws_match_template *mt;
-       struct mlx5hws_action_template *at[MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM];
-       u32 priority;
+       struct mlx5hws_action_template **at;
        u8 num_of_at;
+       u8 size_of_at_array;
        u8 size_log;
+       u32 priority;
        atomic_t num_of_rules;
        struct list_head *rules;
 };
index b61864b320536db008157a8586afdaff16c0f114..37a4497048a6fa343ed71211e64f4ab524568344 100644 (file)
@@ -905,18 +905,48 @@ static int hws_matcher_uninit(struct mlx5hws_matcher *matcher)
        return 0;
 }
 
+static int hws_matcher_grow_at_array(struct mlx5hws_matcher *matcher)
+{
+       void *p;
+
+       if (matcher->size_of_at_array >= MLX5HWS_MATCHER_MAX_AT)
+               return -ENOMEM;
+
+       matcher->size_of_at_array *= 2;
+       p = krealloc(matcher->at,
+                    matcher->size_of_at_array * sizeof(*matcher->at),
+                    __GFP_ZERO | GFP_KERNEL);
+       if (!p) {
+               matcher->size_of_at_array /= 2;
+               return -ENOMEM;
+       }
+
+       matcher->at = p;
+
+       return 0;
+}
+
 int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher,
-                             struct mlx5hws_action_template *at)
+                             struct mlx5hws_action_template *at,
+                             bool *need_rehash)
 {
        bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt);
        struct mlx5hws_context *ctx = matcher->tbl->ctx;
        u32 required_stes;
        int ret;
 
-       if (!matcher->attr.max_num_of_at_attach) {
-               mlx5hws_dbg(ctx, "Num of current at (%d) exceed allowed value\n",
-                           matcher->num_of_at);
-               return -EOPNOTSUPP;
+       *need_rehash = false;
+
+       if (unlikely(matcher->num_of_at >= matcher->size_of_at_array)) {
+               ret = hws_matcher_grow_at_array(matcher);
+               if (ret)
+                       return ret;
+
+               if (matcher->col_matcher) {
+                       ret = hws_matcher_grow_at_array(matcher->col_matcher);
+                       if (ret)
+                               return ret;
+               }
        }
 
        ret = hws_matcher_check_and_process_at(matcher, at);
@@ -927,12 +957,11 @@ int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher,
        if (matcher->action_ste.max_stes < required_stes) {
                mlx5hws_dbg(ctx, "Required STEs [%d] exceeds initial action template STE [%d]\n",
                            required_stes, matcher->action_ste.max_stes);
-               return -ENOMEM;
+               *need_rehash = true;
        }
 
        matcher->at[matcher->num_of_at] = *at;
        matcher->num_of_at += 1;
-       matcher->attr.max_num_of_at_attach -= 1;
 
        if (matcher->col_matcher)
                matcher->col_matcher->num_of_at = matcher->num_of_at;
@@ -960,8 +989,9 @@ hws_matcher_set_templates(struct mlx5hws_matcher *matcher,
        if (!matcher->mt)
                return -ENOMEM;
 
-       matcher->at = kvcalloc(num_of_at + matcher->attr.max_num_of_at_attach,
-                              sizeof(*matcher->at),
+       matcher->size_of_at_array =
+               num_of_at + matcher->attr.max_num_of_at_attach;
+       matcher->at = kvcalloc(matcher->size_of_at_array, sizeof(*matcher->at),
                               GFP_KERNEL);
        if (!matcher->at) {
                mlx5hws_err(ctx, "Failed to allocate action template array\n");
index 020de70270c501dc67a4b75642f4b0b26e1e28bc..20b32012c418beb1584879186c66966ba29fdc1a 100644 (file)
@@ -23,6 +23,9 @@
  */
 #define MLX5HWS_MATCHER_ACTION_RTC_UPDATE_MULT 1
 
+/* Maximum number of action templates that can be attached to a matcher. */
+#define MLX5HWS_MATCHER_MAX_AT 128
+
 enum mlx5hws_matcher_offset {
        MLX5HWS_MATCHER_OFFSET_TAG_DW1 = 12,
        MLX5HWS_MATCHER_OFFSET_TAG_DW0 = 13,
@@ -72,6 +75,7 @@ struct mlx5hws_matcher {
        struct mlx5hws_match_template *mt;
        struct mlx5hws_action_template *at;
        u8 num_of_at;
+       u8 size_of_at_array;
        u8 num_of_mt;
        /* enum mlx5hws_matcher_flags */
        u8 flags;
index 5121951f2778a8e07398767ee39dfc381fecdba3..8ed8a715a2eb26bdaf057308b68db13b9531efbf 100644 (file)
@@ -399,11 +399,14 @@ int mlx5hws_matcher_destroy(struct mlx5hws_matcher *matcher);
  *
  * @matcher: Matcher to attach the action template to.
  * @at: Action template to be attached to the matcher.
+ * @need_rehash: Output parameter that tells callers if the matcher needs to be
+ * rehashed.
  *
  * Return: Zero on success, non-zero otherwise.
  */
 int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher,
-                             struct mlx5hws_action_template *at);
+                             struct mlx5hws_action_template *at,
+                             bool *need_rehash);
 
 /**
  * mlx5hws_matcher_resize_set_target - Link two matchers and enable moving rules.