]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
net/mlx5: DR, Add support for multiple destination table action
authorAlex Vesker <valex@mellanox.com>
Sun, 15 Dec 2019 19:27:54 +0000 (21:27 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Tue, 7 Jan 2020 18:42:49 +0000 (10:42 -0800)
A multiple destination table action allows HW packet duplication
to multiple destinations, this is useful for multicast or mirroring
traffic for debug. Duplicating is done using a FW flow table with
multiple destinations.

The new action creation function, mlx5dr_action_create_mult_dest_tbl
will allow creating a single table to iterate over several dr actions.

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

index 3e2318761c8cf4a885960bccc47dd04b1e346ba1..9359eed1088958502cb3bdef9bdefa99f762fdd9 100644 (file)
@@ -981,6 +981,104 @@ mlx5dr_action_create_dest_table(struct mlx5dr_table *tbl)
        return NULL;
 }
 
+struct mlx5dr_action *
+mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn,
+                                  struct mlx5dr_action_dest *dests,
+                                  u32 num_of_dests)
+{
+       struct mlx5dr_cmd_flow_destination_hw_info *hw_dests;
+       struct mlx5dr_action **ref_actions;
+       struct mlx5dr_action *action;
+       bool reformat_req = false;
+       u32 num_of_ref = 0;
+       int ret;
+       int i;
+
+       if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) {
+               mlx5dr_err(dmn, "Multiple destination support is for FDB only\n");
+               return NULL;
+       }
+
+       hw_dests = kzalloc(sizeof(*hw_dests) * num_of_dests, GFP_KERNEL);
+       if (!hw_dests)
+               return NULL;
+
+       ref_actions = kzalloc(sizeof(*ref_actions) * num_of_dests * 2, GFP_KERNEL);
+       if (!ref_actions)
+               goto free_hw_dests;
+
+       for (i = 0; i < num_of_dests; i++) {
+               struct mlx5dr_action *reformat_action = dests[i].reformat;
+               struct mlx5dr_action *dest_action = dests[i].dest;
+
+               ref_actions[num_of_ref++] = dest_action;
+
+               switch (dest_action->action_type) {
+               case DR_ACTION_TYP_VPORT:
+                       hw_dests[i].vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID;
+                       hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
+                       hw_dests[i].vport.num = dest_action->vport.caps->num;
+                       hw_dests[i].vport.vhca_id = dest_action->vport.caps->vhca_gvmi;
+                       if (reformat_action) {
+                               reformat_req = true;
+                               hw_dests[i].vport.reformat_id =
+                                       reformat_action->reformat.reformat_id;
+                               ref_actions[num_of_ref++] = reformat_action;
+                               hw_dests[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
+                       }
+                       break;
+
+               case DR_ACTION_TYP_FT:
+                       hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+                       if (dest_action->dest_tbl.is_fw_tbl)
+                               hw_dests[i].ft_id = dest_action->dest_tbl.fw_tbl.id;
+                       else
+                               hw_dests[i].ft_id = dest_action->dest_tbl.tbl->table_id;
+                       break;
+
+               default:
+                       mlx5dr_dbg(dmn, "Invalid multiple destinations action\n");
+                       goto free_ref_actions;
+               }
+       }
+
+       action = dr_action_create_generic(DR_ACTION_TYP_FT);
+       if (!action)
+               goto free_ref_actions;
+
+       ret = mlx5dr_fw_create_md_tbl(dmn,
+                                     hw_dests,
+                                     num_of_dests,
+                                     reformat_req,
+                                     &action->dest_tbl.fw_tbl.id,
+                                     &action->dest_tbl.fw_tbl.group_id);
+       if (ret)
+               goto free_action;
+
+       refcount_inc(&dmn->refcount);
+
+       for (i = 0; i < num_of_ref; i++)
+               refcount_inc(&ref_actions[i]->refcount);
+
+       action->dest_tbl.is_fw_tbl = true;
+       action->dest_tbl.fw_tbl.dmn = dmn;
+       action->dest_tbl.fw_tbl.type = FS_FT_FDB;
+       action->dest_tbl.fw_tbl.ref_actions = ref_actions;
+       action->dest_tbl.fw_tbl.num_of_ref_actions = num_of_ref;
+
+       kfree(hw_dests);
+
+       return action;
+
+free_action:
+       kfree(action);
+free_ref_actions:
+       kfree(ref_actions);
+free_hw_dests:
+       kfree(hw_dests);
+       return NULL;
+}
+
 struct mlx5dr_action *
 mlx5dr_action_create_dest_flow_fw_table(struct mlx5dr_domain *dmn,
                                        struct mlx5_flow_table *ft)
