From 6ad7231c00287b7c1241c6e1dbbfda86f15798b4 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Thu, 10 Jan 2019 08:56:38 -0800 Subject: VOM: IP route ECMP support Change-Id: Iede0c30aacfe7289f428062bb9540410097c40e2 Signed-off-by: Neale Ranns --- extras/vom/vom/route.cpp | 45 ++++++++++++++++++++++++++++++++++--------- extras/vom/vom/route_cmds.cpp | 25 ++++++++++++------------ extras/vom/vom/route_cmds.hpp | 10 +++++++--- test/ext/vom_test.cpp | 38 +++++++++++++++++++++++++++--------- 4 files changed, 85 insertions(+), 33 deletions(-) diff --git a/extras/vom/vom/route.cpp b/extras/vom/vom/route.cpp index c713de9ee99..5aed82bac2a 100644 --- a/extras/vom/vom/route.cpp +++ b/extras/vom/vom/route.cpp @@ -339,8 +339,9 @@ void ip_route::sweep() { if (m_hw) { - HW::enqueue( - new ip_route_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix)); + for (auto& p : m_paths) + HW::enqueue( + new ip_route_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix, p)); } HW::write(); } @@ -349,8 +350,9 @@ void ip_route::replay() { if (m_hw) { - HW::enqueue( - new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths)); + for (auto& p : m_paths) + HW::enqueue( + new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, p)); } } std::string @@ -367,12 +369,37 @@ ip_route::to_string() const void ip_route::update(const ip_route& r) { - /* -* create the table if it is not yet created -*/ if (rc_t::OK != m_hw.rc()) { - HW::enqueue( - new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, m_paths)); + /* + * route not yet installed. install each of the desired paths + */ + m_paths = r.m_paths; + + for (auto& p : m_paths) + HW::enqueue( + new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, p)); + } else { + /* + * add each path that is not installed yet and remove each that is no longer + * wanted + */ + path_list_t to_add; + set_difference(r.m_paths.begin(), r.m_paths.end(), m_paths.begin(), + m_paths.end(), std::inserter(to_add, to_add.begin())); + + for (auto& p : to_add) + HW::enqueue( + new ip_route_cmds::update_cmd(m_hw, m_rd->table_id(), m_prefix, p)); + + path_list_t to_del; + set_difference(m_paths.begin(), m_paths.end(), r.m_paths.begin(), + r.m_paths.end(), std::inserter(to_del, to_del.begin())); + + for (auto& p : to_del) + HW::enqueue( + new ip_route_cmds::delete_cmd(m_hw, m_rd->table_id(), m_prefix, p)); + + m_paths = r.m_paths; } } diff --git a/extras/vom/vom/route_cmds.cpp b/extras/vom/vom/route_cmds.cpp index 26d6593df78..e3f635fe09a 100644 --- a/extras/vom/vom/route_cmds.cpp +++ b/extras/vom/vom/route_cmds.cpp @@ -25,20 +25,19 @@ namespace ip_route_cmds { update_cmd::update_cmd(HW::item& item, table_id_t id, const prefix_t& prefix, - const path_list_t& paths) + const path& path) : rpc_cmd(item) , m_id(id) , m_prefix(prefix) - , m_paths(paths) + , m_path(path) { - // no multipath yet. - assert(paths.size() == 1); } bool update_cmd::operator==(const update_cmd& other) const { - return ((m_prefix == other.m_prefix) && (m_id == other.m_id)); + return ((m_prefix == other.m_prefix) && (m_id == other.m_id) && + (m_path == other.m_path)); } rc_t @@ -54,9 +53,7 @@ update_cmd::issue(connection& con) m_prefix.to_vpp(&payload.is_ipv6, payload.dst_address, &payload.dst_address_length); - - for (auto& p : m_paths) - to_vpp(p, payload); + to_vpp(m_path, payload); VAPI_CALL(req.execute()); @@ -68,24 +65,27 @@ update_cmd::to_string() const { std::ostringstream s; s << "ip-route-create: " << m_hw_item.to_string() << " table-id:" << m_id - << " prefix:" << m_prefix.to_string() << " paths:" << m_paths; + << " prefix:" << m_prefix.to_string() << " paths:" << m_path.to_string(); return (s.str()); } delete_cmd::delete_cmd(HW::item& item, table_id_t id, - const prefix_t& prefix) + const prefix_t& prefix, + const path& path) : rpc_cmd(item) , m_id(id) , m_prefix(prefix) + , m_path(path) { } bool delete_cmd::operator==(const delete_cmd& other) const { - return ((m_prefix == other.m_prefix) && (m_id == other.m_id)); + return ((m_prefix == other.m_prefix) && (m_id == other.m_id) && + (m_path == other.m_path)); } rc_t @@ -99,6 +99,7 @@ delete_cmd::issue(connection& con) m_prefix.to_vpp(&payload.is_ipv6, payload.dst_address, &payload.dst_address_length); + to_vpp(m_path, payload); VAPI_CALL(req.execute()); @@ -113,7 +114,7 @@ delete_cmd::to_string() const { std::ostringstream s; s << "ip-route-delete: " << m_hw_item.to_string() << " id:" << m_id - << " prefix:" << m_prefix.to_string(); + << " prefix:" << m_prefix.to_string() << " paths:" << m_path.to_string(); return (s.str()); } diff --git a/extras/vom/vom/route_cmds.hpp b/extras/vom/vom/route_cmds.hpp index 2e6ce73068c..6db7b5894ef 100644 --- a/extras/vom/vom/route_cmds.hpp +++ b/extras/vom/vom/route_cmds.hpp @@ -38,7 +38,7 @@ public: update_cmd(HW::item& item, table_id_t id, const prefix_t& prefix, - const path_list_t& paths); + const path& path); /** * Issue the command to VPP/HW @@ -58,7 +58,7 @@ public: private: route::table_id_t m_id; prefix_t m_prefix; - const path_list_t m_paths; + const path m_path; }; /** @@ -70,7 +70,10 @@ public: /** * Constructor */ - delete_cmd(HW::item& item, table_id_t id, const prefix_t& prefix); + delete_cmd(HW::item& item, + table_id_t id, + const prefix_t& prefix, + const path& path); /** * Issue the command to VPP/HW @@ -90,6 +93,7 @@ public: private: route::table_id_t m_id; prefix_t m_prefix; + const path m_path; }; /** diff --git a/test/ext/vom_test.cpp b/test/ext/vom_test.cpp index 69de5f1ad3d..d72c4db9748 100644 --- a/test/ext/vom_test.cpp +++ b/test/ext/vom_test.cpp @@ -1732,23 +1732,39 @@ BOOST_AUTO_TEST_CASE(test_routing) { * A route via interface 1 in the default table */ route::prefix_t pfx_5("5.5.5.5", 32); + boost::asio::ip::address nh_9 = boost::asio::ip::address::from_string("10.10.10.9"); + route::path *path_9 = new route::path(nh_9, itf1); boost::asio::ip::address nh_10 = boost::asio::ip::address::from_string("10.10.10.11"); route::path *path_10 = new route::path(nh_10, itf1); route::ip_route *route_5 = new route::ip_route(pfx_5); route_5->add(*path_10); + route_5->add(*path_9); HW::item hw_route_5(true, rc_t::OK); - ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5, 0, pfx_5, {*path_10})); + ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5, 0, pfx_5, *path_9)); + ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5, 0, pfx_5, *path_10)); TRY_CHECK_RC(OM::write(ian, *route_5)); + route_5->remove(*path_9); + ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5, 0, pfx_5, *path_9)); + TRY_CHECK_RC(OM::write(ian, *route_5)); + + delete path_9; + /* * A route via interface 2 in the non-default table */ boost::asio::ip::address nh_11 = boost::asio::ip::address::from_string("11.11.11.10"); route::path *path_11 = new route::path(nh_11, *itf2); + boost::asio::ip::address nh_12 = boost::asio::ip::address::from_string("11.11.11.12"); + route::path *path_12 = new route::path(nh_12, *itf2); route::ip_route *route_5_2 = new route::ip_route(rd4, pfx_5); route_5_2->add(*path_11); HW::item hw_route_5_2(true, rc_t::OK); - ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5_2, 1, pfx_5, {*path_11})); + ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5_2, 1, pfx_5, *path_11)); + TRY_CHECK_RC(OM::write(ian, *route_5_2)); + + route_5_2->add(*path_12); + ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_5_2, 1, pfx_5, *path_12)); TRY_CHECK_RC(OM::write(ian, *route_5_2)); /* @@ -1768,7 +1784,7 @@ BOOST_AUTO_TEST_CASE(test_routing) { route::ip_route *route_dvr = new route::ip_route(pfx_6); route_dvr->add(*path_l2); HW::item hw_route_dvr(true, rc_t::OK); - ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_dvr, 0, pfx_6, {*path_l2})); + ADD_EXPECT(route::ip_route_cmds::update_cmd(hw_route_dvr, 0, pfx_6, *path_l2)); TRY_CHECK_RC(OM::write(ian, *route_dvr)); /* @@ -1798,11 +1814,8 @@ BOOST_AUTO_TEST_CASE(test_routing) { delete l3_10; delete itf2; delete route_5; - delete path_10; delete route_5_2; - delete path_11; delete route_dvr; - delete path_l2; delete ne; delete mroute_4; @@ -1817,9 +1830,16 @@ BOOST_AUTO_TEST_CASE(test_routing) { 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)); - ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5, 0, pfx_5)); + ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_dvr, 0, pfx_6, *path_l2)); + ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5_2, 1, pfx_5, *path_11)); + ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5_2, 1, pfx_5, *path_12)); + ADD_EXPECT(route::ip_route_cmds::delete_cmd(hw_route_5, 0, pfx_5, *path_10)); + + delete path_10; + delete path_11; + delete path_12; + delete path_l2; + ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_10_unbind, hw_ifh.data(), pfx_10)); ADD_EXPECT(l3_binding_cmds::unbind_cmd(hw_l3_11_unbind, hw_ifh2.data(), pfx_11)); ADD_EXPECT(interface_cmds::state_change_cmd(hw_as_down, hw_ifh)); -- cgit 1.2.3-korg