VOM: logging, populate and stats fixes

logging: allow a client to register a callback handler to recieve log messages
         that way the client can maintain a correctly sequenced log
populate: fix the creation of interface and the setting of the handle
stats: the reset promise idea is not defined behaviour.
       Use an eanble/disable command pair

Change-Id: I347720bb65df2874c7619e722d593bc863ee2bf1
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
diff --git a/src/vpp-api/vom/bridge_domain.cpp b/src/vpp-api/vom/bridge_domain.cpp
index 583e35d..38cc89b 100644
--- a/src/vpp-api/vom/bridge_domain.cpp
+++ b/src/vpp-api/vom/bridge_domain.cpp
@@ -159,15 +159,15 @@
     VOM_LOG(log_level_t::DEBUG) << "dump: " << bd.to_string();
 
     /*
- * Write each of the discovered interfaces into the OM,
- * but disable the HW Command q whilst we do, so that no
- * commands are sent to VPP
- */
+     * Write each of the discovered bridge-domains into the OM,
+     * but disable the HW Command q whilst we do, so that no
+     * commands are sent to VPP
+     */
     OM::commit(key, bd);
 
     /**
- * For each interface in the BD construct an l2_binding
- */
+     * For each interface in the BD construct an l2_binding
+     */
     for (unsigned int ii = 0; ii < payload.n_sw_ifs; ii++) {
       std::shared_ptr<interface> itf =
         interface::find(payload.sw_if_details[ii].sw_if_index);
diff --git a/src/vpp-api/vom/bridge_domain_entry.cpp b/src/vpp-api/vom/bridge_domain_entry.cpp
index de1c4b7..9723bde 100644
--- a/src/vpp-api/vom/bridge_domain_entry.cpp
+++ b/src/vpp-api/vom/bridge_domain_entry.cpp
@@ -166,11 +166,21 @@
 
     std::shared_ptr<interface> itf = interface::find(payload.sw_if_index);
     std::shared_ptr<bridge_domain> bd = bridge_domain::find(payload.bd_id);
+
+    if (!bd || !itf) {
+      VOM_LOG(log_level_t::ERROR) << "bridge-domain-entry dump:"
+                                  << " itf:" << payload.sw_if_index
+                                  << " bd:" << payload.bd_id;
+      continue;
+    }
+
     mac_address_t mac(payload.mac);
     bridge_domain_entry bd_e(*bd, mac, *itf);
 
-    VOM_LOG(log_level_t::DEBUG) << "bd-entry-dump: " << bd->to_string()
-                                << mac.to_string() << itf->to_string();
+    VOM_LOG(log_level_t::DEBUG) << "bridge-domain-entry dump:"
+                                << " " << bd->to_string() << " "
+                                << itf->to_string() << " mac:["
+                                << mac.to_string() << "]";
 
     /*
      * Write each of the discovered interfaces into the OM,
diff --git a/src/vpp-api/vom/dhcp_config_cmds.cpp b/src/vpp-api/vom/dhcp_config_cmds.cpp
index 144df98..ff24fe2 100644
--- a/src/vpp-api/vom/dhcp_config_cmds.cpp
+++ b/src/vpp-api/vom/dhcp_config_cmds.cpp
@@ -138,14 +138,14 @@
 events_cmd::issue(connection& con)
 {
   /*
- * Set the call back to handle DHCP complete envets.
- */
+   * Set the call back to handle DHCP complete envets.
+   */
   m_reg.reset(new reg_t(con.ctx(), std::ref(*this)));
 
   /*
- * return in-progress so the command stays in the pending list.
- */
-  return (rc_t::INPROGRESS);
+   * return in-progress so the command stays in the pending list.
+   */
+  return (rc_t::OK);
 }
 
 void
diff --git a/src/vpp-api/vom/hw.cpp b/src/vpp-api/vom/hw.cpp
index 4150d5f..91faf9d 100644
--- a/src/vpp-api/vom/hw.cpp
+++ b/src/vpp-api/vom/hw.cpp
@@ -77,20 +77,6 @@
 }
 
 void
