VOM: NAT updates

Change-Id: I112afaa1f2ccd2ee62a436c73802afaea9b44779
Signed-off-by: Neale Ranns <neale.ranns@cisco.com>
diff --git a/src/vpp-api/vom/nat_binding.cpp b/src/vpp-api/vom/nat_binding.cpp
index ce73ae4..a2e71b3 100644
--- a/src/vpp-api/vom/nat_binding.cpp
+++ b/src/vpp-api/vom/nat_binding.cpp
@@ -29,6 +29,13 @@
   : enum_base(v, s)
 {
 }
+const nat_binding::zone_t&
+nat_binding::zone_t::from_vpp(u8 is_inside)
+{
+  if (is_inside)
+    return zone_t::INSIDE;
+  return zone_t::OUTSIDE;
+}
 
 /**
  * Construct a new object matching the desried state
@@ -57,7 +64,19 @@
 nat_binding::~nat_binding()
 {
   sweep();
-  m_db.release(make_tuple(m_itf->key(), m_dir, m_proto), this);
+  m_db.release(key(), this);
+}
+
+const nat_binding::key_t
+nat_binding::key() const
+{
+  return (make_tuple(m_itf->key(), m_dir, m_proto));
+}
+
+bool
+nat_binding::operator==(const nat_binding& n) const
+{
+  return ((key() == n.key()) && (m_zone == n.m_zone));
 }
 
 void
@@ -68,7 +87,8 @@
       HW::enqueue(new nat_binding_cmds::unbind_44_input_cmd(
         m_binding, m_itf->handle(), m_zone));
     } else {
-      assert(!"Unimplemented");
+      HW::enqueue(new nat_binding_cmds::unbind_44_output_cmd(
+        m_binding, m_itf->handle(), m_zone));
     }
   }
   HW::write();
@@ -82,7 +102,8 @@
       HW::enqueue(new nat_binding_cmds::bind_44_input_cmd(
         m_binding, m_itf->handle(), m_zone));
     } else {
-      assert(!"Unimplemented");
+      HW::enqueue(new nat_binding_cmds::bind_44_output_cmd(
+        m_binding, m_itf->handle(), m_zone));
     }
   }
 }
@@ -98,7 +119,8 @@
       HW::enqueue(new nat_binding_cmds::bind_44_input_cmd(
         m_binding, m_itf->handle(), m_zone));
     } else {
-      assert(!"Unimplemented");
+      HW::enqueue(new nat_binding_cmds::bind_44_input_cmd(
+        m_binding, m_itf->handle(), m_zone));
     }
   }
 }
@@ -107,8 +129,9 @@
 nat_binding::to_string() const
 {
   std::ostringstream s;
-  s << "nat-binding:[" << m_itf->to_string() << " " << m_dir.to_string() << " "
-    << m_proto.to_string() << " " << m_zone.to_string() << "]";
+  s << "nat-binding:[" << m_itf->to_string()
+    << " direction:" << m_dir.to_string() << " proto:" << m_proto.to_string()
+    << " zone:" << m_zone.to_string() << "]";
 
   return (s.str());
 }
@@ -116,8 +139,13 @@
 std::shared_ptr<nat_binding>
 nat_binding::find_or_add(const nat_binding& temp)
 {
-  return (m_db.find_or_add(
-    make_tuple(temp.m_itf->key(), temp.m_dir, temp.m_proto), temp));
+  return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<nat_binding>
+nat_binding::find(const key_t& key)
+{
+  return (m_db.find(key));
 }
 
 std::shared_ptr<nat_binding>
@@ -156,9 +184,35 @@
 void
 nat_binding::event_handler::handle_populate(const client_db::key_t& key)
 {
-  /**
- * This is done while populating the interfaces
- */
+  std::shared_ptr<nat_binding_cmds::dump_input_44_cmd> icmd =
+    std::make_shared<nat_binding_cmds::dump_input_44_cmd>();
+
+  HW::enqueue(icmd);
+  HW::write();
+
+  for (auto& record : *icmd) {
+    auto& payload = record.get_payload();
+
+    std::shared_ptr<interface> itf = interface::find(payload.sw_if_index);
+    nat_binding nb(*itf, direction_t::INPUT, l3_proto_t::IPV4,
+                   zone_t::from_vpp(payload.is_inside));
+    OM::commit(key, nb);
+  }
+
+  std::shared_ptr<nat_binding_cmds::dump_output_44_cmd> ocmd =
+    std::make_shared<nat_binding_cmds::dump_output_44_cmd>();
+
+  HW::enqueue(ocmd);
+  HW::write();
+
+  for (auto& record : *ocmd) {
+    auto& payload = record.get_payload();
+
+    std::shared_ptr<interface> itf = interface::find(payload.sw_if_index);
+    nat_binding nb(*itf, direction_t::OUTPUT, l3_proto_t::IPV4,
+                   zone_t::from_vpp(payload.is_inside));
+    OM::commit(key, nb);
+  }
 }
 
 dependency_t