@@ -1566,6 +1664,22 @@ int mlx5dr_action_destroy(struct mlx5dr_action *action)
                        refcount_dec(&action->dest_tbl.fw_tbl.dmn->refcount);
                else
                        refcount_dec(&action->dest_tbl.tbl->refcount);
+
+               if (action->dest_tbl.is_fw_tbl &&
+                   action->dest_tbl.fw_tbl.num_of_ref_actions) {
+                       struct mlx5dr_action **ref_actions;
+                       int i;
+
+                       ref_actions = action->dest_tbl.fw_tbl.ref_actions;
+                       for (i = 0; i < action->dest_tbl.fw_tbl.num_of_ref_actions; i++)
+                               refcount_dec(&ref_actions[i]->refcount);
+
+                       kfree(ref_actions);
+
+                       mlx5dr_fw_destroy_md_tbl(action->dest_tbl.fw_tbl.dmn,
+                                                action->dest_tbl.fw_tbl.id,
+                                                action->dest_tbl.fw_tbl.group_id);
+               }
                break;
        case DR_ACTION_TYP_TNL_L2_TO_L2:
                refcount_dec(&action->reformat.dmn->refcount);
index 27f1d931bf9fe70e54925cbdb49b94aa36d96632..0fc52d634e107664840ad54feca494781c9990f8 100644 (file)
@@ -745,9 +745,12 @@ struct mlx5dr_action {
                                struct {
                                        struct mlx5dr_domain *dmn;
                                        u32 id;
+                                       u32 group_id;
                                        enum fs_flow_table_type type;
                                        u64 rx_icm_addr;
                                        u64 tx_icm_addr;
+                                       struct mlx5dr_action **ref_actions;
+                                       u32 num_of_ref_actions;
                                } fw_tbl;
                        };
                } dest_tbl;
index 932362d89c66ac357194dfcdf4ec0bf0d6a538f8..e1edc9c247b75c1941ac55170890aa7ce98a4161 100644 (file)
@@ -33,6 +33,11 @@ struct mlx5dr_match_parameters {
        u64 *match_buf; /* Device spec format */
 };
 
+struct mlx5dr_action_dest {
+       struct mlx5dr_action *dest;
+       struct mlx5dr_action *reformat;
+};
+
 #ifdef CONFIG_MLX5_SW_STEERING
 
 struct mlx5dr_domain *
@@ -83,6 +88,11 @@ mlx5dr_action_create_dest_vport(struct mlx5dr_domain *domain,
                                u32 vport, u8 vhca_id_valid,
                                u16 vhca_id);
 
+struct mlx5dr_action *
+mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn,
+                                  struct mlx5dr_action_dest *dests,
+                                  u32 num_of_dests);
+
 struct mlx5dr_action *mlx5dr_action_create_drop(void);
 
 struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value);
@@ -173,6 +183,11 @@ mlx5dr_action_create_dest_vport(struct mlx5dr_domain *domain,
                                u32 vport, u8 vhca_id_valid,
                                u16 vhca_id) { return NULL; }
 
+static inline struct mlx5dr_action *
+mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn,
+                                  struct mlx5dr_action_dest *dests,
+                                  u32 num_of_dests)  { return NULL; }
+
 static inline struct mlx5dr_action *
 mlx5dr_action_create_drop(void) { return NULL; }