Update README and add contrib dir

This commit is contained in:
2025-12-01 15:56:02 +01:00
parent 1b80de2153
commit cd9ba93d58
150 changed files with 25563 additions and 0 deletions

View File

@@ -0,0 +1,283 @@
// Include a header file from your module to test.
#include "ns3/tsn-net-device.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("CbsTestSuite");
// Add a doxygen group for tests.
// If you have more than one test, this should be in only one of them.
/**
* \defgroup cbs-tests Tests for cbs
* \ingroup tsn
* \ingroup tests
*/
/**
* \ingroup Cbs-tests
* Check if message crossed a point to point tsn channel
*/
class CbsBasicTestCase : public TestCase
{
public:
CbsBasicTestCase();
virtual ~CbsBasicTestCase();
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
CbsBasicTestCase::CbsBasicTestCase()
: TestCase("Check if paquets cross a point to point ethernet channel, tsn net device and a CBS")
{
}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
CbsBasicTestCase::~CbsBasicTestCase()
{
}
void
CbsBasicTestCase::SendTx(Ptr<const Packet> p)
{
m_sent += p->GetSize();
}
void
CbsBasicTestCase::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
CbsBasicTestCase::DoRun()
{
//Create two nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
//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 CBS and add FIFOs
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>>());
//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));
app0->SetAttribute("PCP", UintegerValue(0));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
//Callback to trace the message being send and received
net0->TraceConnectWithoutContext("MacTx",
MakeCallback(&CbsBasicTestCase::SendTx, this));
net1->TraceConnectWithoutContext("MacRx",
MakeCallback(&CbsBasicTestCase::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 Cbs-tests
* Check last message latency with a point to point network
*/
class CbsLatencyTestCase : public TestCase
{
public:
CbsLatencyTestCase(uint16_t burstSize, Time latency, DataRate datarate);
virtual ~CbsLatencyTestCase();
private:
void DoRun() override;
void Latency(Ptr<const Packet> p);
uint16_t m_burstSize;
Time m_true_latency;
Time m_latency;
DataRate m_datarate;
};
CbsLatencyTestCase::CbsLatencyTestCase(uint16_t burstSize, Time latency, DataRate datarate)
: TestCase("Check last message latency with a point to point network with CBS")
{
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
CbsLatencyTestCase::~CbsLatencyTestCase()
{
}
void
CbsLatencyTestCase::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
CbsLatencyTestCase::DoRun()
{
//Create two nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
//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 CBS and add FIFOs
Ptr<Cbs> cbs = CreateObject<Cbs>();
cbs->SetTsnNetDevice(net0);
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("5Mb/s")));
cbs->SetAttribute("portTransmitRate", DataRateValue(m_datarate));
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
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));
app0->SetAttribute("PCP", UintegerValue(0));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(1));
//Callback to trace the latency
net1->TraceConnectWithoutContext("Latency",
MakeCallback(&CbsLatencyTestCase::Latency, this));
//Execute the simulation
Simulator::Stop(Seconds(12));
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 cbs-tests
* TestSuite for module cbs
*/
class CbsTestSuite : public TestSuite
{
public:
CbsTestSuite();
};
CbsTestSuite::CbsTestSuite()
: TestSuite("cbs", UNIT)
{
LogComponentEnable("CbsTestSuite", LOG_LEVEL_ALL);
LogComponentEnable("Cbs", LOG_LEVEL_ALL);
//Point to point network with cbs
AddTestCase(new CbsBasicTestCase, TestCase::QUICK);
AddTestCase(new CbsLatencyTestCase(1, Time(NanoSeconds((1400 + 22 + 8)*8 +25)), DataRate("1Gb/s")), TestCase::QUICK);
AddTestCase(new CbsLatencyTestCase(2, Time(NanoSeconds(2307200 + (1400 + 22 + 8)*8 + 25)), DataRate("1Gb/s")), TestCase::QUICK); //2307200 is the time needed to restore the credit after an emission
AddTestCase(new CbsLatencyTestCase(3, Time(NanoSeconds(2307200*2 + (1400 + 22 + 8)*8 + 25)), DataRate("1Gb/s")), TestCase::QUICK);
AddTestCase(new CbsLatencyTestCase(10, Time(NanoSeconds(2307200*9 + (1400 + 22 + 8)*8 + 25)), DataRate("1Gb/s")), TestCase::QUICK);
if(Time::GetResolution()==Time::PS){
AddTestCase(new CbsLatencyTestCase(2, Time(NanoSeconds(2307200 + (1400 + 22 + 8)*3.2 + 25)), DataRate("2.5Gb/s")), TestCase::QUICK);
AddTestCase(new CbsLatencyTestCase(2, Time(NanoSeconds(2307200 + (1400 + 22 + 8)*1.6 + 25)), DataRate("5Gb/s")), TestCase::QUICK);
AddTestCase(new CbsLatencyTestCase(2, Time(NanoSeconds(2307200 + (1400 + 22 + 8)*0.8 + 25)), DataRate("10Gb/s")), TestCase::QUICK);
}
}
// Do not forget to allocate an instance of this TestSuite
/**
* \ingroup cbs-tests
* Static variable for test initialization
*/
static CbsTestSuite m_cbsTestSuite;

View File