diff --git a/src/vpp-api/vom/nat_binding.hpp b/src/vpp-api/vom/nat_binding.hpp
index 7761250..a99d23a 100644
--- a/src/vpp-api/vom/nat_binding.hpp
+++ b/src/vpp-api/vom/nat_binding.hpp
@@ -54,6 +54,8 @@
      * Deny Zone
      */
     const static zone_t OUTSIDE;
+
+    const static zone_t& from_vpp(u8 is_inside);
   };
 
   /**
@@ -86,6 +88,16 @@
   ~nat_binding();
 
   /**
+   * Comparison operator - for UT
+   */
+  bool operator==(const nat_binding& n) const;
+
+  /**
+   * Return the binding's key
+   */
+  const key_t key() const;
+
+  /**
    * Return the 'singular instance' of the L2 config that matches this
    * object
    */
@@ -97,6 +109,11 @@
   std::string to_string() const;
 
   /**
+   * Static function to find the bridge_domain in the model
+   */
+  static std::shared_ptr<nat_binding> find(const key_t& key);
+
+  /**
    * Dump all nat_bindings into the stream provided
    */
   static void dump(std::ostream& os);
diff --git a/src/vpp-api/vom/nat_binding_cmds.cpp b/src/vpp-api/vom/nat_binding_cmds.cpp
index 106ec5e..66b2827 100644
--- a/src/vpp-api/vom/nat_binding_cmds.cpp
+++ b/src/vpp-api/vom/nat_binding_cmds.cpp
@@ -101,22 +101,106 @@
   return (s.str());
 }
 
-dump_44_cmd::dump_44_cmd()
-{
-}
-
-dump_44_cmd::dump_44_cmd(const dump_44_cmd& d)
+bind_44_output_cmd::bind_44_output_cmd(HW::item<bool>& item,
+                                       const handle_t& itf,
+                                       const nat_binding::zone_t& zone)
+  : rpc_cmd(item)
+  , m_itf(itf)
+  , m_zone(zone)
 {
 }
 
 bool
