aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--extras/vom/vom/CMakeLists.txt2
-rw-r--r--extras/vom/vom/api_types.cpp54
-rw-r--r--extras/vom/vom/api_types.hpp7
-rw-r--r--extras/vom/vom/mroute_cmds.cpp193
-rw-r--r--extras/vom/vom/mroute_cmds.hpp181
-rw-r--r--extras/vom/vom/prefix.cpp131
-rw-r--r--extras/vom/vom/prefix.hpp118
-rw-r--r--extras/vom/vom/route.cpp345
-rw-r--r--extras/vom/vom/route.hpp194
-rw-r--r--extras/vom/vom/route_api_types.cpp119
-rw-r--r--extras/vom/vom/route_api_types.hpp35
-rw-r--r--extras/vom/vom/route_cmds.cpp44
-rw-r--r--src/vnet/fib/fib_types.h4
-rw-r--r--src/vnet/ip/ip.api10
-rw-r--r--src/vnet/ip/ip_api.c10
-rw-r--r--src/vnet/mfib/mfib_entry.c13
-rw-r--r--test/ext/vom_test.cpp41
17 files changed, 1378 insertions, 123 deletions
diff --git a/extras/vom/vom/CMakeLists.txt b/extras/vom/vom/CMakeLists.txt
index bd8986a4864..475672a001a 100644
--- a/extras/vom/vom/CMakeLists.txt
+++ b/extras/vom/vom/CMakeLists.txt
@@ -158,6 +158,7 @@ list(APPEND VOM_SOURCES
neighbour.cpp
neighbour_cmds.cpp
object_base.cpp
+ mroute_cmds.cpp
om.cpp
pipe.cpp
pipe_cmds.cpp
@@ -165,6 +166,7 @@ list(APPEND VOM_SOURCES
ra_config.cpp
ra_prefix.cpp
route.cpp
+ route_api_types.cpp
route_cmds.cpp
route_domain.cpp
route_domain_cmds.cpp
diff --git a/extras/vom/vom/api_types.cpp b/extras/vom/vom/api_types.cpp
index 53cd047332a..4a81a41daa9 100644
--- a/extras/vom/vom/api_types.cpp
+++ b/extras/vom/vom/api_types.cpp
@@ -28,6 +28,21 @@ to_api(const ip_address_t& a, vapi_type_address& v)
memcpy(v.un.ip6, a.to_v6().to_bytes().data(), 16);
}
}
+
+void
+to_api(const ip_address_t& a,
+ vapi_union_address_union& u,
+ vapi_enum_address_family& af)
+{
+ if (a.is_v4()) {
+ af = ADDRESS_IP4;
+ memcpy(u.ip4, a.to_v4().to_bytes().data(), 4);
+ } else {
+ af = ADDRESS_IP6;
+ memcpy(u.ip6, a.to_v6().to_bytes().data(), 16);
+ }
+}
+
void
to_api(const boost::asio::ip::address& a, vapi_type_ip4_address& v)
{
@@ -54,6 +69,26 @@ from_api(const vapi_type_address& v)
return addr;
}
+ip_address_t
+from_api(const vapi_union_address_union& u, vapi_enum_address_family af)
+{
+ boost::asio::ip::address addr;
+
+ if (ADDRESS_IP6 == af) {
+ std::array<uint8_t, 16> a;
+ std::copy(u.ip6, u.ip6 + 16, std::begin(a));
+ boost::asio::ip::address_v6 v6(a);
+ addr = v6;
+ } else {
+ std::array<uint8_t, 4> a;
+ std::copy(u.ip6, u.ip6 + 4, std::begin(a));
+ boost::asio::ip::address_v4 v4(a);
+ addr = v4;
+ }
+
+ return addr;
+}
+
void
to_api(const mac_address_t& a, vapi_type_mac_address& v)
{
@@ -80,6 +115,25 @@ to_api(const route::prefix_t& p)
v.address_length = p.mask_width();
return v;
}
+
+route::mprefix_t
+from_api(const vapi_type_mprefix& v)
+{
+ return route::mprefix_t(from_api(v.src_address, v.af),
+ from_api(v.grp_address, v.af), v.grp_address_length);
+}
+
+vapi_type_mprefix
+to_api(const route::mprefix_t& p)
+{
+ vapi_enum_address_family af;
+ vapi_type_mprefix v;
+ to_api(p.grp_address(), v.grp_address, af);
+ to_api(p.src_address(), v.src_address, af);
+ v.grp_address_length = p.mask_width();
+ v.af = af;
+ return v;
+}
};
/*
diff --git a/extras/vom/vom/api_types.hpp b/extras/vom/vom/api_types.hpp
index 784ace2c293..5856c22d339 100644
--- a/extras/vom/vom/api_types.hpp
+++ b/extras/vom/vom/api_types.hpp
@@ -25,17 +25,24 @@ typedef boost::asio::ip::address ip_address_t;
void to_api(const ip_address_t& a, vapi_type_address& v);
void to_api(const boost::asio::ip::address& a, vapi_type_ip4_address& v);
+void to_api(const boost::asio::ip::address& a,
+ vapi_union_address_union& u,
+ vapi_enum_address_family& af);
ip_address_t from_api(const vapi_type_address& v);
ip_address_t from_api(const vapi_type_ip4_address& v);
+ip_address_t from_api(const vapi_union_address_union& u,
+ vapi_enum_address_family af);
void to_api(const mac_address_t& a, vapi_type_mac_address& m);
mac_address_t from_api(const vapi_type_mac_address& v);
route::prefix_t from_api(const vapi_type_prefix&);
+route::mprefix_t from_api(const vapi_type_mprefix&);
vapi_type_prefix to_api(const route::prefix_t&);
+vapi_type_mprefix to_api(const route::mprefix_t&);
};
/*
diff --git a/extras/vom/vom/mroute_cmds.cpp b/extras/vom/vom/mroute_cmds.cpp
new file mode 100644
index 00000000000..e4df00a6ddd
--- /dev/null
+++ b/extras/vom/vom/mroute_cmds.cpp
@@ -0,0 +1,193 @@
+/*
+ * 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.
+ */
+
+#include <sstream>
+
+#include "vom/api_types.hpp"
+#include "vom/mroute_cmds.hpp"
+#include "vom/route_api_types.hpp"
+
+namespace VOM {
+namespace route {
+namespace ip_mroute_cmds {
+
+update_cmd::update_cmd(HW::item<bool>& item,
+ table_id_t id,
+ const mprefix_t& mprefix,
+ const path& path,
+ const itf_flags_t& flags)
+ : rpc_cmd(item)
+ , m_id(id)
+ , m_mprefix(mprefix)
+ , m_path(path)
+ , m_flags(flags)
+{
+}
+
+bool
+update_cmd::operator==(const update_cmd& other) const
+{
+ return ((m_mprefix == other.m_mprefix) && (m_id == other.m_id));
+}
+
+rc_t
+update_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+
+ payload.table_id = m_id;
+ payload.is_add = 1;
+
+ m_mprefix.to_vpp(&payload.is_ipv6, payload.grp_address, payload.src_address,
+ &payload.grp_address_length);
+
+ to_vpp(m_path, payload);
+ payload.itf_flags = m_flags.value();
+
+ VAPI_CALL(req.execute());
+
+ return (wait());
+}
+
+std::string
+update_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "ip-mroute-create: " << m_hw_item.to_string() << " table-id:" << m_id
+ << " mprefix:" << m_mprefix.to_string() << " path:" << m_path.to_string()
+ << " flags:" << m_flags;
+
+ return (s.str());
+}
+
+delete_cmd::delete_cmd(HW::item<bool>& item,
+ table_id_t id,
+ const mprefix_t& mprefix,
+ const path& path,
+ const itf_flags_t& flags)
+ : rpc_cmd(item)
+ , m_id(id)
+ , m_mprefix(mprefix)
+ , m_path(path)
+ , m_flags(flags)
+{
+}
+
+bool
+delete_cmd::operator==(const delete_cmd& other) const
+{
+ return ((m_mprefix == other.m_mprefix) && (m_id == other.m_id));
+}
+
+rc_t
+delete_cmd::issue(connection& con)
+{
+ msg_t req(con.ctx(), std::ref(*this));
+
+ auto& payload = req.get_request().get_payload();
+ payload.table_id = m_id;
+ payload.is_add = 0;
+
+ m_mprefix.to_vpp(&payload.is_ipv6, payload.grp_address, payload.src_address,
+ &payload.grp_address_length);
+
+ to_vpp(m_path, payload);
+ payload.itf_flags = m_flags.value();
+
+ VAPI_CALL(req.execute());
+
+ wait();
+ m_hw_item.set(rc_t::NOOP);
+
+ return rc_t::OK;
+}
+
+std::string
+delete_cmd::to_string() const
+{
+ std::ostringstream s;
+ s << "ip-mroute-delete: " << m_hw_item.to_string() << " id:" << m_id
+ << " mprefix:" << m_mprefix.to_string();
+
+ return (s.str());
+}
+
+dump_v4_cmd::dump_v4_cmd()
+{
+}
+
+bool
+dump_v4_cmd::operator==(const dump_v4_cmd& other) const
+{
+ return (true);
+}
+
+rc_t
+dump_v4_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_v4_cmd::to_string() const
+{
+ return ("ip-mroute-v4-dump");
+}
+
+dump_v6_cmd::dump_v6_cmd()
+{
+}
+
+bool
+dump_v6_cmd::operator==(const dump_v6_cmd& other) const
+{
+ return (true);
+}
+
+rc_t
+dump_v6_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_v6_cmd::to_string() const
+{
+ return ("ip-mroute-v6-dump");
+}
+} // namespace ip_mroute_cmds
+} // namespace mroute
+} // namespace vom
+ /*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/mroute_cmds.hpp b/extras/vom/vom/mroute_cmds.hpp
new file mode 100644
index 00000000000..b8f18f6b45b
--- /dev/null
+++ b/extras/vom/vom/mroute_cmds.hpp
@@ -0,0 +1,181 @@
+/*
+ * 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_MROUTE_CMDS_H__
+#define __VOM_MROUTE_CMDS_H__
+
+#include "vom/dump_cmd.hpp"
+#include "vom/route.hpp"
+#include "vom/rpc_cmd.hpp"
+
+#include <vapi/ip.api.vapi.hpp>
+
+namespace VOM {
+namespace route {
+namespace ip_mroute_cmds {
+
+/**
+ * A command class that creates or updates the route
+ */
+class update_cmd : public rpc_cmd<HW::item<bool>, vapi::Ip_mroute_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ update_cmd(HW::item<bool>& item,
+ table_id_t id,
+ const mprefix_t& mprefix,
+ const path& path,
+ const itf_flags_t& flags);
+
+ /**
+ * 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 update_cmd& i) const;
+
+private:
+ route::table_id_t m_id;
+ mprefix_t m_mprefix;
+ const path m_path;
+ const itf_flags_t& m_flags;
+};
+
+/**
+ * A cmd class that deletes a route
+ */
+class delete_cmd : public rpc_cmd<HW::item<bool>, vapi::Ip_mroute_add_del>
+{
+public:
+ /**
+ * Constructor
+ */
+ delete_cmd(HW::item<bool>& item,
+ table_id_t id,
+ const mprefix_t& mprefix,
+ const path& path,
+ const itf_flags_t& flags);
+
+ /**
+ * 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 delete_cmd& i) const;
+
+private:
+ route::table_id_t m_id;
+ mprefix_t m_mprefix;
+ const path m_path;
+ const itf_flags_t& m_flags;
+};
+
+/**
+ * A cmd class that Dumps ipv4 fib
+ */
+class dump_v4_cmd : public VOM::dump_cmd<vapi::Ip_mfib_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_v4_cmd();
+ dump_v4_cmd(const dump_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_v4_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+
+/**
+ * A cmd class that Dumps ipv6 fib
+ */
+class dump_v6_cmd : public VOM::dump_cmd<vapi::Ip6_mfib_dump>
+{
+public:
+ /**
+ * Constructor
+ */
+ dump_v6_cmd();
+ dump_v6_cmd(const dump_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_v6_cmd& i) const;
+
+private:
+ /**
+ * HW reutrn code
+ */
+ HW::item<bool> item;
+};
+
+}; // namespace ip_mroute_cmds
+}; // namespace route
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
+
+#endif
diff --git a/extras/vom/vom/prefix.cpp b/extras/vom/vom/prefix.cpp
index abd589eef9f..fdad67998d1 100644
--- a/extras/vom/vom/prefix.cpp
+++ b/extras/vom/vom/prefix.cpp
@@ -190,7 +190,7 @@ route::prefix_t::to_string() const
}
boost::asio::ip::address
-from_bytes(uint8_t is_ip6, uint8_t* bytes)
+from_bytes(uint8_t is_ip6, const uint8_t* bytes)
{
boost::asio::ip::address addr;
@@ -420,6 +420,135 @@ route::prefix_t::high() const
return (pfx);
}
+/**
+ * The all Zeros prefix
+ */
+const route::mprefix_t route::mprefix_t::ZERO;
+const route::mprefix_t route::mprefix_t::ZEROv6;
+
+route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr, uint8_t len)
+ : m_gaddr(gaddr)
+ , m_saddr()
+ , m_len(len)
+{
+}
+
+route::mprefix_t::mprefix_t(const boost::asio::ip::address& gaddr)
+ : m_gaddr(gaddr)
+ , m_saddr()
+ , m_len(VOM::mask_width(gaddr))
+{
+}
+
+route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
+ const boost::asio::ip::address& gaddr)
+ : m_gaddr(gaddr)
+ , m_saddr(saddr)
+ , m_len(2 * VOM::mask_width(gaddr))
+{
+}
+
+route::mprefix_t::mprefix_t(const boost::asio::ip::address& saddr,
+ const boost::asio::ip::address& gaddr,
+ uint16_t len)
+ : m_gaddr(gaddr)
+ , m_saddr(saddr)
+ , m_len(len)
+{
+}
+
+route::mprefix_t::mprefix_t(const mprefix_t& o)
+ : m_gaddr(o.m_gaddr)
+ , m_saddr(o.m_saddr)
+ , m_len(o.m_len)
+{
+}
+route::mprefix_t::mprefix_t()
+ : m_gaddr()
+ , m_saddr()
+ , m_len(0)
+{
+}
+
+route::mprefix_t::~mprefix_t()
+{
+}
+
+const boost::asio::ip::address&
+route::mprefix_t::grp_address() const
+{
+ return (m_gaddr);
+}
+
+const boost::asio::ip::address&
+route::mprefix_t::src_address() const
+{
+ return (m_saddr);
+}
+
+uint8_t
+route::mprefix_t::mask_width() const
+{
+ return (m_len);
+}
+
+void
+route::mprefix_t::to_vpp(uint8_t* is_ip6,
+ uint8_t* saddr,
+ uint8_t* gaddr,
+ uint16_t* len) const
+{
+ *len = m_len;
+ to_bytes(m_saddr, is_ip6, saddr);
+ to_bytes(m_gaddr, is_ip6, gaddr);
+}
+
+route::mprefix_t&
+route::mprefix_t::operator=(const route::mprefix_t& o)
+{
+ m_gaddr = o.m_gaddr;
+ m_saddr = o.m_saddr;
+ m_len = o.m_len;
+
+ return (*this);
+}
+
+bool
+route::mprefix_t::operator<(const route::mprefix_t& o) const
+{
+ if (m_len == o.m_len) {
+ if (m_saddr == o.m_saddr)
+ return (m_gaddr < o.m_gaddr);
+ else
+ return (m_saddr < o.m_saddr);
+ } else {
+ return (m_len < o.m_len);
+ }
+}
+
+bool
+route::mprefix_t::operator==(const route::mprefix_t& o) const
+{
+ return (m_len == o.m_len && m_gaddr == o.m_gaddr && m_saddr == o.m_saddr);
+}
+
+bool
+route::mprefix_t::operator!=(const route::mprefix_t& o) const
+{
+ return (!(*this == o));
+}
+
+std::string
+route::mprefix_t::to_string() const
+{
+ std::ostringstream s;
+
+ s << "(" << m_saddr.to_string() << "," << m_gaddr.to_string() << "/"
+ << std::to_string(m_len) << ")";
+
+ return (s.str());
+}
+
}; // namespace VOM
/*
diff --git a/extras/vom/vom/prefix.hpp b/extras/vom/vom/prefix.hpp
index 836554123f5..1b6a06874d3 100644
--- a/extras/vom/vom/prefix.hpp
+++ b/extras/vom/vom/prefix.hpp
@@ -171,8 +171,8 @@ public:
const static prefix_t ZEROv6;
/**
- * Convert the prefix into VPP API parameters
- */
+ * Convert the prefix into VPP API parameters
+ */
void to_vpp(uint8_t* is_ip6, uint8_t* addr, uint8_t* len) const;
/**
@@ -206,8 +206,120 @@ private:
*/
uint8_t m_len;
};
+
+/**
+* A prefix defintion. Address + length
+*/
+class mprefix_t
+{
+public:
+ /**
+ * Default Constructor - creates ::/0
+ */
+ mprefix_t();
+ /**
+ * Constructor for (S,G)
+ */
+ mprefix_t(const boost::asio::ip::address& saddr,
+ const boost::asio::ip::address& gaddr);
+ /*
+ * Constructor for (*,G)
+ */
+ mprefix_t(const boost::asio::ip::address& gaddr);
+
+ /*
+ * Constructor for (*,G/n)
+ */
+ mprefix_t(const boost::asio::ip::address& gaddr, uint8_t len);
+
+ /**
+*Constructor for (S,G)
+*/
+ mprefix_t(const boost::asio::ip::address& saddr,
+ const boost::asio::ip::address& gaddr,
+ uint16_t len);
+
+ /**
+ * Copy Constructor
+ */
+ mprefix_t(const mprefix_t&);
+
+ /**
+ * Destructor
+ */
+ ~mprefix_t();
+
+ /**
+ * Get the address
+ */
+ const boost::asio::ip::address& grp_address() const;
+ const boost::asio::ip::address& src_address() const;
+
+ /**
+ * Get the network mask width
+ */
+ uint8_t mask_width() const;
+
+ /**
+ * Assignement
+ */
+ mprefix_t& operator=(const mprefix_t&);
+
+ /**
+ * Less than operator
+ */
+ bool operator<(const mprefix_t& o) const;
+
+ /**
+ * equals operator
+ */
+ bool operator==(const mprefix_t& o) const;
+
+ /**
+ * not equal opartor
+ */
+ bool operator!=(const mprefix_t& o) const;
+
+ /**
+ * convert to string format for debug purposes
+ */
+ std::string to_string() const;
+
+ /**
+ * The all Zeros prefix
+ */
+ const static mprefix_t ZERO;
+
+ /**
+ * The all Zeros v6 prefix
+ */
+ const static mprefix_t ZEROv6;
+
+ /**
+ * Get the L3 protocol
+ */
+ l3_proto_t l3_proto() const;
+
+ void to_vpp(uint8_t* is_ip6,
+ uint8_t* saddr,
+ uint8_t* gaddr,
+ uint16_t* len) const;
+
+private:
+ /**
+ * The address
+ */
+ boost::asio::ip::address m_gaddr;
+ boost::asio::ip::address m_saddr;
+
+ /**
+ * The prefix length
+ */
+ uint8_t m_len;
};
+}; // namespace route
+
boost::asio::ip::address_v4 operator|(const boost::asio::ip::address_v4& addr1,
const boost::asio::ip::address_v4& addr2);
@@ -254,7 +366,7 @@ uint32_t mask_width(const boost::asio::ip::address& addr);
/**
* Convert a VPP byte stinrg into a boost addresss
*/
-boost::asio::ip::address from_bytes(uint8_t is_ip6, uint8_t* array);
+boost::asio::ip::address from_bytes(uint8_t is_ip6, const uint8_t* array);
};
/*
diff --git a/extras/vom/vom/route.cpp b/extras/vom/vom/route.cpp
index ec56c44a0d7..c713de9ee99 100644
--- a/extras/vom/vom/route.cpp
+++ b/extras/vom/vom/route.cpp
@@ -14,19 +14,24 @@
*/
#include "vom/route.hpp"
+#include "vom/api_types.hpp"
+#include "vom/mroute_cmds.hpp"
+#include "vom/route_api_types.hpp"
#include "vom/route_cmds.hpp"
#include "vom/singular_db_funcs.hpp"
namespace VOM {
namespace route {
ip_route::event_handler ip_route::m_evh;
+ip_mroute::event_handler ip_mroute::m_evh;
singular_db<ip_route::key_t, ip_route> ip_route::m_db;
+singular_db<ip_mroute::key_t, ip_mroute> ip_mroute::m_db;
const path::special_t path::special_t::STANDARD(0, "standard");
-const path::special_t path::special_t::LOCAL(0, "local");
-const path::special_t path::special_t::DROP(0, "standard");
-const path::special_t path::special_t::UNREACH(0, "unreachable");
-const path::special_t path::special_t::PROHIBIT(0, "prohibit");
+const path::special_t path::special_t::LOCAL(1, "local");
+const path::special_t path::special_t::DROP(2, "standard");
+const path::special_t path::special_t::UNREACH(3, "unreachable");
+const path::special_t path::special_t::PROHIBIT(4, "prohibit");
path::special_t::special_t(int v, const std::string& s)
: enum_base<path::special_t>(v, s)
@@ -41,6 +46,23 @@ path::flags_t::flags_t(int v, const std::string& s)
{
}
+const itf_flags_t itf_flags_t::NONE(0, "none");
+const itf_flags_t itf_flags_t::ACCEPT((1 << 2), "accept");
+const itf_flags_t itf_flags_t::FORWARD((1 << 3), "forward");
+
+itf_flags_t::itf_flags_t(int v, const std::string& s)
+ : enum_base<itf_flags_t>(v, s)
+{
+}
+const itf_flags_t&
+itf_flags_t::from_vpp(uint32_t val)
+{
+ if (itf_flags_t::ACCEPT == (int)val)
+ return itf_flags_t::ACCEPT;
+ else
+ return itf_flags_t::FORWARD;
+}
+
path::path(special_t special)
: m_type(special)
, m_nh_proto(nh_proto_t::IPV4)
@@ -124,16 +146,24 @@ path::operator<(const path& p) const
return false;
if (!m_rd && p.m_rd)
return true;
- if (m_rd->table_id() < p.m_rd->table_id())
- return true;
+ if (m_rd && p.m_rd) {
+ if (m_rd->table_id() < p.m_rd->table_id())
+ return true;
+ else if (m_rd->table_id() > p.m_rd->table_id())
+ return false;
+ }
if (m_nh < p.m_nh)
return true;
if (m_interface && !p.m_interface)
return false;
if (!m_interface && p.m_interface)
return true;
- if (m_interface->handle() < p.m_interface->handle())
- return true;
+ if (m_interface && p.m_interface) {
+ if (m_interface->handle() < p.m_interface->handle())
+ return true;
+ if (p.m_interface->handle() < m_interface->handle())
+ return false;
+ }
return (false);
}
@@ -410,36 +440,7 @@ ip_route::event_handler::handle_populate(const client_db::key_t& key)
ip_route ip_r(rd_temp, pfx);
for (unsigned int i = 0; i < payload.count; i++) {
- vapi_type_fib_path p = payload.path[i];
- if (p.is_local) {
- path path_v4(path::special_t::LOCAL);
- ip_r.add(path_v4);
- } else if (p.is_drop) {
- path path_v4(path::special_t::DROP);
- ip_r.add(path_v4);
- } else if (p.is_unreach) {
- path path_v4(path::special_t::UNREACH);
- ip_r.add(path_v4);
- } else if (p.is_prohibit) {
- path path_v4(path::special_t::PROHIBIT);
- ip_r.add(path_v4);
- } else {
- boost::asio::ip::address address = from_bytes(0, p.next_hop);
- std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
- if (itf) {
- if (p.is_dvr) {
- path path_v4(*itf, nh_proto_t::IPV4, route::path::flags_t::DVR,
- p.weight, p.preference);
- ip_r.add(path_v4);
- } else {
- path path_v4(address, *itf, p.weight, p.preference);
- ip_r.add(path_v4);
- }
- } else {
- path path_v4(rd_temp, address, p.weight, p.preference);
- ip_r.add(path_v4);
- }
- }
+ ip_r.add(from_vpp(payload.path[i], nh_proto_t::IPV4));
}
VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
@@ -463,36 +464,7 @@ ip_route::event_handler::handle_populate(const client_db::key_t& key)
ip_route ip_r(rd_temp, pfx);
for (unsigned int i = 0; i < payload.count; i++) {
- vapi_type_fib_path p = payload.path[i];
- if (p.is_local) {
- path path_v6(path::special_t::LOCAL);
- ip_r.add(path_v6);
- } else if (p.is_drop) {
- path path_v6(path::special_t::DROP);
- ip_r.add(path_v6);
- } else if (p.is_unreach) {
- path path_v6(path::special_t::UNREACH);
- ip_r.add(path_v6);
- } else if (p.is_prohibit) {
- path path_v6(path::special_t::PROHIBIT);
- ip_r.add(path_v6);
- } else {
- std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
- boost::asio::ip::address address = from_bytes(1, p.next_hop);
- if (itf) {
- if (p.is_dvr) {
- path path_v6(*itf, nh_proto_t::IPV6, route::path::flags_t::DVR,
- p.weight, p.preference);
- ip_r.add(path_v6);
- } else {
- path path_v6(address, *itf, p.weight, p.preference);
- ip_r.add(path_v6);
- }
- } else {
- path path_v6(rd_temp, address, p.weight, p.preference);
- ip_r.add(path_v6);
- }
- }
+ ip_r.add(from_vpp(payload.path[i], nh_proto_t::IPV6));
}
VOM_LOG(log_level_t::DEBUG) << "ip-route-dump: " << ip_r.to_string();
@@ -517,6 +489,219 @@ ip_route::event_handler::show(std::ostream& os)
db_dump(m_db, os);
}
+ip_mroute::ip_mroute(const mprefix_t& mprefix)
+ : m_hw(false)
+ , m_rd(route_domain::get_default())
+ , m_mprefix(mprefix)
+ , m_paths()
+{
+}
+
+ip_mroute::ip_mroute(const ip_mroute& r)
+ : m_hw(r.m_hw)
+ , m_rd(r.m_rd)
+ , m_mprefix(r.m_mprefix)
+ , m_paths(r.m_paths)
+{
+}
+
+ip_mroute::ip_mroute(const route_domain& rd, const mprefix_t& mprefix)
+ : m_hw(false)
+ , m_rd(rd.singular())
+ , m_mprefix(mprefix)
+ , m_paths()
+{
+}
+
+void
+ip_mroute::add(const path& path, const itf_flags_t& flag)
+{
+ m_paths.insert(std::make_pair(path, flag));
+}
+
+ip_mroute::~ip_mroute()
+{
+ sweep();
+ m_db.release(key(), this);
+}
+
+const ip_mroute::key_t
+ip_mroute::key() const
+{
+ return (std::make_pair(m_rd->table_id(), m_mprefix));
+}
+
+bool
+ip_mroute::operator==(const ip_mroute& i) const
+{
+ return ((key() == i.key()) && (m_paths == i.m_paths));
+}
+
+void
+ip_mroute::sweep()
+{
+ if (m_hw) {
+ for (auto& p : m_paths)
+ HW::enqueue(new ip_mroute_cmds::delete_cmd(m_hw, m_rd->table_id(),
+ m_mprefix, p.first, p.second));
+ }
+ HW::write();
+}
+
+void
+ip_mroute::replay()
+{
+ if (m_hw) {
+ for (auto& p : m_paths)
+ HW::enqueue(new ip_mroute_cmds::update_cmd(m_hw, m_rd->table_id(),
+ m_mprefix, p.first, p.second));
+ }
+}
+std::string
+ip_mroute::to_string() const
+{
+ std::ostringstream s;
+ s << "route:[" << m_rd->to_string() << ", " << m_mprefix.to_string() << " ["
+ << m_paths << "]"
+ << "]";
+
+ return (s.str());
+}
+
+void
+ip_mroute::update(const ip_mroute& r)
+{
+ if (rc_t::OK != m_hw.rc()) {
+ for (auto& p : m_paths)
+ HW::enqueue(new ip_mroute_cmds::update_cmd(m_hw, m_rd->table_id(),
+ m_mprefix, p.first, p.second));
+ }
+}
+
+std::shared_ptr<ip_mroute>
+ip_mroute::find_or_add(const ip_mroute& temp)
+{
+ return (m_db.find_or_add(temp.key(), temp));
+}
+
+std::shared_ptr<ip_mroute>
+ip_mroute::find(const key_t& k)
+{
+ return (m_db.find(k));
+}
+
+std::shared_ptr<ip_mroute>
+ip_mroute::singular() const
+{
+ return find_or_add(*this);
+}
+
+void
+ip_mroute::dump(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
+ip_mroute::event_handler::event_handler()
+{
+ OM::register_listener(this);
+ inspect::register_handler({ "ip-route" }, "ip route configurations", this);
+}
+
+void
+ip_mroute::event_handler::handle_replay()
+{
+ m_db.replay();
+}
+
+void
+ip_mroute::event_handler::handle_populate(const client_db::key_t& key)
+{
+ std::shared_ptr<ip_mroute_cmds::dump_v4_cmd> cmd_v4 =
+ std::make_shared<ip_mroute_cmds::dump_v4_cmd>();
+ std::shared_ptr<ip_mroute_cmds::dump_v6_cmd> cmd_v6 =
+ std::make_shared<ip_mroute_cmds::dump_v6_cmd>();
+
+ HW::enqueue(cmd_v4);
+ HW::enqueue(cmd_v6);
+ HW::write();
+
+ VOM_LOG(log_level_t::INFO) << "ip-mroute-dump: ";
+
+ for (auto& record : *cmd_v4) {
+ auto& payload = record.get_payload();
+
+ ip_address_t gaddr = from_bytes(0, payload.grp_address);
+ ip_address_t saddr = from_bytes(0, payload.src_address);
+ mprefix_t pfx(saddr, gaddr, payload.address_length);
+
+ /**
+ * populating the route domain here
+ */
+ route_domain rd_temp(payload.table_id);
+ std::shared_ptr<route_domain> rd = route_domain::find(payload.table_id);
+ if (!rd) {
+ OM::commit(key, rd_temp);
+ }
+ ip_mroute ip_r(rd_temp, pfx);
+
+ for (unsigned int i = 0; i < payload.count; i++) {
+ vapi_type_mfib_path& p = payload.path[i];
+ ip_r.add(from_vpp(p.path, nh_proto_t::IPV4),
+ itf_flags_t::from_vpp(p.itf_flags));
+ }
+ VOM_LOG(log_level_t::INFO) << "ip-mroute-dump: " << ip_r.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, ip_r);
+ }
+
+ for (auto& record : *cmd_v6) {
+ auto& payload = record.get_payload();
+
+ ip_address_t gaddr = from_bytes(1, payload.grp_address);
+ ip_address_t saddr = from_bytes(1, payload.src_address);
+ mprefix_t pfx(saddr, gaddr, payload.address_length);
+
+ route_domain rd_temp(payload.table_id);
+ std::shared_ptr<route_domain> rd = route_domain::find(payload.table_id);
+ if (!rd) {
+ OM::commit(key, rd_temp);
+ }
+ ip_mroute ip_r(rd_temp, pfx);
+
+ for (unsigned int i = 0; i < payload.count; i++) {
+ vapi_type_mfib_path& p = payload.path[i];
+ ip_r.add(from_vpp(p.path, nh_proto_t::IPV6),
+ itf_flags_t::from_vpp(p.itf_flags));
+ }
+ VOM_LOG(log_level_t::INFO) << "ip-mroute-dump: " << ip_r.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, ip_r);
+ }
+}
+
+dependency_t
+ip_mroute::event_handler::order() const
+{
+ return (dependency_t::TABLE);
+}
+
+void
+ip_mroute::event_handler::show(std::ostream& os)
+{
+ db_dump(m_db, os);
+}
+
std::ostream&
operator<<(std::ostream& os, const ip_route::key_t& key)
{
@@ -526,6 +711,14 @@ operator<<(std::ostream& os, const ip_route::key_t& key)
}
std::ostream&
+operator<<(std::ostream& os, const ip_mroute::key_t& key)
+{
+ os << "[" << key.first << ", " << key.second.to_string() << "]";
+
+ return (os);
+}
+
+std::ostream&
operator<<(std::ostream& os, const path_list_t& key)
{
os << "[";
@@ -536,8 +729,22 @@ operator<<(std::ostream& os, const path_list_t& key)
return (os);
}
+
+std::ostream&
+operator<<(std::ostream& os, const mpath_list_t& key)
+{
+ os << "[";
+ for (auto k : key) {
+ os << "[" << k.first.to_string() << ", " << k.second.to_string() << "]";
+ }
+ os << "]";
+
+ return (os);
}
-}
+
+}; // namespace route
+}; // namespace VOM
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/extras/vom/vom/route.hpp b/extras/vom/vom/route.hpp
index 65797b7c2f9..a09f704f60c 100644
--- a/extras/vom/vom/route.hpp
+++ b/extras/vom/vom/route.hpp
@@ -204,15 +204,44 @@ private:
uint8_t m_preference;
};
+class itf_flags_t : public enum_base<itf_flags_t>
+{
+public:
+ const static itf_flags_t NONE;
+ /**
+ * Path is accepting multicast traffic
+ */
+ const static itf_flags_t ACCEPT;
+
+ /**
+ * A local/for-us/recieve
+ */
+ const static itf_flags_t FORWARD;
+
+ static const itf_flags_t& from_vpp(uint32_t val);
+
+private:
+ /**
+ * Private constructor taking the value and the string name
+ */
+ itf_flags_t(int v, const std::string& s);
+};
+
/**
* A path-list is a set of paths
*/
typedef std::set<path> path_list_t;
/**
+ * A mpath-list is a set of paths and interface flags
+ */
+typedef std::set<std::pair<path, itf_flags_t>> mpath_list_t;
+
+/**
* ostream output for iterator
*/
std::ostream& operator<<(std::ostream& os, const path_list_t& path_list);
+std::ostream& operator<<(std::ostream& os, const mpath_list_t& path_list);
/**
* A IP route
@@ -392,10 +421,171 @@ private:
static singular_db<key_t, ip_route> m_db;
};
-std::ostream& operator<<(std::ostream& os, const ip_route::key_t& key);
-};
+/**
+ * A IP multicast route
+ */
+class ip_mroute : public object_base
+{
+public:
+ /**
+ * The key for a route
+ */
+ typedef std::pair<route::table_id_t, mprefix_t> key_t;
+
+ /**
+ * Construct a route in the default table
+ */
+ ip_mroute(const mprefix_t& mprefix);
+
+ /**
+ * Copy Construct
+ */
+ ip_mroute(const ip_mroute& r);
+
+ /**
+ * Construct a route in the given route domain
+ */
+ ip_mroute(const route_domain& rd, const mprefix_t& mprefix);
+
+ /**
+ * Destructor
+ */
+ ~ip_mroute();
+
+ /**
+ * Get the route's key
+ */
+ const key_t key() const;
+
+ /**
+ * Comparison operator
+ */
+ bool operator==(const ip_mroute& i) const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ std::shared_ptr<ip_mroute> singular() const;
+
+ /**
+ * Find the instnace of the route domain in the OM
+ */
+ static std::shared_ptr<ip_mroute> find(const ip_mroute& temp);
+
+ /**
+ * Dump all route-doamin into the stream provided
+ */
+ static void dump(std::ostream& os);
+
+ /**
+ * replay the object to create it in hardware
+ */
+ void replay(void);
+
+ /**
+ * Convert to string for debugging
+ */
+ std::string to_string() const;
+
+ /**
+ * Return the matching 'singular instance'
+ */
+ static std::shared_ptr<ip_mroute> find(const key_t& k);
+
+ void add(const path& path, const itf_flags_t& flag);
+
+private:
+ /**
+ * Class definition for listeners to OM events
+ */
+ class event_handler : public OM::listener, public inspect::command_handler
+ {
+ public:
+ event_handler();
+ virtual ~event_handler() = default;
+
+ /**
+ * Handle a populate event
+ */
+ void handle_populate(const client_db::key_t& key);
+
+ /**
+ * Handle a replay event
+ */
+ void handle_replay();
+
+ /**
+ * Show the object in the Singular DB
+ */
+ void show(std::ostream& os);
+
+ /**
+ * Get the sortable Id of the listener
+ */
+ dependency_t order() const;
+ };
+
+ /**
+ * event_handler to register with OM
+ */
+ static event_handler m_evh;
+
+ /**
+ * Find or add the instnace of the route domain in the OM
+ */
+ static std::shared_ptr<ip_mroute> find_or_add(const ip_mroute& temp);
+
+ /*
+ * It's the OM class that updates the objects in HW
+ */
+ friend class VOM::OM;
+
+ /**
+ * It's the singular_db class that calls replay()
+ */
+ friend class singular_db<key_t, ip_mroute>;
+
+ /**
+ * Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
+ */
+ void update(const ip_mroute& obj);
+
+ /**
+ * Sweep/reap the object if still stale
+ */
+ void sweep(void);
+
+ /**
+ * HW configuration for the result of creating the route
+ */
+ HW::item<bool> m_hw;
+
+ /**
+ * The route domain the route is in.
+ */
+ std::shared_ptr<route_domain> m_rd;
+
+ /**
+ * The mprefix to match
+ */
+ mprefix_t m_mprefix;
+
+ /**
+ * The set of paths
+ */
+ mpath_list_t m_paths;
+
+ /**
+ * A map of all routes
+ */
+ static singular_db<key_t, ip_mroute> m_db;
};
+std::ostream& operator<<(std::ostream& os, const ip_route::key_t& key);
+std::ostream& operator<<(std::ostream& os, const ip_mroute::key_t& key);
+}; // namespace route
+}; // namesapce VPP
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/extras/vom/vom/route_api_types.cpp b/extras/vom/vom/route_api_types.cpp
new file mode 100644
index 00000000000..85fca05b35a
--- /dev/null
+++ b/extras/vom/vom/route_api_types.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#include <vom/route.hpp>
+#include <vom/route_api_types.hpp>
+
+namespace VOM {
+
+void
+to_vpp(const route::path& p, vapi_payload_ip_add_del_route& payload)
+{
+ payload.is_drop = 0;
+ payload.is_unreach = 0;
+ payload.is_prohibit = 0;
+ payload.is_local = 0;
+ payload.is_classify = 0;
+ payload.is_multipath = 0;
+ payload.is_resolve_host = 0;
+ payload.is_resolve_attached = 0;
+
+ if (route::path::flags_t::DVR & p.flags()) {
+ payload.is_dvr = 1;
+ }
+
+ if (route::path::special_t::STANDARD == p.type()) {
+ uint8_t path_v6;
+ to_bytes(p.nh(), &path_v6, payload.next_hop_address);
+
+ if (p.rd()) {
+ payload.next_hop_table_id = p.rd()->table_id();
+ }
+ if (p.itf()) {
+ payload.next_hop_sw_if_index = p.itf()->handle().value();
+ }
+ } else if (route::path::special_t::DROP == p.type()) {
+ payload.is_drop = 1;
+ } else if (route::path::special_t::UNREACH == p.type()) {
+ payload.is_unreach = 1;
+ } else if (route::path::special_t::PROHIBIT == p.type()) {
+ payload.is_prohibit = 1;
+ } else if (route::path::special_t::LOCAL == p.type()) {
+ payload.is_local = 1;
+ }
+ payload.next_hop_weight = p.weight();
+ payload.next_hop_preference = p.preference();
+ payload.next_hop_via_label = 0;
+ payload.classify_table_index = 0;
+}
+
+void
+to_vpp(const route::path& p, vapi_payload_ip_mroute_add_del& payload)
+{
+ if (route::path::special_t::STANDARD == p.type()) {
+ uint8_t path_v6;
+ to_bytes(p.nh(), &path_v6, payload.nh_address);
+
+ if (p.itf()) {
+ payload.next_hop_sw_if_index = p.itf()->handle().value();
+ }
+
+ payload.next_hop_afi = p.nh_proto();
+ }
+}
+
+route::path
+from_vpp(const vapi_type_fib_path& p, const nh_proto_t& nhp)
+{
+ if (p.is_local) {
+ return route::path(route::path::special_t::LOCAL);
+ } else if (p.is_drop) {
+ return route::path(route::path::special_t::DROP);
+ } else if (p.is_unreach) {
+ return route::path(route::path::special_t::UNREACH);
+ } else if (p.is_prohibit) {
+ return route::path(route::path::special_t::PROHIBIT);
+ } else {
+ boost::asio::ip::address address =
+ from_bytes(nh_proto_t::IPV6 == nhp, p.next_hop);
+ std::shared_ptr<interface> itf = interface::find(p.sw_if_index);
+ if (itf) {
+ if (p.is_dvr) {
+ return route::path(*itf, nhp, route::path::flags_t::DVR, p.weight,
+ p.preference);
+ } else {
+ return route::path(address, *itf, p.weight, p.preference);
+ }
+ } else {
+ std::shared_ptr<route_domain> rd = route_domain::find(p.table_id);
+ if (rd) {
+ return route::path(*rd, address, p.weight, p.preference);
+ }
+ }
+ }
+
+ VOM_LOG(log_level_t::ERROR) << "cannot decode: ";
+
+ return route::path(route::path::special_t::DROP);
+}
+};
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/route_api_types.hpp b/extras/vom/vom/route_api_types.hpp
new file mode 100644
index 00000000000..09015485cdb
--- /dev/null
+++ b/extras/vom/vom/route_api_types.hpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#include <vom/route.hpp>
+
+#include <vapi/ip.api.vapi.hpp>
+
+namespace VOM {
+
+void to_vpp(const route::path& p, vapi_payload_ip_mroute_add_del& payload);
+void to_vpp(const route::path& p, vapi_payload_ip_add_del_route& payload);
+
+route::path from_vpp(const vapi_type_fib_path& p, const nh_proto_t& nh);
+
+}; // namespace VOM
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "mozilla")
+ * End:
+ */
diff --git a/extras/vom/vom/route_cmds.cpp b/extras/vom/vom/route_cmds.cpp
index 240592f909f..26d6593df78 100644
--- a/extras/vom/vom/route_cmds.cpp
+++ b/extras/vom/vom/route_cmds.cpp
@@ -15,53 +15,13 @@
#include <sstream>
-#include "vom/route_cmds.hpp"
+#include <vom/route_api_types.hpp>
+#include <vom/route_cmds.hpp>
namespace VOM {
namespace route {
namespace ip_route_cmds {
-static void
-to_vpp(const route::path& p, vapi_payload_ip_add_del_route& payload)
-{
- payload.is_drop = 0;
- payload.is_unreach = 0;
- payload.is_prohibit = 0;
- payload.is_local = 0;
- payload.is_classify = 0;
- payload.is_multipath = 0;
- payload.is_resolve_host = 0;
- payload.is_resolve_attached = 0;
-
- if (route::path::flags_t::DVR & p.flags()) {
- payload.is_dvr = 1;
- }
-
- if (route::path::special_t::STANDARD == p.type()) {
- uint8_t path_v6;
- to_bytes(p.nh(), &path_v6, payload.next_hop_address);
-
- if (p.rd()) {
- payload.next_hop_table_id = p.rd()->table_id();
- }
- if (p.itf()) {
- payload.next_hop_sw_if_index = p.itf()->handle().value();
- }
- } else if (route::path::special_t::DROP == p.type()) {
- payload.is_drop = 1;
- } else if (route::path::special_t::UNREACH == p.type()) {
- payload.is_unreach = 1;
- } else if (route::path::special_t::PROHIBIT == p.type()) {
- payload.is_prohibit = 1;
- } else if (route::path::special_t::LOCAL == p.type()) {
- payload.is_local = 1;
- }
- payload.next_hop_weight = p.weight();
- payload.next_hop_preference = p.preference();
- payload.next_hop_via_label = 0;
- payload.classify_table_index = 0;
-}
-
update_cmd::update_cmd(HW::item<bool>& item,
table_id_t id,
const prefix_t& prefix,
diff --git a/src/vnet/fib/fib_types.h b/src/vnet/fib/fib_types.h
index 714a1d9e9a8..472ce888b4e 100644
--- a/src/vnet/fib/fib_types.h
+++ b/src/vnet/fib/fib_types.h
@@ -528,6 +528,10 @@ typedef struct fib_route_path_t_ {
* Exclusive DPO
*/
dpo_id_t dpo;
+ /**
+ * MFIB interface flags
+ */
+ u32 frp_mitf_flags;
};
/**
* A path that resolves via a BIER Table.
diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api
index 4b418bea71f..025fd577cf5 100644
--- a/src/vnet/ip/ip.api
+++ b/src/vnet/ip/ip.api
@@ -502,6 +502,12 @@ define ip_mfib_dump
@param count - the number of fib_path in path
@param path - array of of fib_path structures
*/
+typedef mfib_path
+{
+ vl_api_fib_path_t path;
+ u32 itf_flags;
+};
+
manual_endian manual_print define ip_mfib_details
{
u32 context;
@@ -513,7 +519,7 @@ manual_endian manual_print define ip_mfib_details
u8 src_address[4];
u32 count;
u32 stats_index;
- vl_api_fib_path_t path[count];
+ vl_api_mfib_path_t path[count];
};
/** \brief Dump IP6 multicast fib table
@@ -541,7 +547,7 @@ manual_endian manual_print define ip6_mfib_details
u8 grp_address[16];
u8 src_address[16];
u32 count;
- vl_api_fib_path_t path[count];
+ vl_api_mfib_path_t path[count];
};
define ip_address_details
diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c
index d59aa23d7e5..f58ca079b04 100644
--- a/src/vnet/ip/ip_api.c
+++ b/src/vnet/ip/ip_api.c
@@ -410,7 +410,7 @@ send_ip_mfib_details (vl_api_registration_t * reg,
vl_api_ip_mfib_details_t *mp;
const mfib_prefix_t *pfx;
mfib_entry_t *mfib_entry;
- vl_api_fib_path_t *fp;
+ vl_api_mfib_path_t *fp;
int path_count;
mfib_entry = mfib_entry_get (mfei);
@@ -438,7 +438,8 @@ send_ip_mfib_details (vl_api_registration_t * reg,
fp = mp->path;
vec_foreach (api_rpath, api_rpaths)
{
- fib_api_path_encode (api_rpath, fp);
+ fib_api_path_encode (api_rpath, &fp->path);
+ fp->itf_flags = ntohl (api_rpath->rpath.frp_mitf_flags);
fp++;
}
vec_free (api_rpaths);
@@ -508,7 +509,7 @@ send_ip6_mfib_details (vpe_api_main_t * am,
{
vl_api_ip6_mfib_details_t *mp;
fib_route_path_encode_t *api_rpath;
- vl_api_fib_path_t *fp;
+ vl_api_mfib_path_t *fp;
int path_count;
path_count = vec_len (api_rpaths);
@@ -530,7 +531,8 @@ send_ip6_mfib_details (vpe_api_main_t * am,
fp = mp->path;
vec_foreach (api_rpath, api_rpaths)
{
- fib_api_path_encode (api_rpath, fp);
+ fib_api_path_encode (api_rpath, &fp->path);
+ fp->itf_flags = ntohl (api_rpath->rpath.frp_mitf_flags);
fp++;
}
diff --git a/src/vnet/mfib/mfib_entry.c b/src/vnet/mfib/mfib_entry.c
index 79d2f9a50a3..18562219ce2 100644
--- a/src/vnet/mfib/mfib_entry.c
+++ b/src/vnet/mfib/mfib_entry.c
@@ -1325,6 +1325,7 @@ void
mfib_entry_encode (fib_node_index_t mfib_entry_index,
fib_route_path_encode_t **api_rpaths)
{
+ fib_route_path_encode_t *api_rpath;
mfib_entry_t *mfib_entry;
mfib_entry_src_t *bsrc;
@@ -1338,6 +1339,18 @@ mfib_entry_encode (fib_node_index_t mfib_entry_index,
fib_path_encode,
api_rpaths);
}
+
+ vec_foreach(api_rpath, *api_rpaths)
+ {
+ mfib_itf_t *mfib_itf;
+
+ mfib_itf = mfib_entry_itf_find(bsrc->mfes_itfs,
+ api_rpath->rpath.frp_sw_if_index);
+ if (mfib_itf)
+ {
+ api_rpath->rpath.frp_mitf_flags = mfib_itf->mfi_flags;
+ }
+ }
}
const mfib_prefix_t *
diff --git a/test/ext/vom_test.cpp b/test/ext/vom_test.cpp
index 7d7325413bd..69de5f1ad3d 100644
--- a/test/ext/vom_test.cpp
+++ b/test/ext/vom_test.cpp
@@ -38,6 +38,7 @@
#include "vom/prefix.hpp"
#include "vom/route.hpp"
#include "vom/route_cmds.hpp"
+#include "vom/mroute_cmds.hpp"
#include "vom/route_domain.hpp"
#include "vom/route_domain_cmds.hpp"
#include "vom/vxlan_tunnel.hpp"
@@ -251,6 +252,14 @@ public:
{
rc = handle_derived<route::ip_route_cmds::delete_cmd>(f_exp, f_act);
}
+ else if (typeid(*f_exp) == typeid(route::ip_mroute_cmds::update_cmd))
+ {
+ rc = handle_derived<route::ip_mroute_cmds::update_cmd>(f_exp, f_act);
+ }
+ else if (typeid(*f_exp) == typeid(route::ip_mroute_cmds::delete_cmd))
+ {
+ rc = handle_derived<route::ip_mroute_cmds::delete_cmd>(f_exp, f_act);
+ }
else if (typeid(*f_exp) == typeid(neighbour_cmds::create_cmd))
{
rc = handle_derived<neighbour_cmds::create_cmd>(f_exp, f_act);
@@ -1762,6 +1771,26 @@ BOOST_AUTO_TEST_CASE(test_routing) {
ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_dvr, 0, pfx_6, {*path_l2}));
TRY_CHECK_RC(OM::write(ian, *route_dvr));
+ /*
+ * a multicast route
+ */
+ route::mprefix_t mpfx_4(boost::asio::ip::address::from_string("232.1.1.1"), 32);
+ route::ip_mroute *mroute_4 = new route::ip_mroute(mpfx_4);
+
+ route::path *mp1 = new route::path(itf1, nh_proto_t::IPV4);
+ route::path *mp2 = new route::path(*itf2, nh_proto_t::IPV4);
+ mroute_4->add(*mp1, route::itf_flags_t::FORWARD);
+ mroute_4->add(*mp1, route::itf_flags_t::ACCEPT);
+ mroute_4->add(*mp2, route::itf_flags_t::FORWARD);
+ HW::item<bool> hw_mroute_4(true, rc_t::OK);
+ ADD_EXPECT(route::ip_mroute_cmds::update_cmd(hw_mroute_4, 0, mpfx_4,
+ *mp1, route::itf_flags_t::FORWARD));
+ ADD_EXPECT(route::ip_mroute_cmds::update_cmd(hw_mroute_4, 0, mpfx_4,
+ *mp2, route::itf_flags_t::FORWARD));
+ ADD_EXPECT(route::ip_mroute_cmds::update_cmd(hw_mroute_4, 0, mpfx_4,
+ *mp1, route::itf_flags_t::ACCEPT));
+ TRY_CHECK_RC(OM::write(ian, *mroute_4));
+
STRICT_ORDER_OFF();
// delete the stack objects that hold references to others
// so the OM::remove is the call that removes the last reference
@@ -1775,6 +1804,18 @@ BOOST_AUTO_TEST_CASE(test_routing) {
delete route_dvr;
delete path_l2;
delete ne;
+ delete mroute_4;
+
+ ADD_EXPECT(route::ip_mroute_cmds::delete_cmd(hw_mroute_4, 0, mpfx_4,
+ *mp1, route::itf_flags_t::FORWARD));
+ ADD_EXPECT(route::ip_mroute_cmds::delete_cmd(hw_mroute_4, 0, mpfx_4,
+ *mp2, route::itf_flags_t::FORWARD));
+ ADD_EXPECT(route::ip_mroute_cmds::delete_cmd(hw_mroute_4, 0, mpfx_4,
+ *mp1, route::itf_flags_t::ACCEPT));
+
+ delete mp1;
+ delete mp2;
+
ADD_EXPECT(neighbour_cmds::delete_cmd(hw_neighbour, hw_ifh.data(), mac_n, nh_10));
ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_dvr, 0, pfx_6));
ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5_2, 1, pfx_5));