@@ -0,0 +1,43 @@
#! /usr/bin/env python3
# A list of C++ examples to run in order to ensure that they remain
# buildable and runnable over time. Each tuple in the list contains
#
# (example_name, do_run, do_valgrind_run).
#
# See test.py for more information.
cpp_examples = [
("tsn-point2point", "True", "True"),
("tsn-point2point-withCBS", "True", "True"),
("tsn-point2point-withTAS", "True", "True"),
("tsn-point2point-withTAS-CBS", "True", "True"),
("tsn-point2point-withTAS-GuardBand --none", "True", "True"),
("tsn-point2point-withTAS-GuardBand --mtu", "True", "True"),
("tsn-point2point-withTAS-GuardBand --pktsize", "True", "True"),
("tsn-point2point-withTAS-gPTP", "True", "True"),
("tsn-point2point-withPSFP-MaxSDUSizeFilter", "True", "True"),
("tsn-point2point-withPSFP-FlowMeter", "True", "True"),
("tsn-switched-withFRER", "True", "True"),
("tsn-switched-withFRER-recoveryAlgo --match", "True", "True"),
("tsn-switched-withFRER-recoveryAlgo --vector", "True", "True"),
("tsn-switched-withFRER-activeSid", "True", "True"),
("tsn-switched-withFRERonES-integratedSW", "True", "True"),
("tsn-switched-withFRERonES-aggregation", "True", "True"),
("tsn-point2point-withGPTP", "True", "True"),
("tsn-point2point-withGPTP-Multidomain", "True", "True"),
("tsn-point2point-withGPTP-fixPrecisionClock", "True", "True"),
("tsn-switched-withGPTP", "True", "True"),
("tsn-multidrop", "True", "True"),
("tsn-multidrop-withCBS", "True", "True"),
("tsn-multidrop-withTAS", "True", "True"),
("tsn-multidrop-withTAS-CBS", "True", "True"),
("tsn-switched-multidrop", "True", "True"),
]
# A list of Python examples to run in order to ensure that they remain
# runnable over time. Each tuple in the list contains
#
# (example_name, do_run).
#
# See test.py for more information.
python_examples = []

View File