-dump_44_cmd::operator==(const dump_44_cmd& other) const
+bind_44_output_cmd::operator==(const bind_44_output_cmd& other) const
+{
+  return ((m_itf == other.m_itf) && (m_zone == other.m_zone));
+}
+
+rc_t
+bind_44_output_cmd::issue(connection& con)
+{
+  msg_t req(con.ctx(), std::ref(*this));
+
+  auto& payload = req.get_request().get_payload();
+  payload.is_add = 1;
+  payload.is_inside = (nat_binding::zone_t::INSIDE == m_zone ? 1 : 0);
+  payload.sw_if_index = m_itf.value();
+
+  VAPI_CALL(req.execute());
+
+  m_hw_item.set(wait());
+
+  return rc_t::OK;
+}
+
+std::string
+bind_44_output_cmd::to_string() const
+{
+  std::ostringstream s;
+  s << "nat-44-output-binding-create: " << m_hw_item.to_string()
+    << " itf:" << m_itf << " " << m_zone.to_string();
+
+  return (s.str());
+}
+
+unbind_44_output_cmd::unbind_44_output_cmd(HW::item<bool>& item,
+                                           const handle_t& itf,
+                                           const nat_binding::zone_t& zone)
+  : rpc_cmd(item)
+  , m_itf(itf)
+  , m_zone(zone)
+{
+}
+
+bool
+unbind_44_output_cmd::operator==(const unbind_44_output_cmd& other) const
+{
+  return ((m_itf == other.m_itf) && (m_zone == other.m_zone));
+}
+
+rc_t
+unbind_44_output_cmd::issue(connection& con)
+{
+  msg_t req(con.ctx(), std::ref(*this));
+
+  auto& payload = req.get_request().get_payload();
+  payload.is_add = 0;
+  payload.is_inside = (nat_binding::zone_t::INSIDE == m_zone ? 1 : 0);
+  payload.sw_if_index = m_itf.value();
+
+  VAPI_CALL(req.execute());
+
+  m_hw_item.set(wait());
+
+  return rc_t::OK;
+}
+
+std::string
+unbind_44_output_cmd::to_string() const
+{
+  std::ostringstream s;
+  s << "nat-44-output-binding-create: " << m_hw_item.to_string()
+    << " itf:" << m_itf << " " << m_zone.to_string();
+
+  return (s.str());
+}
+
+dump_input_44_cmd::dump_input_44_cmd()
+{
+}
+
+dump_input_44_cmd::dump_input_44_cmd(const dump_input_44_cmd& d)
+{
+}
+
+bool
+dump_input_44_cmd::operator==(const dump_input_44_cmd& other) const
 {
   return (true);
 }
 
 rc_t
-dump_44_cmd::issue(connection& con)
+dump_input_44_cmd::issue(connection& con)
 {
   m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
 
@@ -128,13 +212,46 @@
 }
 
 std::string
-dump_44_cmd::to_string() const
+dump_input_44_cmd::to_string() const
 {
-  return ("nat-binding-dump");
+  return ("nat-input-binding-dump");
 }
+
+dump_output_44_cmd::dump_output_44_cmd()
+{
 }
+
+dump_output_44_cmd::dump_output_44_cmd(const dump_output_44_cmd& d)
+{
 }
 
+bool
+dump_output_44_cmd::operator==(const dump_output_44_cmd& other) const
+{
+  return (true);
+}
+
+rc_t
+dump_output_44_cmd::issue(connection& con)
+{
+  m_dump.reset(new msg_t(con.ctx(), std::ref(*this)));
+
+  VAPI_CALL(m_dump->execute());
+
+  wait();
+
+  return rc_t::OK;
+}
+
+std::string
+dump_output_44_cmd::to_string() const
+{
+  return ("nat-output-binding-dump");
+}
+
+}; // namespace nat_binding_cmds
+}; // namespace VOM
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vpp-api/vom/nat_binding_cmds.hpp b/src/vpp-api/vom/nat_binding_cmds.hpp
index ed9048a..bb94048 100644
--- a/src/vpp-api/vom/nat_binding_cmds.hpp
+++ b/src/vpp-api/vom/nat_binding_cmds.hpp
@@ -1,131 +1,269 @@
+/*
+ * Copyright (c) 2017 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #ifndef __VOM_NAT_BINDING_CMDS_H__
 #define __VOM_NAT_BINDING_CMDS_H__
 
+#include "vom/dump_cmd.hpp"
 #include "vom/nat_binding.hpp"
 #include "vom/rpc_cmd.hpp"
-#include "vom/dump_cmd.hpp"
 
 #include <vapi/nat.api.vapi.hpp>
 
 namespace VOM {
 namespace nat_binding_cmds {
 /**
- * A functor class that binds L2 configuration to an interface
+ * A functor class that binds a NAT configuration to an input interface
  */
 class bind_44_input_cmd
