From d1134f2b43fe06e66cea4ef7b79e950024be6fdd Mon Sep 17 00:00:00 2001 From: shashwat Date: Tue, 10 Jun 2025 14:32:28 +0530 Subject: [PATCH] internet: Add Tests for GlobalRouteManagerImpl testsuite --- .../global-route-manager-impl-test-suite.cc | 832 +++++++++++++++++- 1 file changed, 785 insertions(+), 47 deletions(-) diff --git a/src/internet/test/global-route-manager-impl-test-suite.cc b/src/internet/test/global-route-manager-impl-test-suite.cc index a4ce8b59a..21b919950 100644 --- a/src/internet/test/global-route-manager-impl-test-suite.cc +++ b/src/internet/test/global-route-manager-impl-test-suite.cc @@ -6,19 +6,53 @@ * * Authors: Tom Henderson (tomhend@u.washington.edu) * + * Modified By: Shashwat Patni (shashwatpatni25@gmail.com) + * * Kunihiro Ishigura, Toshiaki Takada (GNU Zebra) are attributed authors * of the quagga 0.99.7/src/ospfd/ospf_spf.c code which was ported here */ #include "ns3/candidate-queue.h" +#include "ns3/config.h" #include "ns3/global-route-manager-impl.h" +#include "ns3/internet-module.h" +#include "ns3/internet-stack-helper.h" +#include "ns3/ipv4-global-routing-helper.h" +#include "ns3/ipv4-global-routing.h" +#include "ns3/network-module.h" +#include "ns3/node-container.h" +#include "ns3/rng-seed-manager.h" +#include "ns3/simple-net-device-helper.h" #include "ns3/simulator.h" #include "ns3/test.h" #include // for rand() - using namespace ns3; +NS_LOG_COMPONENT_DEFINE("GlobalRouteManagerImplTestSuite"); + +// +// This test suite is designed to check the Working of the GlobalRouteManagerImpl +// For that reason, the tests in this suite manually build LSAs for each topology +// we manually call DebugSPFCalculate() to fill routing tables of the node we are interested in. +// +// TestCase 1: LinkRoutesTestCase +// This test case tests that: +// - GLobalRouteManagerLSDB stores the LSAs with key as the correct link state ID +// - GlobalRouteManagerImpl checks for stubnodes and computes default routes for them +// - HostRoutes are computed correctly for point-to-point links +// +// TestCase 2: LanRoutesTestCase +// This test case tests that: +// - Network LSAs are handled by the GlobalRouteManagerImpl +// - GlobalRouteManagerImpl computes the routes correctly for a LAN topology +// +// TestCase 3: RandomEcmpRoutesTestCase +// This test case tests that: +// - GlobalRouteManagerImpl computes ECMP routes correctly. +// - Those random routes are in fact used by the GlobalRouting protocol +// + /** * @ingroup internet * @ingroup tests @@ -30,39 +64,60 @@ using namespace ns3; * * @brief Global Route Manager Test */ -class GlobalRouteManagerImplTestCase : public TestCase +class LinkRoutesTestCase : public TestCase { public: - GlobalRouteManagerImplTestCase(); + LinkRoutesTestCase(); + void DoSetup() override; void DoRun() override; + + private: + /** + *@brief Builds the LSAs for the topology. These LSAs are manually created and inserted into the + * GlobalRouteManagerLSDB.Each node exports a router LSA. + */ + void BuildLsa(); + + /** + * @brief Checks the Routing Table Entries for the expected output. + * @param globalroutingprotocol The routing protocol for the node whose routing table is to be + * checked. + * @param dests The expected destinations. + * @param gws The expected gateways. + */ + void CheckRoutes(Ptr& globalroutingprotocol, + std::vector& dests, + std::vector& gws); + + NodeContainer nodes; //!< NodeContainer to hold the nodes in the topology + std::vector m_lsas; //!< The LSAs for the topology }; -GlobalRouteManagerImplTestCase::GlobalRouteManagerImplTestCase() - : TestCase("GlobalRouteManagerImplTestCase") +LinkRoutesTestCase::LinkRoutesTestCase() + : TestCase("LinkRoutesTestCase") { } void -GlobalRouteManagerImplTestCase::DoRun() +LinkRoutesTestCase::CheckRoutes(Ptr& globalroutingprotocol, + std::vector& dests, + std::vector& gws) { - CandidateQueue candidate; - - for (int i = 0; i < 100; ++i) + // check each individual Routing Table Entry for its destination and gateway + for (uint32_t i = 0; i < globalroutingprotocol->GetNRoutes(); i++) { - auto v = new SPFVertex; - v->SetDistanceFromRoot(std::rand() % 100); - candidate.Push(v); + Ipv4RoutingTableEntry* route = globalroutingprotocol->GetRoute(i); + NS_LOG_DEBUG("dest " << route->GetDest() << " gw " << route->GetGateway()); + NS_TEST_ASSERT_MSG_EQ(route->GetDest(), dests[i], "Error-- wrong destination"); + NS_TEST_ASSERT_MSG_EQ(route->GetGateway(), gws[i], "Error-- wrong gateway"); } +} - for (int i = 0; i < 100; ++i) - { - SPFVertex* v = candidate.Pop(); - delete v; - v = nullptr; - } - - // Build fake link state database; four routers (0-3), 3 point-to-point - // links +void +LinkRoutesTestCase::DoSetup() +{ + // Simple p2p links. n0,n1 and n3 are stub nodes + // // // n0 // \ link 0 @@ -72,18 +127,56 @@ GlobalRouteManagerImplTestCase::DoRun() // / link 1 // n1 // - // link0: 10.1.1.1/30, 10.1.1.2/30 - // link1: 10.1.2.1/30, 10.1.2.2/30 - // link2: 10.1.3.1/30, 10.1.3.2/30 + // link0: n0->10.1.1.1/30, n2-> 10.1.1.2/30 + // link1: n1-> 10.1.2.1/30, n2->10.1.2.2/30 + // link2: n2->10.1.3.1/30, n3-> 10.1.3.2/30 // + // + // + + nodes.Create(4); + + Ipv4GlobalRoutingHelper globalhelper; + InternetStackHelper stack; + stack.SetRoutingHelper(globalhelper); + stack.Install(nodes); + + SimpleNetDeviceHelper devHelper; + devHelper.SetNetDevicePointToPointMode(true); + Ptr channel1 = CreateObject(); + NetDeviceContainer d02 = devHelper.Install(nodes.Get(0), channel1); + d02.Add(devHelper.Install(nodes.Get(2), channel1)); + Ptr channel2 = CreateObject(); + NetDeviceContainer d12 = devHelper.Install(nodes.Get(1), channel2); + d12.Add(devHelper.Install(nodes.Get(2), channel2)); + Ptr channel3 = CreateObject(); + NetDeviceContainer d23 = devHelper.Install(nodes.Get(2), channel3); + d23.Add(devHelper.Install(nodes.Get(3), channel3)); + + // Assign IP addresses to the devices + Ipv4AddressHelper address; + address.SetBase("10.1.1.0", "255.255.255.252"); + Ipv4InterfaceContainer i02 = address.Assign(d02); + address.SetBase("10.1.2.0", "255.255.255.252"); + Ipv4InterfaceContainer i12 = address.Assign(d12); + address.SetBase("10.1.3.0", "255.255.255.252"); + Ipv4InterfaceContainer i23 = address.Assign(d23); +} + +void +LinkRoutesTestCase::BuildLsa() +{ + // Manually build the link state database; four routers (0-3), 3 point-to-point + // links + // Router 0 auto lr0 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, - "0.0.0.2", // router ID 0.0.0.2 - "10.1.1.1", // local ID + "0.0.0.2", // link id -> router ID 0.0.0.2 + "10.1.1.1", // link data -> Local IP address of router 0 1); // metric auto lr1 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, - "10.1.1.1", + "10.1.1.2", // link id ->adjacent neighbor's IP address "255.255.255.252", 1); @@ -91,8 +184,10 @@ GlobalRouteManagerImplTestCase::DoRun() lsa0->SetLSType(GlobalRoutingLSA::RouterLSA); lsa0->SetLinkStateId("0.0.0.0"); lsa0->SetAdvertisingRouter("0.0.0.0"); + lsa0->SetNode(nodes.Get(0)); lsa0->AddLinkRecord(lr0); lsa0->AddLinkRecord(lr1); + m_lsas.push_back(lsa0); // Router 1 auto lr2 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, @@ -101,7 +196,7 @@ GlobalRouteManagerImplTestCase::DoRun() 1); auto lr3 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, - "10.1.2.1", + "10.1.2.2", "255.255.255.252", 1); @@ -111,6 +206,8 @@ GlobalRouteManagerImplTestCase::DoRun() lsa1->SetAdvertisingRouter("0.0.0.1"); lsa1->AddLinkRecord(lr2); lsa1->AddLinkRecord(lr3); + lsa1->SetNode(nodes.Get(1)); + m_lsas.push_back(lsa1); // Router 2 auto lr4 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, @@ -119,7 +216,7 @@ GlobalRouteManagerImplTestCase::DoRun() 1); auto lr5 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, - "10.1.1.2", + "10.1.1.1", "255.255.255.252", 1); @@ -135,7 +232,7 @@ GlobalRouteManagerImplTestCase::DoRun() auto lr8 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, "0.0.0.3", - "10.1.3.2", + "10.1.3.1", 1); auto lr9 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, @@ -153,15 +250,17 @@ GlobalRouteManagerImplTestCase::DoRun() lsa2->AddLinkRecord(lr7); lsa2->AddLinkRecord(lr8); lsa2->AddLinkRecord(lr9); + lsa2->SetNode(nodes.Get(2)); + m_lsas.push_back(lsa2); // Router 3 auto lr10 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, "0.0.0.2", - "10.1.2.1", + "10.1.3.2", 1); auto lr11 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, - "10.1.2.1", + "10.1.3.1", "255.255.255.252", 1); @@ -171,37 +270,674 @@ GlobalRouteManagerImplTestCase::DoRun() lsa3->SetAdvertisingRouter("0.0.0.3"); lsa3->AddLinkRecord(lr10); lsa3->AddLinkRecord(lr11); + lsa3->SetNode(nodes.Get(3)); + m_lsas.push_back(lsa3); +} + +void +LinkRoutesTestCase::DoRun() +{ + // This test is for checking the individual working of GlobalRouteManagerImpl + // and GlobalRouteManagerLSDB, so we will not use the GlobalRoutingHelper + // to create the routing tables, but instead we will manually create the LSAs + // and insert them into the GlobalRouteManagerLSDB, and then use the + // GlobalRouteManagerImpl to calculate the routes based on the LSDB. + // This is a manual setup of the LSAs, which would normally be done by the + // GlobalRoutingHelper. + + BuildLsa(); // Test the database auto srmlsdb = new GlobalRouteManagerLSDB(); - srmlsdb->Insert(lsa0->GetLinkStateId(), lsa0); - srmlsdb->Insert(lsa1->GetLinkStateId(), lsa1); - srmlsdb->Insert(lsa2->GetLinkStateId(), lsa2); - srmlsdb->Insert(lsa3->GetLinkStateId(), lsa3); - NS_TEST_ASSERT_MSG_EQ(lsa2, - srmlsdb->GetLSA(lsa2->GetLinkStateId()), - "The Ipv4Address is not stored as the link state ID"); + srmlsdb->Insert(m_lsas[0]->GetLinkStateId(), m_lsas[0]); + srmlsdb->Insert(m_lsas[1]->GetLinkStateId(), m_lsas[1]); + srmlsdb->Insert(m_lsas[2]->GetLinkStateId(), m_lsas[2]); + srmlsdb->Insert(m_lsas[3]->GetLinkStateId(), m_lsas[3]); + + NS_TEST_ASSERT_MSG_EQ( + m_lsas[2], + srmlsdb->GetLSA(m_lsas[2]->GetLinkStateId()), + "The Ipv4Address is not stored as the link state ID"); // LSAs are mapped by router id as + // key here we check that they are + // indeed getting the right lsa for + // the right key // next, calculate routes based on the manually created LSDB auto srm = new GlobalRouteManagerImpl(); srm->DebugUseLsdb(srmlsdb); // manually add in an LSDB - // Note-- this will succeed without any nodes in the topology - // because the NodeList is empty - srm->DebugSPFCalculate(lsa0->GetLinkStateId()); // node n0 + + srm->DebugSPFCalculate(m_lsas[0]->GetLinkStateId()); // fill routing table for node n0 + + srm->DebugSPFCalculate(m_lsas[1]->GetLinkStateId()); // fill routing table for node n1 + + srm->DebugSPFCalculate(m_lsas[2]->GetLinkStateId()); // fill routing table for node n2 + + srm->DebugSPFCalculate(m_lsas[3]->GetLinkStateId()); // fill routing table for node n3 Simulator::Run(); - /// @todo here we should do some verification of the routes built + //-----------------Now the tests------------------ + // Test 1: Check if the SPF calculate Sets default routes for Stub nodes + Ptr ip0 = nodes.Get(0)->GetObject(); + NS_TEST_ASSERT_MSG_NE(ip0, nullptr, "Error-- no Ipv4 object at node 0"); + Ptr routing0 = ip0->GetRoutingProtocol(); + NS_TEST_ASSERT_MSG_NE(routing0, nullptr, "Error-- no Ipv4 routing protocol object at node 0"); + Ptr globalRouting0 = routing0->GetObject(); + NS_TEST_ASSERT_MSG_NE(globalRouting0, nullptr, "Error-- no Ipv4GlobalRouting object at node 0"); + // Check that the right number of entries are in the routing table + uint32_t nRoutes0 = globalRouting0->GetNRoutes(); + NS_TEST_ASSERT_MSG_EQ(nRoutes0, 1, "Error-- default route not found for stub node"); + + Ipv4RoutingTableEntry* route = nullptr; + route = globalRouting0->GetRoute(0); + // the only route is the default route on this node + NS_TEST_ASSERT_MSG_EQ(route->GetDest(), + Ipv4Address("0.0.0.0"), + "Error-- wrong destination for default route"); + NS_TEST_ASSERT_MSG_EQ(route->GetGateway(), Ipv4Address("10.1.1.2"), "Error-- wrong gateway"); + + // Test 2: Check if SPFCalculate sets the correct routes for node 2 + Ptr ip2 = nodes.Get(2)->GetObject(); + NS_TEST_ASSERT_MSG_NE(ip2, nullptr, "Error-- no Ipv4 object at node 2"); + Ptr routing2 = ip2->GetRoutingProtocol(); + NS_TEST_ASSERT_MSG_NE(routing2, nullptr, "Error-- no Ipv4 routing protocol object at node 2"); + Ptr globalRouting2 = routing2->GetObject(); + NS_TEST_ASSERT_MSG_NE(globalRouting2, nullptr, "Error-- no Ipv4GlobalRouting object at node 2"); + + // check that the correct number of routes were built + uint32_t nRoutes2 = globalRouting2->GetNRoutes(); + NS_LOG_DEBUG("LinkRoutesTest nRoutes2 " << nRoutes2); + NS_TEST_ASSERT_MSG_EQ(nRoutes2, 6, "Error--- Incorrect number of routes found on node 2"); + + // check that all the routes in the routing table are correct for node 2 + std::vector expecteddests; + std::vector expectedgws; + expecteddests.emplace_back("10.1.1.1"); + expecteddests.emplace_back("10.1.2.1"); + expecteddests.emplace_back("10.1.3.2"); + expecteddests.emplace_back("10.1.1.0"); + expecteddests.emplace_back("10.1.2.0"); + expecteddests.emplace_back("10.1.3.0"); + + expectedgws.emplace_back("10.1.1.1"); + expectedgws.emplace_back("10.1.2.1"); + expectedgws.emplace_back("10.1.3.2"); + expectedgws.emplace_back("10.1.1.1"); + expectedgws.emplace_back("10.1.2.1"); + expectedgws.emplace_back("10.1.3.2"); + + CheckRoutes(globalRouting2, expecteddests, expectedgws); + + Simulator::Run(); + + Simulator::Stop(Seconds(3)); Simulator::Destroy(); // This delete clears the srm, which deletes the LSDB, which clears // all of the LSAs, which each destroys the attached LinkRecords. delete srm; + // reset the router ID counter to zero so that it does not affect other tests + // that may run after this one in the same program run. + GlobalRouteManager::ResetRouterId(); +} - /// @todo Testing - // No testing has actually been done other than making sure that this code - // does not crash +/** + * @ingroup internet-test + * + * @brief This test case is to check if NetworkRoutes are being built correctly, i.e if route + * computation works for a LAN Topology. + */ +class LanRoutesTestCase : public TestCase +{ + public: + LanRoutesTestCase(); + void DoSetup() override; + void DoRun() override; + + private: + /** + *@brief Builds the LSAs for the topology. These LSAs are manually created and inserted into the + * GlobalRouteManagerLSDB.Each node exports a router LSA. In addition,the designated router + * also Exports the Network LSA. + */ + void BuildLsa(); + + NodeContainer nodes; //!< NodeContainer to hold the nodes in the topology + std::vector m_lsas; //!< The LSAs for the topology +}; + +LanRoutesTestCase::LanRoutesTestCase() + : TestCase("LanRoutesTestCase") +{ +} + +void +LanRoutesTestCase::DoSetup() +{ + // Simple Csma Network with three nodes + // + // n0 n1 + // | (shared csma/cd) | + // ------------------------- + // | + // n2 + // + // n0:10.1.1.1/29 + // n1:10.1.1.2/29 + // n2:10.1.1.3/29 + nodes.Create(3); + Ipv4GlobalRoutingHelper globalhelper; + InternetStackHelper stack; + stack.SetRoutingHelper(globalhelper); + stack.Install(nodes); + SimpleNetDeviceHelper devHelper; + Ptr channel = CreateObject(); + NetDeviceContainer d012 = devHelper.Install(nodes.Get(0), channel); + d012.Add(devHelper.Install(nodes.Get(1), channel)); + d012.Add(devHelper.Install(nodes.Get(2), channel)); + + // assign IP addresses to the devices + Ipv4AddressHelper address; + address.SetBase("10.1.1.0", "255.255.255.248"); + Ipv4InterfaceContainer i012 = address.Assign(d012); +} + +void +LanRoutesTestCase::BuildLsa() +{ + // we manually create the link state database, we could have used BuildRoutingTables() but this + // way testing the GlobalRouteManagerImpl without the involvement of GLobalRouter makes it + // easier to debug each individually + + // router 0 + auto lr0 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::TransitNetwork, + "10.1.1.1", + "10.1.1.1", + 1); + auto lsa0 = new GlobalRoutingLSA(); + lsa0->SetLSType(GlobalRoutingLSA::RouterLSA); + lsa0->AddLinkRecord(lr0); + lsa0->SetLinkStateId("0.0.0.0"); + lsa0->SetAdvertisingRouter("0.0.0.0"); + lsa0->SetNode(nodes.Get(0)); + m_lsas.push_back(lsa0); + + // router 1 + auto lr1 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::TransitNetwork, + "10.1.1.1", + "10.1.1.2", + 1); + auto lsa1 = new GlobalRoutingLSA(); + lsa1->SetLSType(GlobalRoutingLSA::RouterLSA); + lsa1->AddLinkRecord(lr1); + lsa1->SetLinkStateId("0.0.0.1"); + lsa1->SetAdvertisingRouter("0.0.0.1"); + lsa1->SetNode(nodes.Get(1)); + m_lsas.push_back(lsa1); + + // router 2 + auto lr2 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::TransitNetwork, + "10.1.1.1", + "10.1.1.3", + 1); + auto lsa2 = new GlobalRoutingLSA(); + lsa2->SetLSType(GlobalRoutingLSA::RouterLSA); + lsa2->AddLinkRecord(lr2); + lsa2->SetLinkStateId("0.0.0.2"); + lsa2->SetAdvertisingRouter("0.0.0.2"); + lsa2->SetNode(nodes.Get(2)); + m_lsas.push_back(lsa2); + + // router0 is the designated router for the LAN. it also exports the network LSA + auto lsa0network = new GlobalRoutingLSA(); + lsa0network->SetLSType(GlobalRoutingLSA::NetworkLSA); + lsa0network->SetLinkStateId("10.1.1.1"); + lsa0network->SetAdvertisingRouter("0.0.0.0"); + lsa0network->AddAttachedRouter("10.1.1.1"); + lsa0network->AddAttachedRouter("10.1.1.2"); + lsa0network->AddAttachedRouter("10.1.1.3"); + lsa0network->SetNetworkLSANetworkMask("255.255.255.248"); + m_lsas.push_back(lsa0network); // note the index of the network lsa +} + +void +LanRoutesTestCase::DoRun() +{ + BuildLsa(); + // insert the LSAs into the GlobalRouteManagerLSDB + auto srmlsdb = new GlobalRouteManagerLSDB(); + + srmlsdb->Insert(m_lsas[0]->GetLinkStateId(), m_lsas[0]); + srmlsdb->Insert(m_lsas[1]->GetLinkStateId(), m_lsas[1]); + srmlsdb->Insert(m_lsas[2]->GetLinkStateId(), m_lsas[2]); + srmlsdb->Insert(m_lsas[3]->GetLinkStateId(), m_lsas[3]); + + // create the GlobalRouteManagerImpl + auto srm = new GlobalRouteManagerImpl(); + srm->DebugUseLsdb(srmlsdb); + + srm->DebugSPFCalculate(m_lsas[0]->GetLinkStateId()); // fill the routing table for node 0 + + // now the tests----------------------- + + Ptr ip0 = nodes.Get(0)->GetObject(); + NS_TEST_ASSERT_MSG_NE(ip0, nullptr, "Error-- no Ipv4 object at node 0"); + Ptr routing0 = ip0->GetRoutingProtocol(); + NS_TEST_ASSERT_MSG_NE(routing0, nullptr, "Error-- no Ipv4 routing protocol object at node 0"); + Ptr globalRouting0 = routing0->GetObject(); + NS_TEST_ASSERT_MSG_NE(globalRouting0, nullptr, "Error-- no Ipv4GlobalRouting object at node 0"); + + // The only route to check is the network route + uint32_t nRoutes0 = globalRouting0->GetNRoutes(); + NS_TEST_ASSERT_MSG_EQ(nRoutes0, 1, "Error-- Network route not found for node 0"); + Ipv4RoutingTableEntry* route = globalRouting0->GetRoute(0); + NS_TEST_ASSERT_MSG_EQ(route->GetDest(), + Ipv4Address("10.1.1.0"), + "Error-- wrong destination for network route"); + NS_TEST_ASSERT_MSG_EQ(route->GetGateway(), + Ipv4Address("0.0.0.0"), + "Error-- wrong gateway for network route"); + + Simulator::Run(); + + Simulator::Stop(Seconds(3)); + Simulator::Destroy(); + // This delete clears the srm, which deletes the LSDB, which clears + // all of the LSAs, which each destroys the attached LinkRecords. + delete srm; + GlobalRouteManager::ResetRouterId(); +} + +/** + * @ingroup internet-test + * + * @brief The purpose of this test is to check if Equal Cost MultiPath (ECMP) Routes are being built + * and used correctly. + */ +class RandomEcmpTestCase : public TestCase +{ + public: + RandomEcmpTestCase(); + + void DoSetup() override; + void DoRun() override; + + private: + /** + *@brief Builds the LSAs for the topology. These LSAs are manually created and inserted into the + * GlobalRouteManagerLSDB.Each node exports a router LSA. + */ + void BuildLsa(); + + /** + * @brief Helper function that checks the output of the routing path + * and increments the corresponding route counter. + * @param route The routing path to check + */ + void IncrementCount(Ptr& route); + /** + * @brief function that checks the routing table entries for the expected output. + * @param globalroutingprotocol The routing protocol for the node whose routing table is to be + * checked. + * @param dests The expected destinations. + * @param gws The expected gateways. + */ + void CheckRoutes(Ptr& globalroutingprotocol, + std::vector& dests, + std::vector& gws); + uint32_t route1 = 0; //!< Counter to keep track of the number of times route1 is used + uint32_t route2 = 0; //!< Counter to keep track of the number of times route2 is used + NodeContainer nodes; //!< NodeContainer to hold the nodes in the topology + std::vector m_lsas; //!< The LSAs for the topology +}; + +RandomEcmpTestCase::RandomEcmpTestCase() + : TestCase("RandomEcmpTestCase") +{ +} + +void +RandomEcmpTestCase::DoSetup() +{ + Config::SetDefault("ns3::Ipv4GlobalRouting::RandomEcmpRouting", BooleanValue(true)); + /* + // Creating a Simple topology with 4 nodes and 3 links + // + // + // + // ------n1------ + // / \ + // / \ + // n0 n3 + // \ / + // \ / + // ------n2------ + // + // Link n0-n1: 10.1.1.1/30,10.1.1.2/30 + // Link n0-n2: 10.1.2.1/30,10.1.2.2/30 + // Link n1-n3: 10.1.3.1/30,10.1.3.2/30 + // Link n2-n3: 10.1.4.1/30,10.1.4.2/30 + */ + nodes.Create(4); + + Ipv4GlobalRoutingHelper globalhelper; + InternetStackHelper stack; + stack.SetRoutingHelper(globalhelper); + stack.Install(nodes); + SimpleNetDeviceHelper devHelper; + devHelper.SetNetDevicePointToPointMode(true); + Ptr channel1 = CreateObject(); + NetDeviceContainer d01 = devHelper.Install(nodes.Get(0), channel1); + d01.Add(devHelper.Install(nodes.Get(1), channel1)); + Ptr channel2 = CreateObject(); + NetDeviceContainer d23 = devHelper.Install(nodes.Get(2), channel2); + d23.Add(devHelper.Install(nodes.Get(3), channel2)); + Ptr channel3 = CreateObject(); + NetDeviceContainer d02 = devHelper.Install(nodes.Get(0), channel3); + d02.Add(devHelper.Install(nodes.Get(2), channel3)); + Ptr channel4 = CreateObject(); + NetDeviceContainer d13 = devHelper.Install(nodes.Get(1), channel4); + d13.Add(devHelper.Install(nodes.Get(3), channel4)); + + // Assign IP addresses to the devices + Ipv4AddressHelper address; + address.SetBase("10.1.1.0", "255.255.255.252"); + Ipv4InterfaceContainer i01 = address.Assign(d01); + + address.SetBase("10.1.2.0", "255.255.255.252"); + Ipv4InterfaceContainer i02 = address.Assign(d02); + + address.SetBase("10.1.3.0", "255.255.255.252"); + Ipv4InterfaceContainer i13 = address.Assign(d13); + + address.SetBase("10.1.4.0", "255.255.255.252"); + Ipv4InterfaceContainer i23 = address.Assign(d23); +} + +void +RandomEcmpTestCase::CheckRoutes(Ptr& globalroutingprotocol, + std::vector& dests, + std::vector& gws) +{ + // check each individual routes destination and gateway + for (uint32_t i = 0; i < globalroutingprotocol->GetNRoutes(); i++) + { + Ipv4RoutingTableEntry* route = globalroutingprotocol->GetRoute(i); + NS_LOG_DEBUG("dest " << route->GetDest() << " gw " << route->GetGateway()); + NS_TEST_ASSERT_MSG_EQ(route->GetDest(), dests[i], "Error-- wrong destination"); + NS_TEST_ASSERT_MSG_EQ(route->GetGateway(), gws[i], "Error-- wrong gateway"); + } +} + +void +RandomEcmpTestCase::IncrementCount(Ptr& route) +{ + if (route->GetGateway() == Ipv4Address("10.1.1.2")) + { + route1++; + } + else if (route->GetGateway() == Ipv4Address("10.1.2.2")) + { + route2++; + } +} + +void +RandomEcmpTestCase::BuildLsa() +{ + // we manually create the link state database, we could have used BuildRoutingTables() but this + // way testing the GlobalRouteManagerImpl without the involvement of GLobalRouter makes it + // easier to debug each individually + + // router 0 + auto lr0 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.1", + "10.1.1.1", + 1); + auto lr1 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.1.2", + "255.255.255.252", + 1); + + auto lr2 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.2.1", + 1); + auto lr3 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.2.2", + "255.255.255.252", + 1); + + auto lsa0 = new GlobalRoutingLSA(); + lsa0->SetLSType(GlobalRoutingLSA::RouterLSA); + lsa0->SetStatus(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED); + lsa0->SetLinkStateId("0.0.0.0"); + lsa0->SetAdvertisingRouter("0.0.0.0"); + lsa0->SetNode(nodes.Get(0)); + lsa0->AddLinkRecord(lr0); + lsa0->AddLinkRecord(lr1); + lsa0->AddLinkRecord(lr2); + lsa0->AddLinkRecord(lr3); + m_lsas.push_back(lsa0); + + // router 1 + auto lr4 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.0", + "10.1.1.2", + 1); + auto lr5 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.1.1", + "255.255.255.252", + 1); + + auto lr6 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.3", + "10.1.3.1", + 1); + auto lr7 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.3.2", + "255.255.255.252", + 1); + + auto lsa1 = new GlobalRoutingLSA(); + lsa1->SetLSType(GlobalRoutingLSA::RouterLSA); + lsa1->SetStatus(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED); + lsa1->SetLinkStateId("0.0.0.1"); + lsa1->SetAdvertisingRouter("0.0.0.1"); + lsa1->SetNode(nodes.Get(1)); + lsa1->AddLinkRecord(lr4); + lsa1->AddLinkRecord(lr5); + lsa1->AddLinkRecord(lr6); + lsa1->AddLinkRecord(lr7); + m_lsas.push_back(lsa1); + + // router 2 + auto lr8 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.0", + "10.1.2.2", + 1); + auto lr9 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.2.1", + "255.255.255.252", + 1); + auto lr10 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.3", + "10.1.4.1", + 1); + auto lr11 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.4.2", + "255.255.255.252", + 1); + + auto lsa2 = new GlobalRoutingLSA(); + lsa2->SetLSType(GlobalRoutingLSA::RouterLSA); + lsa2->SetStatus(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED); + lsa2->SetLinkStateId("0.0.0.2"); + lsa2->SetAdvertisingRouter("0.0.0.2"); + lsa2->SetNode(nodes.Get(2)); + lsa2->AddLinkRecord(lr8); + lsa2->AddLinkRecord(lr9); + lsa2->AddLinkRecord(lr10); + lsa2->AddLinkRecord(lr11); + m_lsas.push_back(lsa2); + + // router 3 + auto lr12 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.1", + "10.1.3.2", + 1); + auto lr13 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.3.1", + "255.255.255.252", + 1); + auto lr14 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::PointToPoint, + "0.0.0.2", + "10.1.4.2", + 1); + auto lr15 = new GlobalRoutingLinkRecord(GlobalRoutingLinkRecord::StubNetwork, + "10.1.4.1", + "255.255.255.252", + 1); + + auto lsa3 = new GlobalRoutingLSA(); + lsa3->SetLSType(GlobalRoutingLSA::RouterLSA); + lsa3->SetStatus(GlobalRoutingLSA::LSA_SPF_NOT_EXPLORED); + lsa3->SetLinkStateId("0.0.0.3"); + lsa3->SetAdvertisingRouter("0.0.0.3"); + lsa3->SetNode(nodes.Get(3)); + lsa3->AddLinkRecord(lr12); + lsa3->AddLinkRecord(lr13); + lsa3->AddLinkRecord(lr14); + lsa3->AddLinkRecord(lr15); + m_lsas.push_back(lsa3); +} + +void +RandomEcmpTestCase::DoRun() +{ + // We need a deterministic output to pass the test. So we set a fixed seed and run for our + // UniformRandomVariable + uint32_t oldseed = RngSeedManager::GetSeed(); + uint32_t oldrun = RngSeedManager::GetRun(); + RngSeedManager::SetSeed(1); + RngSeedManager::SetRun(1); + + BuildLsa(); + + // insert the LSAs into the GlobalRouteManagerLSDB + auto srmlsdb = new GlobalRouteManagerLSDB(); + srmlsdb->Insert(m_lsas[0]->GetLinkStateId(), m_lsas[0]); + srmlsdb->Insert(m_lsas[1]->GetLinkStateId(), m_lsas[1]); + srmlsdb->Insert(m_lsas[2]->GetLinkStateId(), m_lsas[2]); + srmlsdb->Insert(m_lsas[3]->GetLinkStateId(), m_lsas[3]); + + // create the GlobalRouteManagerImpl + auto srm = new GlobalRouteManagerImpl(); + srm->DebugUseLsdb(srmlsdb); + + // we manually call the DebugSPFCalculate to fill the routing tables for node 0 + srm->DebugSPFCalculate(m_lsas[0]->GetLinkStateId()); + + // now the tests----------------------- + + Ptr ip0 = nodes.Get(0)->GetObject(); + NS_TEST_ASSERT_MSG_NE(ip0, nullptr, "Error-- no Ipv4 object at node 0"); + Ptr routing0 = ip0->GetRoutingProtocol(); + NS_TEST_ASSERT_MSG_NE(routing0, nullptr, "Error-- no Ipv4 routing protocol object at node 0"); + Ptr globalRouting0 = routing0->GetObject(); + NS_TEST_ASSERT_MSG_NE(globalRouting0, nullptr, "Error-- no Ipv4GlobalRouting object at node 0"); + + // assign streams to the UniformRandomVariable + globalRouting0->AssignStreams(0); + // check that the correct number of routes were built + uint32_t nRoutes0 = globalRouting0->GetNRoutes(); + NS_TEST_ASSERT_MSG_EQ(nRoutes0, 14, "Error-- incorrect number of routes found on node 0"); + + // check that the routes are correct + std::vector expectedDests; + std::vector expectedNextHops; + + // add all the expected destinations and gateways. This is pretty verbose + // Please Note: The order of the following line is important because we check the routing table + // entries in order. The test will fail if we reorder the vector entries. + + // For Routing table of Node 0 we check the following Destinations and Gateways + expectedDests.emplace_back("10.1.1.2"); + expectedDests.emplace_back("10.1.3.1"); + expectedDests.emplace_back("10.1.2.2"); + expectedDests.emplace_back("10.1.4.1"); + expectedDests.emplace_back("10.1.3.2"); + expectedDests.emplace_back("10.1.3.2"); + expectedDests.emplace_back("10.1.4.2"); + expectedDests.emplace_back("10.1.4.2"); + expectedDests.emplace_back("10.1.1.0"); + expectedDests.emplace_back("10.1.3.0"); + expectedDests.emplace_back("10.1.3.0"); + expectedDests.emplace_back("10.1.4.0"); + expectedDests.emplace_back("10.1.4.0"); + expectedDests.emplace_back("10.1.2.0"); + + expectedNextHops.emplace_back("10.1.1.2"); + expectedNextHops.emplace_back("10.1.1.2"); + expectedNextHops.emplace_back("10.1.2.2"); + expectedNextHops.emplace_back("10.1.2.2"); + expectedNextHops.emplace_back("10.1.1.2"); + expectedNextHops.emplace_back("10.1.2.2"); + expectedNextHops.emplace_back("10.1.1.2"); + expectedNextHops.emplace_back("10.1.2.2"); + expectedNextHops.emplace_back("10.1.1.2"); + expectedNextHops.emplace_back("10.1.1.2"); + expectedNextHops.emplace_back("10.1.2.2"); + expectedNextHops.emplace_back("10.1.1.2"); + expectedNextHops.emplace_back("10.1.2.2"); + expectedNextHops.emplace_back("10.1.2.2"); + + // Test 1: Check the Routing Table of Node 0 + CheckRoutes(globalRouting0, expectedDests, expectedNextHops); + + // Test 2: Check that the equal cost routes are being used at least once. + // we need to call RouteOutput() at node 0 and check the output + // route from the table. The thing to check here is that different equal cost routes are + // returned across different calls to this method. + + Socket::SocketErrno errno_; + Ptr oif(nullptr); + Ptr packet = Create(); + Ipv4Header ipHeader; + ipHeader.SetSource(Ipv4Address("10.1.1.1")); + ipHeader.SetDestination(Ipv4Address("10.1.4.2")); + + for (uint32_t i = 0; i < 10; i++) + { + Ptr route = globalRouting0->RouteOutput(packet, ipHeader, oif, errno_); + IncrementCount(route); + } + + Simulator::Run(); + + NS_TEST_ASSERT_MSG_GT_OR_EQ( + route1, + 1, + "The routing path for node 0 to node 3 does not match the expected output, " + "Equal Cost MultiPath (ECMP) routes are not being used correctly"); + NS_TEST_ASSERT_MSG_GT_OR_EQ( + route2, + 1, + "The routing path for node 0 to node 3 does not match the expected output, " + "Equal Cost MultiPath (ECMP) routes are not being used correctly"); + + // end of test-------------------- + + Simulator::Stop(Seconds(5)); + + Simulator::Destroy(); + + RngSeedManager::SetSeed(oldseed); + RngSeedManager::SetRun(oldrun); + // This delete clears the srm, which deletes the LSDB, which clears + // all of the LSAs, which each destroys the attached LinkRecords. + delete srm; } /** @@ -220,7 +956,9 @@ class GlobalRouteManagerImplTestSuite : public TestSuite GlobalRouteManagerImplTestSuite::GlobalRouteManagerImplTestSuite() : TestSuite("global-route-manager-impl", Type::UNIT) { - AddTestCase(new GlobalRouteManagerImplTestCase(), TestCase::Duration::QUICK); + AddTestCase(new LinkRoutesTestCase(), TestCase::Duration::QUICK); + AddTestCase(new LanRoutesTestCase(), TestCase::Duration::QUICK); + AddTestCase(new RandomEcmpTestCase(), TestCase::Duration::QUICK); } static GlobalRouteManagerImplTestSuite