1037 lines
39 KiB
C++
1037 lines
39 KiB
C++
|
|
|
||
|
|
// 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<const Packet> p);
|
||
|
|
void ReceiveRx(Ptr<const Packet> 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<const Packet> p)
|
||
|
|
{
|
||
|
|
m_sent += p->GetSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
EthernetBasicTestCase::ReceiveRx(Ptr<const Packet> 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<Node> n0 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n1 = CreateObject<Node>();
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Ethernet Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
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<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
//Application description
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
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<const Packet> 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<const Packet> 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<Node> n0 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n1 = CreateObject<Node>();
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||
|
|
net0->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||
|
|
net1->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Ethernet Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
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<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
//Application description
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
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<const Packet> 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<const Packet> p)
|
||
|
|
{
|
||
|
|
TimestampTag tag;
|
||
|
|
if (!p->FindFirstMatchingByteTag(tag))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Ptr<Packet> 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<Node> n0 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n1 = CreateObject<Node>();
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Ethernet Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
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<DropTailQueue<Packet>>());
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
//Application descriptions
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
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<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||
|
|
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<const Packet> p);
|
||
|
|
void ReceiveRx(Ptr<const Packet> 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<const Packet> p)
|
||
|
|
{
|
||
|
|
m_sent += p->GetSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
EthernetSwtichBasicTestCase::ReceiveRx(Ptr<const Packet> 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<Node> n0 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n1 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n2 = CreateObject<Node>();
|
||
|
|
|
||
|
|
//Create and add a netDevice to each end station node
|
||
|
|
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create and add a netDevice to each switch port
|
||
|
|
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n2->AddDevice(swnet0);
|
||
|
|
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n2->AddDevice(swnet1);
|
||
|
|
|
||
|
|
//Create Ethernet Channels and connect switch to the end-stations
|
||
|
|
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel0);
|
||
|
|
swnet0->Attach(channel0);
|
||
|
|
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||
|
|
net1->Attach(channel1);
|
||
|
|
swnet1->Attach(channel1);
|
||
|
|
|
||
|
|
//Create and add a switch net device to the switch node
|
||
|
|
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
||
|
|
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<DropTailQueue<Packet>>());
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
sw->SetAddress(Mac48Address::Allocate());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
//Add forwarding table
|
||
|
|
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 1, {swnet1});
|
||
|
|
|
||
|
|
//Application descriptions
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
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<const Packet> p);
|
||
|
|
void ReceiveRx(Ptr<const Packet> 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<const Packet> p)
|
||
|
|
{
|
||
|
|
m_sent += p->GetSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
EthernetSwtichMulticastTestCase::ReceiveRx(Ptr<const Packet> 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<Node> n0 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n1 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n2 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n3 = CreateObject<Node>();
|
||
|
|
|
||
|
|
//Create and add a netDevice to each end station node
|
||
|
|
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
|
||
|
|
n2->AddDevice(net2);
|
||
|
|
|
||
|
|
//Create and add a netDevice to each switch port
|
||
|
|
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n3->AddDevice(swnet0);
|
||
|
|
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n3->AddDevice(swnet1);
|
||
|
|
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
|
||
|
|
n3->AddDevice(swnet2);
|
||
|
|
|
||
|
|
//Create Ethernet Channels and connect switch to the end-stations
|
||
|
|
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel0);
|
||
|
|
swnet0->Attach(channel0);
|
||
|
|
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||
|
|
net1->Attach(channel1);
|
||
|
|
swnet1->Attach(channel1);
|
||
|
|
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
|
||
|
|
net2->Attach(channel2);
|
||
|
|
swnet2->Attach(channel2);
|
||
|
|
|
||
|
|
//Create and add a switch net device to the switch node
|
||
|
|
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
||
|
|
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<DropTailQueue<Packet>>());
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
sw->SetAddress(Mac48Address::Allocate());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
//Add forwarding table
|
||
|
|
sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 1, {swnet1, swnet2});
|
||
|
|
|
||
|
|
//Application descriptions
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
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<const Packet> 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<const Packet> p)
|
||
|
|
{
|
||
|
|
TimestampTag tag;
|
||
|
|
if (!p->FindFirstMatchingByteTag(tag))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Ptr<Packet> 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<Node> n0 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n1 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n2 = CreateObject<Node>();
|
||
|
|
|
||
|
|
//Create and add a netDevice to each end station node
|
||
|
|
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||
|
|
net0->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||
|
|
net1->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create and add a netDevice to each switch port
|
||
|
|
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||
|
|
swnet0->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n2->AddDevice(swnet0);
|
||
|
|
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||
|
|
swnet1->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n2->AddDevice(swnet1);
|
||
|
|
|
||
|
|
//Create Ethernet Channels and connect switch to the end-stations
|
||
|
|
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel0);
|
||
|
|
swnet0->Attach(channel0);
|
||
|
|
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||
|
|
net1->Attach(channel1);
|
||
|
|
swnet1->Attach(channel1);
|
||
|
|
|
||
|
|
//Create and add a switch net device to the switch node
|
||
|
|
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
||
|
|
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<DropTailQueue<Packet>>());
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
sw->SetAddress(Mac48Address::Allocate());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
//Add forwarding table
|
||
|
|
sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 1, {swnet1});
|
||
|
|
|
||
|
|
//Application descriptions
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
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<const Packet> 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<const Packet> p)
|
||
|
|
{
|
||
|
|
TimestampTag tag;
|
||
|
|
if (!p->FindFirstMatchingByteTag(tag))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Ptr<Packet> 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<Node> n0 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n1 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n2 = CreateObject<Node>();
|
||
|
|
Ptr<Node> n3 = CreateObject<Node>();
|
||
|
|
|
||
|
|
//Create and add a netDevice to each end station node
|
||
|
|
Ptr<EthernetNetDevice> net0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<EthernetNetDevice> net1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
Ptr<EthernetNetDevice> net2 = CreateObject<EthernetNetDevice>();
|
||
|
|
n2->AddDevice(net2);
|
||
|
|
|
||
|
|
//Create and add a netDevice to each switch port
|
||
|
|
Ptr<EthernetNetDevice> swnet0 = CreateObject<EthernetNetDevice>();
|
||
|
|
n3->AddDevice(swnet0);
|
||
|
|
Ptr<EthernetNetDevice> swnet1 = CreateObject<EthernetNetDevice>();
|
||
|
|
n3->AddDevice(swnet1);
|
||
|
|
Ptr<EthernetNetDevice> swnet2 = CreateObject<EthernetNetDevice>();
|
||
|
|
n3->AddDevice(swnet2);
|
||
|
|
|
||
|
|
//Create Ethernet Channels and connect switch to the end-stations
|
||
|
|
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel0);
|
||
|
|
swnet0->Attach(channel0);
|
||
|
|
Ptr<EthernetChannel> channel1 = CreateObject<EthernetChannel>();
|
||
|
|
net1->Attach(channel1);
|
||
|
|
swnet1->Attach(channel1);
|
||
|
|
Ptr<EthernetChannel> channel2 = CreateObject<EthernetChannel>();
|
||
|
|
net2->Attach(channel2);
|
||
|
|
swnet2->Attach(channel2);
|
||
|
|
|
||
|
|
//Create and add a switch net device to the switch node
|
||
|
|
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
||
|
|
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<DropTailQueue<Packet>>());
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
sw->SetAddress(Mac48Address::Allocate());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
swnet2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
//Add forwarding table
|
||
|
|
sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 1, {swnet1, swnet2});
|
||
|
|
|
||
|
|
//Application descriptions
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
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<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||
|
|
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;
|