-    : public rpc_cmd<HW::item<bool>,
-                     rc_t,
-                     vapi::Nat44_interface_add_del_feature>
+  : public rpc_cmd<HW::item<bool>, rc_t, vapi::Nat44_interface_add_del_feature>
 {
 public:
-    /**
-     * Constructor
-     */
-    bind_44_input_cmd(HW::item<bool>& item,
-                      const handle_t& itf,
-                      const nat_binding::zone_t& zone);
+  /**
+   * Constructor
+   */
+  bind_44_input_cmd(HW::item<bool>& item,
+                    const handle_t& itf,
+                    const nat_binding::zone_t& zone);
 
-    /**
-     * Issue the command to VPP/HW
-     */
-    rc_t issue(connection& con);
-    /**
-     * convert to string format for debug purposes
-     */
-    std::string to_string() const;
+  /**
+   * 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 bind_44_input_cmd& i) const;
+  /**
+   * Comparison operator - only used for UT
+   */
+  bool operator==(const bind_44_input_cmd& i) const;
 
 private:
-    /**
-     * The interface to bind
-     */
-    const handle_t m_itf;
+  /**
+   * The interface to bind
+   */
+  const handle_t m_itf;
 
-    /**
-     * The zone the interface is in
-     */
-    const nat_binding::zone_t m_zone;
+  /**
+   * The zone the interface is in
+   */
+  const nat_binding::zone_t m_zone;
 };
 
 /**
- * A cmd class that Unbinds L2 configuration from an interface
+ * A cmd class that unbinds a NAT configuration from an input interface
  */
 class unbind_44_input_cmd
-    : public rpc_cmd<HW::item<bool>,
-                     rc_t,
-                     vapi::Nat44_interface_add_del_feature>
+  : public rpc_cmd<HW::item<bool>, rc_t, vapi::Nat44_interface_add_del_feature>
 {
 public:
-    /**
-     * Constructor
-     */
-    unbind_44_input_cmd(HW::item<bool>& item,
-                        const handle_t& itf,
-                        const nat_binding::zone_t& zone);
+  /**
+   * Constructor
+   */
+  unbind_44_input_cmd(HW::item<bool>& item,
+                      const handle_t& itf,
+                      const nat_binding::zone_t& zone);
 
-    /**
-     * Issue the command to VPP/HW
-     */
-    rc_t issue(connection& con);
-    /**
-     * convert to string format for debug purposes
-     */
-    std::string to_string() const;
+  /**
+   * 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 unbind_44_input_cmd& i) const;
+  /**
+   * Comparison operator - only used for UT
+   */
+  bool operator==(const unbind_44_input_cmd& i) const;
 
 private:
-    /**
-     * The interface to bind
-     */
-    const handle_t m_itf;
+  /**
+   * The interface to bind
+   */
+  const handle_t m_itf;
 
-    /**
-     * The zone the interface is in
-     */
-    const nat_binding::zone_t m_zone;
+  /**
+   * The zone the interface is in
+   */
+  const nat_binding::zone_t m_zone;
+};
+
+/**
+ * A functor class that binds a NAT configuration to an output interface
+ */
+class bind_44_output_cmd
+  : public rpc_cmd<HW::item<bool>,
+                   rc_t,
+                   vapi::Nat44_interface_add_del_output_feature>
+{
+public:
+  /**
+   * Constructor
+   */
+  bind_44_output_cmd(HW::item<bool>& item,
+                     const handle_t& itf,
+                     const nat_binding::zone_t& zone);
+
+  /**
+   * 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 bind_44_output_cmd& i) const;
+
+private:
+  /**
+   * The interface to bind
+   */
+  const handle_t m_itf;
+
+  /**
+   * The zone the interface is in
+   */
+  const nat_binding::zone_t m_zone;
+};
+
+/**
+ * A cmd class that unbinds a NAT configuration from an output interface
+ */
+class unbind_44_output_cmd
+  : public rpc_cmd<HW::item<bool>,
+                   rc_t,
+                   vapi::Nat44_interface_add_del_output_feature>
+{
+public:
+  /**
+   * Constructor
+   */
+  unbind_44_output_cmd(HW::item<bool>& item,
+                       const handle_t& itf,
+                       const nat_binding::zone_t& zone);
+
+  /**
+   * 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 unbind_44_output_cmd& i) const;
+
+private:
+  /**
+   * The interface to bind
+   */
+  const handle_t m_itf;
+
+  /**
+   * The zone the interface is in
+   */
+  const nat_binding::zone_t m_zone;
 };
 
 /**
  * A cmd class that Dumps all the nat_statics
  */
