diff --git a/xroot_clients/CTACmd.cpp b/xroot_clients/CTACmd.cpp
index 809afbce2f734543039dc025b57e56196c19452c..903531801dbe731c6c278ec7af4cde8cca4ccc62 100644
--- a/xroot_clients/CTACmd.cpp
+++ b/xroot_clients/CTACmd.cpp
@@ -32,6 +32,9 @@ void CTACmd::usage(std::ostream &os) const throw() {
     "\t" << m_programName << " mkpool <tapepool_name> <\"comment\">\n"
     "\t" << m_programName << " rmpool <tapepool_name>\n"
     "\t" << m_programName << " lspool\n"
+    "\t" << m_programName << " mkroute <storage_class_name> <copy_number> <tapepool_name> <\"comment\">\n"
+    "\t" << m_programName << " rmroute <storage_class_name> <copy_number>\n"
+    "\t" << m_programName << " lsroute\n"
     "\t" << m_programName << " mkadminuser <uid> <gid>\n"
     "\t" << m_programName << " rmadminuser <uid> <gid>\n"
     "\t" << m_programName << " lsadminuser\n"
diff --git a/xroot_plugins/XrdProFilesystem.cpp b/xroot_plugins/XrdProFilesystem.cpp
index eb0cefac1f650a1ec3b9c2801c17cb7433c8faf7..17c53ed8be986e7860b6e11979a2edf53ac8a07e 100644
--- a/xroot_plugins/XrdProFilesystem.cpp
+++ b/xroot_plugins/XrdProFilesystem.cpp
@@ -149,7 +149,6 @@ int XrdProFilesystem::executeMkclassCommand(const ParsedRequest &req, XrdOucErrI
     uint8_t numberOfCopies;
     std::istringstream ss(req.args.at(1));
     ss >> numberOfCopies;
-    cta::SecurityIdentity requester;
     m_clientAPI->createStorageClass(requester, req.args.at(0), numberOfCopies, req.args.at(2));
     std::ostringstream responseSS;
     responseSS << "[OK] Created storage class " << req.args.at(0) << " with " << req.args.at(1) << " tape copies with the following comment: \"" << req.args.at(2) << "\"" ;
@@ -321,7 +320,7 @@ int XrdProFilesystem::executeLsclassCommand(const ParsedRequest &req, XrdOucErrI
     for(std::list<cta::StorageClass>::iterator it = stgList.begin(); it != stgList.end(); it++) {
       responseSS << "\n" << it->getName() << " " << it->getNbCopies() << " " 
               << it->getCreator().uid << " " << it->getCreator().gid << " " 
-              << it->getCreationTime() << " " << it->getComment();
+              << it->getCreationTime() << " \"" << it->getComment() << "\"";
     }
     eInfo.setErrInfo(responseSS.str().length()+1, responseSS.str().c_str());
     return SFS_DATA;
@@ -537,7 +536,116 @@ int XrdProFilesystem::executeLspoolCommand(const ParsedRequest &req, XrdOucErrIn
     responseSS << "[OK] Listing of the tape pools:";
     for(std::list<cta::TapePool>::iterator it = poolList.begin(); it != poolList.end(); it++) {
       responseSS << "\n" << it->getName() << " " << it->getCreator().uid << " " << it->getCreator().gid << " " 
-              << it->getCreationTime() << " " << it->getComment();
+              << it->getCreationTime() << " \"" << it->getComment() << "\"";
+    }
+    eInfo.setErrInfo(responseSS.str().length()+1, responseSS.str().c_str());
+    return SFS_DATA;
+  } catch (cta::Exception &ex) {
+    std::string response = "[ERROR] CTA exception caught: ";
+    response += ex.what();
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  } catch (std::exception &ex) {
+    std::string response = "[ERROR] Exception caught: ";
+    response += ex.what();
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  } catch (...) {
+    std::string response = "[ERROR] Unknown exception caught!";
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  }
+}
+
+//------------------------------------------------------------------------------
+// executeMkrouteCommand
+//------------------------------------------------------------------------------
+int XrdProFilesystem::executeMkrouteCommand(const ParsedRequest &req, XrdOucErrInfo &eInfo, const cta::SecurityIdentity &requester) const {
+  if(req.args.size() != 4) {
+    std::string response = "[ERROR] Wrong number of arguments provided";
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  }
+  try {
+    uint8_t copyNo;
+    std::istringstream ss(req.args.at(1));
+    ss >> copyNo;
+    m_clientAPI->createMigrationRoute(requester, req.args.at(0), copyNo, req.args.at(2), req.args.at(3));
+    std::ostringstream responseSS;
+    responseSS << "[OK] Migration route from storage class " << req.args.at(0) << " with copy number " << copyNo << " to tape pool " << req.args.at(2) << " created with comment \"" << req.args.at(3) << "\"";
+    eInfo.setErrInfo(responseSS.str().length()+1, responseSS.str().c_str());
+    return SFS_DATA;
+  } catch (cta::Exception &ex) {
+    std::string response = "[ERROR] CTA exception caught: ";
+    response += ex.what();
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  } catch (std::exception &ex) {
+    std::string response = "[ERROR] Exception caught: ";
+    response += ex.what();
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  } catch (...) {
+    std::string response = "[ERROR] Unknown exception caught!";
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  }
+}
+
+//------------------------------------------------------------------------------
+// executeRmrouteCommand
+//------------------------------------------------------------------------------
+int XrdProFilesystem::executeRmrouteCommand(const ParsedRequest &req, XrdOucErrInfo &eInfo, const cta::SecurityIdentity &requester) const {
+  if(req.args.size() != 2) {
+    std::string response = "[ERROR] Wrong number of arguments provided";
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  }
+  try {
+    uint8_t copyNo;
+    std::istringstream ss(req.args.at(1));
+    ss >> copyNo;
+    m_clientAPI->deleteMigrationRoute(requester, req.args.at(0), copyNo);
+    std::ostringstream responseSS;
+    responseSS << "[OK] Migration route from storage class " << req.args.at(0) << " with copy number " << copyNo << " removed";
+    eInfo.setErrInfo(responseSS.str().length()+1, responseSS.str().c_str());
+    return SFS_DATA;
+  } catch (cta::Exception &ex) {
+    std::string response = "[ERROR] CTA exception caught: ";
+    response += ex.what();
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  } catch (std::exception &ex) {
+    std::string response = "[ERROR] Exception caught: ";
+    response += ex.what();
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  } catch (...) {
+    std::string response = "[ERROR] Unknown exception caught!";
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  }
+}
+
+//------------------------------------------------------------------------------
+// executeLsrouteCommand
+//------------------------------------------------------------------------------
+int XrdProFilesystem::executeLsrouteCommand(const ParsedRequest &req, XrdOucErrInfo &eInfo, const cta::SecurityIdentity &requester) const {
+  if(req.args.size() != 0) {
+    std::string response = "[ERROR] Wrong number of arguments provided";
+    eInfo.setErrInfo(response.length()+1, response.c_str());
+    return SFS_DATA;
+  }
+  try {
+    std::list<cta::MigrationRoute> routeList = m_clientAPI->getMigrationRoutes(requester);
+    std::ostringstream responseSS;
+    responseSS << "[OK] Listing of the migration routes:";
+    for(std::list<cta::MigrationRoute>::iterator it = routeList.begin(); it != routeList.end(); it++) {
+      responseSS << "\n" << it->getStorageClassName() << ":" << it->getCopyNb() 
+              << " " << it->getTapePoolName()
+              << " " << it->getCreator().uid 
+              << " " << it->getCreator().gid 
+              << " \"" << it->getComment() << "\"";
     }
     eInfo.setErrInfo(responseSS.str().length()+1, responseSS.str().c_str());
     return SFS_DATA;
@@ -825,6 +933,18 @@ int XrdProFilesystem::dispatchRequest(const XrdSfsFSctl &args, XrdOucErrInfo &eI
   {  
     return executeLspoolCommand(req, eInfo, requester);
   }  
+  else if(strcmp(req.cmd.c_str(), "/mkroute") == 0)
+  {  
+    return executeMkrouteCommand(req, eInfo, requester);
+  }  
+  else if(strcmp(req.cmd.c_str(), "/rmroute") == 0)
+  {  
+    return executeRmrouteCommand(req, eInfo, requester);
+  }  
+  else if(strcmp(req.cmd.c_str(), "/lsroute") == 0)
+  {  
+    return executeLsrouteCommand(req, eInfo, requester);
+  }  
   else if(strcmp(req.cmd.c_str(), "/mkadminuser") == 0)
   {  
     return executeMkadminuserCommand(req, eInfo, requester);
diff --git a/xroot_plugins/XrdProFilesystem.hpp b/xroot_plugins/XrdProFilesystem.hpp
index 262873a41625c0af6ad703760d2f2af8c7fb963e..a8559faabc24d3e9e8c27c95cdd2ddf0e596d62e 100644
--- a/xroot_plugins/XrdProFilesystem.hpp
+++ b/xroot_plugins/XrdProFilesystem.hpp
@@ -186,6 +186,36 @@ protected:
    */
   int executeLspoolCommand(const ParsedRequest &req, XrdOucErrInfo &eInfo, const cta::SecurityIdentity &requester) const;
   
+  /**
+   * Executes the command contained within the request structure
+   * 
+   * @param req     parsed request
+   * @param eInfo   Error information
+   * @param requester The UserIdentity structure of the requester
+   * @return SFS_DATA
+   */
+  int executeMkrouteCommand(const ParsedRequest &req, XrdOucErrInfo &eInfo, const cta::SecurityIdentity &requester) const;
+  
+  /**
+   * Executes the command contained within the request structure
+   * 
+   * @param req     parsed request
+   * @param eInfo   Error information
+   * @param requester The UserIdentity structure of the requester
+   * @return SFS_DATA
+   */
+  int executeRmrouteCommand(const ParsedRequest &req, XrdOucErrInfo &eInfo, const cta::SecurityIdentity &requester) const;
+  
+  /**
+   * Executes the command contained within the request structure
+   * 
+   * @param req     parsed request
+   * @param eInfo   Error information
+   * @param requester The UserIdentity structure of the requester
+   * @return SFS_DATA
+   */
+  int executeLsrouteCommand(const ParsedRequest &req, XrdOucErrInfo &eInfo, const cta::SecurityIdentity &requester) const;
+  
   /**
    * Executes the command contained within the request structure
    *