DVR: run L3 output features

- rename l2_bridged to is_dvr. Including on the ip.api
    this was new in the 18.01 release so no compatability issues.
- steal the free space in vnet_buffer_opaque_t for use with flags.
- run the ipX-output feature arc from the DVR DPO

Change-Id: I040e5976d1dbe076fcdda3a40a7804f56337ce3f
Signed-off-by: Neale Ranns <nranns@cisco.com>
diff --git a/src/vpp-api/vom/prefix.cpp b/src/vpp-api/vom/prefix.cpp
index e754999..abd589e 100644
--- a/src/vpp-api/vom/prefix.cpp
+++ b/src/vpp-api/vom/prefix.cpp
@@ -53,6 +53,19 @@
   return IPV4;
 }
 
+const nh_proto_t&
+l3_proto_t::to_nh_proto() const
+{
+  if (*this == IPV4)
+    return nh_proto_t::IPV4;
+  else if (*this == IPV6)
+    return nh_proto_t::IPV6;
+  else if (*this == MPLS)
+    return nh_proto_t::MPLS;
+
+  return nh_proto_t::IPV4;
+}
+
 std::ostream&
 operator<<(std::ostream& os, const l3_proto_t& l3p)
 {
diff --git a/src/vpp-api/vom/prefix.hpp b/src/vpp-api/vom/prefix.hpp
index 25b188f..3950f6f 100644
--- a/src/vpp-api/vom/prefix.hpp
+++ b/src/vpp-api/vom/prefix.hpp
@@ -26,34 +26,6 @@
  */
 
 /**
- * An L3 protocol can be used to construct a prefix that is used
- * to match packets are part of a route.
- */
-class l3_proto_t : public enum_base<l3_proto_t>
-{
-public:
-  const static l3_proto_t IPV4;
-  const static l3_proto_t IPV6;
-  const static l3_proto_t MPLS;
-
-  bool is_ipv4();
-  bool is_ipv6();
-
-  static const l3_proto_t& from_address(const boost::asio::ip::address& addr);
-
-private:
-  /**
-   * Private constructor taking the value and the string name
-   */
-  l3_proto_t(int v, const std::string& s);
-};
-
-/**
- * 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.
  */
@@ -74,6 +46,36 @@
   nh_proto_t(int v, const std::string& s);
 };
 