-class dump_44_cmd : public dump_cmd<vapi::Nat44_interface_dump>
+class dump_input_44_cmd : public dump_cmd<vapi::Nat44_interface_dump>
 {
 public:
-    /**
-     * Constructor
-     */
-    dump_44_cmd();
-    dump_44_cmd(const dump_44_cmd& d);
+  /**
+   * Constructor
+   */
+  dump_input_44_cmd();
+  dump_input_44_cmd(const dump_input_44_cmd& d);
 
-    /**
-     * Issue the command to VPP/HW
-     */
-    rc_t issue(connection& con);
-    /**
-     * convert to string format for debug purposes
-     */
-    std::string to_string() const;
+  /**
+   * 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 dump_44_cmd& i) const;
+  /**
+   * Comparison operator - only used for UT
+   */
+  bool operator==(const dump_input_44_cmd& i) const;
 
 private:
-    /**
-     * HW reutrn code
-     */
-    HW::item<bool> item;
+  /**
+   * HW reutrn code
+   */
+  HW::item<bool> item;
 };
+
+/**
+ * A cmd class that Dumps all the nat_statics
+ */
+class dump_output_44_cmd
+  : public dump_cmd<vapi::Nat44_interface_output_feature_dump>
+{
+public:
+  /**
+   * Constructor
+   */
+  dump_output_44_cmd();
+  dump_output_44_cmd(const dump_output_44_cmd& d);
+
+  /**
+   * 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 dump_output_44_cmd& i) const;
+
+private:
+  /**
+   * HW reutrn code
+   */
+  HW::item<bool> item;
 };
-};
+
+}; // namespace nat_binding_cmds
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
 
 #endif
diff --git a/src/vpp-api/vom/nat_static.cpp b/src/vpp-api/vom/nat_static.cpp
index 619cc3b..a90b0bc 100644
--- a/src/vpp-api/vom/nat_static.cpp
+++ b/src/vpp-api/vom/nat_static.cpp
@@ -52,7 +52,19 @@
   sweep();
 
   // not in the DB anymore.
-  m_db.release(std::make_pair(m_rd->key(), m_outside), this);
+  m_db.release(key(), this);
+}
+
+const nat_static::key_t
+nat_static::key() const
+{
+  return (std::make_pair(m_rd->key(), m_outside));
+}
+
+bool
+nat_static::operator==(const nat_static& n) const
+{
+  return ((key() == n.key()) && (m_inside == n.m_inside));
 }
 
 void
@@ -97,8 +109,8 @@
 {
   std::ostringstream s;
   s << "nat-static:["
-    << "table:" << m_rd->to_string() << " inside: " << m_inside.to_string()
-    << " outside " << m_outside.to_string() << "]";
+    << "table:" << m_rd->to_string() << " inside:" << m_inside.to_string()
+    << " outside:" << m_outside.to_string() << "]";
 
   return (s.str());
 }