@@ -0,0 +1,359 @@
// Include a header file from your module to test.
#include "ns3/tsn-node.h"
#include "ns3/tsn-net-device.h"
#include "ns3/switch-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/ethernet-generator.h"
#include "ns3/ethernet-header2.h"
#include "ns3/stream-identification-function.h"
#include "ns3/stream-identification-function-null.h"
#include "ns3/frer-sequence-generation-function.h"
#include "ns3/frer-sequence-recovery-function.h"
#include "ns3/frer-latent-error-detection-function.h"
#include "ns3/frer-match-recovery-function.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("FRERTestSuite");
// Add a doxygen group for tests.
// If you have more than one test, this should be in only one of them.
/**
* \defgroup FRER-tests Tests for FRER
* \ingroup tsn
* \ingroup tests
*/
/**
* \ingroup FRER-tests
* Check if paquets are correctly replicated and eliminated on a 4 SW / 2 ES network
*
* / ==== SW2 ==== \
* ESsource ==== SW1 SW4 ==== ESdest
* \ ==== SW3 ==== /
*
* The FRER use in this test use the SW1 to do the replication
* using mulitcast and SW4 to do the elimination. The stream identification is
* done by the null stream identification function. The match recovery function,
* latent error detection function are also used in this example.
* Two flows go from ESsource to ESdest. Only the VLAN 100 flow use FRER mechanisms.
*
*
*/
class FRERBasicMulticastTestCase : public TestCase
{
public:
FRERBasicMulticastTestCase();
virtual ~FRERBasicMulticastTestCase();
private:
void DoRun() override;
void SendTx(Ptr<const Packet> p);
void ReceiveRx(Ptr<const Packet> p);
uint64_t m_replicated{0}; //!< number of bytes sent
uint64_t m_received{0}; //!< number of bytes received
uint64_t m_pktSize = 500;
uint64_t m_expected_replicated = (1400 + 22 + 6) * 2 + (500+22); //the 1400Bytes pkt is replicated two time and RTAGed (+6bits), the 500Bytes pkt is not replicated
uint64_t m_expected_receive = (1400 + 22) + (500+22);
};
// Add some help text to this case to describe what it is intended to test
FRERBasicMulticastTestCase::FRERBasicMulticastTestCase()
: TestCase("Check if paquets are correctly replicated and eliminated")
{}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
FRERBasicMulticastTestCase::~FRERBasicMulticastTestCase()
{
}
void
FRERBasicMulticastTestCase::SendTx(Ptr<const Packet> p)
{
m_replicated += p->GetSize();
}
void
FRERBasicMulticastTestCase::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
FRERBasicMulticastTestCase::DoRun()
{
//Create six nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Names::Add("ESsource", n0);
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Names::Add("ESdest", n1);
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Names::Add("SW1", n2);
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
Names::Add("SW2", n3);
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
Names::Add("SW3", n4);
Ptr<TsnNode> n5 = CreateObject<TsnNode>();
Names::Add("SW4", n5);
//Create and add a netDevices to each node
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
n0->AddDevice(net0);
Names::Add("ESsource#01", net0);
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
n1->AddDevice(net1);
Names::Add("ESdest#01", net1);
Ptr<TsnNetDevice> net2_1 = CreateObject<TsnNetDevice>();
n2->AddDevice(net2_1);
Ptr<TsnNetDevice> net2_2 = CreateObject<TsnNetDevice>();
n2->AddDevice(net2_2);
Ptr<TsnNetDevice> net2_3 = CreateObject<TsnNetDevice>();
n2->AddDevice(net2_3);
Ptr<TsnNetDevice> net3_1 = CreateObject<TsnNetDevice>();
n3->AddDevice(net3_1);
Ptr<TsnNetDevice> net3_2 = CreateObject<TsnNetDevice>();
n3->AddDevice(net3_2);
Ptr<TsnNetDevice> net4_1 = CreateObject<TsnNetDevice>();
n4->AddDevice(net4_1);
Ptr<TsnNetDevice> net4_2 = CreateObject<TsnNetDevice>();
n4->AddDevice(net4_2);
Ptr<TsnNetDevice> net5_1 = CreateObject<TsnNetDevice>();
n5->AddDevice(net5_1);
Ptr<TsnNetDevice> net5_2 = CreateObject<TsnNetDevice>();
n5->AddDevice(net5_2);
Ptr<TsnNetDevice> net5_3 = CreateObject<TsnNetDevice>();
n5->AddDevice(net5_3);
//Create Ethernet Channels and attach it to the netDevices
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
net0->Attach(l0);
net2_1->Attach(l0);
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
net2_2->Attach(l1);
net3_1->Attach(l1);
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
net2_3->Attach(l2);
net4_1->Attach(l2);
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
net3_2->Attach(l3);
net5_1->Attach(l3);
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
l4->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
net4_2->Attach(l4);
net5_2->Attach(l4);
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
l5->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
net5_3->Attach(l5);
net1->Attach(l5);
//Create and add switche net devices to the switch nodes
Ptr<SwitchNetDevice> sw1 = CreateObject<SwitchNetDevice>();
sw1->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
sw1->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
n2->AddDevice(sw1);
sw1->AddSwitchPort(net2_1);
sw1->AddSwitchPort(net2_2);
sw1->AddSwitchPort(net2_3);
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
n3->AddDevice(sw2);
sw2->AddSwitchPort(net3_1);
sw2->AddSwitchPort(net3_2);
Ptr<SwitchNetDevice> sw3 = CreateObject<SwitchNetDevice>();
sw3->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
sw3->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
n4->AddDevice(sw3);
sw3->AddSwitchPort(net4_1);
sw3->AddSwitchPort(net4_2);
Ptr<SwitchNetDevice> sw4 = CreateObject<SwitchNetDevice>();
sw4->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
sw4->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
n5->AddDevice(sw4);
sw4->AddSwitchPort(net5_1);
sw4->AddSwitchPort(net5_2);
sw4->AddSwitchPort(net5_3);
//Allocate a Mac address
net0->SetAddress(Mac48Address::Allocate());
net1->SetAddress(Mac48Address::Allocate());
sw1->SetAddress(Mac48Address::Allocate());
sw2->SetAddress(Mac48Address::Allocate());
sw3->SetAddress(Mac48Address::Allocate());
sw4->SetAddress(Mac48Address::Allocate());
//Create and add eight FIFO on each net device
for (int i=0; i<8; i++)
{
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net4_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net4_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net5_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net5_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net5_3->SetQueue(CreateObject<DropTailQueue<Packet>>());
}
//Add forwarding table
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net2_2, net2_3});
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net3_2});
sw3->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net4_2});
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net5_3});
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net2_2});
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net3_2});
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net5_3});
//Stream Indentification + FRER
//First switch
//Stream identification
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
uint16_t StreamHandle = 1;
sif0->SetAttribute("VlanID", UintegerValue(100));
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
n2->AddStreamIdentificationFunction(StreamHandle, sif0, {net2_1}, {}, {}, {});
//Sequencing : Sequence generation
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqf0->SetStreamHandle({StreamHandle});
n2->AddSequenceGenerationFunction(seqf0);
//Sequence encode
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
seqEnc0->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqEnc0->SetAttribute("Active", BooleanValue(true));
seqEnc0->SetStreamHandle({StreamHandle});
seqEnc0->SetPort(net2_1);
n2->AddSequenceEncodeDecodeFunction(seqEnc0);
//Last switch
//Stream identification
Ptr<NullStreamIdentificationFunction> sif1 = CreateObject<NullStreamIdentificationFunction>();
StreamHandle = 1;
sif1->SetAttribute("VlanID", UintegerValue(100));
sif1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
n5->AddStreamIdentificationFunction(StreamHandle, sif1, {}, {}, {net5_3}, {});
//Sequence Decode
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
seqEnc1->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqEnc1->SetAttribute("Active", BooleanValue(false));
seqEnc1->SetStreamHandle({StreamHandle});
seqEnc1->SetPort(net5_3);
n5->AddSequenceEncodeDecodeFunction(seqEnc1);
//Sequencing : Sequence recovery
Ptr<SequenceRecoveryFunction> seqfreco0 = CreateObject<SequenceRecoveryFunction>();
seqfreco0->SetAttribute("Direction", BooleanValue(false)); //in-facing
seqfreco0->SetAttribute("TakeNoSequence", BooleanValue(false));
seqfreco0->SetAttribute("IndividualRecovery", BooleanValue(false));
seqfreco0->SetStreamHandle({StreamHandle});
seqfreco0->SetPorts({net5_3});
n5->AddSequenceRecoveryFunction(seqfreco0);
//Sequencing : Sequence recovery : recovery function
Ptr<MatchRecoveryFunction> recf0 = CreateObject<MatchRecoveryFunction>();
seqfreco0->SetRecoveryFunction(recf0);
//Sequencing : Sequence recovery : latent error detection function
Ptr<LatentErrorDetectionFunction> latf0 = CreateObject<LatentErrorDetectionFunction>();
latf0->SetAttribute("LatentErrorPaths", UintegerValue(2));
latf0->SetRecoveryFunction(recf0);
seqfreco0->SetLatentErrorDetectionFunction(latf0);
//Application description
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("BurstSize", UintegerValue(1));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(MilliSeconds(20)));
app0->SetAttribute("PCP", UintegerValue(1));
app0->SetAttribute("VlanID", UintegerValue(100));
n0->AddApplication(app0);
app0->SetStartTime(MilliSeconds(0));
app0->SetStopTime(MilliSeconds(20));
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
app1->Setup(net0);
app1->SetAttribute("BurstSize", UintegerValue(1));
app1->SetAttribute("PayloadSize", UintegerValue(500));
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
app1->SetAttribute("PCP", UintegerValue(0));
app1->SetAttribute("VlanID", UintegerValue(101));
n0->AddApplication(app1);
app1->SetStartTime(Seconds(0));
app1->SetStopTime(MilliSeconds(20));
//Callback to trace the message being replicated and eliminated
net2_2->TraceConnectWithoutContext("MacTx",
MakeCallback(&FRERBasicMulticastTestCase::SendTx, this));
net2_3->TraceConnectWithoutContext("MacTx",
MakeCallback(&FRERBasicMulticastTestCase::SendTx, this));
net1->TraceConnectWithoutContext("MacRx",
MakeCallback(&FRERBasicMulticastTestCase::ReceiveRx, this));
//Execute the simulation
Simulator::Stop(MilliSeconds(50));
Simulator::Run();
Simulator::Destroy();
NS_TEST_ASSERT_MSG_EQ(m_replicated, m_expected_replicated, "All Packets have been replicated");
NS_TEST_ASSERT_MSG_EQ(m_received, m_expected_receive, "All Packets have been eliminated");
}
// 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 FRER-tests
* TestSuite for module FRER
*/
class FRERTestSuite : public TestSuite
{
public:
FRERTestSuite();
};
FRERTestSuite::FRERTestSuite()
: TestSuite("frer", UNIT)
{
LogComponentEnable("FRERTestSuite", LOG_LEVEL_ALL);
//Pkt in a switched network with multicast FRER
AddTestCase(new FRERBasicMulticastTestCase(), TestCase::QUICK);
}
// Do not forget to allocate an instance of this TestSuite
/**
* \ingroup FRER-tests
* Static variable for test initialization
*/
static FRERTestSuite m_FRERTestSuite;