-HW::cmd_q::dequeue(cmd* c)
-{
-  c->retire(m_conn);
-  m_pending.erase(c);
-}
-
-void
-HW::cmd_q::dequeue(std::shared_ptr<cmd> c)
-{
-  c->retire(m_conn);
-  m_pending.erase(c.get());
-}
-
-void
 HW::cmd_q::connect()
 {
   if (m_connected) {
@@ -144,33 +130,18 @@
        * ince a async event can be recieved before the command
        * completes
        */
-      m_pending[c.get()] = c;
-
       rc = c->issue(m_conn);
 
-      if (rc_t::INPROGRESS == rc) {
+      if (rc_t::OK == rc) {
         /*
-         * this command completes asynchronously
-         * leave the command in the pending store
+         * move to the next
          */
       } else {
         /*
-         * the command completed, remove from the pending store
+         * barf out without issuing the rest
          */
-        m_pending.erase(c.get());
-
-        if (rc_t::OK == rc) {
-          /*
-           * move to the next
-           */
-        } else {
-          /*
-           * barf out without issuing the rest
-           */
-          VOM_LOG(log_level_t::ERROR) << "Failed to execute: "
-                                      << c->to_string();
-          break;
-        }
+        VOM_LOG(log_level_t::ERROR) << "Failed to execute: " << c->to_string();
+        break;
       }
     } else {
       /*
@@ -233,18 +204,6 @@
 }
 
 void
-HW::dequeue(cmd* cmd)
-{
-  m_cmdQ->dequeue(cmd);
-}
-
-void
-HW::dequeue(std::shared_ptr<cmd> cmd)
-{
-  m_cmdQ->dequeue(cmd);
-}
-
-void
 HW::connect()
 {
   m_cmdQ->connect();
diff --git a/src/vpp-api/vom/hw.hpp b/src/vpp-api/vom/hw.hpp
index 7e30b67..903aa78 100644
--- a/src/vpp-api/vom/hw.hpp
+++ b/src/vpp-api/vom/hw.hpp
@@ -215,16 +215,6 @@
     virtual void enqueue(std::queue<cmd*>& c);
 
     /**
-     * dequeue a command from the Q.
-     */
-    virtual void dequeue(cmd* c);
-
-    /**
-     * dequeue a command from the Q.
-     */
-    virtual void dequeue(std::shared_ptr<cmd> c);
-
-    /**
      * Write all the commands to HW
      */
     virtual rc_t write();
@@ -312,16 +302,6 @@
   static void enqueue(std::queue<cmd*>& c);
 
   /**
-   * dequeue A command for execution
-   */
-  static void dequeue(cmd* f);
-
-  /**
-   * dequeue A command for execution
-   */
-  static void dequeue(std::shared_ptr<cmd> c);
-
-  /**
    * Write/Execute all commands hitherto enqueued.
    */
   static rc_t write();
diff --git a/src/vpp-api/vom/interface.cpp b/src/vpp-api/vom/interface.cpp
index c7b7e43..10728ce 100644
--- a/src/vpp-api/vom/interface.cpp
+++ b/src/vpp-api/vom/interface.cpp
@@ -49,21 +49,6 @@
 {
 }
 
-interface::interface(const handle_t& handle,
-                     const l2_address_t& l2_address,
-                     const std::string& name,
-                     interface::type_t type,
-                     interface::admin_state_t state)
-  : m_hdl(handle, rc_t::OK)
-  , m_name(name)
-  , m_type(type)
-  , m_state(state, rc_t::OK)
-  , m_table_id(route::DEFAULT_TABLE)
-  , m_l2_address(l2_address)
-  , m_oper(oper_state_t::DOWN)
-{
-}
-
 interface::interface(const std::string& name,
                      interface::type_t itf_type,
                      interface::admin_state_t itf_state,
@@ -172,8 +157,10 @@
       new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl));
   }
 
-  if (m_stats)
-    HW::dequeue(m_stats);
+  if (m_stats) {
+    HW::enqueue(new interface_cmds::stats_disable_cmd(m_hdl.data()));
+    m_stats.reset();
+  }
 
   // If the interface is up, bring it down
   if (m_state && interface::admin_state_t::UP == m_state.data()) {
@@ -364,6 +351,12 @@
 }
 
 void
+interface::set(const handle_t& hdl)
+{
+  m_hdl = hdl;
+}
+
+void
 interface::set(const oper_state_t& state)
 {
   m_oper = state;
@@ -372,7 +365,7 @@
 void
 interface::enable_stats_i(interface::stat_listener& el)
 {
-  m_stats.reset(new interface_cmds::stats_cmd(el, handle_i()));
+  m_stats.reset(new interface_cmds::stats_enable_cmd(el, handle_i()));
   HW::enqueue(m_stats);
   HW::write();
 }
@@ -442,7 +435,7 @@
   HW::write();
 
   for (auto& itf_record : *cmd) {
-    std::unique_ptr<interface> itf =
+    std::shared_ptr<interface> itf =
       interface_factory::new_interface(itf_record.get_payload());
 
     if (itf && interface::type_t::LOCAL != itf->type()) {
diff --git a/src/vpp-api/vom/interface.hpp b/src/vpp-api/vom/interface.hpp
index 8cba2fa..da0db40 100644
--- a/src/vpp-api/vom/interface.hpp
+++ b/src/vpp-api/vom/interface.hpp
@@ -31,7 +31,7 @@
  * Forward declaration of the stats and events command
  */
 namespace interface_cmds {
-class stats_cmd;
+class stats_enable_cmd;
 class events_cmd;
 };
 
@@ -390,7 +390,8 @@
      * Virtual function called on the listener when the command has data
      * ready to process
      */
-    virtual void handle_interface_stat(interface_cmds::stats_cmd* cmd) = 0;
+    virtual void handle_interface_stat(
+      interface_cmds::stats_enable_cmd* cmd) = 0;
 
     /**
      * Return the HW::item representing the status
@@ -426,13 +427,10 @@
 
 protected:
   /**
-   * Construct an interface object with a handle and a HW address
+   * Set the handle of an interface object. Only called by the interface
+   * factory during the populate
    */
-  interface(const handle_t& handle,
-            const l2_address_t& l2_address,
-            const std::string& name,
-            type_t type,
-            admin_state_t state);
+  void set(const handle_t& handle);
   friend class interface_factory;
 
   /**
@@ -560,7 +558,7 @@
   /**
    * shared pointer to the stats object for this interface.
    */
-  std::shared_ptr<interface_cmds::stats_cmd> m_stats;
+  std::shared_ptr<interface_cmds::stats_enable_cmd> m_stats;
 
   /**
    * The state of the interface
diff --git a/src/vpp-api/vom/interface_cmds.cpp b/src/vpp-api/vom/interface_cmds.cpp
index 750ad1f..031aaea 100644
--- a/src/vpp-api/vom/interface_cmds.cpp
+++ b/src/vpp-api/vom/interface_cmds.cpp
@@ -366,7 +366,7 @@
 
   wait();
 
-  return (rc_t::INPROGRESS);
+  return (rc_t::OK);
 }
 
 void
@@ -401,7 +401,8 @@
 /**
  * Interface statistics
  */
-stats_cmd::stats_cmd(interface::stat_listener& el, const handle_t& handle)
+stats_enable_cmd::stats_enable_cmd(interface::stat_listener& el,
+                                   const handle_t& handle)
   : event_cmd(el.status())
   , m_listener(el)
   , m_swifindex(handle)
@@ -409,13 +410,13 @@
 }
 
 bool
-stats_cmd::operator==(const stats_cmd& other) const
+stats_enable_cmd::operator==(const stats_enable_cmd& other) const
 {
   return (true);
 }
 
 rc_t
-stats_cmd::issue(connection& con)
+stats_enable_cmd::issue(connection& con)
 {
   /*
    * First set the call back to handle the interface stats
@@ -438,11 +439,11 @@
 
   wait();
 
-  return (rc_t::INPROGRESS);
+  return (rc_t::OK);
 }
 
 void
-stats_cmd::retire(connection& con)
+stats_enable_cmd::retire(connection& con)
 {
   /*
    * disable interface stats.
@@ -461,21 +462,65 @@
 }
 
 void
-stats_cmd::notify()
+stats_enable_cmd::notify()
 {
   m_listener.handle_interface_stat(this);
 }
 
 std::string
-stats_cmd::to_string() const
+stats_enable_cmd::to_string() const
 {
-  return ("itf-stats");
+  std::ostringstream s;
+  s << "itf-stats-enable itf:" << m_swifindex.to_string();
+  return (s.str());
 }
 
 dump_cmd::dump_cmd()
 {
 }
 
+stats_disable_cmd::stats_disable_cmd(const handle_t& handle)
+  : rpc_cmd(m_res)
+  , m_swifindex(handle)
+{
+}
+
+bool
+stats_disable_cmd::operator==(const stats_disable_cmd& other) const
+{
+  return (true);
+}
+
+rc_t
+stats_disable_cmd::issue(connection& con)
+{
+  /*
+   * then send the request to enable them
+   */
+  msg_t req(con.ctx(), 1, std::ref(*this));
+
+  auto& payload = req.get_request().get_payload();
+  payload.enable_disable = 0;
+  payload.pid = getpid();
+  payload.num = 1;
+
+  payload.sw_ifs[0] = m_swifindex.value();
+
+  VAPI_CALL(req.execute());
+
+  wait();
+
+  return (rc_t::OK);
+}
+
+std::string
+stats_disable_cmd::to_string() const
+{
+  std::ostringstream s;
+  s << "itf-stats-disable itf:" << m_swifindex.to_string();
+  return (s.str());
+}
+
 bool
 dump_cmd::operator==(const dump_cmd& other) const
 {
diff --git a/src/vpp-api/vom/interface_cmds.hpp b/src/vpp-api/vom/interface_cmds.hpp
index c86df92..f21a7f3 100644
--- a/src/vpp-api/vom/interface_cmds.hpp
+++ b/src/vpp-api/vom/interface_cmds.hpp
@@ -370,14 +370,15 @@
 /**
  * A command class represents our desire to recieve interface stats
  */
-class stats_cmd : public event_cmd<vapi::Want_per_interface_combined_stats,
-                                   vapi::Vnet_per_interface_combined_counters>
+class stats_enable_cmd
+  : public event_cmd<vapi::Want_per_interface_combined_stats,
+                     vapi::Vnet_per_interface_combined_counters>
 {
 public:
   /**
    * Constructor taking the listner to notify
    */
-  stats_cmd(interface::stat_listener& el, const handle_t& handle);
+  stats_enable_cmd(interface::stat_listener& el, const handle_t& handle);
 
   /**
    * Issue the command to VPP/HW
@@ -397,7 +398,7 @@
   /**
    * Comparison operator - only used for UT
    */
-  bool operator==(const stats_cmd& i) const;
+  bool operator==(const stats_enable_cmd& i) const;
 
   /**
    * Called when it's time to poke the listeners
@@ -410,6 +411,46 @@
    */
   interface::stat_listener& m_listener;
 
+  /**
+   * The interface on which we are enabling states
+   */
+  handle_t m_swifindex;
+};
+
+/**
+ * A command class represents our desire to recieve interface stats
+ */
+class stats_disable_cmd
+  : public rpc_cmd<HW::item<bool>,
+                   rc_t,
+                   vapi::Want_per_interface_combined_stats>
+{
+public:
+  /**
+   * Constructor taking the listner to notify
+   */
+  stats_disable_cmd(const handle_t& handle);
+
+  /**
+   * Issue the command to VPP/HW
+   */
+  rc_t issue(connection& con);
+
+  /**
+   * convert to string format for debug purposes
+   */
+  std::string to_string() const;
+
+  /**
+   * Comparison operator - only used for UT
+   */
+  bool operator==(const stats_disable_cmd& i) const;
+
+private:
+  HW::item<bool> m_res;
+  /**
+   * The interface on which we are disabling states
+   */
   handle_t m_swifindex;
 };
 
diff --git a/src/vpp-api/vom/interface_factory.cpp b/src/vpp-api/vom/interface_factory.cpp
index cd2d373..b8815ed 100644
--- a/src/vpp-api/vom/interface_factory.cpp
+++ b/src/vpp-api/vom/interface_factory.cpp
@@ -20,14 +20,14 @@
 #include "vom/tap_interface.hpp"
 
 namespace VOM {
-std::unique_ptr<interface>
+std::shared_ptr<interface>
 interface_factory::new_interface(const vapi_payload_sw_interface_details& vd)
 {
-  std::unique_ptr<interface> up_itf;
+  std::shared_ptr<interface> sp;
 
   /**
- * Determine the interface type from the name and VLAN attributes
- */
+   * Determine the interface type from the name and VLAN attributes
+   */
   std::string name = reinterpret_cast<const char*>(vd.interface_name);
   interface::type_t type = interface::type_t::from_string(name);
   interface::admin_state_t state =
@@ -37,48 +37,54 @@
 
   if (interface::type_t::AFPACKET == type) {
     /*
- * need to strip VPP's "host-" prefix from the interface name
- */
+     * need to strip VPP's "host-" prefix from the interface name
+     */
     name = name.substr(5);
   }
   /**
- * if the tag is set, then we wrote that to specify a name to make
- * the interface type more specific
- */
+   * if the tag is set, then we wrote that to specify a name to make
+   * the interface type more specific
+   */
   if (vd.tag[0] != 0) {
     name = std::string(reinterpret_cast<const char*>(vd.tag));
     type = interface::type_t::from_string(name);
   }
 
   /*
- * pull out the other special cases
- */
+   * pull out the other special cases
+   */
   if (interface::type_t::TAP == type) {
     /*
- * TAP interface
- */
-    up_itf.reset(new tap_interface(hdl, name, state, route::prefix_t()));
+     * TAP interface
+     */
+    sp = tap_interface(name, state, route::prefix_t()).singular();
   } else if ((name.find(".") != std::string::npos) && (0 != vd.sub_id)) {
     /*
- * Sub-interface
- *   split the name into the parent and VLAN
- */
+     * Sub-interface
+     *   split the name into the parent and VLAN
+     */
     std::vector<std::string> parts;
     boost::split(parts, name, boost::is_any_of("."));
 
     interface parent(parts[0], type, state);
-    up_itf.reset(new sub_interface(hdl, parent, state, vd.sub_id));
+    sp = sub_interface(parent, state, vd.sub_id).singular();
   } else if (interface::type_t::VXLAN == type) {
     /*
- * there's not enough inforation in a SW interface record to
- * construct
- * a VXLAN tunnel. so skip it.
- */
+     * there's not enough information in a SW interface record to
+     * construct a VXLAN tunnel. so skip it.
+     */
   } else {
-    up_itf.reset(new interface(hdl, l2_address, name, type, state));
+    sp = interface(name, type, state).singular();
+    sp->set(l2_address);
   }
 
-  return (up_itf);
+  /*
+   * set the handle on the intterface - N.B. this is the sigluar instance
+   * not a stack local.
+   */
+  sp->set(hdl);
+
+  return (sp);
 }
 }; // namespace VOM
 
diff --git a/src/vpp-api/vom/interface_factory.hpp b/src/vpp-api/vom/interface_factory.hpp
index 47faecc..e1cbb38 100644
--- a/src/vpp-api/vom/interface_factory.hpp
+++ b/src/vpp-api/vom/interface_factory.hpp
@@ -30,7 +30,7 @@
   /**
    * Factory method to construct a new interface from the VPP record
    */
-  static std::unique_ptr<interface> new_interface(
+  static std::shared_ptr<interface> new_interface(
     const vapi_payload_sw_interface_details& vd);
 };
 };
diff --git a/src/vpp-api/vom/logger.cpp b/src/vpp-api/vom/logger.cpp
index 07e2749..80f2d92 100644
--- a/src/vpp-api/vom/logger.cpp
+++ b/src/vpp-api/vom/logger.cpp
@@ -43,7 +43,7 @@
 
 log_t::log_t()
   : m_level(log_level_t::ERROR)
-  , m_o_stream(&std::cout)
+  , m_handler(new cout_handler())
 {
 }
 
@@ -54,33 +54,19 @@
 }
 
 void
-log_t::set(const std::string& ofile)
+log_t::set(handler* h)
 {
-  m_file_stream.open(ofile);
-  m_o_stream = &m_file_stream;
+  m_handler = h;
 }
 
-std::ostream&
-log_t::stream(const char* file, int line, const log_level_t& level)
+void
+log_t::write(const std::string& file,
+             const int line,
+             const std::string& function,
+             const log_level_t& level,
+             const std::string& message)
 {
-  auto end = std::chrono::system_clock::now();
-  auto end_time = std::chrono::system_clock::to_time_t(end);
-
-  /*
- * put-time is not support in gcc in 4.8
- * so we play this dance with ctime
- */
-  std::string display = std::ctime(&end_time);
-  display.pop_back();
-
-  std::vector<std::string> dirs;
-  boost::split(dirs, file, boost::is_any_of("/"));
-
-  *m_o_stream << std::endl
-              << display << " [" << level.to_string() << "]"
-              << " " << dirs.back() << ":" << line << ": ";
-
-  return (*m_o_stream);
+  m_handler->handle_message(file, line, function, level, message);
 }
 
 /**
@@ -91,8 +77,90 @@
 {
   return (m_level);
 }
+
+static std::string
+get_filename(const std::string& file)
+{
+  std::vector<std::string> dirs;
+  boost::split(dirs, file, boost::is_any_of("/"));
+
+  return dirs.back();
 }
 
+log_t::entry::entry(const char* file,
+                    const char* function,
+                    int line,
+                    const log_level_t& level)
+  : m_file(get_filename(file))
+  , m_function(function)
+  , m_level(level)
+  , m_line(line)
+{
+}
+
+log_t::entry::~entry()
+{
+  logger().write(m_file, m_line, m_function, m_level, m_stream.str());
+}
+
+std::stringstream&
+log_t::entry::stream()
+{
+  return (m_stream);
+}
+
+static std::string
+get_timestamp()
+{
+  auto end = std::chrono::system_clock::now();
+  auto end_time = std::chrono::system_clock::to_time_t(end);
+
+  /*
+   * put-time is not support in gcc in 4.8
+   * so we play this dance with ctime
+   */
+  std::string display = std::ctime(&end_time);
+  display.pop_back();
+
+  return (display);
+}
+
+file_handler::file_handler(const std::string& ofile)
+{
+  m_file_stream.open(ofile);
+}
+
+file_handler::~file_handler()
+{
+  m_file_stream.close();
+}
+
+void
+file_handler::handle_message(const std::string& file,
+                             const int line,
+                             const std::string& function,
+                             const log_level_t& level,
+                             const std::string& message)
+{
+  m_file_stream << get_timestamp();
+  m_file_stream << " [" << level.to_string() << "]" << file << ":" << line
+                << " " << function << "() " << message << std::endl;
+}
+
+void
+cout_handler::handle_message(const std::string& file,
+                             const int line,
+                             const std::string& function,
+                             const log_level_t& level,
+                             const std::string& message)
+{
+  std::cout << get_timestamp();
+  std::cout << " [" << level.to_string() << "]" << file << ":" << line << " "
+            << function << "() " << message << std::endl;
+}
+
+}; // namespace VOM
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vpp-api/vom/logger.hpp b/src/vpp-api/vom/logger.hpp
index 941623e..6d2e3dd 100644
--- a/src/vpp-api/vom/logger.hpp
+++ b/src/vpp-api/vom/logger.hpp
@@ -18,6 +18,7 @@
 
 #include <fstream>
 #include <iostream>
