Update README and add contrib dir
This commit is contained in:
283
contrib/tsn/test/cbs-test-suite.cc
Normal file
283
contrib/tsn/test/cbs-test-suite.cc
Normal 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;
|
||||
43
contrib/tsn/test/examples-to-run.py
Normal file
43
contrib/tsn/test/examples-to-run.py
Normal 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 = []
|
||||
359
contrib/tsn/test/frer-test-suite.cc
Normal file
359
contrib/tsn/test/frer-test-suite.cc
Normal 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;
|
||||
279
contrib/tsn/test/psfp-test-suite.cc
Normal file
279
contrib/tsn/test/psfp-test-suite.cc
Normal 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;
|
||||
715
contrib/tsn/test/tas-test-suite.cc
Normal file
715
contrib/tsn/test/tas-test-suite.cc
Normal 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;
|
||||
863
contrib/tsn/test/tsn-multidrop-test-suite.cc
Normal file
863
contrib/tsn/test/tsn-multidrop-test-suite.cc
Normal 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;
|
||||
1012
contrib/tsn/test/tsn-test-suite.cc
Normal file
1012
contrib/tsn/test/tsn-test-suite.cc
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user