#include <linux/jhash.h>
 #include <linux/net_namespace.h>
 #include <linux/mutex.h>
+#include <linux/genalloc.h>
 #include <net/netevent.h>
 #include <net/neighbour.h>
 #include <net/arp.h>
 
 static int mlxsw_sp_rif_index_alloc(struct mlxsw_sp *mlxsw_sp, u16 *p_rif_index)
 {
-       int i;
+       *p_rif_index = gen_pool_alloc(mlxsw_sp->router->rifs_table, 1);
+       if (*p_rif_index == 0)
+               return -ENOBUFS;
+       *p_rif_index -= MLXSW_SP_ROUTER_GENALLOC_OFFSET;
 
-       for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
-               if (!mlxsw_sp->router->rifs[i]) {
-                       *p_rif_index = i;
-                       return 0;
-               }
-       }
+       return 0;
+}
 
-       return -ENOBUFS;
+static void mlxsw_sp_rif_index_free(struct mlxsw_sp *mlxsw_sp, u16 rif_index)
+{
+       gen_pool_free(mlxsw_sp->router->rifs_table,
+                     MLXSW_SP_ROUTER_GENALLOC_OFFSET + rif_index, 1);
 }
 
 static struct mlxsw_sp_rif *mlxsw_sp_rif_alloc(size_t rif_size, u16 rif_index,
        dev_put(rif->dev);
        kfree(rif);
 err_rif_alloc:
+       mlxsw_sp_rif_index_free(mlxsw_sp, rif_index);
 err_rif_index_alloc:
        vr->rif_count--;
        mlxsw_sp_vr_put(mlxsw_sp, vr);
        const struct mlxsw_sp_rif_ops *ops = rif->ops;
        struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
        struct mlxsw_sp_fid *fid = rif->fid;
+       u16 rif_index = rif->rif_index;
        struct mlxsw_sp_vr *vr;
        int i;
 
        mlxsw_sp->router->rifs[rif->rif_index] = NULL;
        dev_put(rif->dev);
        kfree(rif);
+       mlxsw_sp_rif_index_free(mlxsw_sp, rif_index);
        vr->rif_count--;
        mlxsw_sp_vr_put(mlxsw_sp, vr);
 }
        }
 
        ul_rif = mlxsw_sp_rif_alloc(sizeof(*ul_rif), rif_index, vr->id, NULL);
-       if (!ul_rif)
-               return ERR_PTR(-ENOMEM);
+       if (!ul_rif) {
+               err = -ENOMEM;
+               goto err_rif_alloc;
+       }
 
        mlxsw_sp->router->rifs[rif_index] = ul_rif;
        ul_rif->mlxsw_sp = mlxsw_sp;
 ul_rif_op_err:
        mlxsw_sp->router->rifs[rif_index] = NULL;
        kfree(ul_rif);
+err_rif_alloc:
+       mlxsw_sp_rif_index_free(mlxsw_sp, rif_index);
        return ERR_PTR(err);
 }
 
 static void mlxsw_sp_ul_rif_destroy(struct mlxsw_sp_rif *ul_rif)
 {
        struct mlxsw_sp *mlxsw_sp = ul_rif->mlxsw_sp;
+       u16 rif_index = ul_rif->rif_index;
 
        atomic_dec(&mlxsw_sp->router->rifs_count);
        mlxsw_sp_rif_ipip_lb_ul_rif_op(ul_rif, false);
        mlxsw_sp->router->rifs[ul_rif->rif_index] = NULL;
        kfree(ul_rif);
+       mlxsw_sp_rif_index_free(mlxsw_sp, rif_index);
 }
 
 static struct mlxsw_sp_rif *
        [MLXSW_SP_RIF_TYPE_IPIP_LB]     = &mlxsw_sp2_rif_ipip_lb_ops,
 };
 
+static int mlxsw_sp_rifs_table_init(struct mlxsw_sp *mlxsw_sp)
+{
+       struct gen_pool *rifs_table;
+       int err;
+
+       rifs_table = gen_pool_create(0, -1);
+       if (!rifs_table)
+               return -ENOMEM;
+
+       gen_pool_set_algo(rifs_table, gen_pool_first_fit_order_align,
+                         NULL);
+
+       err = gen_pool_add(rifs_table, MLXSW_SP_ROUTER_GENALLOC_OFFSET,
+                          MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS), -1);
+       if (err)
+               goto err_gen_pool_add;
+
+       mlxsw_sp->router->rifs_table = rifs_table;
+
+       return 0;
+
+err_gen_pool_add:
+       gen_pool_destroy(rifs_table);
+       return err;
+}
+
+static void mlxsw_sp_rifs_table_fini(struct mlxsw_sp *mlxsw_sp)
+{
+       gen_pool_destroy(mlxsw_sp->router->rifs_table);
+}
+
 static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
 {
        u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
        struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
        struct mlxsw_core *core = mlxsw_sp->core;
+       int err;
 
        if (!MLXSW_CORE_RES_VALID(core, MAX_RIF_MAC_PROFILES))
                return -EIO;
        if (!mlxsw_sp->router->rifs)
                return -ENOMEM;
 
+       err = mlxsw_sp_rifs_table_init(mlxsw_sp);
+       if (err)
+               goto err_rifs_table_init;
+
        idr_init(&mlxsw_sp->router->rif_mac_profiles_idr);
        atomic_set(&mlxsw_sp->router->rif_mac_profiles_count, 0);
        atomic_set(&mlxsw_sp->router->rifs_count, 0);
                                       mlxsw_sp);
 
        return 0;
+
+err_rifs_table_init:
+       kfree(mlxsw_sp->router->rifs);
+       return err;
 }
 
 static void mlxsw_sp_rifs_fini(struct mlxsw_sp *mlxsw_sp)
                                         MLXSW_SP_RESOURCE_RIF_MAC_PROFILES);
        WARN_ON(!idr_is_empty(&mlxsw_sp->router->rif_mac_profiles_idr));
        idr_destroy(&mlxsw_sp->router->rif_mac_profiles_idr);
+       mlxsw_sp_rifs_table_fini(mlxsw_sp);
        kfree(mlxsw_sp->router->rifs);
 }