+#include <sstream>
 
 #include "vom/enum_base.hpp"
 
@@ -35,6 +36,11 @@
    * Private constructor taking the value and the string name
    */
   log_level_t(int v, const std::string& s);
+
+  /*
+   * not allowed to construct
+   */
+  log_level_t() = delete;
 };
 
 /**
@@ -45,14 +51,36 @@
 {
 public:
   /**
-   * Construct a logger
+   *
    */
-  log_t();
+  class handler
+  {
+  public:
+    /**
+   * Default Constructor
+   */
+    handler() = default;
+
+    /**
+     * Default Destructor
+     */
+    virtual ~handler() = default;
+
+    /**
+     * Handle a log message
+     */
+    virtual void handle_message(const std::string& file,
+                                const int line,
+                                const std::string& function,
+                                const log_level_t& level,
+                                const std::string& message) = 0;
+  };
 
   /**
-   * Return the stream
+   * Construct a logger
    */
-  std::ostream& stream(const char* file, int line, const log_level_t& level);
+  log_t(handler* h);
+  log_t();
 
   /**
    * The configured level
@@ -67,23 +95,82 @@
   /**
    * set a file to receive the logging data
    */
-  void set(const std::string& ofile);
+  void set(handler* h);
+
+  /**
+   * An entry in the log
+   */
+  class entry
+  {
+  public:
+    entry(const char* file,
+          const char* function,
+          int line,
+          const log_level_t& level);
+    ~entry();
+
+    std::stringstream& stream();
+
+  private:
+    const std::string m_file;
+    const std::string m_function;
+    const log_level_t m_level;
+    const int m_line;
+
+    std::stringstream m_stream;
+  };
+  /**
+   * Register a log handler to receive the log output
+   */
+  void register_handler(handler& h);
 
 private:
+  void write(const std::string& file,
+             const int line,
+             const std::string& function,
+             const log_level_t& level,
+             const std::string& message);
+
   /**
    * the configured logging level
    */
   log_level_t m_level;
 
   /**
+   * Pointer to a registered handler. Null if no handler registerd
+   */
+  handler* m_handler;
+};
+
+class file_handler : public log_t::handler
+{
+public:
+  file_handler(const std::string& ofile);
+  ~file_handler();
+
+  virtual void handle_message(const std::string& file,
+                              const int line,
+                              const std::string& function,
+                              const log_level_t& level,
+                              const std::string& message);
+
+private:
+  /**
    * Opened file for debugging
    */
   std::ofstream m_file_stream;
+};
 
-  /**
-   * Pointer to the output stream
-   */
-  std::ostream* m_o_stream;
+class cout_handler : public log_t::handler
+{
+public:
+  cout_handler() = default;
+  ~cout_handler() = default;
+  virtual void handle_message(const std::string& file,
+                              const int line,
+                              const std::string& function,
+                              const log_level_t& level,
+                              const std::string& message);
 };
 
 /**
@@ -93,7 +180,7 @@
 
 #define VOM_LOG(lvl)                                                           \
   if (lvl >= logger().level())                                                 \
-  logger().stream(__FILE__, __LINE__, lvl)
+  log_t::entry(__FILE__, __FUNCTION__, __LINE__, lvl).stream()
 };
 
 /*
diff --git a/src/vpp-api/vom/rpc_cmd.hpp b/src/vpp-api/vom/rpc_cmd.hpp
index ae3c675..bd78978 100644
--- a/src/vpp-api/vom/rpc_cmd.hpp
+++ b/src/vpp-api/vom/rpc_cmd.hpp
@@ -79,7 +79,7 @@
      * we reset the promise after setting the value to reuse it
      * when we run the retire command from the same cmd object
      */
