From 352ea0c4931b54012ce8d55634e3dd3f6ee6802b Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Tue, 14 Nov 2017 11:04:28 -0800 Subject: VOM: interface RD update reconfigures L3 bindings Change-Id: I273e1ea28c3c146e4a88d031c790c1cc56dccf00 Signed-off-by: Neale Ranns --- src/vpp-api/vom/interface.cpp | 50 ++++++++++++++++++------ src/vpp-api/vom/interface.hpp | 4 +- src/vpp-api/vom/l3_binding.cpp | 24 +++++++++++- src/vpp-api/vom/l3_binding.hpp | 25 +++++++++--- test/ext/vom_test.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 169 insertions(+), 21 deletions(-) diff --git a/src/vpp-api/vom/interface.cpp b/src/vpp-api/vom/interface.cpp index 8e270136d8b..1c9f20d2a5d 100644 --- a/src/vpp-api/vom/interface.cpp +++ b/src/vpp-api/vom/interface.cpp @@ -149,7 +149,7 @@ interface::cend() void interface::sweep() { - if (m_table_id) { + if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) { m_table_id.data() = route::DEFAULT_TABLE; HW::enqueue( new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl)); @@ -181,7 +181,7 @@ interface::replay() HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl)); } - if (m_table_id) { + if (m_table_id && (m_table_id.data() != route::DEFAULT_TABLE)) { HW::enqueue( new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl)); HW::enqueue( @@ -267,32 +267,58 @@ void interface::update(const interface& desired) { /* - * the desired state is always that the interface should be created - */ + * the desired state is always that the interface should be created + */ if (rc_t::OK != m_hdl.rc()) { std::queue cmds; HW::enqueue(mk_create_cmd(cmds)); } /* - * change the interface state to that which is deisred - */ + * change the interface state to that which is deisred + */ if (m_state.update(desired.m_state)) { HW::enqueue(new interface_cmds::state_change_cmd(m_state, m_hdl)); } /* - * change the interface state to that which is deisred - */ + * change the interface state to that which is deisred + */ if (m_l2_address.update(desired.m_l2_address)) { HW::enqueue(new interface_cmds::set_mac_cmd(m_l2_address, m_hdl)); } /* - * If the interface is mapped into a route domain, set VPP's - * table ID - */ - if (!m_table_id && m_rd) { + * If the interface is mapped into a route domain, set VPP's + * table ID + */ + if (m_rd != desired.m_rd) { + /* + * changing route domains. need to remove all L3 bindings, swap the table + * then reapply the bindings. + */ + auto it = l3_binding::cbegin(); + + while (it != l3_binding::cend()) { + if (it->second.lock()->itf().key() == key()) + it->second.lock()->sweep(); + ++it; + } + m_rd = desired.m_rd; + m_table_id.update(m_rd ? m_rd->table_id() : route::DEFAULT_TABLE); + HW::enqueue( + new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl)); + HW::enqueue( + new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV6, m_hdl)); + HW::write(); + + it = l3_binding::cbegin(); + while (it != l3_binding::cend()) { + if (it->second.lock()->itf().key() == key()) + it->second.lock()->replay(); //(*it->second.lock()); + ++it; + } + } else if (!m_table_id && m_rd) { HW::enqueue( new interface_cmds::set_table_cmd(m_table_id, l3_proto_t::IPV4, m_hdl)); HW::enqueue( diff --git a/src/vpp-api/vom/interface.hpp b/src/vpp-api/vom/interface.hpp index 6fdd1e1eb62..f11e3591a44 100644 --- a/src/vpp-api/vom/interface.hpp +++ b/src/vpp-api/vom/interface.hpp @@ -540,9 +540,9 @@ private: /** * shared pointer to the routeDoamin the interface is in. - * NULL is not mapped - i.e. in eht default table + * NULL is not mapped - i.e. in the default table */ - const std::shared_ptr m_rd; + std::shared_ptr m_rd; /** * The state of the interface diff --git a/src/vpp-api/vom/l3_binding.cpp b/src/vpp-api/vom/l3_binding.cpp index 8bc7c7c3af3..8f90d45eec4 100644 --- a/src/vpp-api/vom/l3_binding.cpp +++ b/src/vpp-api/vom/l3_binding.cpp @@ -71,6 +71,24 @@ l3_binding::prefix() const return (m_pfx); } +const interface& +l3_binding::itf() const +{ + return (*m_itf); +} + +l3_binding::const_iterator_t +l3_binding::cbegin() +{ + return m_db.cbegin(); +} + +l3_binding::const_iterator_t +l3_binding::cend() +{ + return m_db.cend(); +} + std::string l3_binding::to_string() const { @@ -85,8 +103,10 @@ void l3_binding::update(const l3_binding& desired) { /* - * the desired state is always that the interface should be created - */ + * no updates for the binding. chaning the interface or the prefix is a change + * to the + * key, hence a new object + */ if (!m_binding) { HW::enqueue( new l3_binding_cmds::bind_cmd(m_binding, m_itf->handle(), m_pfx)); diff --git a/src/vpp-api/vom/l3_binding.hpp b/src/vpp-api/vom/l3_binding.hpp index d94ff696b23..4403760180e 100644 --- a/src/vpp-api/vom/l3_binding.hpp +++ b/src/vpp-api/vom/l3_binding.hpp @@ -45,6 +45,19 @@ public: */ ~l3_binding(); + /** + * The key type for l3_bindings + */ + typedef std::pair key_type_t; + + /** + * The iterator type + */ + typedef singular_db::const_iterator const_iterator_t; + + static const_iterator_t cbegin(); + static const_iterator_t cend(); + /** * Return the 'singular instance' of the L3-Config that matches this * object @@ -57,19 +70,19 @@ public: std::string to_string() const; /** - * Return the prefix associated with this L3config + * Return the prefix associated with this L3 binding */ const route::prefix_t& prefix() const; /** - * Dump all l3_bindings into the stream provided + * Return the interface associated with this L3 binding */ - static void dump(std::ostream& os); + const interface& itf() const; /** - * The key type for l3_bindings + * Dump all l3_bindings into the stream provided */ - typedef std::pair key_type_t; + static void dump(std::ostream& os); /** * Find an singular instance in the DB for the interface passed @@ -142,6 +155,8 @@ private: */ void replay(void); + friend class interface; + /** * A reference counting pointer the interface that this L3 layer * represents. By holding the reference here, we can guarantee that diff --git a/test/ext/vom_test.cpp b/test/ext/vom_test.cpp index 788208376ef..612a2d3a6cf 100644 --- a/test/ext/vom_test.cpp +++ b/test/ext/vom_test.cpp @@ -1467,4 +1467,91 @@ BOOST_AUTO_TEST_CASE(test_interface_events) { HW::dequeue(itf); } +BOOST_AUTO_TEST_CASE(test_interface_route_domain_change) { + VppInit vi; + const std::string rene = "ReneGoscinny"; + rc_t rc = rc_t::OK; + + /* + * Create an interface with two IP addresses + */ + std::string itf1_name = "host1"; + interface itf1(itf1_name, + interface::type_t::AFPACKET, + interface::admin_state_t::UP); + HW::item hw_ifh1(2, rc_t::OK); + HW::item hw_as_up(interface::admin_state_t::UP, rc_t::OK); + HW::item hw_as_down(interface::admin_state_t::DOWN, rc_t::OK); + ADD_EXPECT(interface_cmds::af_packet_create_cmd(hw_ifh1, itf1_name)); + ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_up, hw_ifh1)); + TRY_CHECK_RC(OM::write(rene, itf1)); + + route::prefix_t pfx_10("10.10.10.10", 24); + l3_binding *l3_1 = new l3_binding(itf1, pfx_10); + HW::item hw_l3_bind1(true, rc_t::OK); + HW::item hw_l3_unbind1(false, rc_t::OK); + ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10)); + TRY_CHECK_RC(OM::write(rene, *l3_1)); + + route::prefix_t pfx_11("10.10.11.11", 24); + l3_binding *l3_2 = new l3_binding(itf1, pfx_11); + HW::item hw_l3_bind2(true, rc_t::OK); + HW::item hw_l3_unbind2(false, rc_t::OK); + ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11)); + TRY_CHECK_RC(OM::write(rene, *l3_2)); + + route_domain rd(1); + HW::item hw_rd_create(true, rc_t::OK); + HW::item hw_rd_delete(false, rc_t::OK); + HW::item hw_rd_bind(1, rc_t::OK); + HW::item hw_rd_unbind(route::DEFAULT_TABLE, rc_t::OK); + ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd_create, l3_proto_t::IPV4, 1)); + ADD_EXPECT(route_domain_cmds::create_cmd(hw_rd_create, l3_proto_t::IPV6, 1)); + TRY_CHECK_RC(OM::write(rene, rd)); + + /* + * update the interface to change to a new route-domain + * expect that the l3-bindings are removed and readded. + */ + interface *itf2 = new interface(itf1_name, + interface::type_t::AFPACKET, + interface::admin_state_t::UP, + rd); + ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10)); + ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11)); + ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_bind, l3_proto_t::IPV4, hw_ifh1)); + ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_bind, l3_proto_t::IPV6, hw_ifh1)); + ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10)); + ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11)); + TRY_CHECK_RC(OM::write(rene, *itf2)); + + /* + * mve the interface back to the default route-domain + */ + interface itf3(itf1_name, + interface::type_t::AFPACKET, + interface::admin_state_t::UP); + ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10)); + ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11)); + ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_unbind, l3_proto_t::IPV4, hw_ifh1)); + ADD_EXPECT(interface_cmds::set_table_cmd(hw_rd_unbind, l3_proto_t::IPV6, hw_ifh1)); + ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind1, hw_ifh1.data(), pfx_10)); + ADD_EXPECT(l3_binding_cmds::bind_cmd(hw_l3_bind2, hw_ifh1.data(), pfx_11)); + TRY_CHECK_RC(OM::write(rene, itf3)); + + delete l3_1; + delete l3_2; + delete itf2; + + STRICT_ORDER_OFF(); + ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind1, hw_ifh1.data(), pfx_10)); + ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_unbind2, hw_ifh1.data(), pfx_11)); + ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh1)); + ADD_EXPECT(interface_cmds::af_packet_delete_cmd(hw_ifh1, itf1_name)); + ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd_delete, l3_proto_t::IPV4, 1)); + ADD_EXPECT(route_domain_cmds::delete_cmd(hw_rd_delete, l3_proto_t::IPV6, 1)); + + TRY_CHECK(OM::remove(rene)); +} + BOOST_AUTO_TEST_SUITE_END() -- cgit 1.2.3-korg