View File

@@ -0,0 +1,279 @@
// Include a header file from your module to test.
#include "ns3/tsn-net-device.h"
#include "ns3/ethernet-channel.h"
#include "ns3/ethernet-header2.h"
#include "ns3/ethernet-generator.h"
#include "ns3/switch-net-device.h"
#include "ns3/stream-identification-function-null.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("PsfpTestSuite");
// Add a doxygen group for tests.
// If you have more than one test, this should be in only one of them.
/**
* \defgroup Psfp-tests Tests for Psfp
* \ingroup tsn
* \ingroup tests
*/
/**
* \ingroup Psfp-tests
* Check if message crossed a point to point tsn channel
*/
class PsfpBasicTestCase : public TestCase
{
public:
PsfpBasicTestCase(
uint64_t receivedExpected,
uint16_t streamHandle,
uint8_t priority,
uint16_t maxSDUSize,
bool streamBlockedDueToOversizeFrameEnable,
DataRate cir,
uint16_t cbs,
DataRate eir,
uint16_t ebs,
bool dropOnYellow,
bool cf,
bool markAllFramesRedEnable);
virtual ~PsfpBasicTestCase();
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_received_expected;
uint16_t m_streamHandle;
uint8_t m_priority;
uint16_t m_maxSDUSize;
bool m_streamBlockedDueToOversizeFrameEnable;
DataRate m_cir;
uint16_t m_cbs;
DataRate m_eir;
uint16_t m_ebs;
bool m_dropOnYellow;
bool m_cf;
bool m_markAllFramesRedEnable;
};
// Add some help text to this case to describe what it is intended to test
PsfpBasicTestCase::PsfpBasicTestCase(
uint64_t receivedExpected,
uint16_t streamHandle,
uint8_t priority,
uint16_t maxSDUSize,
bool streamBlockedDueToOversizeFrameEnable,
DataRate cir,
uint16_t cbs,
DataRate eir,
uint16_t ebs,
bool dropOnYellow,
bool cf,
bool markAllFramesRedEnable)
: TestCase("Check if paquets cross a point to point ethernet channel, tsn net device and PSFP")
{
m_received_expected = receivedExpected;
m_streamHandle = streamHandle;
m_priority = priority;
m_maxSDUSize = maxSDUSize;
m_streamBlockedDueToOversizeFrameEnable = streamBlockedDueToOversizeFrameEnable;
m_cir = cir;
m_cbs = cbs;
m_eir = eir;
m_ebs = ebs;
m_dropOnYellow = dropOnYellow;
m_cf = cf;
m_markAllFramesRedEnable = markAllFramesRedEnable;
}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
PsfpBasicTestCase::~PsfpBasicTestCase()
{
}
void
PsfpBasicTestCase::SendTx(Ptr<const Packet> p)
{
m_sent += p->GetSize();
}
void
PsfpBasicTestCase::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
PsfpBasicTestCase::DoRun()
{
//Create two nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
//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 FIFOs
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
//Stream identification
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
uint16_t StreamHandle = 10;
sif0->SetAttribute("VlanID", UintegerValue(1));
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
n1->AddStreamIdentificationFunction(StreamHandle, sif0, {net1}, {}, {}, {});
//PSFP configuration - Stream Filter
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
sfi0->SetAttribute("StreamHandle", IntegerValue(m_streamHandle));
sfi0->SetAttribute("Priority", IntegerValue(m_priority));
sfi0->SetAttribute("MaxSDUSize", UintegerValue(m_maxSDUSize));
sfi0->SetAttribute("StreamBlockedDueToOversizeFrameEnable", BooleanValue(m_streamBlockedDueToOversizeFrameEnable));
n1->AddStreamFilter(sfi0);
//PSFP configuration - Flow meter
Ptr<FlowMeterInstance> fm0 = CreateObject<FlowMeterInstance>();
fm0->SetAttribute("CIR", DataRateValue(m_cir));
fm0->SetAttribute("CBS", UintegerValue(m_cbs));
fm0->SetAttribute("EIR", DataRateValue(m_eir));
fm0->SetAttribute("EBS", UintegerValue(m_ebs));
fm0->SetAttribute("DropOnYellow", BooleanValue(m_dropOnYellow));
fm0->SetAttribute("CF", BooleanValue(m_cf));
fm0->SetAttribute("MarkAllFramesRedEnable", BooleanValue(m_markAllFramesRedEnable));
uint16_t fmid = n1->AddFlowMeter(fm0);
sfi0->AddFlowMeterInstanceId(fmid);
//Application description
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("BurstSize", UintegerValue(5));
app0->SetAttribute("PayloadSize", UintegerValue(1000));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(0));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(1));
app0->SetStopTime(Seconds(11));
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
app1->Setup(net0);
app1->SetAttribute("BurstSize", UintegerValue(5));
app1->SetAttribute("PayloadSize", UintegerValue(1400));
app1->SetAttribute("Period", TimeValue(Seconds(5)));
app1->SetAttribute("VlanID", UintegerValue(1));
app1->SetAttribute("PCP", UintegerValue(0));
n0->AddApplication(app1);
app1->SetStartTime(Seconds(1.1));
app1->SetStopTime(Seconds(11.1));
//Callback to trace the message being send and received
net0->TraceConnectWithoutContext("MacTx",
MakeCallback(&PsfpBasicTestCase::SendTx, this));
net1->TraceConnectWithoutContext("MacRx",
MakeCallback(&PsfpBasicTestCase::ReceiveRx, this));
//Execute the simulation
Simulator::Stop(Seconds(14));
Simulator::Run();
Simulator::Destroy();
NS_TEST_ASSERT_MSG_EQ(m_sent, 2 * (5 * (1400 + 22) + 5 * (1000 + 22)), "10 Packets have been sent two times");
NS_TEST_ASSERT_MSG_EQ(m_received, m_received_expected, "All Packets sent have been received");
}
// 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 psfp-tests
* TestSuite for module psfp
*/
class PsfpTestSuite : public TestSuite
{
public:
PsfpTestSuite();
};
PsfpTestSuite::PsfpTestSuite()
: TestSuite("psfp", UNIT)
{
LogComponentEnable("PsfpTestSuite", LOG_LEVEL_ALL);
//Point to point network with psfp
// Stream filter test
// All packet should pass because PSFP is well configured
AddTestCase(new PsfpBasicTestCase(2 * (5 * (1400 + 22) + 5 *(1000 + 22)), 10, 0, 1422, false, DataRate("1Gb/s"), 65535, DataRate("1Gb/s"), 65535, false, false, false), TestCase::QUICK);
// No packet should pass due to maxSDUSize filter
AddTestCase(new PsfpBasicTestCase(0, 10, 0, 1021, false, DataRate("1Gb/s"), 65535, DataRate("1Gb/s"), 65535, false, false, false), TestCase::QUICK);
// All packet should pass because the priority spec is wrong
AddTestCase(new PsfpBasicTestCase(2 * (5 * (1400 + 22) + 5 *(1000 + 22)), 10, 1, 1021, false, DataRate("1Gb/s"), 65535, DataRate("1Gb/s"), 65535, false, false, false), TestCase::QUICK);
// All packet should pass because the stream handle spec is wrong
AddTestCase(new PsfpBasicTestCase(2 * (5 * (1400 + 22) + 5 *(1000 + 22)), 11, 0, 1021, false, DataRate("1Gb/s"), 65535, DataRate("1Gb/s"), 65535, false, false, false), TestCase::QUICK);
// Only 2*5 packets of 1022octet packet should pass due to maxSDUSize filter
AddTestCase(new PsfpBasicTestCase(2 * (5 *(1000 + 22)),10 ,0 , 1022, false, DataRate("1Gb/s"), 65535, DataRate("1Gb/s"), 65535, false, false, false), TestCase::QUICK);
// Only 5 packets of 1022octet packet should pass due to maxSDUSize filter with m_streamBlockedDueToOversizeFrameEnable=true
AddTestCase(new PsfpBasicTestCase((5 *(1000 + 22)),10 ,0 , 1022, true, DataRate("1Gb/s"), 65535, DataRate("1Gb/s"), 65535, false, false, false), TestCase::QUICK);
// Flow meter test
//Two packets of 1022octet should pass in green
AddTestCase(new PsfpBasicTestCase(2 * (1000 + 22), 10 ,0 , 1422, false, DataRate("8000b/s"), 1022, DataRate("0Gb/s"), 0, false, false, false), TestCase::QUICK);
//One packets of 1022octet should pass in green
AddTestCase(new PsfpBasicTestCase(1 * (1000 + 22), 10 ,0 , 1422, false, DataRate("7999b/s"), 1022, DataRate("0Gb/s"), 0, false, false, false), TestCase::QUICK);
//Six packets of 1022octet should pass in green
AddTestCase(new PsfpBasicTestCase(6 * (1000 + 22), 10 ,0 , 1422, false, DataRate("8000b/s"), 65535, DataRate("0Gb/s"), 0, false, false, false), TestCase::QUICK);
//One packets of 1022octet should pass in green and the rest are drop due to MarkAllFramesRedEnable
AddTestCase(new PsfpBasicTestCase(1000 + 22, 10 ,0 , 1422, false, DataRate("8000b/s"), 65535, DataRate("0Gb/s"), 0, false, false, true), TestCase::QUICK);
// All packet should pass in yellow
AddTestCase(new PsfpBasicTestCase(2 * (5 * (1400 + 22) + 5 *(1000 + 22)),10 ,0 , 1422, false, DataRate("0Gb/s"), 0, DataRate("1Gb/s"), 65535, false, false, false), TestCase::QUICK);
// All packet should pass in yellow due to compling flag
AddTestCase(new PsfpBasicTestCase(2 * (5 * (1400 + 22) + 5 *(1000 + 22)),10 ,0 , 1422, false, DataRate("1Gb/s"), 999, DataRate("0Gb/s"), 65535, false, true, false), TestCase::QUICK);
// All packet should not pass due to dropOnYellow=true
AddTestCase(new PsfpBasicTestCase(0, 10 ,0 , 1422, false, DataRate("0Gb/s"), 0, DataRate("1Gb/s"), 65535, true, false, false), TestCase::QUICK);
// All packet should pass in yellow due to compling flag and dropOnYellow=true
AddTestCase(new PsfpBasicTestCase(0,10 ,0 , 1422, false, DataRate("1Gb/s"), 999, DataRate("0Gb/s"), 65535, true, true, false), TestCase::QUICK);
}
// Do not forget to allocate an instance of this TestSuite
/**
* \ingroup psfp-tests
* Static variable for test initialization
*/
static PsfpTestSuite m_psfpTestSuite;