-    m_promise = std::promise<DATA>();
+    //    m_promise = std::promise<DATA>();
   }
 
   /**
diff --git a/src/vpp-api/vom/sub_interface.cpp b/src/vpp-api/vom/sub_interface.cpp
index 01f4a54..94baa3d 100644
--- a/src/vpp-api/vom/sub_interface.cpp
+++ b/src/vpp-api/vom/sub_interface.cpp
@@ -29,20 +29,6 @@
 {
 }
 
-sub_interface::sub_interface(const handle_t& handle,
-                             const interface& parent,
-                             admin_state_t state,
-                             vlan_id_t vlan)
-  : interface(handle,
-              l2_address_t::ZERO,
-              mk_name(parent, vlan),
-              parent.type(),
-              state)
-  , m_parent(parent.singular())
-  , m_vlan(vlan)
-{
-}
-
 sub_interface::~sub_interface()
 {
   sweep();
diff --git a/src/vpp-api/vom/sub_interface.hpp b/src/vpp-api/vom/sub_interface.hpp
index 1c65782..41786e4 100644
--- a/src/vpp-api/vom/sub_interface.hpp
+++ b/src/vpp-api/vom/sub_interface.hpp
@@ -60,20 +60,6 @@
 
 private:
   /**
-   * Construct with handle
-   */
-  sub_interface(const handle_t& handle,
-                const interface& parent,
-                admin_state_t state,
-                vlan_id_t vlan);
-  friend class interface_factory;
-
-  /**
-   * The interface class can construct interfaces with handles
-   */
-  friend class interface;
-
-  /**
    * Return the matching 'instance' of the sub-interface
    *  over-ride from the base class
    */
