unsigned char addr[ETH_ALEN];
        int mtu;
        u16 rif_index;
+       u8 mac_profile_id;
        u16 vr_id;
        const struct mlxsw_sp_rif_ops *ops;
        struct mlxsw_sp *mlxsw_sp;
        void (*fdb_del)(struct mlxsw_sp_rif *rif, const char *mac);
 };
 
+struct mlxsw_sp_rif_mac_profile {
+       unsigned char mac_prefix[ETH_ALEN];
+       refcount_t ref_count;
+       u8 id;
+};
+
 struct mlxsw_sp_router_ops {
        int (*init)(struct mlxsw_sp *mlxsw_sp);
        int (*ipips_init)(struct mlxsw_sp *mlxsw_sp);
        mlxsw_sp_rif_destroy(rif);
 }
 
+static int mlxsw_sp_rif_mac_profile_index_alloc(struct mlxsw_sp *mlxsw_sp,
+                                               struct mlxsw_sp_rif_mac_profile *profile,
+                                               struct netlink_ext_ack *extack)
+{
+       u8 max_rif_mac_profiles = mlxsw_sp->router->max_rif_mac_profile;
+       struct mlxsw_sp_router *router = mlxsw_sp->router;
+       int id;
+
+       id = idr_alloc(&router->rif_mac_profiles_idr, profile, 0,
+                      max_rif_mac_profiles, GFP_KERNEL);
+
+       if (id >= 0) {
+               profile->id = id;
+               return 0;
+       }
+
+       if (id == -ENOSPC)
+               NL_SET_ERR_MSG_MOD(extack,
+                                  "Exceeded number of supported router interface MAC profiles");
+
+       return id;
+}
+
+static struct mlxsw_sp_rif_mac_profile *
+mlxsw_sp_rif_mac_profile_index_free(struct mlxsw_sp *mlxsw_sp, u8 mac_profile)
+{
+       struct mlxsw_sp_rif_mac_profile *profile;
+
+       profile = idr_remove(&mlxsw_sp->router->rif_mac_profiles_idr,
+                            mac_profile);
+       WARN_ON(!profile);
+       return profile;
+}
+
+static struct mlxsw_sp_rif_mac_profile *
+mlxsw_sp_rif_mac_profile_alloc(const char *mac)
+{
+       struct mlxsw_sp_rif_mac_profile *profile;
+
+       profile = kzalloc(sizeof(*profile), GFP_KERNEL);
+       if (!profile)
+               return NULL;
+
+       ether_addr_copy(profile->mac_prefix, mac);
+       refcount_set(&profile->ref_count, 1);
+       return profile;
+}
+
+static struct mlxsw_sp_rif_mac_profile *
+mlxsw_sp_rif_mac_profile_find(const struct mlxsw_sp *mlxsw_sp, const char *mac)
+{
+       struct mlxsw_sp_router *router = mlxsw_sp->router;
+       struct mlxsw_sp_rif_mac_profile *profile;
+       int id;
+
+       idr_for_each_entry(&router->rif_mac_profiles_idr, profile, id) {
+               if (!profile)
+                       continue;
+
+               if (ether_addr_equal_masked(profile->mac_prefix, mac,
+                                           mlxsw_sp->mac_mask))
+                       return profile;
+       }
+
+       return NULL;
+}
+
+static u64 mlxsw_sp_rif_mac_profiles_occ_get(void *priv)
+{
+       const struct mlxsw_sp *mlxsw_sp = priv;
+
+       return atomic_read(&mlxsw_sp->router->rif_mac_profiles_count);
+}
+
+static struct mlxsw_sp_rif_mac_profile *
+mlxsw_sp_rif_mac_profile_create(struct mlxsw_sp *mlxsw_sp, const char *mac,
+                               struct netlink_ext_ack *extack)
+{
+       struct mlxsw_sp_rif_mac_profile *profile;
+       int err;
+
+       profile = mlxsw_sp_rif_mac_profile_alloc(mac);
+       if (!profile)
+               return ERR_PTR(-ENOMEM);
+
+       err = mlxsw_sp_rif_mac_profile_index_alloc(mlxsw_sp, profile, extack);
+       if (err)
+               goto profile_index_alloc_err;
+
+       atomic_inc(&mlxsw_sp->router->rif_mac_profiles_count);
+       return profile;
+
+profile_index_alloc_err:
+       kfree(profile);
+       return ERR_PTR(err);
+}
+
+static void mlxsw_sp_rif_mac_profile_destroy(struct mlxsw_sp *mlxsw_sp,
+                                            u8 mac_profile)
+{
+       struct mlxsw_sp_rif_mac_profile *profile;
+
+       atomic_dec(&mlxsw_sp->router->rif_mac_profiles_count);
+       profile = mlxsw_sp_rif_mac_profile_index_free(mlxsw_sp, mac_profile);
+       kfree(profile);
+}
+
+static int mlxsw_sp_rif_mac_profile_get(struct mlxsw_sp *mlxsw_sp,
+                                       const char *mac, u8 *p_mac_profile,
+                                       struct netlink_ext_ack *extack)
+{
+       struct mlxsw_sp_rif_mac_profile *profile;
+
+       profile = mlxsw_sp_rif_mac_profile_find(mlxsw_sp, mac);
+       if (profile) {
+               refcount_inc(&profile->ref_count);
+               goto out;
+       }
+
+       profile = mlxsw_sp_rif_mac_profile_create(mlxsw_sp, mac, extack);
+       if (IS_ERR(profile))
+               return PTR_ERR(profile);
+
+out:
+       *p_mac_profile = profile->id;
+       return 0;
+}
+
+static void mlxsw_sp_rif_mac_profile_put(struct mlxsw_sp *mlxsw_sp,
+                                        u8 mac_profile)
+{
+       struct mlxsw_sp_rif_mac_profile *profile;
+
+       profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
+                          mac_profile);
+       if (WARN_ON(!profile))
+               return;
+
+       if (!refcount_dec_and_test(&profile->ref_count))
+               return;
+
+       mlxsw_sp_rif_mac_profile_destroy(mlxsw_sp, mac_profile);
+}
+
+static bool mlxsw_sp_rif_mac_profile_is_shared(const struct mlxsw_sp_rif *rif)
+{
+       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+       struct mlxsw_sp_rif_mac_profile *profile;
+
+       profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
+                          rif->mac_profile_id);
+       if (WARN_ON(!profile))
+               return false;
+
+       return refcount_read(&profile->ref_count) > 1;
+}
+
+static int mlxsw_sp_rif_mac_profile_edit(struct mlxsw_sp_rif *rif,
+                                        const char *new_mac)
+{
+       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+       struct mlxsw_sp_rif_mac_profile *profile;
+
+       profile = idr_find(&mlxsw_sp->router->rif_mac_profiles_idr,
+                          rif->mac_profile_id);
+       if (WARN_ON(!profile))
+               return -EINVAL;
+
+       ether_addr_copy(profile->mac_prefix, new_mac);
+       return 0;
+}
+
+static int
+mlxsw_sp_rif_mac_profile_replace(struct mlxsw_sp *mlxsw_sp,
+                                struct mlxsw_sp_rif *rif,
+                                const char *new_mac,
+                                struct netlink_ext_ack *extack)
+{
+       u8 mac_profile;
+       int err;
+
+       if (!mlxsw_sp_rif_mac_profile_is_shared(rif))
+               return mlxsw_sp_rif_mac_profile_edit(rif, new_mac);
+
+       err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, new_mac,
+                                          &mac_profile, extack);
+       if (err)
+               return err;
+
+       mlxsw_sp_rif_mac_profile_put(mlxsw_sp, rif->mac_profile_id);
+       rif->mac_profile_id = mac_profile;
+       return 0;
+}
+
 static int
 __mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan,
                                 struct net_device *l3_dev,
        return 0;
 }
 