@@ -106,8 +118,13 @@
 std::shared_ptr<nat_static>
 nat_static::find_or_add(const nat_static& temp)
 {
-  return (
-    m_db.find_or_add(std::make_pair(temp.m_rd->key(), temp.m_outside), temp));
+  return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<nat_static>
+nat_static::find(const key_t& key)
+{
+  return (m_db.find(key));
 }
 
 std::shared_ptr<nat_static>
@@ -142,61 +159,34 @@
   m_db.replay();
 }
 
-/* void nat_static::populate_i(const client_db::key_t &key, */
-/*                            std::shared_ptr<interface> itf, */
-/*                            const l3_proto_t &proto) */
-/* { */
-/*     /\* */
-/*      * dump VPP current states */
-/*      *\/ */
-/*     std::shared_ptr<nat_static::dump_cmd> cmd = */
-/*         std::make_shared<nat_static::dump_cmd>(nat_static::dump_cmd(itf->handle(),
- * proto)); */
-
-/*     HW::enqueue(cmd); */
-/*     HW::write(); */
-
-/*     for (auto & record : *cmd) */
-/*     { */
-/*         /\* */
-/*          * construct a nat_static from each recieved record. */
-/*          *\/ */
-/*         auto &payload = record.get_payload(); */
-
-/*      mac_address_t mac(payload.mac_address); */
-/*         boost::asio::ip::address ip_addr = from_bytes(payload.is_ipv6, */
-/*                                                       payload.ip_address);
- */
-/*         nat_static n(*itf, mac, ip_addr); */
-
-/*         VOM_LOG(log_level_t::DEBUG) << "nat_static-dump: " */
-/*                                                << itf->to_string() */
-/*                                                << mac.to_string() */
-/*                                                << ip_addr.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 */
-/*          *\/ */
-/*         OM::commit(key, n); */
-/*     } */
-/* } */
-
 void
 nat_static::event_handler::handle_populate(const client_db::key_t& key)
 {
-  /* auto it = interface::cbegin(); */
+  /*
+   * dump VPP current states
+   */
+  std::shared_ptr<nat_static_cmds::dump_44_cmd> cmd =
+    std::make_shared<nat_static_cmds::dump_44_cmd>();
 
-  /* while (it != interface::cend()) */
-  /* { */
-  /*     nat_static::populate_i(key, it->second.lock(), l3_proto_t::IPV4);
- */
-  /*     nat_static::populate_i(key, it->second.lock(), l3_proto_t::IPV6);
- */
+  HW::enqueue(cmd);
+  HW::write();
 
-  /*     ++it; */
-  /* } */
+  for (auto& record : *cmd) {
+
+    auto& payload = record.get_payload();
+
+    boost::asio::ip::address inside = from_bytes(0, payload.local_ip_address);
+    boost::asio::ip::address outside =
+      from_bytes(0, payload.external_ip_address);
+    nat_static n(route_domain(payload.vrf_id), inside, outside.to_v4());
+
+    /*
+     * Write each of the discovered mappings into the OM,
+     * but disable the HW Command q whilst we do, so that no
+     * commands are sent to VPP
+     */
+    OM::commit(key, n);
+  }
 }
 
 dependency_t
diff --git a/src/vpp-api/vom/nat_static.hpp b/src/vpp-api/vom/nat_static.hpp
index 1560968..4c2dab1 100644
--- a/src/vpp-api/vom/nat_static.hpp
+++ b/src/vpp-api/vom/nat_static.hpp
@@ -60,6 +60,16 @@
   ~nat_static();
 
   /**
+   * Comparison operator - for UT
+   */
+  bool operator==(const nat_static& n) const;
+
+  /**
+   * Return the object's key
+   */
+  const key_t key() const;
+
+  /**
    * Return the matching 'singular instance'
    */
   std::shared_ptr<nat_static> singular() const;
@@ -67,7 +77,7 @@
   /**
    * Find the instnace of the bridge_domain domain in the OM
    */