diff --git a/src/vpp-api/vom/tap_interface.cpp b/src/vpp-api/vom/tap_interface.cpp
index 4f88d3b..1f85ca1 100644
--- a/src/vpp-api/vom/tap_interface.cpp
+++ b/src/vpp-api/vom/tap_interface.cpp
@@ -43,16 +43,6 @@
 {
 }
 
-tap_interface::tap_interface(const handle_t& hdl,
-                             const std::string& name,
-                             admin_state_t state,
-                             route::prefix_t prefix)
-  : interface(hdl, l2_address_t::ZERO, name, type_t::TAP, state)
-  , m_prefix(prefix)
-  , m_l2_address(l2_address_t::ZERO)
-{
-}
-
 tap_interface::~tap_interface()
 {
   sweep();
diff --git a/src/vpp-api/vom/tap_interface.hpp b/src/vpp-api/vom/tap_interface.hpp
index 08dba50..d9df9a9 100644
--- a/src/vpp-api/vom/tap_interface.hpp
+++ b/src/vpp-api/vom/tap_interface.hpp
@@ -75,16 +75,6 @@
   static event_handler m_evh;
 
   /**
-   * Construct with a handle
-   */
-  tap_interface(const handle_t& hdl,
-                const std::string& name,
-                admin_state_t state,
-                route::prefix_t prefix);
-
-  friend class interface_factory;
-
-  /**
    * Ip Prefix
    */
   route::prefix_t m_prefix;
diff --git a/src/vpp-api/vom/tap_interface_cmds.cpp b/src/vpp-api/vom/tap_interface_cmds.cpp
index 799b9af..b088560 100644
--- a/src/vpp-api/vom/tap_interface_cmds.cpp
+++ b/src/vpp-api/vom/tap_interface_cmds.cpp
@@ -112,7 +112,7 @@
 
   wait();
 
-  return rc_t::INPROGRESS;
+  return rc_t::OK;
 }
 
 std::string
