net/mlx5: DR, Create multiple destination action from dr_create_fte
authorAlex Vesker <valex@mellanox.com>
Sun, 15 Dec 2019 19:50:32 +0000 (21:50 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Tue, 7 Jan 2020 18:43:02 +0000 (10:43 -0800)
Until now it was possible to pass a packet to a single destination such
as vport or flow table. With the new support if multiple vports or multiple
tables are provided as destinations, fs_dr will create a multiple
destination table action, this action should replace other destination
actions provided to mlx5dr_create_rule.
Each vport destination can be provided with a reformat actions which
will be done before forwarding the packet to the vport.

Signed-off-by: Alex Vesker <valex@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
drivers/net/ethernet/mellanox/mlx5/core/steering/fs_dr.c

index e51262ec77bbe11c7ae310b7252c84f4d3b63c93..b43275cde8bfc29a451baf5bd32822272a96f539 100644 (file)
@@ -206,6 +206,12 @@ static struct mlx5dr_action *create_action_push_vlan(struct mlx5dr_domain *domai
        return mlx5dr_action_create_push_vlan(domain, htonl(vlan_hdr));
 }
 
+static bool contain_vport_reformat_action(struct mlx5_flow_rule *dst)
+{
+       return dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
+               dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
+}
+
 #define MLX5_FLOW_CONTEXT_ACTION_MAX  20
 static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                                  struct mlx5_flow_table *ft,
@@ -213,7 +219,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                                  struct fs_fte *fte)
 {
        struct mlx5dr_domain *domain = ns->fs_dr_domain.dr_domain;
-       struct mlx5dr_action *term_action = NULL;
+       struct mlx5dr_action_dest *term_actions;
        struct mlx5dr_match_parameters params;
        struct mlx5_core_dev *dev = ns->dev;
        struct mlx5dr_action **fs_dr_actions;
@@ -223,6 +229,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
        struct mlx5dr_rule *rule;
        struct mlx5_flow_rule *dst;
        int fs_dr_num_actions = 0;
+       int num_term_actions = 0;
        int num_actions = 0;
        size_t match_sz;
        int err = 0;
@@ -233,18 +240,38 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
 
        actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX, sizeof(*actions),
                          GFP_KERNEL);
-       if (!actions)
-               return -ENOMEM;
+       if (!actions) {
+               err = -ENOMEM;
+               goto out_err;
+       }
 
        fs_dr_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX,
                                sizeof(*fs_dr_actions), GFP_KERNEL);
        if (!fs_dr_actions) {
-               kfree(actions);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto free_actions_alloc;
+       }
+
+       term_actions = kcalloc(MLX5_FLOW_CONTEXT_ACTION_MAX,
+                              sizeof(*term_actions), GFP_KERNEL);
+       if (!term_actions) {
+               err = -ENOMEM;
+               goto free_fs_dr_actions_alloc;
        }
 
        match_sz = sizeof(fte->val);
 
+       /* Drop reformat action bit if destination vport set with reformat */
+       if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
+               list_for_each_entry(dst, &fte->node.children, node.list) {
+                       if (!contain_vport_reformat_action(dst))
+                               continue;
+
+                       fte->action.action &= ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
+                       break;
+               }
+       }
+
        /* The order of the actions are must to be keep, only the following
         * order is supported by SW steering:
         * TX: push vlan -> modify header -> encap
@@ -335,7 +362,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                        goto free_actions;
                }
                fs_dr_actions[fs_dr_num_actions++] = tmp_action;
-               term_action = tmp_action;
+               term_actions[num_term_actions++].dest = tmp_action;
        }
 
        if (fte->flow_context.flow_tag) {
@@ -354,7 +381,8 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                        enum mlx5_flow_destination_type type = dst->dest_attr.type;
                        u32 id;
 
-                       if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX) {
+                       if (num_actions == MLX5_FLOW_CONTEXT_ACTION_MAX ||
+                           num_term_actions >= MLX5_FLOW_CONTEXT_ACTION_MAX) {
                                err = -ENOSPC;
                                goto free_actions;
                        }
@@ -379,7 +407,7 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                                        goto free_actions;
                                }
                                fs_dr_actions[fs_dr_num_actions++] = tmp_action;
-                               term_action = tmp_action;
+                               term_actions[num_term_actions++].dest = tmp_action;
                                break;
                        case MLX5_FLOW_DESTINATION_TYPE_VPORT:
                                tmp_action = create_vport_action(domain, dst);
@@ -388,7 +416,14 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                                        goto free_actions;
                                }
                                fs_dr_actions[fs_dr_num_actions++] = tmp_action;
-                               term_action = tmp_action;
+                               term_actions[num_term_actions].dest = tmp_action;
+
+                               if (dst->dest_attr.vport.flags &
+                                   MLX5_FLOW_DEST_VPORT_REFORMAT_ID)
+                                       term_actions[num_term_actions].reformat =
+                                               dst->dest_attr.vport.pkt_reformat->action.dr_action;
+
+                               num_term_actions++;
                                break;
                        default:
                                err = -EOPNOTSUPP;
@@ -399,9 +434,22 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
 
        params.match_sz = match_sz;
        params.match_buf = (u64 *)fte->val;
-
-       if (term_action)
-               actions[num_actions++] = term_action;
+       if (num_term_actions == 1) {
+               if (term_actions->reformat)
+                       actions[num_actions++] = term_actions->reformat;
+
+               actions[num_actions++] = term_actions->dest;
+       } else if (num_term_actions > 1) {
+               tmp_action = mlx5dr_action_create_mult_dest_tbl(domain,
+                                                               term_actions,
+                                                               num_term_actions);
+               if (!tmp_action) {
+                       err = -EOPNOTSUPP;
+                       goto free_actions;
+               }
+               fs_dr_actions[fs_dr_num_actions++] = tmp_action;
+               actions[num_actions++] = tmp_action;
+       }
 
        rule = mlx5dr_rule_create(group->fs_dr_matcher.dr_matcher,
                                  &params,
@@ -412,7 +460,9 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
                goto free_actions;
        }
 
+       kfree(term_actions);
        kfree(actions);
+
        fte->fs_dr_rule.dr_rule = rule;
        fte->fs_dr_rule.num_actions = fs_dr_num_actions;
        fte->fs_dr_rule.dr_actions = fs_dr_actions;
@@ -420,13 +470,18 @@ static int mlx5_cmd_dr_create_fte(struct mlx5_flow_root_namespace *ns,
        return 0;
 
 free_actions:
-       for (i = 0; i < fs_dr_num_actions; i++)
+       /* Free in reverse order to handle action dependencies */
+       for (i = fs_dr_num_actions - 1; i >= 0; i--)
                if (!IS_ERR_OR_NULL(fs_dr_actions[i]))
                        mlx5dr_action_destroy(fs_dr_actions[i]);
 
-       mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err);
-       kfree(actions);
+       kfree(term_actions);
+free_fs_dr_actions_alloc:
        kfree(fs_dr_actions);
+free_actions_alloc:
+       kfree(actions);
+out_err:
+       mlx5_core_err(dev, "Failed to create dr rule err(%d)\n", err);
        return err;
 }
 
@@ -533,7 +588,8 @@ static int mlx5_cmd_dr_delete_fte(struct mlx5_flow_root_namespace *ns,
        if (err)
                return err;
 
-       for (i = 0; i < rule->num_actions; i++)
+       /* Free in reverse order to handle action dependencies */
+       for (i = rule->num_actions - 1; i >= 0; i--)
                if (!IS_ERR_OR_NULL(rule->dr_actions[i]))
                        mlx5dr_action_destroy(rule->dr_actions[i]);