// Include a header file from your module to test. #include "ns3/ethernet-net-device.h" #include "ns3/ethernet-channel.h" #include "ns3/ethernet-header2.h" #include "ns3/ethernet-generator.h" #include "ns3/switch-net-device.h" // An essential include is test.h #include "ns3/test.h" #include "ns3/core-module.h" #include "ns3/drop-tail-queue.h" #include "ns3/timestamp-tag.h" // Do not put your test classes in namespace ns3. You may find it useful // to use the using directive to access the ns3 namespace directly using namespace ns3; NS_LOG_COMPONENT_DEFINE("EthernetTestSuite"); // Add a doxygen group for tests. // If you have more than one test, this should be in only one of them. /** * \defgroup ethernet-tests Tests for ethernet * \ingroup ethernet * \ingroup tests */ /** * \ingroup ethernet-tests * Check if message crossed a point to point ethernet channel */ class EthernetBasicTestCase : public TestCase { public: EthernetBasicTestCase(); virtual ~EthernetBasicTestCase(); private: void DoRun() override; void SendTx(Ptr p); void ReceiveRx(Ptr p); uint64_t m_sent{0}; //!< number of bytes sent uint64_t m_received{0}; //!< number of bytes received }; // Add some help text to this case to describe what it is intended to test EthernetBasicTestCase::EthernetBasicTestCase() : TestCase("Check if paquets cross a point to point ethernet channel") { } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself EthernetBasicTestCase::~EthernetBasicTestCase() { } void EthernetBasicTestCase::SendTx(Ptr p) { m_sent += p->GetSize(); } void EthernetBasicTestCase::ReceiveRx(Ptr p) { m_received += p->GetSize(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void EthernetBasicTestCase::DoRun() { //Create two nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); n0->AddDevice(net0); Ptr net1 = CreateObject(); n1->AddDevice(net1); //Create a Ethernet Channel and attach it two the two netDevices Ptr channel = CreateObject(); net0->Attach(channel); net1->Attach(channel); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); //Application description Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(10)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(10)); //Callback to trace the message being send and received net0->TraceConnectWithoutContext("MacTx", MakeCallback(&EthernetBasicTestCase::SendTx, this)); net1->TraceConnectWithoutContext("MacRx", MakeCallback(&EthernetBasicTestCase::ReceiveRx, this)); //Execute the simulation Simulator::Stop(Seconds(12)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_sent, 2 * 10 * (1400 + 22), "10 Packets have been sent two times"); NS_TEST_ASSERT_MSG_EQ(m_sent, m_received, "All Packets sent have been received"); } /** * \ingroup ethernet-tests * Check if latency are correct with 1 flow with variable datarate */ class EthernetLatencyTestCase1 : public TestCase { public: EthernetLatencyTestCase1(uint16_t burstSize, Time latency, DataRate datarate); virtual ~EthernetLatencyTestCase1(); private: void DoRun() override; void Latency(Ptr p); Time m_latency{0}; DataRate m_datarate; uint16_t m_burstSize; Time m_true_latency; }; // Add some help text to this case to describe what it is intended to test EthernetLatencyTestCase1::EthernetLatencyTestCase1(uint16_t burstSize, Time latency, DataRate datarate) : TestCase("Check if latency are correct on a point to point ethernet channel with one flow") { m_burstSize = burstSize; m_true_latency = latency; m_datarate = datarate; } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself EthernetLatencyTestCase1::~EthernetLatencyTestCase1() { } void EthernetLatencyTestCase1::Latency(Ptr p) { TimestampTag tag; if (!p->FindFirstMatchingByteTag(tag)) { return; } Time arrival = Simulator::Now(); m_latency = arrival - tag.GetTimestamp(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void EthernetLatencyTestCase1::DoRun() { //Create two nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); net0->SetAttribute("DataRate", DataRateValue(m_datarate)); n0->AddDevice(net0); Ptr net1 = CreateObject(); net1->SetAttribute("DataRate", DataRateValue(m_datarate)); n1->AddDevice(net1); //Create a Ethernet Channel and attach it two the two netDevices Ptr channel = CreateObject(); net0->Attach(channel); net1->Attach(channel); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); //Application description Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(m_burstSize)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(1)); //Callback to trace the latency net1->TraceConnectWithoutContext("Latency", MakeCallback(&EthernetLatencyTestCase1::Latency, this)); //Execute the simulation Simulator::Stop(Seconds(1)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_latency, m_true_latency, "Packet experience the correct latency"); } /** * \ingroup ethernet-tests * Check if latency are correct with 2 flow */ class EthernetLatencyTestCase2 : public TestCase { public: EthernetLatencyTestCase2(uint16_t burstSizeApp0, uint16_t burstSizeApp1, uint16_t offset0, uint16_t offset1, uint8_t pcpApp0, uint8_t pcpApp1, Time latency); virtual ~EthernetLatencyTestCase2(); private: void DoRun() override; void Latency(Ptr p); Time m_latency{0}; uint16_t m_burstSizeApp0; uint16_t m_burstSizeApp1; uint16_t m_offset0; uint16_t m_offset1; uint8_t m_pcpApp0; uint8_t m_pcpApp1; Time m_true_latency; }; // Add some help text to this case to describe what it is intended to test EthernetLatencyTestCase2::EthernetLatencyTestCase2(uint16_t burstSizeApp0, uint16_t burstSizeApp1, uint16_t offset0, uint16_t offset1, uint8_t pcpApp0, uint8_t pcpApp1, Time latency) : TestCase("Check if latency are correct on a point to point ethernet channel with two flows") { m_burstSizeApp0 = burstSizeApp0; m_burstSizeApp1 = burstSizeApp1; m_offset0 = offset0; m_offset1 = offset1; m_pcpApp0 = pcpApp0; m_pcpApp1 = pcpApp1; m_true_latency = latency; } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself EthernetLatencyTestCase2::~EthernetLatencyTestCase2() { } void EthernetLatencyTestCase2::Latency(Ptr p) { TimestampTag tag; if (!p->FindFirstMatchingByteTag(tag)) { return; } Ptr originalPacket = p->Copy(); EthernetHeader2 ethHeader; originalPacket->RemoveHeader(ethHeader); if (ethHeader.GetVid()!=1) { return; } Time arrival = Simulator::Now(); m_latency = arrival - tag.GetTimestamp(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void EthernetLatencyTestCase2::DoRun() { //Create two nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); //Create and add a netDevice to each node Ptr net0 = CreateObject(); n0->AddDevice(net0); Ptr net1 = CreateObject(); n1->AddDevice(net1); //Create a Ethernet Channel and attach it two the two netDevices Ptr channel = CreateObject(); net0->Attach(channel); net1->Attach(channel); //Allocate a Mac address and create a FIFO (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); //Application descriptions Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(m_burstSizeApp0)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetAttribute("Offset", TimeValue(NanoSeconds(m_offset0))); app0->SetAttribute("PCP", UintegerValue(m_pcpApp0)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(1)); Ptr app1 = CreateObject(); app1->Setup(net0); app1->SetAttribute("BurstSize", UintegerValue(m_burstSizeApp1)); app1->SetAttribute("PayloadSize", UintegerValue(100)); app1->SetAttribute("Period", TimeValue(Seconds(5))); app1->SetAttribute("VlanID", UintegerValue(2)); app1->SetAttribute("Offset", TimeValue(NanoSeconds(m_offset1))); app1->SetAttribute("PCP", UintegerValue(m_pcpApp1)); n0->AddApplication(app1); app1->SetStartTime(Seconds(0)); app1->SetStopTime(Seconds(1)); //Callback to trace the latency net1->TraceConnectWithoutContext("Latency", MakeCallback(&EthernetLatencyTestCase2::Latency, this)); //Execute the simulation Simulator::Stop(Seconds(1)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_latency, m_true_latency, "Packet experience the correct latency"); } /** * \ingroup ethernet-tests * Check if message crossed a ethernet switch */ class EthernetSwtichBasicTestCase : public TestCase { public: EthernetSwtichBasicTestCase(); virtual ~EthernetSwtichBasicTestCase(); private: void DoRun() override; void SendTx(Ptr p); void ReceiveRx(Ptr p); uint64_t m_sent{0}; //!< number of bytes sent uint64_t m_received{0}; //!< number of bytes received }; // Add some help text to this case to describe what it is intended to test EthernetSwtichBasicTestCase::EthernetSwtichBasicTestCase() : TestCase("Check if paquets cross an ethernet switch") { } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself EthernetSwtichBasicTestCase::~EthernetSwtichBasicTestCase() { } void EthernetSwtichBasicTestCase::SendTx(Ptr p) { m_sent += p->GetSize(); } void EthernetSwtichBasicTestCase::ReceiveRx(Ptr p) { m_received += p->GetSize(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void EthernetSwtichBasicTestCase::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); //Create and add a netDevice to each end station node Ptr net0 = CreateObject(); n0->AddDevice(net0); Ptr net1 = CreateObject(); n1->AddDevice(net1); //Create and add a netDevice to each switch port Ptr swnet0 = CreateObject(); n2->AddDevice(swnet0); Ptr swnet1 = CreateObject(); n2->AddDevice(swnet1); //Create Ethernet Channels and connect switch to the end-stations Ptr channel0 = CreateObject(); net0->Attach(channel0); swnet0->Attach(channel0); Ptr channel1 = CreateObject(); net1->Attach(channel1); swnet1->Attach(channel1); //Create and add a switch net device to the switch node Ptr sw = CreateObject(); sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10))); sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10))); n2->AddDevice(sw); sw->AddSwitchPort(swnet0); sw->AddSwitchPort(swnet1); //Allocate a Mac address and create 2 FIFOs (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); sw->SetAddress(Mac48Address::Allocate()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); //Add forwarding table sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 1, {swnet1}); //Application descriptions Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("Address", AddressValue(net1->GetAddress())); app0->SetAttribute("BurstSize", UintegerValue(10)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(2.5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetAttribute("PCP", UintegerValue(1)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(5)); //Callback to trace the message being send and received net0->TraceConnectWithoutContext("MacTx", MakeCallback(&EthernetSwtichBasicTestCase::SendTx, this)); net1->TraceConnectWithoutContext("MacRx", MakeCallback(&EthernetSwtichBasicTestCase::ReceiveRx, this)); //Execute the simulation Simulator::Stop(Seconds(10)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_sent, 2 * 10 * (1400 + 22), "10 Packets have been sent two times"); NS_TEST_ASSERT_MSG_EQ(m_sent, m_received, "All Packets sent have been received"); } /** * \ingroup ethernet-tests * Check if multicast message crossed a ethernet switch */ class EthernetSwtichMulticastTestCase : public TestCase { public: EthernetSwtichMulticastTestCase(); virtual ~EthernetSwtichMulticastTestCase(); private: void DoRun() override; void SendTx(Ptr p); void ReceiveRx(Ptr p); uint64_t m_sent{0}; //!< number of bytes sent uint64_t m_received{0}; //!< number of bytes received }; // Add some help text to this case to describe what it is intended to test EthernetSwtichMulticastTestCase::EthernetSwtichMulticastTestCase() : TestCase("Check if multicast paquets cross an ethernet switch") { } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself EthernetSwtichMulticastTestCase::~EthernetSwtichMulticastTestCase() { } void EthernetSwtichMulticastTestCase::SendTx(Ptr p) { m_sent += p->GetSize(); } void EthernetSwtichMulticastTestCase::ReceiveRx(Ptr p) { m_received += p->GetSize(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void EthernetSwtichMulticastTestCase::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); Ptr n3 = CreateObject(); //Create and add a netDevice to each end station node Ptr net0 = CreateObject(); n0->AddDevice(net0); Ptr net1 = CreateObject(); n1->AddDevice(net1); Ptr net2 = CreateObject(); n2->AddDevice(net2); //Create and add a netDevice to each switch port Ptr swnet0 = CreateObject(); n3->AddDevice(swnet0); Ptr swnet1 = CreateObject(); n3->AddDevice(swnet1); Ptr swnet2 = CreateObject(); n3->AddDevice(swnet2); //Create Ethernet Channels and connect switch to the end-stations Ptr channel0 = CreateObject(); net0->Attach(channel0); swnet0->Attach(channel0); Ptr channel1 = CreateObject(); net1->Attach(channel1); swnet1->Attach(channel1); Ptr channel2 = CreateObject(); net2->Attach(channel2); swnet2->Attach(channel2); //Create and add a switch net device to the switch node Ptr sw = CreateObject(); sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10))); sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10))); n3->AddDevice(sw); sw->AddSwitchPort(swnet0); sw->AddSwitchPort(swnet1); sw->AddSwitchPort(swnet2); //Allocate a Mac address and create 2 FIFOs (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); sw->SetAddress(Mac48Address::Allocate()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); swnet2->SetQueue(CreateObject>()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); swnet2->SetQueue(CreateObject>()); //Add forwarding table sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 1, {swnet1, swnet2}); //Application descriptions Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff"))); app0->SetAttribute("BurstSize", UintegerValue(10)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(2.5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetAttribute("PCP", UintegerValue(1)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(5)); //Callback to trace the message being send and received net0->TraceConnectWithoutContext("MacTx", MakeCallback(&EthernetSwtichMulticastTestCase::SendTx, this)); net0->TraceConnectWithoutContext("MacRx", MakeCallback(&EthernetSwtichMulticastTestCase::ReceiveRx, this)); net1->TraceConnectWithoutContext("MacRx", MakeCallback(&EthernetSwtichMulticastTestCase::ReceiveRx, this)); net2->TraceConnectWithoutContext("MacRx", MakeCallback(&EthernetSwtichMulticastTestCase::ReceiveRx, this)); //Execute the simulation Simulator::Stop(Seconds(10)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_sent, 2 * 10 * (1400 + 22), "10 Packets have been sent two times"); NS_TEST_ASSERT_MSG_EQ(m_sent * 2, m_received, "All Packets sent have been received on the two destination"); } /** * \ingroup ethernet-tests * Check if latency are correct in a ethernet switched network with one flow */ class EthernetSwitchLatencyTestCase1 : public TestCase { public: EthernetSwitchLatencyTestCase1(uint16_t burstSizeApp0, Time latency, DataRate datarate); virtual ~EthernetSwitchLatencyTestCase1(); private: void DoRun() override; void Latency(Ptr p); Time m_latency{0}; uint16_t m_burstSizeApp0; Time m_true_latency; DataRate m_datarate; }; // Add some help text to this case to describe what it is intended to test EthernetSwitchLatencyTestCase1::EthernetSwitchLatencyTestCase1(uint16_t burstSizeApp0, Time latency, DataRate datarate) : TestCase("Check if latency are correct in a ethernet switched network with one flow") { m_burstSizeApp0 = burstSizeApp0; m_true_latency = latency; m_datarate = datarate; } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself EthernetSwitchLatencyTestCase1::~EthernetSwitchLatencyTestCase1() { } void EthernetSwitchLatencyTestCase1::Latency(Ptr p) { TimestampTag tag; if (!p->FindFirstMatchingByteTag(tag)) { return; } Ptr originalPacket = p->Copy(); EthernetHeader2 ethHeader; originalPacket->RemoveHeader(ethHeader); if (ethHeader.GetVid()!=1) { return; } Time arrival = Simulator::Now(); m_latency = arrival - tag.GetTimestamp(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void EthernetSwitchLatencyTestCase1::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); //Create and add a netDevice to each end station node Ptr net0 = CreateObject(); net0->SetAttribute("DataRate", DataRateValue(m_datarate)); n0->AddDevice(net0); Ptr net1 = CreateObject(); net1->SetAttribute("DataRate", DataRateValue(m_datarate)); n1->AddDevice(net1); //Create and add a netDevice to each switch port Ptr swnet0 = CreateObject(); swnet0->SetAttribute("DataRate", DataRateValue(m_datarate)); n2->AddDevice(swnet0); Ptr swnet1 = CreateObject(); swnet1->SetAttribute("DataRate", DataRateValue(m_datarate)); n2->AddDevice(swnet1); //Create Ethernet Channels and connect switch to the end-stations Ptr channel0 = CreateObject(); net0->Attach(channel0); swnet0->Attach(channel0); Ptr channel1 = CreateObject(); net1->Attach(channel1); swnet1->Attach(channel1); //Create and add a switch net device to the switch node Ptr sw = CreateObject(); sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10))); sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10))); n2->AddDevice(sw); sw->AddSwitchPort(swnet0); sw->AddSwitchPort(swnet1); //Allocate a Mac address and create 2 FIFOs (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); sw->SetAddress(Mac48Address::Allocate()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); //Add forwarding table sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 1, {swnet1}); //Application descriptions Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(m_burstSizeApp0)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(1)); //Callback to compute the packet latency net1->TraceConnectWithoutContext("Latency", MakeCallback(&EthernetSwitchLatencyTestCase1::Latency, this)); //Execute the simulation Simulator::Stop(Seconds(2)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_latency, m_true_latency, "Packet experience the correct latency"); } /** * \ingroup ethernet-tests * Check if latency are correct in a ethernet switched network with 2 flow */ class EthernetSwitchLatencyTestCase2 : public TestCase { public: EthernetSwitchLatencyTestCase2(uint16_t burstSizeApp0, uint16_t burstSizeApp1, uint16_t offset0, uint16_t offset1, uint8_t pcpApp0, uint8_t pcpApp1, Time latency); virtual ~EthernetSwitchLatencyTestCase2(); private: void DoRun() override; void Latency(Ptr p); Time m_latency{0}; uint16_t m_burstSizeApp0; uint16_t m_burstSizeApp1; uint16_t m_offset0; uint16_t m_offset1; uint8_t m_pcpApp0; uint8_t m_pcpApp1; Time m_true_latency; }; // Add some help text to this case to describe what it is intended to test EthernetSwitchLatencyTestCase2::EthernetSwitchLatencyTestCase2(uint16_t burstSizeApp0, uint16_t burstSizeApp1, uint16_t offset0, uint16_t offset1, uint8_t pcpApp0, uint8_t pcpApp1, Time latency) : TestCase("Check if latency are correct in a ethernet switched network with two flows") { m_burstSizeApp0 = burstSizeApp0; m_burstSizeApp1 = burstSizeApp1; m_offset0 = offset0; m_offset1 = offset1; m_pcpApp0 = pcpApp0; m_pcpApp1 = pcpApp1; m_true_latency = latency; } // This destructor does nothing but we include it as a reminder that // the test case should clean up after itself EthernetSwitchLatencyTestCase2::~EthernetSwitchLatencyTestCase2() { } void EthernetSwitchLatencyTestCase2::Latency(Ptr p) { TimestampTag tag; if (!p->FindFirstMatchingByteTag(tag)) { return; } Ptr originalPacket = p->Copy(); EthernetHeader2 ethHeader; originalPacket->RemoveHeader(ethHeader); if (ethHeader.GetVid()!=1) { return; } Time arrival = Simulator::Now(); m_latency = arrival - tag.GetTimestamp(); } // // This method is the pure virtual method from class TestCase that every // TestCase must implement // void EthernetSwitchLatencyTestCase2::DoRun() { //Create four nodes Ptr n0 = CreateObject(); Ptr n1 = CreateObject(); Ptr n2 = CreateObject(); Ptr n3 = CreateObject(); //Create and add a netDevice to each end station node Ptr net0 = CreateObject(); n0->AddDevice(net0); Ptr net1 = CreateObject(); n1->AddDevice(net1); Ptr net2 = CreateObject(); n2->AddDevice(net2); //Create and add a netDevice to each switch port Ptr swnet0 = CreateObject(); n3->AddDevice(swnet0); Ptr swnet1 = CreateObject(); n3->AddDevice(swnet1); Ptr swnet2 = CreateObject(); n3->AddDevice(swnet2); //Create Ethernet Channels and connect switch to the end-stations Ptr channel0 = CreateObject(); net0->Attach(channel0); swnet0->Attach(channel0); Ptr channel1 = CreateObject(); net1->Attach(channel1); swnet1->Attach(channel1); Ptr channel2 = CreateObject(); net2->Attach(channel2); swnet2->Attach(channel2); //Create and add a switch net device to the switch node Ptr sw = CreateObject(); sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10))); sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10))); n3->AddDevice(sw); sw->AddSwitchPort(swnet0); sw->AddSwitchPort(swnet1); sw->AddSwitchPort(swnet2); //Allocate a Mac address and create 2 FIFOs (for the output port) //for each netDevice. net0->SetAddress(Mac48Address::Allocate()); net0->SetQueue(CreateObject>()); net0->SetQueue(CreateObject>()); net1->SetAddress(Mac48Address::Allocate()); net1->SetQueue(CreateObject>()); net1->SetQueue(CreateObject>()); sw->SetAddress(Mac48Address::Allocate()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); swnet2->SetQueue(CreateObject>()); swnet0->SetQueue(CreateObject>()); swnet1->SetQueue(CreateObject>()); swnet2->SetQueue(CreateObject>()); //Add forwarding table sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 1, {swnet1, swnet2}); //Application descriptions Ptr app0 = CreateObject(); app0->Setup(net0); app0->SetAttribute("BurstSize", UintegerValue(m_burstSizeApp0)); app0->SetAttribute("PayloadSize", UintegerValue(1400)); app0->SetAttribute("Period", TimeValue(Seconds(5))); app0->SetAttribute("VlanID", UintegerValue(1)); app0->SetAttribute("Offset", TimeValue(NanoSeconds(m_offset0))); app0->SetAttribute("PCP", UintegerValue(m_pcpApp0)); n0->AddApplication(app0); app0->SetStartTime(Seconds(0)); app0->SetStopTime(Seconds(1)); Ptr app1 = CreateObject(); app1->Setup(net0); app1->SetAttribute("BurstSize", UintegerValue(m_burstSizeApp1)); app1->SetAttribute("PayloadSize", UintegerValue(100)); app1->SetAttribute("Period", TimeValue(Seconds(5))); app1->SetAttribute("VlanID", UintegerValue(2)); app1->SetAttribute("Offset", TimeValue(NanoSeconds(m_offset1))); app1->SetAttribute("PCP", UintegerValue(m_pcpApp1)); n0->AddApplication(app1); app1->SetStartTime(Seconds(0)); app1->SetStopTime(Seconds(1)); //Callback to trace the message being send and received net0->TraceConnectWithoutContext("Latency", MakeCallback(&EthernetSwitchLatencyTestCase2::Latency, this)); net0->TraceConnectWithoutContext("Latency", MakeCallback(&EthernetSwitchLatencyTestCase2::Latency, this)); net1->TraceConnectWithoutContext("Latency", MakeCallback(&EthernetSwitchLatencyTestCase2::Latency, this)); net2->TraceConnectWithoutContext("Latency", MakeCallback(&EthernetSwitchLatencyTestCase2::Latency, this)); //Execute the simulation Simulator::Stop(Seconds(2)); Simulator::Run(); Simulator::Destroy(); NS_TEST_ASSERT_MSG_EQ(m_latency, m_true_latency, "Packet experience the correct latency"); } // The TestSuite class names the TestSuite, identifies what type of TestSuite, // and enables the TestCases to be run. Typically, only the constructor for // this class must be defined /** * \ingroup ethernet-tests * TestSuite for module ethernet */ class EthernetTestSuite : public TestSuite { public: EthernetTestSuite(); }; EthernetTestSuite::EthernetTestSuite() : TestSuite("ethernet", UNIT) { LogComponentEnable("EthernetTestSuite", LOG_LEVEL_ALL); //Mandatory for multi-giga (applied to all other tests ==> May cause other tests to fail) Time::SetResolution(Time::PS); //Point to point network AddTestCase(new EthernetBasicTestCase, TestCase::QUICK); //Latency test with one flow at 100Mb/s, 1Gb/s, 2.5Gb/s, 5Gb/s and 10Gb/s AddTestCase(new EthernetLatencyTestCase1(1, Time(NanoSeconds((1400 + 22 + 8) * 80 + 25)), DataRate("100Mb/s")), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase1(1, Time(NanoSeconds((1400 + 22 + 8) * 8 + 25)), DataRate("1Gb/s")), TestCase::QUICK); if(Time::GetResolution()==Time::PS){ AddTestCase(new EthernetLatencyTestCase1(1, Time(PicoSeconds(1000*((1400 + 22 + 8) * 3.2 + 25))), DataRate("2.5Gb/s")), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase1(1, Time(PicoSeconds(1000*((1400 + 22 + 8) * 1.6 + 25))), DataRate("5Gb/s")), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase1(1, Time(PicoSeconds(1000*((1400 + 22 + 8) * 0.8 + 25))), DataRate("10Gb/s")), TestCase::QUICK); } AddTestCase(new EthernetLatencyTestCase1(5, Time(PicoSeconds(1000*(((1400 + 22 + 8 + 12)*5 - 12) * 8 + 25))), DataRate("1Gb/s")), TestCase::QUICK); //Latency test with 2 flows //Flow under study have higher priority AddTestCase(new EthernetLatencyTestCase2(1,1,0,0,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(2,1,0,0,1,0, Time(NanoSeconds((1400+22+8+12 + 1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(1,2,0,0,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25))), TestCase::QUICK); //Flow under study have higher priority but a packet is already being sent AddTestCase(new EthernetLatencyTestCase2(1,1,1,0,1,0, Time(NanoSeconds((100+22+8+12 + 1400+22+8) * 8 + 25 - 1))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(2,1,1,0,1,0, Time(NanoSeconds((100+22+8+12 + 1400+22+8+12 + 1400+22+8) * 8 + 25 - 1))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(1,2,1,0,1,0, Time(NanoSeconds((100+22+8+12 + 1400+22+8) * 8 + 25 - 1))), TestCase::QUICK); //Flow under study have lower priority AddTestCase(new EthernetLatencyTestCase2(1,1,0,0,0,1, Time(NanoSeconds((100+22+8+12 + 1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(2,1,0,0,0,1, Time(NanoSeconds((100+22+8+12+ 1400+22+8+12 + 1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(1,2,0,0,0,1, Time(NanoSeconds((100+22+8+12+ 100+22+8+12 + 1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(2,2,0,1,0,1, Time(NanoSeconds((1400+22+8+12 + 100+22+8+12 + 100+22+8+12 + 1400+22+8) * 8 + 25))), TestCase::QUICK); //Flow under study is alone AddTestCase(new EthernetLatencyTestCase2(1,1,0,1,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(2,1,0,1,1,0, Time(NanoSeconds((1400+22+8+12 + 1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetLatencyTestCase2(1,2,0,1,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25))), TestCase::QUICK); //Switched network AddTestCase(new EthernetSwtichBasicTestCase, TestCase::QUICK); AddTestCase(new EthernetSwtichMulticastTestCase, TestCase::QUICK); //Latency test with one flow AddTestCase(new EthernetSwitchLatencyTestCase1(1, Time(NanoSeconds((1400+22+8) * 80 + 25 + 10000 + (1400+22+8) * 80 + 25)), DataRate("100Mb/s")), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase1(1, Time(NanoSeconds((1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25)), DataRate("1Gb/s")), TestCase::QUICK); if(Time::GetResolution()==Time::PS){ AddTestCase(new EthernetSwitchLatencyTestCase1(1, Time(PicoSeconds(1000*((1400+22+8) * 3.2 + 25 + 10000 + (1400+22+8) * 3.2 + 25))), DataRate("2.5Gb/s")), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase1(1, Time(PicoSeconds(1000*((1400+22+8) * 1.6 + 25 + 10000 + (1400+22+8) * 1.6 + 25))), DataRate("5Gb/s")), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase1(1, Time(PicoSeconds(1000*((1400+22+8) * 0.8 + 25 + 10000 + (1400+22+8) * 0.8 + 25))), DataRate("10Gb/s")), TestCase::QUICK); } AddTestCase(new EthernetSwitchLatencyTestCase1(5, Time(NanoSeconds(((1400+22+8+12)*5-12)*8 + 25 + 10000 + (1400+22+8)*8 + 25)), DataRate("1Gb/s")), TestCase::QUICK); //Latency test with 2 flows //Flow under study have higher priority AddTestCase(new EthernetSwitchLatencyTestCase2(1,1,0,0,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(2,1,0,0,1,0, Time(NanoSeconds((1400+22+8+12 + 1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(1,2,0,0,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); //Flow under study have higher priority but a packet is already being sent AddTestCase(new EthernetSwitchLatencyTestCase2(1,1,1,0,1,0, Time(NanoSeconds((100+22+8+12 + 1400+22+8) * 8 - 1 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(2,1,1,0,1,0, Time(NanoSeconds((100+22+8+12 + 1400+22+8+12 + 1400+22+8) * 8 - 1 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(1,2,1,0,1,0, Time(NanoSeconds((100+22+8+12 + 1400+22+8) * 8 - 1 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); //Flow under study have lower priority AddTestCase(new EthernetSwitchLatencyTestCase2(1,1,0,0,0,1, Time(NanoSeconds((100+22+8+12 + 1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(2,1,0,0,0,1, Time(NanoSeconds((100+22+8+12 + 1400+22+8+12 + 1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(1,2,0,0,0,1, Time(NanoSeconds((100+22+8+12 + 100+22+8+12 + 1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(2,2,0,1,0,1, Time(NanoSeconds((100+22+8+12 + 100+22+8+12 + 1400+22+8+12 + 1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); //Flow under study is alone AddTestCase(new EthernetSwitchLatencyTestCase2(1,1,0,1,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(2,1,0,1,1,0, Time(NanoSeconds((1400+22+8+12 + 1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); AddTestCase(new EthernetSwitchLatencyTestCase2(1,2,0,1,1,0, Time(NanoSeconds((1400+22+8) * 8 + 25 + 10000 + (1400+22+8) * 8 + 25))), TestCase::QUICK); } // Do not forget to allocate an instance of this TestSuite /** * \ingroup ethernet-tests * Static variable for test initialization */ static EthernetTestSuite m_ethernetTestSuite;