716 lines
23 KiB
C++
716 lines
23 KiB
C++
|
|
// Include a header file from your module to test.
|
||
|
|
#include "ns3/tsn-net-device.h"
|
||
|
|
#include "ns3/tas.h"
|
||
|
|
#include "ns3/cbs.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("TasTestSuite");
|
||
|
|
// Add a doxygen group for tests.
|
||
|
|
// If you have more than one test, this should be in only one of them.
|
||
|
|
/**
|
||
|
|
* \defgroup Tas-tests Tests for tas
|
||
|
|
* \ingroup tsn
|
||
|
|
* \ingroup tests
|
||
|
|
*/
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* \ingroup Tas-tests
|
||
|
|
* Check if message crossed a point to point tsn channel with a TAS
|
||
|
|
*/
|
||
|
|
class TasBasicTestCase : public TestCase
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
TasBasicTestCase(uint64_t pktSize, uint64_t expected_receive, uint8_t pcp);
|
||
|
|
virtual ~TasBasicTestCase();
|
||
|
|
|
||
|
|
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
|
||
|
|
uint64_t m_pktSize;
|
||
|
|
uint64_t m_expected_receive;
|
||
|
|
uint8_t m_pcp;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Add some help text to this case to describe what it is intended to test
|
||
|
|
TasBasicTestCase::TasBasicTestCase(uint64_t pktSize, uint64_t expected_receive, uint8_t pcp)
|
||
|
|
: TestCase("Check if paquets cross a point to point ethernet channel, tsn net device and a TAS")
|
||
|
|
{
|
||
|
|
m_pktSize = pktSize;
|
||
|
|
m_expected_receive = expected_receive;
|
||
|
|
m_pcp = pcp;
|
||
|
|
}
|
||
|
|
|
||
|
|
// This destructor does nothing but we include it as a reminder that
|
||
|
|
// the test case should clean up after itself
|
||
|
|
TasBasicTestCase::~TasBasicTestCase()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TasBasicTestCase::SendTx(Ptr<const Packet> p)
|
||
|
|
{
|
||
|
|
m_sent += p->GetSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TasBasicTestCase::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
|
||
|
|
TasBasicTestCase::DoRun()
|
||
|
|
{
|
||
|
|
//Create two nodes
|
||
|
|
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||
|
|
|
||
|
|
//Add perfect clock on each node
|
||
|
|
n0->AddClock(CreateObject<Clock>());
|
||
|
|
n1->AddClock(CreateObject<Clock>());
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Tsn Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel);
|
||
|
|
net1->Attach(channel);
|
||
|
|
|
||
|
|
//Allocate a Mac address for each netDevice.
|
||
|
|
net0->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
|
||
|
|
//Create and add 8 FIFOs per net device
|
||
|
|
for (int i=0; i<8; i++)
|
||
|
|
{
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
}
|
||
|
|
|
||
|
|
//Add two GCL entry on net0 and start TAS
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(10)), 0);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(10)), 32);
|
||
|
|
net0->StartTas();
|
||
|
|
|
||
|
|
|
||
|
|
//Application description
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
app0->Setup(net0);
|
||
|
|
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PayloadSize", UintegerValue(m_pktSize));
|
||
|
|
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||
|
|
app0->SetAttribute("VlanID", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PCP", UintegerValue(m_pcp));
|
||
|
|
n0->AddApplication(app0);
|
||
|
|
app0->SetStartTime(Seconds(0));
|
||
|
|
app0->SetStopTime(Seconds(5));
|
||
|
|
|
||
|
|
|
||
|
|
//Callback to trace the message being send and received
|
||
|
|
net0->TraceConnectWithoutContext("MacTx",
|
||
|
|
MakeCallback(&TasBasicTestCase::SendTx, this));
|
||
|
|
net1->TraceConnectWithoutContext("MacRx",
|
||
|
|
MakeCallback(&TasBasicTestCase::ReceiveRx, this));
|
||
|
|
|
||
|
|
//Execute the simulation
|
||
|
|
Simulator::Stop(Seconds(5));
|
||
|
|
Simulator::Run();
|
||
|
|
Simulator::Destroy();
|
||
|
|
|
||
|
|
NS_TEST_ASSERT_MSG_EQ(m_sent, m_pktSize+22, "All Packets have been sent");
|
||
|
|
NS_TEST_ASSERT_MSG_EQ(m_received, m_expected_receive, "All Packets have been received");
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* \ingroup Tas-tests
|
||
|
|
* Check if message crossed a point to point tsn channel with a TAS according to guard band
|
||
|
|
*/
|
||
|
|
class TasGuardBandTestCase : public TestCase
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
TasGuardBandTestCase(uint64_t pktSize, uint64_t expected_receive, Tas::GuardBandModes guardBandMode);
|
||
|
|
virtual ~TasGuardBandTestCase();
|
||
|
|
|
||
|
|
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
|
||
|
|
uint64_t m_pktSize;
|
||
|
|
uint64_t m_expected_receive;
|
||
|
|
Tas::GuardBandModes m_guardBandMode;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Add some help text to this case to describe what it is intended to test
|
||
|
|
TasGuardBandTestCase::TasGuardBandTestCase(uint64_t pktSize, uint64_t expected_receive, Tas::GuardBandModes guardBandMode)
|
||
|
|
: TestCase("Check if paquets cross a point to point ethernet channel, tsn net device and a TAS according to guard band mode")
|
||
|
|
{
|
||
|
|
m_pktSize = pktSize;
|
||
|
|
m_expected_receive = expected_receive;
|
||
|
|
m_guardBandMode = guardBandMode;
|
||
|
|
}
|
||
|
|
|
||
|
|
// This destructor does nothing but we include it as a reminder that
|
||
|
|
// the test case should clean up after itself
|
||
|
|
TasGuardBandTestCase::~TasGuardBandTestCase()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TasGuardBandTestCase::SendTx(Ptr<const Packet> p)
|
||
|
|
{
|
||
|
|
m_sent += p->GetSize();
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
TasGuardBandTestCase::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
|
||
|
|
TasGuardBandTestCase::DoRun()
|
||
|
|
{
|
||
|
|
//Create two nodes
|
||
|
|
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||
|
|
|
||
|
|
//Add perfect clock on each node
|
||
|
|
n0->AddClock(CreateObject<Clock>());
|
||
|
|
n1->AddClock(CreateObject<Clock>());
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Tsn Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel);
|
||
|
|
net1->Attach(channel);
|
||
|
|
|
||
|
|
//Allocate a Mac address for each netDevice.
|
||
|
|
net0->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
|
||
|
|
//Create and add 8 FIFOs per net device
|
||
|
|
for (int i=0; i<8; i++)
|
||
|
|
{
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
}
|
||
|
|
|
||
|
|
//Add two GCL entry on net0 and start TAS
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(10)), 0);
|
||
|
|
net0->AddGclEntry(Time(NanoSeconds(4336)), 32);
|
||
|
|
net0->StartTas();
|
||
|
|
|
||
|
|
//Set Tas Guard Band Mode
|
||
|
|
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(m_guardBandMode));
|
||
|
|
|
||
|
|
//Application description
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
app0->Setup(net0);
|
||
|
|
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PayloadSize", UintegerValue(m_pktSize));
|
||
|
|
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||
|
|
app0->SetAttribute("VlanID", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PCP", UintegerValue(5));
|
||
|
|
n0->AddApplication(app0);
|
||
|
|
app0->SetStartTime(Seconds(0));
|
||
|
|
app0->SetStopTime(Seconds(5));
|
||
|
|
|
||
|
|
|
||
|
|
//Callback to trace the message being send and received
|
||
|
|
net0->TraceConnectWithoutContext("MacTx",
|
||
|
|
MakeCallback(&TasGuardBandTestCase::SendTx, this));
|
||
|
|
net1->TraceConnectWithoutContext("MacRx",
|
||
|
|
MakeCallback(&TasGuardBandTestCase::ReceiveRx, this));
|
||
|
|
|
||
|
|
//Execute the simulation
|
||
|
|
Simulator::Stop(Seconds(5));
|
||
|
|
Simulator::Run();
|
||
|
|
Simulator::Destroy();
|
||
|
|
|
||
|
|
NS_TEST_ASSERT_MSG_EQ(m_sent, m_pktSize+22, "All Packets have been sent");
|
||
|
|
NS_TEST_ASSERT_MSG_EQ(m_received, m_expected_receive, "All Packets have been received");
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* \ingroup Tas-tests
|
||
|
|
* Check last message latency that crossed a point to point tsn channel with a TAS
|
||
|
|
*/
|
||
|
|
class TasLatencyTestCase : public TestCase
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
TasLatencyTestCase(uint64_t pktSize, uint64_t pcp, uint64_t offset, Time expected_latency, DataRate datarate);
|
||
|
|
virtual ~TasLatencyTestCase();
|
||
|
|
|
||
|
|
private:
|
||
|
|
void DoRun() override;
|
||
|
|
void Latency(Ptr<const Packet> p);
|
||
|
|
uint64_t m_pktSize;
|
||
|
|
uint64_t m_pcp;
|
||
|
|
uint64_t m_offset;
|
||
|
|
Time m_expected_latency;
|
||
|
|
Time m_latency = Time(0);
|
||
|
|
DataRate m_datarate;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Add some help text to this case to describe what it is intended to test
|
||
|
|
TasLatencyTestCase::TasLatencyTestCase(uint64_t pktSize, uint64_t pcp, uint64_t offset, Time expected_latency, DataRate datarate)
|
||
|
|
: TestCase("Check last message latency that crossed a point to point tsn channel with a TAS")
|
||
|
|
{
|
||
|
|
m_pktSize = pktSize;
|
||
|
|
m_pcp = pcp;
|
||
|
|
m_offset = offset;
|
||
|
|
m_expected_latency = expected_latency;
|
||
|
|
m_datarate = datarate;
|
||
|
|
}
|
||
|
|
|
||
|
|
// This destructor does nothing but we include it as a reminder that
|
||
|
|
// the test case should clean up after itself
|
||
|
|
TasLatencyTestCase::~TasLatencyTestCase()
|
||
|
|
{}
|
||
|
|
|
||
|
|
void
|
||
|
|
TasLatencyTestCase::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
|
||
|
|
TasLatencyTestCase::DoRun()
|
||
|
|
{
|
||
|
|
//Create two nodes
|
||
|
|
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||
|
|
|
||
|
|
//Add perfect clock on each node
|
||
|
|
n0->AddClock(CreateObject<Clock>());
|
||
|
|
n1->AddClock(CreateObject<Clock>());
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||
|
|
net0->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||
|
|
net1->SetAttribute("DataRate", DataRateValue(m_datarate));
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Tsn Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel);
|
||
|
|
net1->Attach(channel);
|
||
|
|
|
||
|
|
//Allocate a Mac address for each netDevice.
|
||
|
|
net0->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
|
||
|
|
//Create and add 8 FIFOs per net device
|
||
|
|
for (int i=0; i<8; i++)
|
||
|
|
{
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
}
|
||
|
|
|
||
|
|
//Add two GCL entry on net0 and start TAS
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(10)), 0);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(10)), 1);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(5)), 32);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(5)), 16);
|
||
|
|
net0->StartTas();
|
||
|
|
|
||
|
|
//Application description
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
app0->Setup(net0);
|
||
|
|
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PayloadSize", UintegerValue(m_pktSize));
|
||
|
|
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||
|
|
app0->SetAttribute("VlanID", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PCP", UintegerValue(m_pcp));
|
||
|
|
app0->SetAttribute("Offset", TimeValue(NanoSeconds(m_offset)));
|
||
|
|
n0->AddApplication(app0);
|
||
|
|
app0->SetStartTime(Seconds(0));
|
||
|
|
app0->SetStopTime(Seconds(5));
|
||
|
|
|
||
|
|
//Callback to trace the message latency
|
||
|
|
net1->TraceConnectWithoutContext("Latency", MakeCallback(&TasLatencyTestCase::Latency, this));
|
||
|
|
|
||
|
|
//Execute the simulation
|
||
|
|
Simulator::Stop(Seconds(5));
|
||
|
|
Simulator::Run();
|
||
|
|
Simulator::Destroy();
|
||
|
|
|
||
|
|
NS_TEST_ASSERT_MSG_EQ(m_latency, m_expected_latency, "Packet experience the expected latency");
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* \ingroup Tas-tests
|
||
|
|
* Check last vlan1 message latency that crossed a point to point tsn channel with a TAS with
|
||
|
|
* mulitple gate open at the same time
|
||
|
|
*/
|
||
|
|
class TasLatencyTestCase2 : public TestCase
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
TasLatencyTestCase2(uint64_t pcp1, uint64_t pcp2, uint64_t offset1, uint64_t offset2, int64_t expected_latency);
|
||
|
|
virtual ~TasLatencyTestCase2();
|
||
|
|
|
||
|
|
private:
|
||
|
|
void DoRun() override;
|
||
|
|
void Latency(Ptr<const Packet> p);
|
||
|
|
uint64_t m_pcp1;
|
||
|
|
uint64_t m_pcp2;
|
||
|
|
uint64_t m_offset1;
|
||
|
|
uint64_t m_offset2;
|
||
|
|
int64_t m_expected_latency;
|
||
|
|
Time m_latency = Time(0);
|
||
|
|
};
|
||
|
|
|
||
|
|
// Add some help text to this case to describe what it is intended to test
|
||
|
|
TasLatencyTestCase2::TasLatencyTestCase2(uint64_t pcp1, uint64_t pcp2, uint64_t offset1, uint64_t offset2, int64_t expected_latency)
|
||
|
|
: TestCase("Check last vlan1 message latency that crossed a point to point tsn channel with a TAS with flow at the same time")
|
||
|
|
{
|
||
|
|
m_pcp1 = pcp1;
|
||
|
|
m_pcp2 = pcp2;
|
||
|
|
m_offset1 = offset1;
|
||
|
|
m_offset2 = offset2;
|
||
|
|
m_expected_latency = expected_latency;
|
||
|
|
}
|
||
|
|
|
||
|
|
// This destructor does nothing but we include it as a reminder that
|
||
|
|
// the test case should clean up after itself
|
||
|
|
TasLatencyTestCase2::~TasLatencyTestCase2()
|
||
|
|
{}
|
||
|
|
|
||
|
|
void
|
||
|
|
TasLatencyTestCase2::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
|
||
|
|
TasLatencyTestCase2::DoRun()
|
||
|
|
{
|
||
|
|
//Create two nodes
|
||
|
|
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||
|
|
|
||
|
|
//Add perfect clock on each node
|
||
|
|
n0->AddClock(CreateObject<Clock>());
|
||
|
|
n1->AddClock(CreateObject<Clock>());
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Tsn Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel);
|
||
|
|
net1->Attach(channel);
|
||
|
|
|
||
|
|
//Allocate a Mac address for each netDevice.
|
||
|
|
net0->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
|
||
|
|
//Create and add 8 FIFOs per net device
|
||
|
|
for (int i=0; i<8; i++)
|
||
|
|
{
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
}
|
||
|
|
|
||
|
|
//Add two GCL entry on net0 and start TAS
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(10)), 32);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(10)), 0);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(5)), 8);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(5)), 5);
|
||
|
|
net0->StartTas();
|
||
|
|
|
||
|
|
//Application description
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
app0->Setup(net0);
|
||
|
|
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PayloadSize", UintegerValue(500));
|
||
|
|
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||
|
|
app0->SetAttribute("VlanID", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PCP", UintegerValue(m_pcp2));
|
||
|
|
app0->SetAttribute("Offset", TimeValue(NanoSeconds(m_offset1)));
|
||
|
|
n0->AddApplication(app0);
|
||
|
|
app0->SetStartTime(Seconds(0));
|
||
|
|
app0->SetStopTime(MilliSeconds(30));
|
||
|
|
|
||
|
|
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||
|
|
app1->Setup(net0);
|
||
|
|
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||
|
|
app1->SetAttribute("PayloadSize", UintegerValue(1000));
|
||
|
|
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||
|
|
app1->SetAttribute("VlanID", UintegerValue(2));
|
||
|
|
app1->SetAttribute("PCP", UintegerValue(m_pcp2));
|
||
|
|
app1->SetAttribute("Offset", TimeValue(NanoSeconds(m_offset2)));
|
||
|
|
n0->AddApplication(app1);
|
||
|
|
app1->SetStartTime(Seconds(0));
|
||
|
|
app1->SetStopTime(MilliSeconds(30));
|
||
|
|
|
||
|
|
//Callback to trace the message latency
|
||
|
|
net1->TraceConnectWithoutContext("Latency", MakeCallback(&TasLatencyTestCase2::Latency, this));
|
||
|
|
|
||
|
|
//Execute the simulation
|
||
|
|
Simulator::Stop(MilliSeconds(40));
|
||
|
|
Simulator::Run();
|
||
|
|
Simulator::Destroy();
|
||
|
|
|
||
|
|
NS_TEST_ASSERT_MSG_EQ(m_latency.GetNanoSeconds(), m_expected_latency, "Packet experience the expected latency");
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* \ingroup Tas-tests
|
||
|
|
* Check last message latency that crossed a point to point tsn channel with a TAS
|
||
|
|
*/
|
||
|
|
class TasCbsLatencyTestCase : public TestCase
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
TasCbsLatencyTestCase(int64_t expected_latency);
|
||
|
|
virtual ~TasCbsLatencyTestCase();
|
||
|
|
|
||
|
|
private:
|
||
|
|
void DoRun() override;
|
||
|
|
void Latency(Ptr<const Packet> p);
|
||
|
|
int64_t m_expected_latency;
|
||
|
|
Time m_latency = Time(0);
|
||
|
|
};
|
||
|
|
|
||
|
|
// Add some help text to this case to describe what it is intended to test
|
||
|
|
TasCbsLatencyTestCase::TasCbsLatencyTestCase(int64_t expected_latency)
|
||
|
|
: TestCase("Check last message latency that crossed a point to point tsn channel with a TAS and CBS")
|
||
|
|
{
|
||
|
|
m_expected_latency = expected_latency;
|
||
|
|
}
|
||
|
|
|
||
|
|
// This destructor does nothing but we include it as a reminder that
|
||
|
|
// the test case should clean up after itself
|
||
|
|
TasCbsLatencyTestCase::~TasCbsLatencyTestCase()
|
||
|
|
{}
|
||
|
|
|
||
|
|
void
|
||
|
|
TasCbsLatencyTestCase::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
|
||
|
|
TasCbsLatencyTestCase::DoRun()
|
||
|
|
{
|
||
|
|
//Create two nodes
|
||
|
|
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||
|
|
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||
|
|
|
||
|
|
//Add perfect clock on each node
|
||
|
|
n0->AddClock(CreateObject<Clock>());
|
||
|
|
n1->AddClock(CreateObject<Clock>());
|
||
|
|
|
||
|
|
//Create and add a netDevice to each node
|
||
|
|
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||
|
|
n0->AddDevice(net0);
|
||
|
|
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||
|
|
n1->AddDevice(net1);
|
||
|
|
|
||
|
|
//Create a Tsn Channel and attach it two the two netDevices
|
||
|
|
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||
|
|
net0->Attach(channel);
|
||
|
|
net1->Attach(channel);
|
||
|
|
|
||
|
|
//Allocate a Mac address for each netDevice.
|
||
|
|
net0->SetAddress(Mac48Address::Allocate());
|
||
|
|
net1->SetAddress(Mac48Address::Allocate());
|
||
|
|
|
||
|
|
//Create and add 8 FIFOs per net device
|
||
|
|
for (int i=0; i<7; i++)
|
||
|
|
{
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
}
|
||
|
|
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||
|
|
cbs->SetTsnNetDevice(net0);
|
||
|
|
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("5Mb/s")));
|
||
|
|
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("1Gb/s")));
|
||
|
|
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||
|
|
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||
|
|
|
||
|
|
|
||
|
|
//Add two GCL entry on net0 and start TAS
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(3)), 128);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(17)), 0);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(3)), 128);
|
||
|
|
net0->AddGclEntry(Time(MilliSeconds(7)), 0);
|
||
|
|
net0->StartTas();
|
||
|
|
|
||
|
|
//Application description
|
||
|
|
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||
|
|
app0->Setup(net0);
|
||
|
|
app0->SetAttribute("BurstSize", UintegerValue(3));
|
||
|
|
app0->SetAttribute("PayloadSize", UintegerValue(1378));
|
||
|
|
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||
|
|
app0->SetAttribute("VlanID", UintegerValue(1));
|
||
|
|
app0->SetAttribute("PCP", UintegerValue(7));
|
||
|
|
n0->AddApplication(app0);
|
||
|
|
app0->SetStartTime(Seconds(0));
|
||
|
|
app0->SetStopTime(MilliSeconds(3));
|
||
|
|
|
||
|
|
//Callback to trace the message latency
|
||
|
|
net1->TraceConnectWithoutContext("Latency", MakeCallback(&TasCbsLatencyTestCase::Latency, this));
|
||
|
|
|
||
|
|
//Execute the simulation
|
||
|
|
Simulator::Stop(Seconds(5));
|
||
|
|
Simulator::Run();
|
||
|
|
Simulator::Destroy();
|
||
|
|
|
||
|
|
NS_TEST_ASSERT_MSG_EQ(m_latency.GetNanoSeconds(), m_expected_latency, "Packet experience the expected 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 tas-tests
|
||
|
|
* TestSuite for module tas
|
||
|
|
*/
|
||
|
|
class TasTestSuite : public TestSuite
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
TasTestSuite();
|
||
|
|
};
|
||
|
|
|
||
|
|
TasTestSuite::TasTestSuite()
|
||
|
|
: TestSuite("tas", UNIT)
|
||
|
|
{
|
||
|
|
LogComponentEnable("TasTestSuite", LOG_LEVEL_ALL);
|
||
|
|
LogComponentEnable("Tas", LOG_LEVEL_ALL);
|
||
|
|
//Point to point network with tas
|
||
|
|
uint64_t pktSize = 500;
|
||
|
|
//Pkt crossed the link with TAS
|
||
|
|
AddTestCase(new TasBasicTestCase(pktSize, pktSize + 22, 5), TestCase::QUICK);
|
||
|
|
AddTestCase(new TasBasicTestCase(pktSize, 0, 4), TestCase::QUICK);
|
||
|
|
|
||
|
|
//Pkt crossed the link with TAS or not according to GuardBandMode
|
||
|
|
AddTestCase(new TasGuardBandTestCase(pktSize, 0, Tas::MTU), TestCase::QUICK);
|
||
|
|
AddTestCase(new TasGuardBandTestCase(pktSize, pktSize + 22, Tas::PKTSIZE), TestCase::QUICK);
|
||
|
|
|
||
|
|
//Latency
|
||
|
|
//Pkt ready before gate open
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 5, 0, Time(NanoSeconds(20*pow(10,6) + (pktSize + 22 + 8)*8 +25)), DataRate("1Gb/s")), TestCase::QUICK);
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 5, 18*pow(10,6), Time(NanoSeconds(2*pow(10,6) + (pktSize + 22 + 8)*8 +25)), DataRate("1Gb/s")), TestCase::QUICK);
|
||
|
|
//Pkt ready when gate open
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 5, 20*pow(10,6), Time(NanoSeconds((pktSize + 22 + 8)*8 +25)), DataRate("1Gb/s")), TestCase::QUICK);
|
||
|
|
//Pkt ready after gate open
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 5, 22*pow(10,6), Time(NanoSeconds((pktSize + 22 + 8)*8 +25)), DataRate("1Gb/s")), TestCase::QUICK);
|
||
|
|
//Pkt never transmitted because his gate never open
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 7, 0, Time(NanoSeconds(0)), DataRate("1Gb/s")), TestCase::QUICK);
|
||
|
|
//MultiGig
|
||
|
|
if(Time::GetResolution()==Time::PS){
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 5, 25*pow(10,6) - 1500*3.2, Time(NanoSeconds((pktSize + 22 + 8)*3.2 +25)), DataRate("2.5Gb/s")), TestCase::QUICK); //Send at window closing - MTU duration
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 5, 25*pow(10,6) - 1500*1.6, Time(NanoSeconds((pktSize + 22 + 8)*1.6 +25)), DataRate("5Gb/s")), TestCase::QUICK); //Send at window closing - MTU duration
|
||
|
|
AddTestCase(new TasLatencyTestCase(pktSize, 5, 25*pow(10,6) - 1500*0.8, Time(NanoSeconds((pktSize + 22 + 8)*0.8 +25)), DataRate("10Gb/s")), TestCase::QUICK); //Send at window closing - MTU duration
|
||
|
|
}
|
||
|
|
|
||
|
|
//Latency TAS with two flow on same gate
|
||
|
|
AddTestCase(new TasLatencyTestCase2(5, 5, 1, 0, (1000 + 22 + 8 + 12 + 500 + 22 +8)*8+ 25 - 1), TestCase::QUICK);
|
||
|
|
AddTestCase(new TasLatencyTestCase2(5, 5, 0, 0, (500 + 22 +8)*8+ 25), TestCase::QUICK);
|
||
|
|
AddTestCase(new TasLatencyTestCase2(5, 5, 0, 1, (500 + 22 +8)*8+ 25), TestCase::QUICK);
|
||
|
|
//Latency TAS with multiple gate open at the same time
|
||
|
|
AddTestCase(new TasLatencyTestCase2(2, 0, 0, 0, 25*pow(10,6) + (500 + 22 +8)*8+ 25), TestCase::QUICK);
|
||
|
|
AddTestCase(new TasLatencyTestCase2(2, 0, 25*pow(10,6)+1, 0, (1000 + 22 + 8 + 12 + 500 + 22 +8)*8+ 25 -1), TestCase::QUICK);
|
||
|
|
|
||
|
|
|
||
|
|
//Latency TAS + CBS
|
||
|
|
//the last pkt need to wait the second gate opening to be transmitted
|
||
|
|
AddTestCase(new TasCbsLatencyTestCase(21555289), TestCase::QUICK);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Do not forget to allocate an instance of this TestSuite
|
||
|
|
/**
|
||
|
|
* \ingroup tas-tests
|
||
|
|
* Static variable for test initialization
|
||
|
|
*/
|
||
|
|
static TasTestSuite m_tasTestSuite;
|