tree_put_node(node);
        return 0;
 }
+
+static struct fs_prio *find_prio(struct mlx5_flow_namespace *ns,
+                                unsigned int prio)
+{
+       struct fs_prio *iter_prio;
+
+       fs_for_each_prio(iter_prio, ns) {
+               if (iter_prio->prio == prio)
+                       return iter_prio;
+       }
+
+       return NULL;
+}
+
+static unsigned int find_next_free_level(struct fs_prio *prio)
+{
+       if (!list_empty(&prio->node.children)) {
+               struct mlx5_flow_table *ft;
+
+               ft = list_last_entry(&prio->node.children,
+                                    struct mlx5_flow_table,
+                                    node.list);
+               return ft->level + 1;
+       }
+       return prio->start_level;
+}
+
+static bool masked_memcmp(void *mask, void *val1, void *val2, size_t size)
+{
+       unsigned int i;
+
+       for (i = 0; i < size; i++, mask++, val1++, val2++)
+               if ((*((u8 *)val1) & (*(u8 *)mask)) !=
+                   ((*(u8 *)val2) & (*(u8 *)mask)))
+                       return false;
+
+       return true;
+}
+
+static bool compare_match_value(struct mlx5_flow_group_mask *mask,
+                               void *fte_param1, void *fte_param2)
+{
+       if (mask->match_criteria_enable &
+           1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_OUTER_HEADERS) {
+               void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
+                                               fte_param1, outer_headers);
+               void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
+                                               fte_param2, outer_headers);
+               void *fte_mask = MLX5_ADDR_OF(fte_match_param,
+                                             mask->match_criteria, outer_headers);
+
+               if (!masked_memcmp(fte_mask, fte_match1, fte_match2,
+                                  MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
+                       return false;
+       }
+
+       if (mask->match_criteria_enable &
+           1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_MISC_PARAMETERS) {
+               void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
+                                               fte_param1, misc_parameters);
+               void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
+                                               fte_param2, misc_parameters);
+               void *fte_mask = MLX5_ADDR_OF(fte_match_param,
+                                         mask->match_criteria, misc_parameters);
+
+               if (!masked_memcmp(fte_mask, fte_match1, fte_match2,
+                                  MLX5_ST_SZ_BYTES(fte_match_set_misc)))
+                       return false;
+       }
+
+       if (mask->match_criteria_enable &
+           1 << MLX5_CREATE_FLOW_GROUP_IN_MATCH_CRITERIA_ENABLE_INNER_HEADERS) {
+               void *fte_match1 = MLX5_ADDR_OF(fte_match_param,
+                                               fte_param1, inner_headers);
+               void *fte_match2 = MLX5_ADDR_OF(fte_match_param,
+                                               fte_param2, inner_headers);
+               void *fte_mask = MLX5_ADDR_OF(fte_match_param,
+                                         mask->match_criteria, inner_headers);
+
+               if (!masked_memcmp(fte_mask, fte_match1, fte_match2,
+                                  MLX5_ST_SZ_BYTES(fte_match_set_lyr_2_4)))
+                       return false;
+       }
+       return true;
+}
+
+static bool compare_match_criteria(u8 match_criteria_enable1,
+                                  u8 match_criteria_enable2,
+                                  void *mask1, void *mask2)
+{
+       return match_criteria_enable1 == match_criteria_enable2 &&
+               !memcmp(mask1, mask2, MLX5_ST_SZ_BYTES(fte_match_param));
+}
 
 struct mlx5_flow_table {
        struct fs_node                  node;
        u32                             id;
+       unsigned int                    level;
        enum fs_flow_table_type         type;
 };
 
        u32                             action;
 };
 
+struct fs_prio {
+       struct fs_node                  node;
+       unsigned int                    max_ft;
+       unsigned int                    start_level;
+       unsigned int                    prio;
+};
+
+struct mlx5_flow_namespace {
+       /* parent == NULL => root ns */
+       struct  fs_node                 node;
+};
+
+struct mlx5_flow_group_mask {
+       u8      match_criteria_enable;
+       u32     match_criteria[MLX5_ST_SZ_DW(fte_match_param)];
+};
+
+#define fs_get_obj(v, _node)  {v = container_of((_node), typeof(*v), node); }
+
+#define fs_list_for_each_entry(pos, root)              \
+       list_for_each_entry(pos, root, node.list)
+
+#define fs_for_each_ns_or_ft_reverse(pos, prio)                                \
+       list_for_each_entry_reverse(pos, &(prio)->node.children, list)
+
+#define fs_for_each_ns_or_ft(pos, prio)                                        \
+       list_for_each_entry(pos, (&(prio)->node.children), list)
+
+#define fs_for_each_prio(pos, ns)                      \
+       fs_list_for_each_entry(pos, &(ns)->node.children)
+
+#define fs_for_each_fg(pos, ft)                        \
+       fs_list_for_each_entry(pos, &(ft)->node.children)
+
+#define fs_for_each_fte(pos, fg)                       \
+       fs_list_for_each_entry(pos, &(fg)->node.children)
+
+#define fs_for_each_dst(pos, fte)                      \
+       fs_list_for_each_entry(pos, &(fte)->node.children)
+
 #endif