diff --git a/src/vpp-api/vom/types.cpp b/src/vpp-api/vom/types.cpp
index c5325d2..cdced0f 100644
--- a/src/vpp-api/vom/types.cpp
+++ b/src/vpp-api/vom/types.cpp
@@ -49,9 +49,8 @@
 const rc_t rc_t::UNSET(0, "un-set");
 const rc_t rc_t::NOOP(1, "no-op");
 const rc_t rc_t::OK(2, "ok");
-const rc_t rc_t::INPROGRESS(3, "in-progess");
-const rc_t rc_t::INVALID(4, "invalid");
-const rc_t rc_t::TIMEOUT(5, "timeout");
+const rc_t rc_t::INVALID(3, "invalid");
+const rc_t rc_t::TIMEOUT(4, "timeout");
 
 const handle_t handle_t::INVALID(~0);
 
diff --git a/src/vpp-api/vom/types.hpp b/src/vpp-api/vom/types.hpp
index b57867f..839b29a 100644
--- a/src/vpp-api/vom/types.hpp
+++ b/src/vpp-api/vom/types.hpp
@@ -106,12 +106,6 @@
   const static rc_t OK;
 
   /**
-   * HW write is in progress. Also used for the 'want' events
-   * that never complete
-   */
-  const static rc_t INPROGRESS;
-
-  /**
    * HW write reported invalid input
    */
   const static rc_t INVALID;