-  static std::shared_ptr<nat_static> find(const nat_static& temp);
+  static std::shared_ptr<nat_static> find(const key_t& key);
 
   /**
    * Dump all bridge_domain-doamin into the stream provided
diff --git a/src/vpp-api/vom/nat_static_cmds.cpp b/src/vpp-api/vom/nat_static_cmds.cpp
index 2abe0d2..facc7c6 100644
--- a/src/vpp-api/vom/nat_static_cmds.cpp
+++ b/src/vpp-api/vom/nat_static_cmds.cpp
@@ -123,14 +123,6 @@
   return (s.str());
 }
 
-dump_44_cmd::dump_44_cmd()
-{
-}
-
-dump_44_cmd::dump_44_cmd(const dump_44_cmd& d)
-{
-}
-
 bool
 dump_44_cmd::operator==(const dump_44_cmd& other) const
 {
@@ -154,8 +146,9 @@
 {
   return ("nat-static-dump");
 }
-} // namespace nat_static_cmds
-} // namespace VOM
+
+}; // namespace nat_static_cmds
+}; // namespace VOM
 
 /*
  * fd.io coding-style-patch-verification: ON
diff --git a/src/vpp-api/vom/nat_static_cmds.hpp b/src/vpp-api/vom/nat_static_cmds.hpp
index 1db2571..a4adcef 100644
--- a/src/vpp-api/vom/nat_static_cmds.hpp
+++ b/src/vpp-api/vom/nat_static_cmds.hpp
@@ -105,8 +105,8 @@
   /**
    * Constructor
    */
-  dump_44_cmd();
-  dump_44_cmd(const dump_44_cmd& d);
+  dump_44_cmd() = default;
+  ~dump_44_cmd() = default;
 
   /**
    * Issue the command to VPP/HW
@@ -128,6 +128,7 @@
    */
   HW::item<bool> item;
 };
+
 }; // namespace nat_static_cmds
 }; // namespace vom
 
diff --git a/src/vpp-api/vom/prefix.cpp b/src/vpp-api/vom/prefix.cpp
index 269c28f..e754999 100644
--- a/src/vpp-api/vom/prefix.cpp
+++ b/src/vpp-api/vom/prefix.cpp
@@ -53,6 +53,13 @@
   return IPV4;
 }
 
+std::ostream&
+operator<<(std::ostream& os, const l3_proto_t& l3p)
+{
+  os << l3p.to_string();
+  return os;
+}
+
 /*
  * Keep this in sync with VPP's dpo_proto_t
  */
diff --git a/src/vpp-api/vom/prefix.hpp b/src/vpp-api/vom/prefix.hpp
index e395e17..25b188f 100644
--- a/src/vpp-api/vom/prefix.hpp
+++ b/src/vpp-api/vom/prefix.hpp
@@ -49,6 +49,11 @@
 };
 
 /**
+ * Ostream output for l3_proto_t
+ */
+std::ostream& operator<<(std::ostream& os, const l3_proto_t& l3p);
+
+/**
  * A next-hop protocol describes the protocol of a peer to which packets
  * are sent after matching a route.
  */
diff --git a/src/vpp-api/vom/types.cpp b/src/vpp-api/vom/types.cpp
index cdced0f..9df5314 100644
--- a/src/vpp-api/vom/types.cpp
+++ b/src/vpp-api/vom/types.cpp
@@ -261,8 +261,15 @@
   : enum_base(v, s)
 {
 }
+std::ostream&
+operator<<(std::ostream& os, const direction_t& dir)
+{
+  os << dir.to_string();
+  return os;
 }
 
+}; // namespace VOM
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
diff --git a/src/vpp-api/vom/types.hpp b/src/vpp-api/vom/types.hpp
index 839b29a..61a25e7 100644
--- a/src/vpp-api/vom/types.hpp
+++ b/src/vpp-api/vom/types.hpp
@@ -154,6 +154,11 @@
 };
 
 /**
+ * Output ostream for direction_t
+ */
+std::ostream& operator<<(std::ostream& os, const direction_t& dir);
+
+/**
  * A type declaration of an interface handle in VPP
  */
 struct handle_t