View File

@@ -0,0 +1,715 @@
// 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;

View File

@@ -0,0 +1,863 @@
// Include a header file from your module to test.
#include "ns3/tsn-multidrop-net-device.h"
#include "ns3/tsn-multidrop-channel.h"
#include "ns3/tsn-net-device.h"
#include "ns3/tsn-node.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("TsnMultidropTestSuite");
// Add a doxygen group for tests.
// If you have more than one test, this should be in only one of them.
/**
* \defgroup tsn-multidrop-tests Tests for multidrop tsn
* \ingroup tsn
* \ingroup tests
*/
/**
* \ingroup tsn-multidrop-tests
* Check if message crossed an tsn multidrop channel
*/
class TsnMultiDropBasicTestCase1Flow : public TestCase
{
public:
TsnMultiDropBasicTestCase1Flow();
virtual ~TsnMultiDropBasicTestCase1Flow();
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
TsnMultiDropBasicTestCase1Flow::TsnMultiDropBasicTestCase1Flow()
: TestCase("Check if message crossed an tsn multidrop channel")
{
}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
TsnMultiDropBasicTestCase1Flow::~TsnMultiDropBasicTestCase1Flow()
{
}
void
TsnMultiDropBasicTestCase1Flow::SendTx(Ptr<const Packet> p)
{
m_sent += p->GetSize();
}
void
TsnMultiDropBasicTestCase1Flow::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
TsnMultiDropBasicTestCase1Flow::DoRun()
{
//Create four nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
//Create and add a netDevice to each node
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
n0->AddDevice(net0);
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
n1->AddDevice(net1);
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
n2->AddDevice(net2);
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
n3->AddDevice(net3);
//Create a 10Base-T1S Channel and attach it two the netDevices
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
net0->Attach(channel);
net1->Attach(channel);
net2->Attach(channel);
net3->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>>());
net2->SetAddress(Mac48Address::Allocate());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->SetAddress(Mac48Address::Allocate());
net3->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));
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
n0->AddApplication(app0);
//Callback to trace the message being send and received
net0->TraceConnectWithoutContext("MacTx",
MakeCallback(&TsnMultiDropBasicTestCase1Flow::SendTx, this));
net1->TraceConnectWithoutContext("MacRx",
MakeCallback(&TsnMultiDropBasicTestCase1Flow::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 tsn-multidrop-tests
* Check if message crossed an tsn multidrop channel from multiple
* sources.
*/
class TsnMultiDropBasicTestCase3Flows : public TestCase
{
public:
TsnMultiDropBasicTestCase3Flows();
virtual ~TsnMultiDropBasicTestCase3Flows();
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
TsnMultiDropBasicTestCase3Flows::TsnMultiDropBasicTestCase3Flows()
: TestCase("Check if message crossed an tsn multidrop channel from"
" multiple sources")
{
}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
TsnMultiDropBasicTestCase3Flows::~TsnMultiDropBasicTestCase3Flows()
{
}
void
TsnMultiDropBasicTestCase3Flows::SendTx(Ptr<const Packet> p)
{
m_sent += p->GetSize();
}
void
TsnMultiDropBasicTestCase3Flows::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
TsnMultiDropBasicTestCase3Flows::DoRun()
{
//Create four nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
//Create and add a netDevice to each node
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
n0->AddDevice(net0);
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
n1->AddDevice(net1);
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
n2->AddDevice(net2);
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
n3->AddDevice(net3);
//Create a 10Base-T1S Channel and attach it two the netDevices
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
net0->Attach(channel);
net1->Attach(channel);
net2->Attach(channel);
net3->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>>());
net2->SetAddress(Mac48Address::Allocate());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->SetAddress(Mac48Address::Allocate());
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->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));
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
n0->AddApplication(app0);
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
app1->Setup(net1);
app1->SetAttribute("BurstSize", UintegerValue(1));
app1->SetAttribute("PayloadSize", UintegerValue(100));
app1->SetAttribute("Period", TimeValue(Seconds(5)));
app1->SetAttribute("VlanID", UintegerValue(1));
app1->SetAttribute("PCP", UintegerValue(1));
app1->SetStartTime(Seconds(0));
app1->SetStopTime(Seconds(10));
n1->AddApplication(app1);
Ptr<EthernetGenerator> app2 = CreateObject<EthernetGenerator>();
app2->Setup(net2);
app2->SetAttribute("BurstSize", UintegerValue(2));
app2->SetAttribute("PayloadSize", UintegerValue(500));
app2->SetAttribute("Period", TimeValue(Seconds(5)));
app2->SetAttribute("VlanID", UintegerValue(1));
app2->SetAttribute("PCP", UintegerValue(1));
app2->SetStartTime(Seconds(6));
app2->SetStopTime(Seconds(7));
n3->AddApplication(app2);
//Callback to trace the message being send and received
net0->TraceConnectWithoutContext("MacTx",
MakeCallback(&TsnMultiDropBasicTestCase3Flows::SendTx, this));
net1->TraceConnectWithoutContext("MacRx",
MakeCallback(&TsnMultiDropBasicTestCase3Flows::ReceiveRx, this));
net2->TraceConnectWithoutContext("MacRx",
MakeCallback(&TsnMultiDropBasicTestCase3Flows::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 by net0");
NS_TEST_ASSERT_MSG_EQ(m_received, 2*2*10*(1400 + 22) + 2*1*(100+22) + 2*1*(500+22), "All Packets sent have been received");
}
/**
* \ingroup tsn-multidrop-tests
* Check if message crossed an tsn multidrop channel with the expected latency
*/
class TsnMultiDropLatencyTestCase1Flow : public TestCase
{
public:
TsnMultiDropLatencyTestCase1Flow(bool isLocalNodeId0, Time startTime, Time expectedLatency);
virtual ~TsnMultiDropLatencyTestCase1Flow();
private:
void DoRun() override;
void LatencyCallback(Ptr<const Packet> p);
bool m_is_local_node_id_0;
Time m_expected_latency;
Time m_latency;
Time m_start_time;
};
// Add some help text to this case to describe what it is intended to test
TsnMultiDropLatencyTestCase1Flow::TsnMultiDropLatencyTestCase1Flow(bool isLocalNodeId0, Time startTime, Time expectedLatency)
: TestCase("Check if message crossed an tsn multidrop channel with the expected latency")
{
m_is_local_node_id_0 = isLocalNodeId0;
m_expected_latency = expectedLatency;
m_start_time = startTime;
}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
TsnMultiDropLatencyTestCase1Flow::~TsnMultiDropLatencyTestCase1Flow()
{
}
void
TsnMultiDropLatencyTestCase1Flow::LatencyCallback(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
TsnMultiDropLatencyTestCase1Flow::DoRun()
{
//Create four nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
//Create and add a netDevice to each node
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
if (m_is_local_node_id_0){
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
}
else
{
net0->SetAttribute("PLCALocalNodeId", UintegerValue(2));
}
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
n0->AddDevice(net0);
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
n1->AddDevice(net1);
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
if (m_is_local_node_id_0){
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
}
else
{
net2->SetAttribute("PLCALocalNodeId", UintegerValue(0));
}
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
n2->AddDevice(net2);
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
n3->AddDevice(net3);
//Create a 10Base-T1S Channel and attach it two the netDevices
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
net0->Attach(channel);
net1->Attach(channel);
net2->Attach(channel);
net3->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>>());
net2->SetAddress(Mac48Address::Allocate());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->SetAddress(Mac48Address::Allocate());
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
//Application description
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("BurstSize", UintegerValue(1));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetStartTime(m_start_time);
app0->SetStopTime(Seconds(1));
n0->AddApplication(app0);
//Callback to trace the message being send and received
net1->TraceConnectWithoutContext("Latency",
MakeCallback(&TsnMultiDropLatencyTestCase1Flow::LatencyCallback, this));
//Execute the simulation
Simulator::Stop(Seconds(1));
Simulator::Run();
Simulator::Destroy();
NS_TEST_ASSERT_MSG_EQ(m_latency, m_expected_latency, "The simulated latency is equal to the expected latency");
}
/**
* \ingroup tsn-multidrop-tests
* Check if message crossed an tsn multidrop channel with the expected latency
* when the channel is shared with two other flows
*/
class TsnMultiDropLatencyTestCase3Flows : public TestCase
{
public:
TsnMultiDropLatencyTestCase3Flows(uint8_t burstSize, uint8_t priority, Time startTime, Time expectedLatency);
virtual ~TsnMultiDropLatencyTestCase3Flows();
private:
void DoRun() override;
void LatencyCallback(Ptr<const Packet> p);
uint8_t m_burst_size;
uint8_t m_priority;
Time m_expected_latency;
Time m_latency;
Time m_start_time;
};
// Add some help text to this case to describe what it is intended to test
TsnMultiDropLatencyTestCase3Flows::TsnMultiDropLatencyTestCase3Flows(uint8_t burstSize, uint8_t priority, Time startTime, Time expectedLatency)
: TestCase("Check if message crossed an tsn multidrop channel with the "
"expected latency when the channel is shared with two other flows")
{
m_burst_size = burstSize;
m_priority = priority;
m_expected_latency = expectedLatency;
m_start_time = startTime;
}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
TsnMultiDropLatencyTestCase3Flows::~TsnMultiDropLatencyTestCase3Flows()
{
}
void
TsnMultiDropLatencyTestCase3Flows::LatencyCallback(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
TsnMultiDropLatencyTestCase3Flows::DoRun()
{
//Create four nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
//Create and add a netDevice to each node
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
n0->AddDevice(net0);
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
n1->AddDevice(net1);
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
n2->AddDevice(net2);
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
n3->AddDevice(net3);
//Create a 10Base-T1S Channel and attach it two the netDevices
Ptr<TsnMultidropChannel> channel = CreateObject<TsnMultidropChannel>();
net0->Attach(channel);
net1->Attach(channel);
net2->Attach(channel);
net3->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>>());
net2->SetAddress(Mac48Address::Allocate());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->SetAddress(Mac48Address::Allocate());
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
//Application description
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("BurstSize", UintegerValue(m_burst_size));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(1));
app0->SetAttribute("PCP", UintegerValue(m_priority));
app0->SetStartTime(m_start_time);
app0->SetStopTime(Seconds(1));
n0->AddApplication(app0);
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
app1->Setup(net0);
app1->SetAttribute("BurstSize", UintegerValue(2));
app1->SetAttribute("PayloadSize", UintegerValue(1000));
app1->SetAttribute("Period", TimeValue(Seconds(5)));
app1->SetAttribute("VlanID", UintegerValue(2));
app1->SetAttribute("PCP", UintegerValue(0));
app1->SetStartTime(NanoSeconds(10));
app1->SetStopTime(Seconds(1));
n0->AddApplication(app1);
Ptr<EthernetGenerator> app2 = CreateObject<EthernetGenerator>();
app2->Setup(net2);
app2->SetAttribute("BurstSize", UintegerValue(1));
app2->SetAttribute("PayloadSize", UintegerValue(100));
app2->SetAttribute("Period", TimeValue(Seconds(5)));
app2->SetAttribute("VlanID", UintegerValue(3));
app2->SetAttribute("PCP", UintegerValue(1));
app2->SetStartTime(NanoSeconds(0));
app2->SetStopTime(Seconds(1));
n2->AddApplication(app2);
//Callback to trace the message being send and received
net1->TraceConnectWithoutContext("Latency",
MakeCallback(&TsnMultiDropLatencyTestCase3Flows::LatencyCallback, this));
//Execute the simulation
Simulator::Stop(Seconds(1));
Simulator::Run();
Simulator::Destroy();
NS_TEST_ASSERT_MSG_EQ(m_latency, m_expected_latency, "The simulated latency is equal to the expected latency");
}
/**
* \ingroup tsn-multidrop-tests
* Check if message can crossed from a switched network to a 10Base-T1S bus
* and from a 10Base-T1S bus to a switched network
*/
class TsnMultiDropSwitchedBasicTestCase : public TestCase
{
public:
TsnMultiDropSwitchedBasicTestCase();
virtual ~TsnMultiDropSwitchedBasicTestCase();
private:
void DoRun() override;
void ReceiveRxFrom10BaseT1SBus(Ptr<const Packet> p);
void ReceiveRxFromSwitchedNetwork(Ptr<const Packet> p);
uint64_t m_received_from_switched_network{0}; //!< number of bytes
uint64_t m_received_from_10BaseT1S_bus{0}; //!< number of bytes
};
// Add some help text to this case to describe what it is intended to test
TsnMultiDropSwitchedBasicTestCase::TsnMultiDropSwitchedBasicTestCase()
: TestCase("Check if message can crossed from a switched network to a 10Base-T1S"
"bus and from a 10Base-T1S bus to a switched network")
{
}
// This destructor does nothing but we include it as a reminder that
// the test case should clean up after itself
TsnMultiDropSwitchedBasicTestCase::~TsnMultiDropSwitchedBasicTestCase()
{
}
void
TsnMultiDropSwitchedBasicTestCase::ReceiveRxFrom10BaseT1SBus(Ptr<const Packet> p)
{
m_received_from_10BaseT1S_bus += p->GetSize();
}
void
TsnMultiDropSwitchedBasicTestCase::ReceiveRxFromSwitchedNetwork(Ptr<const Packet> p)
{
m_received_from_switched_network += p->GetSize();
}
//
// This method is the pure virtual method from class TestCase that every
// TestCase must implement
//
void
TsnMultiDropSwitchedBasicTestCase::DoRun()
{
//Create four nodes
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
//Create and add a netDevice to each node
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
n0->AddDevice(net0);
Ptr<TsnNetDevice> swnet0 = CreateObject<TsnNetDevice>();
n4->AddDevice(swnet0);
Ptr<TsnMultidropNetDevice> swnet1 = CreateObject<TsnMultidropNetDevice>();
swnet1->SetAttribute("PLCALocalNodeId", UintegerValue(0));
swnet1->SetAttribute("PLCANodeCount", UintegerValue(4));
n4->AddDevice(swnet1);
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
n1->AddDevice(net1);
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
n2->AddDevice(net2);
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
n3->AddDevice(net3);
//Create a full-duplex channel
Ptr<EthernetChannel> channel0 = CreateObject<EthernetChannel>();
net0->Attach(channel0);
swnet0->Attach(channel0);
//Create a 10Base-T1S Channel and attach it two the netDevices
Ptr<TsnMultidropChannel> channel1 = CreateObject<TsnMultidropChannel>();
swnet1->Attach(channel1);
net1->Attach(channel1);
net2->Attach(channel1);
net3->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)));
n4->AddDevice(sw);
sw->AddSwitchPort(swnet0);
sw->AddSwitchPort(swnet1);
//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>>());
net2->SetAddress(Mac48Address::Allocate());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->SetAddress(Mac48Address::Allocate());
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetAddress(Mac48Address::Allocate());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet0->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetAddress(Mac48Address::Allocate());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
swnet1->SetQueue(CreateObject<DropTailQueue<Packet>>());
//Add forwarding table
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net1->GetAddress()), 10, {swnet1});
sw->AddForwardingTableEntry(Mac48Address::ConvertFrom(net0->GetAddress()), 20, {swnet0});
//Application description
//From switched network to 10Base-T1S
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
app0->Setup(net0);
app0->SetAttribute("Address", AddressValue(net1->GetAddress()));
app0->SetAttribute("BurstSize", UintegerValue(5));
app0->SetAttribute("PayloadSize", UintegerValue(1400));
app0->SetAttribute("Period", TimeValue(Seconds(5)));
app0->SetAttribute("VlanID", UintegerValue(10));
app0->SetAttribute("PCP", UintegerValue(0));
n0->AddApplication(app0);
app0->SetStartTime(Seconds(0));
app0->SetStopTime(Seconds(10));
//From 10Base-T1S to switched network
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
app1->Setup(net1);
app1->SetAttribute("Address", AddressValue(net0->GetAddress()));
app1->SetAttribute("BurstSize", UintegerValue(2));
app1->SetAttribute("PayloadSize", UintegerValue(100));
app1->SetAttribute("Period", TimeValue(Seconds(5)));
app1->SetAttribute("VlanID", UintegerValue(20));
app1->SetAttribute("PCP", UintegerValue(1));
n1->AddApplication(app1);
app1->SetStartTime(Seconds(0));
app1->SetStopTime(Seconds(10));
//Callback to trace the message being send and received
net0->TraceConnectWithoutContext("MacRx",
MakeCallback(&TsnMultiDropSwitchedBasicTestCase::ReceiveRxFrom10BaseT1SBus, this));
net1->TraceConnectWithoutContext("MacRx",
MakeCallback(&TsnMultiDropSwitchedBasicTestCase::ReceiveRxFromSwitchedNetwork, this));
//Execute the simulation
Simulator::Stop(Seconds(12));
Simulator::Run();
Simulator::Destroy();
NS_TEST_ASSERT_MSG_EQ(m_received_from_10BaseT1S_bus, 2 * 2 * (100 + 22), "4 Packets have been received two times by net0");
NS_TEST_ASSERT_MSG_EQ(m_received_from_switched_network, 2 * 5 * (1400 + 22), "10 Packets have been received two times by net1");
}
// 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 tsn-multidrop-tests
* TestSuite for module tsn with a focus on multidrop
*/
class TsnMultidropTestSuite : public TestSuite
{
public:
TsnMultidropTestSuite();
};
TsnMultidropTestSuite::TsnMultidropTestSuite()
: TestSuite("tsn-multidrop", UNIT)
{
LogComponentEnable("TsnMultidropTestSuite", LOG_LEVEL_ALL);
//Multidrop channel
AddTestCase(new TsnMultiDropBasicTestCase1Flow, TestCase::QUICK);
AddTestCase(new TsnMultiDropBasicTestCase3Flows, TestCase::QUICK);
// Latency with one flow on the channel
//Wait for 10Base-T1S init when producer is local nodeId = 0
AddTestCase(new TsnMultiDropLatencyTestCase1Flow(true, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 1 * 20 + 4 * 32)*800 + 25))), TestCase::QUICK);
//Frame ready just before the opportunity when producer is local nodeId = 0
AddTestCase(new TsnMultiDropLatencyTestCase1Flow(true, Time(NanoSeconds((20 + 4 *32) * 800 - 1)), Time(NanoSeconds((1400 + 22 + 8)*800 + 1 + 25))), TestCase::QUICK);
//Wait for 10Base-T1S init when producer is local nodeId = 2
AddTestCase(new TsnMultiDropLatencyTestCase1Flow(false, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 1 * 20 + (4 + 2) * 32)*800 + 25))), TestCase::QUICK);
//Latency with multiple flows on the channel
AddTestCase(new TsnMultiDropLatencyTestCase3Flows(1, 0, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 1 * 20 + 4 * 32)*800 + 25))), TestCase::QUICK);
AddTestCase(new TsnMultiDropLatencyTestCase3Flows(2, 0, Time(NanoSeconds(0)), Time(NanoSeconds(((1400 + 22 + 8) + 2 * 20 + (4+2) * 32 + (1400 + 22 + 8 + 12 + 100 + 22 + 8 + 12))*800 + 25 * 3))), TestCase::QUICK);
AddTestCase(new TsnMultiDropLatencyTestCase3Flows(2, 0, Time(NanoSeconds(11)), Time(NanoSeconds(((1400 + 22 + 8) + 4 * 20 + (4+ 2 + 3 + 3) * 32 + (1042 * 2 + 1442 + 142))*800 + 25 * 3 - 11))), TestCase::QUICK);
AddTestCase(new TsnMultiDropLatencyTestCase3Flows(2, 1, Time(NanoSeconds(11)), Time(NanoSeconds(((1400 + 22 + 8) + 2 * 20 + (4+ 2) * 32 + (1442 + 142))*800 + 25 * 3 - 11))), TestCase::QUICK);
//Switched network connected to a multidrop channel
AddTestCase(new TsnMultiDropSwitchedBasicTestCase, TestCase::QUICK);
}
// Do not forget to allocate an instance of this TestSuite
/**
* \ingroup tsn-tests
* Static variable for test initialization
*/
static TsnMultidropTestSuite m_tsnMultidropTestSuite;

File diff suppressed because it is too large Load Diff