+/**
+ * An L3 protocol can be used to construct a prefix that is used
+ * to match packets are part of a route.
+ */
+class l3_proto_t : public enum_base<l3_proto_t>
+{
+public:
+  const static l3_proto_t IPV4;
+  const static l3_proto_t IPV6;
+  const static l3_proto_t MPLS;
+
+  bool is_ipv4();
+  bool is_ipv6();
+
+  static const l3_proto_t& from_address(const boost::asio::ip::address& addr);
+
+  const nh_proto_t& to_nh_proto() const;
+
+private:
+  /**
+   * Private constructor taking the value and the string name
+   */
+  l3_proto_t(int v, const std::string& s);
+};
+
+/**
+ * Ostream output for l3_proto_t
+ */
+std::ostream& operator<<(std::ostream& os, const l3_proto_t& l3p);
+
 namespace route {
 /**
  * type def the table-id
diff --git a/src/vpp-api/vom/route.cpp b/src/vpp-api/vom/route.cpp
index 661d99c..78ea8ce 100644
--- a/src/vpp-api/vom/route.cpp
+++ b/src/vpp-api/vom/route.cpp
@@ -33,9 +33,18 @@
 {
 }
 
+const path::flags_t path::flags_t::NONE(0, "none");
+const path::flags_t path::flags_t::DVR((1 << 0), "dvr");
+
+path::flags_t::flags_t(int v, const std::string& s)
+  : enum_base<path::flags_t>(v, s)
+{
+}
+
 path::path(special_t special)
   : m_type(special)
   , m_nh_proto(nh_proto_t::IPV4)
+  , m_flags(flags_t::NONE)
   , m_nh()
   , m_rd(nullptr)
   , m_interface(nullptr)
@@ -50,6 +59,7 @@
            uint8_t preference)
   : m_type(special_t::STANDARD)
   , m_nh_proto(nh_proto_t::from_address(nh))
+  , m_flags(flags_t::NONE)
   , m_nh(nh)
   , m_rd(nullptr)
   , m_interface(interface.singular())
@@ -64,6 +74,7 @@
            uint8_t preference)
   : m_type(special_t::STANDARD)
   , m_nh_proto(nh_proto_t::from_address(nh))
+  , m_flags(flags_t::NONE)
   , m_nh(nh)
   , m_rd(rd.singular())
   , m_interface(nullptr)
@@ -74,10 +85,12 @@
 
 path::path(const interface& interface,
            const nh_proto_t& proto,
+           const flags_t& flags,
            uint8_t weight,
            uint8_t preference)
   : m_type(special_t::STANDARD)
   , m_nh_proto(proto)
+  , m_flags(flags)
   , m_nh()
   , m_rd(nullptr)
   , m_interface(interface.singular())
@@ -89,6 +102,7 @@
 path::path(const path& p)
   : m_type(p.m_type)
   , m_nh_proto(p.m_nh_proto)
+  , m_flags(p.m_flags)
   , m_nh(p.m_nh)
   , m_rd(p.m_rd)
   , m_interface(p.m_interface)
@@ -100,6 +114,10 @@
 bool
 path::operator<(const path& p) const
 {
+  if (m_nh_proto < p.m_nh_proto)
+    return true;
+  if (m_flags < p.m_flags)
+    return true;
   if (m_type < p.m_type)
     return true;
   if (m_rd && !p.m_rd)
@@ -140,7 +158,8 @@
     return false;
   if (m_interface && p.m_interface)
     result &= (*m_interface == *p.m_interface);
-  return (result && (m_type == p.m_type) && (m_nh == p.m_nh));
+  return (result && (m_type == p.m_type) && (m_nh == p.m_nh) &&
+          (m_nh_proto == p.m_nh_proto) && (m_flags == p.m_flags));
 }
 
 std::string
@@ -150,7 +169,7 @@
 
   s << "path:["
     << "type:" << m_type.to_string() << " proto:" << m_nh_proto.to_string()
-    << " neighbour:" << m_nh.to_string();
+    << " flags:" << m_flags.to_string() << " neighbour:" << m_nh.to_string();
   if (m_rd) {
     s << " " << m_rd->to_string();
   }
@@ -175,6 +194,12 @@
   return m_nh_proto;
 }
 
+path::flags_t
+path::flags() const
+{
+  return m_flags;
+}
+
 const boost::asio::ip::address&
 path::nh() const
 {
diff --git a/src/vpp-api/vom/route.hpp b/src/vpp-api/vom/route.hpp
index 2fb855a..65797b7 100644
--- a/src/vpp-api/vom/route.hpp
+++ b/src/vpp-api/vom/route.hpp
@@ -72,6 +72,29 @@
   };
 
   /**
+   * Path flags
+   */
+  class flags_t : public enum_base<flags_t>
+  {
+  public:
+    /**
+     * No flags
+     */
+    const static flags_t NONE;
+
+    /**
+     * A path that resolves via a DVR next-hop
+     */
+    const static flags_t DVR;
+
+  private:
+    /**
+     * Private constructor taking the value and the string name
+     */
+    flags_t(int v, const std::string& s);
+  };
+
+  /**
    * constructor for special paths
    */
   path(special_t special);
@@ -97,6 +120,7 @@
    */
   path(const interface& interface,
        const nh_proto_t& proto,
+       const flags_t& flags = flags_t::NONE,
        uint8_t weight = 1,
        uint8_t preference = 0);
 
@@ -130,6 +154,7 @@
    */
   special_t type() const;
   nh_proto_t nh_proto() const;
+  flags_t flags() const;
   const boost::asio::ip::address& nh() const;
   std::shared_ptr<route_domain> rd() const;
   std::shared_ptr<interface> itf() const;
@@ -148,6 +173,11 @@
   nh_proto_t m_nh_proto;
 
   /**
+   * Flags for the path
+   */
+  flags_t m_flags;
+
+  /**
    * The next-hop
    */
   boost::asio::ip::address m_nh;
diff --git a/src/vpp-api/vom/route_cmds.cpp b/src/vpp-api/vom/route_cmds.cpp
index 0d012a2..83d44cc 100644
--- a/src/vpp-api/vom/route_cmds.cpp
+++ b/src/vpp-api/vom/route_cmds.cpp
@@ -33,8 +33,8 @@
   payload.is_resolve_host = 0;
   payload.is_resolve_attached = 0;
 
-  if (nh_proto_t::ETHERNET == p.nh_proto()) {
-    payload.is_l2_bridged = 1;
+  if (route::path::flags_t::DVR & p.flags()) {
+    payload.is_dvr = 1;
   }
 
   if (route::path::special_t::STANDARD == p.type()) {