-static int mlxsw_sp_router_port_check_rif_addr(struct mlxsw_sp *mlxsw_sp,
-                                              struct net_device *dev,
-                                              const unsigned char *dev_addr,
-                                              struct netlink_ext_ack *extack)
-{
-       struct mlxsw_sp_rif *rif;
-       int i;
-
-       /* A RIF is not created for macvlan netdevs. Their MAC is used to
-        * populate the FDB
-        */
-       if (netif_is_macvlan(dev) || netif_is_l3_master(dev))
-               return 0;
-
-       for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++) {
-               rif = mlxsw_sp->router->rifs[i];
-               if (rif && rif->ops &&
-                   rif->ops->type == MLXSW_SP_RIF_TYPE_IPIP_LB)
-                       continue;
-               if (rif && rif->dev && rif->dev != dev &&
-                   !ether_addr_equal_masked(rif->dev->dev_addr, dev_addr,
-                                            mlxsw_sp->mac_mask)) {
-                       NL_SET_ERR_MSG_MOD(extack, "All router interface MAC addresses must have the same prefix");
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
 static int __mlxsw_sp_inetaddr_event(struct mlxsw_sp *mlxsw_sp,
                                     struct net_device *dev,
                                     unsigned long event,
        if (!mlxsw_sp_rif_should_config(rif, dev, event))
                goto out;
 
-       err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
-                                                 ivi->extack);
-       if (err)
-               goto out;
-
        err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, ivi->extack);
 out:
        mutex_unlock(&mlxsw_sp->router->lock);
        if (!mlxsw_sp_rif_should_config(rif, dev, event))
                goto out;
 
-       err = mlxsw_sp_router_port_check_rif_addr(mlxsw_sp, dev, dev->dev_addr,
-                                                 i6vi->extack);
-       if (err)
-               goto out;
-
        err = __mlxsw_sp_inetaddr_event(mlxsw_sp, dev, event, i6vi->extack);
 out:
        mutex_unlock(&mlxsw_sp->router->lock);
 }
 
 static int mlxsw_sp_rif_edit(struct mlxsw_sp *mlxsw_sp, u16 rif_index,
-                            const char *mac, int mtu)
+                            const char *mac, int mtu, u8 mac_profile)
 {
        char ritr_pl[MLXSW_REG_RITR_LEN];
        int err;
 
        mlxsw_reg_ritr_mtu_set(ritr_pl, mtu);
        mlxsw_reg_ritr_if_mac_memcpy_to(ritr_pl, mac);
+       mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, mac_profile);
        mlxsw_reg_ritr_op_set(ritr_pl, MLXSW_REG_RITR_RIF_CREATE);
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 }
                                  struct netlink_ext_ack *extack)
 {
        struct net_device *dev = rif->dev;
+       u8 old_mac_profile;
        u16 fid_index;
        int err;
 
        if (err)
                return err;
 
+       old_mac_profile = rif->mac_profile_id;
+       err = mlxsw_sp_rif_mac_profile_replace(mlxsw_sp, rif, dev->dev_addr,
+                                              extack);
+       if (err)
+               goto err_rif_mac_profile_replace;
+
        err = mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, dev->dev_addr,
-                               dev->mtu);
+                               dev->mtu, rif->mac_profile_id);
        if (err)
                goto err_rif_edit;
 
        return 0;
 
 err_rif_fdb_op:
-       mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu);
+       mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu,
+                         old_mac_profile);
 err_rif_edit:
+       mlxsw_sp_rif_mac_profile_replace(mlxsw_sp, rif, rif->addr, extack);
+err_rif_mac_profile_replace:
        mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true);
        return err;
 }
 static int mlxsw_sp_router_port_pre_changeaddr_event(struct mlxsw_sp_rif *rif,
                            struct netdev_notifier_pre_changeaddr_info *info)
 {
+       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+       struct mlxsw_sp_rif_mac_profile *profile;
        struct netlink_ext_ack *extack;
+       u8 max_rif_mac_profiles;
+       u64 occ;
 
        extack = netdev_notifier_info_to_extack(&info->info);
-       return mlxsw_sp_router_port_check_rif_addr(rif->mlxsw_sp, rif->dev,
-                                                  info->dev_addr, extack);
+
+       profile = mlxsw_sp_rif_mac_profile_find(mlxsw_sp, info->dev_addr);
+       if (profile)
+               return 0;
+
+       max_rif_mac_profiles = mlxsw_sp->router->max_rif_mac_profile;
+       occ = mlxsw_sp_rif_mac_profiles_occ_get(mlxsw_sp);
+       if (occ < max_rif_mac_profiles)
+               return 0;
+
+       if (!mlxsw_sp_rif_mac_profile_is_shared(rif))
+               return 0;
+
+       NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported router interface MAC profiles");
+       return -ENOBUFS;
 }
 
 int mlxsw_sp_netdevice_router_port_event(struct net_device *dev,
        mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_SP_IF,
                            rif->rif_index, rif->vr_id, rif->dev->mtu);
        mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