diff --git a/src/vpp-api/vom/vxlan_tunnel.cpp b/src/vpp-api/vom/vxlan_tunnel.cpp
index 8961589..f6f3cf5 100644
--- a/src/vpp-api/vom/vxlan_tunnel.cpp
+++ b/src/vpp-api/vom/vxlan_tunnel.cpp
@@ -106,19 +106,6 @@
 {
 }
 
-vxlan_tunnel::vxlan_tunnel(const handle_t& hdl,
-                           const boost::asio::ip::address& src,
-                           const boost::asio::ip::address& dst,
-                           uint32_t vni)
-  : interface(hdl,
-              l2_address_t::ZERO,
-              mk_name(src, dst, vni),
-              interface::type_t::VXLAN,
-              interface::admin_state_t::UP)
-  , m_tep(src, dst, vni)
-{
-}
-
 vxlan_tunnel::vxlan_tunnel(const vxlan_tunnel& o)
   : interface(o)
   , m_tep(o.m_tep)
@@ -233,11 +220,13 @@
     boost::asio::ip::address dst =
       from_bytes(payload.is_ipv6, payload.dst_address);
 
-    vxlan_tunnel vt(hdl, src, dst, payload.vni);
+    std::shared_ptr<vxlan_tunnel> vt =
+      vxlan_tunnel(src, dst, payload.vni).singular();
+    vt->set(hdl);
 
-    VOM_LOG(log_level_t::DEBUG) << "dump: " << vt.to_string();
+    VOM_LOG(log_level_t::DEBUG) << "dump: " << vt->to_string();
 
-    OM::commit(key, vt);
+    OM::commit(key, *vt);
   }
 }