#define MLX5_FS_MAX_TYPES       6
 #define MLX5_FS_MAX_ENTRIES     BIT(16)
 
-static struct mlx5_ib_flow_prio *_get_prio(struct mlx5_flow_namespace *ns,
+static bool mlx5_ib_shared_ft_allowed(struct ib_device *device)
+{
+       struct mlx5_ib_dev *dev = to_mdev(device);
+
+       return MLX5_CAP_GEN(dev->mdev, shared_object_to_user_object_allowed);
+}
+
+static struct mlx5_ib_flow_prio *_get_prio(struct mlx5_ib_dev *dev,
+                                          struct mlx5_flow_namespace *ns,
                                           struct mlx5_ib_flow_prio *prio,
                                           int priority,
                                           int num_entries, int num_groups,
        struct mlx5_flow_table_attr ft_attr = {};
        struct mlx5_flow_table *ft;
 
+       if (mlx5_ib_shared_ft_allowed(&dev->ib_dev))
+               ft_attr.uid = MLX5_SHARED_RESOURCE_UID;
        ft_attr.prio = priority;
        ft_attr.max_fte = num_entries;
        ft_attr.flags = flags;
 
        ft = prio->flow_table;
        if (!ft)
-               return _get_prio(ns, prio, priority, max_table_size, num_groups,
-                                flags);
+               return _get_prio(dev, ns, prio, priority, max_table_size,
+                                num_groups, flags);
 
        return prio;
 }
 
        prio = &dev->flow_db->opfcs[type];
        if (!prio->flow_table) {
-               prio = _get_prio(ns, prio, priority,
+               prio = _get_prio(dev, ns, prio, priority,
                                 dev->num_ports * MAX_OPFC_RULES, 1, 0);
                if (IS_ERR(prio)) {
                        err = PTR_ERR(prio);
        if (prio->flow_table)
                return prio;
 
-       return _get_prio(ns, prio, priority, max_table_size,
+       return _get_prio(dev, ns, prio, priority, max_table_size,
                         MLX5_FS_MAX_TYPES, flags);
 }
 
        return 0;
 }
 
+static int steering_anchor_cleanup(struct ib_uobject *uobject,
+                                  enum rdma_remove_reason why,
+                                  struct uverbs_attr_bundle *attrs)
+{
+       struct mlx5_ib_steering_anchor *obj = uobject->object;
+
+       if (atomic_read(&obj->usecnt))
+               return -EBUSY;
+
+       mutex_lock(&obj->dev->flow_db->lock);
+       put_flow_table(obj->dev, obj->ft_prio, true);
+       mutex_unlock(&obj->dev->flow_db->lock);
+
+       kfree(obj);
+       return 0;
+}
+
 static int mlx5_ib_matcher_ns(struct uverbs_attr_bundle *attrs,
                              struct mlx5_ib_flow_matcher *obj)
 {
        return err;
 }
 
+static int UVERBS_HANDLER(MLX5_IB_METHOD_STEERING_ANCHOR_CREATE)(
+       struct uverbs_attr_bundle *attrs)
+{
+       struct ib_uobject *uobj = uverbs_attr_get_uobject(
+               attrs, MLX5_IB_ATTR_STEERING_ANCHOR_CREATE_HANDLE);
+       struct mlx5_ib_dev *dev = mlx5_udata_to_mdev(&attrs->driver_udata);
+       enum mlx5_ib_uapi_flow_table_type ib_uapi_ft_type;
+       enum mlx5_flow_namespace_type ns_type;
+       struct mlx5_ib_steering_anchor *obj;
+       struct mlx5_ib_flow_prio *ft_prio;
+       u16 priority;
+       u32 ft_id;
+       int err;
+
+       if (!capable(CAP_NET_RAW))
+               return -EPERM;
+
+       err = uverbs_get_const(&ib_uapi_ft_type, attrs,
+                              MLX5_IB_ATTR_STEERING_ANCHOR_FT_TYPE);
+       if (err)
+               return err;
+
+       err = mlx5_ib_ft_type_to_namespace(ib_uapi_ft_type, &ns_type);
+       if (err)
+               return err;
+
+       err = uverbs_copy_from(&priority, attrs,
+                              MLX5_IB_ATTR_STEERING_ANCHOR_PRIORITY);
+       if (err)
+               return err;
+
+       obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+       if (!obj)
+               return -ENOMEM;
+
+       mutex_lock(&dev->flow_db->lock);
+       ft_prio = _get_flow_table(dev, priority, ns_type, 0);
+       if (IS_ERR(ft_prio)) {
+               mutex_unlock(&dev->flow_db->lock);
+               err = PTR_ERR(ft_prio);
+               goto free_obj;
+       }
+
+       ft_prio->refcount++;
+       ft_id = mlx5_flow_table_id(ft_prio->flow_table);
+       mutex_unlock(&dev->flow_db->lock);
+
+       err = uverbs_copy_to(attrs, MLX5_IB_ATTR_STEERING_ANCHOR_FT_ID,
+                            &ft_id, sizeof(ft_id));
+       if (err)
+               goto put_flow_table;
+
+       uobj->object = obj;
+       obj->dev = dev;
+       obj->ft_prio = ft_prio;
+       atomic_set(&obj->usecnt, 0);
+
+       return 0;
+
+put_flow_table:
+       mutex_lock(&dev->flow_db->lock);
+       put_flow_table(dev, ft_prio, true);
+       mutex_unlock(&dev->flow_db->lock);
+free_obj:
+       kfree(obj);
+
+       return err;
+}
+
 static struct ib_flow_action *
 mlx5_ib_create_modify_header(struct mlx5_ib_dev *dev,
                             enum mlx5_ib_uapi_flow_table_type ft_type,
                            &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE),
                            &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY));
 
+DECLARE_UVERBS_NAMED_METHOD(
+       MLX5_IB_METHOD_STEERING_ANCHOR_CREATE,
+       UVERBS_ATTR_IDR(MLX5_IB_ATTR_STEERING_ANCHOR_CREATE_HANDLE,
+                       MLX5_IB_OBJECT_STEERING_ANCHOR,
+                       UVERBS_ACCESS_NEW,
+                       UA_MANDATORY),
+       UVERBS_ATTR_CONST_IN(MLX5_IB_ATTR_STEERING_ANCHOR_FT_TYPE,
+                            enum mlx5_ib_uapi_flow_table_type,
+                            UA_MANDATORY),
+       UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_STEERING_ANCHOR_PRIORITY,
+                          UVERBS_ATTR_TYPE(u16),
+                          UA_MANDATORY),
+       UVERBS_ATTR_PTR_IN(MLX5_IB_ATTR_STEERING_ANCHOR_FT_ID,
+                          UVERBS_ATTR_TYPE(u32),
+                          UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_METHOD_DESTROY(
+       MLX5_IB_METHOD_STEERING_ANCHOR_DESTROY,
+       UVERBS_ATTR_IDR(MLX5_IB_ATTR_STEERING_ANCHOR_DESTROY_HANDLE,
+                       MLX5_IB_OBJECT_STEERING_ANCHOR,
+                       UVERBS_ACCESS_DESTROY,
+                       UA_MANDATORY));
+
+DECLARE_UVERBS_NAMED_OBJECT(
+       MLX5_IB_OBJECT_STEERING_ANCHOR,
+       UVERBS_TYPE_ALLOC_IDR(steering_anchor_cleanup),
+       &UVERBS_METHOD(MLX5_IB_METHOD_STEERING_ANCHOR_CREATE),
+       &UVERBS_METHOD(MLX5_IB_METHOD_STEERING_ANCHOR_DESTROY));
+
 const struct uapi_definition mlx5_ib_flow_defs[] = {
        UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
                MLX5_IB_OBJECT_FLOW_MATCHER),
                &mlx5_ib_fs),
        UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION,
                                &mlx5_ib_flow_actions),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(
+               MLX5_IB_OBJECT_STEERING_ANCHOR,
+               UAPI_DEF_IS_OBJ_SUPPORTED(mlx5_ib_shared_ft_allowed)),
        {},
 };