+       mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
        mlxsw_reg_ritr_sp_if_pack(ritr_pl, rif_subport->lag,
                                  rif_subport->lag ? rif_subport->lag_id :
                                                     rif_subport->system_port,
 static int mlxsw_sp_rif_subport_configure(struct mlxsw_sp_rif *rif,
                                          struct netlink_ext_ack *extack)
 {
+       u8 mac_profile;
        int err;
 
-       err = mlxsw_sp_rif_subport_op(rif, true);
+       err = mlxsw_sp_rif_mac_profile_get(rif->mlxsw_sp, rif->addr,
+                                          &mac_profile, extack);
        if (err)
                return err;
+       rif->mac_profile_id = mac_profile;
+
+       err = mlxsw_sp_rif_subport_op(rif, true);
+       if (err)
+               goto err_rif_subport_op;
 
        err = mlxsw_sp_rif_fdb_op(rif->mlxsw_sp, rif->dev->dev_addr,
                                  mlxsw_sp_fid_index(rif->fid), true);
 
 err_rif_fdb_op:
        mlxsw_sp_rif_subport_op(rif, false);
+err_rif_subport_op:
+       mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, mac_profile);
        return err;
 }
 
                            mlxsw_sp_fid_index(fid), false);
        mlxsw_sp_rif_macvlan_flush(rif);
        mlxsw_sp_rif_subport_op(rif, false);
+       mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
 }
 
 static struct mlxsw_sp_fid *
        mlxsw_reg_ritr_pack(ritr_pl, enable, type, rif->rif_index, rif->vr_id,
                            rif->dev->mtu);
        mlxsw_reg_ritr_mac_pack(ritr_pl, rif->dev->dev_addr);
+       mlxsw_reg_ritr_if_mac_profile_id_set(ritr_pl, rif->mac_profile_id);
        mlxsw_reg_ritr_fid_set(ritr_pl, type, vid_fid);
 
        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
 {
        struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
        u16 fid_index = mlxsw_sp_fid_index(rif->fid);
+       u8 mac_profile;
        int err;
 
+       err = mlxsw_sp_rif_mac_profile_get(mlxsw_sp, rif->addr,
+                                          &mac_profile, extack);
+       if (err)
+               return err;
+       rif->mac_profile_id = mac_profile;
+
        err = mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index,
                                       true);
        if (err)
-               return err;
+               goto err_rif_vlan_fid_op;
 
        err = mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
                                     mlxsw_sp_router_port(mlxsw_sp), true);
                               mlxsw_sp_router_port(mlxsw_sp), false);
 err_fid_mc_flood_set:
        mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
+err_rif_vlan_fid_op:
+       mlxsw_sp_rif_mac_profile_put(mlxsw_sp, mac_profile);
        return err;
 }
 
        mlxsw_sp_fid_flood_set(rif->fid, MLXSW_SP_FLOOD_TYPE_MC,
                               mlxsw_sp_router_port(mlxsw_sp), false);
        mlxsw_sp_rif_vlan_fid_op(rif, MLXSW_REG_RITR_FID_IF, fid_index, false);
+       mlxsw_sp_rif_mac_profile_put(rif->mlxsw_sp, rif->mac_profile_id);
 }
 
 static struct mlxsw_sp_fid *
 static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp)
 {
        u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS);
+       struct mlxsw_core *core = mlxsw_sp->core;
+
+       if (!MLXSW_CORE_RES_VALID(core, MAX_RIF_MAC_PROFILES))
+               return -EIO;
+       mlxsw_sp->router->max_rif_mac_profile =
+               MLXSW_CORE_RES_GET(core, MAX_RIF_MAC_PROFILES);
 
        mlxsw_sp->router->rifs = kcalloc(max_rifs,
                                         sizeof(struct mlxsw_sp_rif *),
        if (!mlxsw_sp->router->rifs)
                return -ENOMEM;
 
+       idr_init(&mlxsw_sp->router->rif_mac_profiles_idr);
+       atomic_set(&mlxsw_sp->router->rif_mac_profiles_count, 0);
+
        return 0;
 }
 
        for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); i++)
                WARN_ON_ONCE(mlxsw_sp->router->rifs[i]);
 
+       WARN_ON(!idr_is_empty(&mlxsw_sp->router->rif_mac_profiles_idr));
+       idr_destroy(&mlxsw_sp->router->rif_mac_profiles_idr);
        kfree(mlxsw_sp->router->rifs);
 }