Update README and add contrib dir
This commit is contained in:
36
contrib/tsn/examples/CMakeLists.txt
Normal file
36
contrib/tsn/examples/CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
set(base_examples
|
||||
tsn-point2point
|
||||
tsn-point2point-withCBS
|
||||
tsn-point2point-withTAS
|
||||
tsn-point2point-withTAS-CBS
|
||||
tsn-point2point-withTAS-gPTP
|
||||
tsn-point2point-withTAS-GuardBand
|
||||
tsn-point2point-withPSFP-MaxSDUSizeFilter
|
||||
tsn-point2point-withPSFP-FlowMeter
|
||||
tsn-switched-withFRER
|
||||
tsn-switched-withFRER-recoveryAlgo
|
||||
tsn-switched-withFRER-activeSid
|
||||
tsn-point2point-withGPTP
|
||||
tsn-point2point-withGPTP-Multidomain
|
||||
tsn-point2point-withGPTP-fixPrecisionClock
|
||||
tsn-switched-withGPTP
|
||||
tsn-multidrop
|
||||
tsn-multidrop-withCBS
|
||||
tsn-multidrop-withTAS
|
||||
tsn-multidrop-withTAS-CBS
|
||||
tsn-switched-multidrop
|
||||
)
|
||||
foreach(
|
||||
example
|
||||
${base_examples}
|
||||
)
|
||||
build_lib_example(
|
||||
NAME ${example}
|
||||
SOURCE_FILES ${example}.cc
|
||||
LIBRARIES_TO_LINK ${libtsn}
|
||||
${libcore}
|
||||
${libnetwork}
|
||||
${libtraffic-generator}
|
||||
${libethernet}
|
||||
)
|
||||
endforeach()
|
||||
191
contrib/tsn/examples/tsn-multidrop-withCBS.cc
Normal file
191
contrib/tsn/examples/tsn-multidrop-withCBS.cc
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/cbs.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S with a CBS on the
|
||||
* highest priority FIFO of ES1
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", 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());
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("8Mb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
|
||||
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());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
292
contrib/tsn/examples/tsn-multidrop-withTAS-CBS.cc
Normal file
292
contrib/tsn/examples/tsn-multidrop-withTAS-CBS.cc
Normal file
@@ -0,0 +1,292 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/cbs.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S with TAS and CBS on
|
||||
* ES1 port
|
||||
*
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
//Add perfect clock on each node
|
||||
n0->AddClock(CreateObject<Clock>());
|
||||
n1->AddClock(CreateObject<Clock>());
|
||||
n2->AddClock(CreateObject<Clock>());
|
||||
n3->AddClock(CreateObject<Clock>());
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", 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
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("1300Kb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("10Mb/s")));
|
||||
cbs->SetAttribute("MultidropMode", BooleanValue(true));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->AddGclEntry(Time(MilliSeconds(4)), 1);
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::MTU));
|
||||
net0->GetTas()->SetAttribute("MultidropMode", BooleanValue(true));
|
||||
net0->StartTas();
|
||||
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
|
||||
// net0->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net0)));
|
||||
// net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
// net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
// net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(20));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
274
contrib/tsn/examples/tsn-multidrop-withTAS.cc
Normal file
274
contrib/tsn/examples/tsn-multidrop-withTAS.cc
Normal file
@@ -0,0 +1,274 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S with TAS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
//Add perfect clock on each node
|
||||
n0->AddClock(CreateObject<Clock>());
|
||||
n1->AddClock(CreateObject<Clock>());
|
||||
n2->AddClock(CreateObject<Clock>());
|
||||
n3->AddClock(CreateObject<Clock>());
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("DataRate", DataRateValue(DataRate("10Mb/s")));
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", 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
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
net3->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->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(2)), 2);
|
||||
net0->AddGclEntry(Time(MilliSeconds(4)), 1);
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::MTU));
|
||||
net0->GetTas()->SetAttribute("MultidropMode", BooleanValue(true));
|
||||
net0->StartTas();
|
||||
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
|
||||
// net0->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net0)));
|
||||
// net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
// net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
// net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(8));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
254
contrib/tsn/examples/tsn-multidrop.cc
Normal file
254
contrib/tsn/examples/tsn-multidrop.cc
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* composed of four end-stations connected by a 10Base-T1S
|
||||
* ES1 ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnMultidropNetDevice> net0 = CreateObject<TsnMultidropNetDevice>();
|
||||
net0->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
net0->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
// net0->SetAttribute("PLCAMaxBurstCount", UintegerValue(1));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", 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(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("VlanID", UintegerValue(1));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net1);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("VlanID", UintegerValue(2));
|
||||
|
||||
n1->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
|
||||
net0->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
119
contrib/tsn/examples/tsn-point2point-withCBS.cc
Normal file
119
contrib/tsn/examples/tsn-point2point-withCBS.cc
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/cbs.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with CBS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the credit value
|
||||
static void
|
||||
CbsCallback(std::string context, double credit)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
NS_LOG_INFO("FIFO:" << context << " : At "<< t.GetNanoSeconds() <<" credit=" << credit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add a CBS shaper and a FIFO on net0 only fifo.
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
Names::Add(Names::FindName(net0) + "-" + "0", cbs); //NetDeviceName-FifoNumber
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("5Mb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
//Create and add a FIFO on net1
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(5));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
//Callback to display the credit update log
|
||||
cbs->TraceConnectWithoutContext("Credit", MakeBoundCallback(&CbsCallback, Names::FindName(cbs)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
127
contrib/tsn/examples/tsn-point2point-withGPTP-Multidomain.cc
Normal file
127
contrib/tsn/examples/tsn-point2point-withGPTP-Multidomain.cc
Normal file
@@ -0,0 +1,127 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP with two domain on a network composed of two
|
||||
* end-stations connected by a 1Gb/s full duplex link.
|
||||
* ES1 is the GPTP Grandmaster for the two domains.
|
||||
* Is this example, all the clock on the same node are slaved on the main clock
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<Clock> c0 = CreateObject<Clock>(); //Perfect clock
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
|
||||
c1->SetAttribute("InitialOffset", TimeValue(Seconds(1)));
|
||||
c1->SetAttribute("DriftRate", DoubleValue(10));
|
||||
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add two fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddDomain(4);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 4);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(1));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddDomain(4);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 4);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(1));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-fix-precision.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP on a network composed of two end-stations
|
||||
* connected by a 1Gb/s full duplex link. ES1 is the GPTP Grandmaster.
|
||||
* This exemple use fix precision clock (non realistic clock made for
|
||||
* research purpose)
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Ptr<Clock> gmClock, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (gmClock->GetLocalTime()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("GPTP", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<Clock> c0 = CreateObject<Clock>(); //Perfect clock
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<FixPrecisionClock> c1 = CreateObject<FixPrecisionClock>();
|
||||
c1->SetAttribute("Precision", TimeValue(NanoSeconds(100)));
|
||||
c1->SetRefClock(c0); //Set GM clock as reference
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add two fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(1));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0, c1);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(1));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1), c0));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
121
contrib/tsn/examples/tsn-point2point-withGPTP.cc
Normal file
121
contrib/tsn/examples/tsn-point2point-withGPTP.cc
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP on a network composed of two end-stations
|
||||
* connected by a 1Gb/s full duplex link. ES1 is the GPTP Grandmaster.
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<Clock> c0 = CreateObject<Clock>(); //Perfect clock
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
|
||||
c1->SetAttribute("InitialOffset", TimeValue(Seconds(1)));
|
||||
c1->SetAttribute("DriftRate", DoubleValue(10));
|
||||
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add two fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(1));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(1));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
142
contrib/tsn/examples/tsn-point2point-withPSFP-FlowMeter.cc
Normal file
142
contrib/tsn/examples/tsn-point2point-withPSFP-FlowMeter.cc
Normal file
@@ -0,0 +1,142 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt transmission
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " entered the transmission FIFO !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//Callbacks to log pkt drop
|
||||
static void
|
||||
MaxSDUSizeFilterDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : Packet #"<< p->GetUid() <<" was dropped by MaxSDUSizeFilter");
|
||||
}
|
||||
|
||||
static void
|
||||
REDFrameDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : Packet #"<< p->GetUid() <<" was dropped by Flow Meter");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("StreamFilterInstance", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("FlowMeterInstance", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 10;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n1->AddStreamIdentificationFunction(StreamHandle, sif0, {net1}, {}, {}, {});
|
||||
|
||||
//PSFP configuration
|
||||
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
|
||||
sfi0->SetAttribute("StreamHandle", IntegerValue(StreamHandle));
|
||||
sfi0->SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard (like in PSFP MIB)
|
||||
sfi0->SetAttribute("MaxSDUSize", UintegerValue(0));
|
||||
n1->AddStreamFilter(sfi0);
|
||||
Ptr<FlowMeterInstance> fm0 = CreateObject<FlowMeterInstance>();
|
||||
fm0->SetAttribute("CIR", DataRateValue(DataRate("40Mb/s")));
|
||||
fm0->SetAttribute("CBS", UintegerValue(1000));
|
||||
fm0->SetAttribute("DropOnYellow", BooleanValue(true));
|
||||
fm0->SetAttribute("MarkAllFramesRedEnable", BooleanValue(false));
|
||||
uint16_t fmid = n1->AddFlowMeter(fm0);
|
||||
sfi0->AddFlowMeterInstanceId(fmid);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(4));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(500));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(5));
|
||||
app0->SetStopTime(Seconds(12));
|
||||
|
||||
//Callback to display the packet log
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
net1->TraceConnectWithoutContext("MaxSDUSizeFilterDrop", MakeBoundCallback(&MaxSDUSizeFilterDrop, Names::FindName(net1)));
|
||||
net1->TraceConnectWithoutContext("REDFrameDrop", MakeBoundCallback(&REDFrameDrop, Names::FindName(net1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(15));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/stream-identification-function-null.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt transmission
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " entered the transmission FIFO !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//Callbacks to log pkt drop
|
||||
static void
|
||||
MaxSDUSizeFilterDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : Packet #"<< p->GetUid() <<" was dropped by MaxSDUSizeFilter ");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("StreamFilterInstance", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif0 = CreateObject<NullStreamIdentificationFunction>();
|
||||
uint16_t StreamHandle = 10;
|
||||
sif0->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif0->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n1->AddStreamIdentificationFunction(StreamHandle, sif0, {net1}, {}, {}, {});
|
||||
//PSFP configuration
|
||||
Ptr<StreamFilterInstance> sfi0 = CreateObject<StreamFilterInstance>();
|
||||
sfi0->SetAttribute("StreamHandle", IntegerValue(StreamHandle));
|
||||
sfi0->SetAttribute("Priority", IntegerValue(-1)); //-1 = wildcard (like in PSFP MIB)
|
||||
sfi0->SetAttribute("MaxSDUSize", UintegerValue(522));
|
||||
sfi0->SetAttribute("StreamBlockedDueToOversizeFrameEnable", BooleanValue(true));
|
||||
n1->AddStreamFilter(sfi0);
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(500));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
Ptr<EthernetGenerator> app1 = CreateObject<EthernetGenerator>();
|
||||
app1->Setup(net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(501));
|
||||
app1->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(100));
|
||||
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(4));
|
||||
app1->SetStopTime(Seconds(5));
|
||||
|
||||
//Callback to display the packet log
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
net1->TraceConnectWithoutContext("MaxSDUSizeFilterDrop", MakeBoundCallback(&MaxSDUSizeFilterDrop, Names::FindName(net1)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
168
contrib/tsn/examples/tsn-point2point-withTAS-CBS.cc
Normal file
168
contrib/tsn/examples/tsn-point2point-withTAS-CBS.cc
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/cbs.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with TAS with CBS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
//A callback to log the credit value
|
||||
static void
|
||||
CbsCallback(std::string context, double credit)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
NS_LOG_INFO("FIFO:" << context << " : At "<< t.GetNanoSeconds() <<" credit=" << credit);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Clock", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//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(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add the FIFO 0 on each net device with a cbs on net0's FIFO
|
||||
Ptr<Cbs> cbs = CreateObject<Cbs>();
|
||||
cbs->SetTsnNetDevice(net0);
|
||||
Names::Add(Names::FindName(net0) + "-" + "0", cbs); //NetDeviceName-FifoNumber
|
||||
cbs->SetAttribute("IdleSlope", DataRateValue(DataRate("2Mb/s")));
|
||||
cbs->SetAttribute("portTransmitRate", DataRateValue(DataRate("100Mb/s")));
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>(), cbs);
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Create and add the last seven FIFO on each net device
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(3)), 1);
|
||||
net0->AddGclEntry(Time(MilliSeconds(17)), 0);
|
||||
net0->StartTas();
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(50)));
|
||||
app0->SetAttribute("PCP", UintegerValue(0));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(MilliSeconds(0));
|
||||
app0->SetStopTime(MilliSeconds(20));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the credit update log
|
||||
cbs->TraceConnectWithoutContext("Credit", MakeBoundCallback(&CbsCallback, Names::FindName(cbs)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(60));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
199
contrib/tsn/examples/tsn-point2point-withTAS-GuardBand.cc
Normal file
199
contrib/tsn/examples/tsn-point2point-withTAS-GuardBand.cc
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of the use of the different TAS guard band mode on a 100Mb/s
|
||||
* full duplex link with TAS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*
|
||||
* This example script can be run using one of this two following commands
|
||||
* according to the algorithm needed :
|
||||
* ./ns3 run <path to the script> -- --none
|
||||
* ./ns3 run <path to the script> -- --mtu
|
||||
* ./ns3 run <path to the script> -- --pktsize
|
||||
*
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !" << p->ToString());
|
||||
}
|
||||
|
||||
//A callback to log the pkt given to the netDevice by the application
|
||||
static void
|
||||
PktSentCallback(std::string context, Ptr<const Packet> p, uint16_t vid)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " given to the netDevice !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
//Command line interpretation
|
||||
bool mtu = false;
|
||||
bool pktsize = false;
|
||||
bool none = false;
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.AddValue("mtu", "Enable mtu guard band mode", mtu);
|
||||
cmd.AddValue("pktsize", "Enable pktsize guard band mode", pktsize);
|
||||
cmd.AddValue("none", "Enable none guard band mode", none);
|
||||
cmd.Parse(argc, argv);
|
||||
if (mtu+pktsize+none > 1)
|
||||
{
|
||||
NS_LOG_INFO("Only one guard band mode can be selected");
|
||||
return 0;
|
||||
}
|
||||
else if (mtu+pktsize+none == 0)
|
||||
{
|
||||
NS_LOG_INFO("A guard band mode must be selected using '--mtu' or '--pktsize' or '--none' ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//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(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->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>>());
|
||||
}
|
||||
|
||||
//Set Tas Guard Band Mode (MTU is the default GuardBandMode)
|
||||
if(mtu)
|
||||
{
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::MTU));
|
||||
}
|
||||
else if(pktsize)
|
||||
{
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::PKTSIZE));
|
||||
}
|
||||
else
|
||||
{
|
||||
net0->GetTas()->SetAttribute("GuardBandMode", EnumValue(Tas::NONE));
|
||||
}
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(NanoSeconds(10)), 2);
|
||||
net0->AddGclEntry(Time(NanoSeconds(4990)), 0);
|
||||
net0->AddGclEntry(Time(MicroSeconds(95)), 2);
|
||||
net0->AddGclEntry(Time(MicroSeconds(9900)), 0);
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->AddGclEntry(Time(MilliSeconds(20)), 0);
|
||||
net0->StartTas();
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(100));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(40)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
app0->TraceConnectWithoutContext("PktSent", MakeBoundCallback(&PktSentCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(30));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
191
contrib/tsn/examples/tsn-point2point-withTAS-gPTP.cc
Normal file
191
contrib/tsn/examples/tsn-point2point-withTAS-gPTP.cc
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/gPTP.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with TAS on ES1 port. ES2 is GPTP grandmaster and ES1 is in
|
||||
* slave state.
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (Simulator::Now()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNode", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Clock", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("GPTP", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<ConstantDriftClock> c0 = CreateObject<ConstantDriftClock>();
|
||||
c0->SetAttribute("InitialOffset", TimeValue(Seconds(5)));
|
||||
c0->SetAttribute("DriftRate", DoubleValue(50));
|
||||
c0->SetAttribute("Granularity", TimeValue(NanoSeconds(1)));
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<Clock> c1 = CreateObject<Clock>(); //Perfect clock for the GM
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
channel->SetAttribute("Delay", TimeValue(NanoSeconds(200)));
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->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>>());
|
||||
}
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::SLAVE, 0);
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(0));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddPort(net1, GPTP::MASTER, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(0));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
//(must be done after GPTP declaration due to clock declaration)
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 1);
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->StartTas();
|
||||
|
||||
//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(15)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Callback to monitor synchronization
|
||||
gPTP0->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n0)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(1.5));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
148
contrib/tsn/examples/tsn-point2point-withTAS.cc
Normal file
148
contrib/tsn/examples/tsn-point2point-withTAS.cc
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include <bitset>
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link with TAS on ES1 port
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log the gate update
|
||||
static void
|
||||
TasCallback(std::string context, uint8_t states)
|
||||
{
|
||||
Time t = Simulator::Now();
|
||||
std::string str = "";
|
||||
std::string binary = std::bitset<8>(states).to_string();
|
||||
std::reverse(binary.begin(), binary.end());
|
||||
|
||||
for (int i = 0; i < (int)binary.length(); i++) {
|
||||
str += " Fifo " + std::to_string(i);
|
||||
std::string c{binary[i]};
|
||||
int state = std::stoi(c);
|
||||
|
||||
if(state)
|
||||
{
|
||||
str += " Open ;";
|
||||
}
|
||||
else
|
||||
{
|
||||
str += " Close;";
|
||||
}
|
||||
}
|
||||
NS_LOG_INFO(context << " : At "<< t.GetNanoSeconds() <<" Tas gate states update :" << str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Tas", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("Clock", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//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(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->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>>());
|
||||
}
|
||||
|
||||
//Callback to display the gate update log (must be before StartTas() to display the initial gate states)
|
||||
net0->GetTas()->TraceConnectWithoutContext("GatesUpdate", MakeBoundCallback(&TasCallback, Names::FindName(net0)));
|
||||
|
||||
//Add two GCL entry on net0 and start TAS
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 0);
|
||||
net0->AddGclEntry(Time(MilliSeconds(10)), 2);
|
||||
net0->StartTas();
|
||||
|
||||
//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(15)));
|
||||
app0->SetAttribute("PCP", UintegerValue(1));
|
||||
app0->SetAttribute("VlanID", UintegerValue(100));
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(4));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(80));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
92
contrib/tsn/examples/tsn-point2point.cc
Normal file
92
contrib/tsn/examples/tsn-point2point.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-node.cc tsn-net-device.cc ethernet-channel.cc
|
||||
* on a network composed of two end-stations connected by a 100Mb/s
|
||||
* full duplex link
|
||||
* ES1 ====== ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received !");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create two nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("100Mb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
|
||||
//Create a Ethernet Channel and attach it two the two netDevices
|
||||
Ptr<EthernetChannel> channel = CreateObject<EthernetChannel>();
|
||||
net0->Attach(channel);
|
||||
net1->Attach(channel);
|
||||
|
||||
//Allocate a Mac address and create a FIFO (for the output port)
|
||||
//for each netDevice.
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Application description
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(Seconds(5)));
|
||||
|
||||
n0->AddApplication(app0);
|
||||
app0->SetStartTime(Seconds(0));
|
||||
app0->SetStopTime(Seconds(10));
|
||||
|
||||
//Callback to display the packet received log
|
||||
std::string context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, context));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(10));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
301
contrib/tsn/examples/tsn-switched-multidrop.cc
Normal file
301
contrib/tsn/examples/tsn-switched-multidrop.cc
Normal file
@@ -0,0 +1,301 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/timestamp-tag.h"
|
||||
|
||||
#include "ns3/tsn-multidrop-net-device.h"
|
||||
#include "ns3/tsn-multidrop-channel.h"
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/ethernet-generator.h"
|
||||
#include "ns3/ethernet-header2.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of tsn-net-device.cc tsn-multidrop-channel.cc on a network
|
||||
* switched network with three end-stations connected by a 10Base-T1S
|
||||
* ES1 ==== SW ====== ES2
|
||||
* ||
|
||||
* ||== ES3
|
||||
* ||
|
||||
* ||== ES4
|
||||
*
|
||||
* There is two flows on this network :
|
||||
* - vlanID = 10 from ES1 to ES2
|
||||
* - vlanID = 20 from ES2 to ES1, ES3, ES4
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
|
||||
//A callback to log pkt fifo entry time
|
||||
static void
|
||||
MacTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << "(VID:" << ethHeader.GetVid() << ") entering the FIFO on the producer");
|
||||
}
|
||||
|
||||
//A callback to log the pkt latency
|
||||
static void
|
||||
LatencyCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
TimestampTag tag;
|
||||
if (!p->FindFirstMatchingByteTag(tag))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Time arrival = Simulator::Now();
|
||||
Time latency = arrival - tag.GetTimestamp();
|
||||
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " received from " << ethHeader.GetSrc() << "(VID:" << ethHeader.GetVid() << ") with a latency=" << latency.GetNanoSeconds() <<"ns");
|
||||
}
|
||||
|
||||
//A callback to log the PLCA state
|
||||
static void
|
||||
PLCAStateCallback(std::string context, TsnMultidropNetDevice::PLCAState state)
|
||||
{
|
||||
std::string stateStr = "";
|
||||
if ( state == TsnMultidropNetDevice::PLCAState::DISABLE)
|
||||
{
|
||||
stateStr = "DISABLE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECOVER)
|
||||
{
|
||||
stateStr = "RECOVER";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RESYNC)
|
||||
{
|
||||
stateStr = "RESYNC";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SEND_BEACON)
|
||||
{
|
||||
stateStr = "SEND_BEACON";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::SYNCING)
|
||||
{
|
||||
stateStr = "SYNCING";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::WAIT_TO)
|
||||
{
|
||||
stateStr = "WAIT_TO";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::COMMIT)
|
||||
{
|
||||
stateStr = "COMMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::TRANSMIT)
|
||||
{
|
||||
stateStr = "TRANSMIT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::BURST)
|
||||
{
|
||||
stateStr = "BURST";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::RECEIVE)
|
||||
{
|
||||
stateStr = "RECEIVE";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::YIELD)
|
||||
{
|
||||
stateStr = "YIELD";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::ABORT)
|
||||
{
|
||||
stateStr = "ABORT";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::NEXT_TX_OPPORTUNITY)
|
||||
{
|
||||
stateStr = "NEXT_TX_OPPORTUNITY";
|
||||
}
|
||||
else if ( state == TsnMultidropNetDevice::PLCAState::EARLY_RECEIVE)
|
||||
{
|
||||
stateStr = "EARLY_RECEIVE";
|
||||
}
|
||||
else
|
||||
{
|
||||
stateStr = "UNKNOWN_STATE";
|
||||
}
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : PLCAState => " << stateStr);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetDevice", LOG_LEVEL_INFO);
|
||||
// LogComponentEnable("TsnMultidropNetChannel", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create four nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("ES4", n3);
|
||||
Ptr<TsnNode> n4 = CreateObject<TsnNode>();
|
||||
Names::Add("SW", n4);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> swnet0 = CreateObject<TsnNetDevice>();
|
||||
n4->AddDevice(swnet0);
|
||||
Names::Add("SW#01", swnet0);
|
||||
|
||||
Ptr<TsnMultidropNetDevice> swnet1 = CreateObject<TsnMultidropNetDevice>();
|
||||
swnet1->SetAttribute("PLCALocalNodeId", UintegerValue(0));
|
||||
swnet1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n4->AddDevice(swnet1);
|
||||
Names::Add("SW#02", swnet1);
|
||||
Ptr<TsnMultidropNetDevice> net1 = CreateObject<TsnMultidropNetDevice>();
|
||||
net1->SetAttribute("PLCALocalNodeId", UintegerValue(1));
|
||||
net1->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnMultidropNetDevice> net2 = CreateObject<TsnMultidropNetDevice>();
|
||||
net2->SetAttribute("PLCALocalNodeId", UintegerValue(2));
|
||||
net2->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
Ptr<TsnMultidropNetDevice> net3 = CreateObject<TsnMultidropNetDevice>();
|
||||
net3->SetAttribute("PLCALocalNodeId", UintegerValue(3));
|
||||
net3->SetAttribute("PLCANodeCount", UintegerValue(4));
|
||||
n3->AddDevice(net3);
|
||||
Names::Add("ES4#01", 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(net2->GetAddress()), 10, {swnet1});
|
||||
sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 20, {swnet0});
|
||||
|
||||
//Application description
|
||||
//From switched network to 10Base-T1S
|
||||
Ptr<EthernetGenerator> app0 = CreateObject<EthernetGenerator>();
|
||||
app0->Setup(net0);
|
||||
app0->SetAttribute("Address", AddressValue(net2->GetAddress()));
|
||||
app0->SetAttribute("BurstSize", UintegerValue(2));
|
||||
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("BurstSize", UintegerValue(1));
|
||||
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 log pkt fifo entry time
|
||||
std::string context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("MacTx", MakeBoundCallback(&MacTxCallback, context));
|
||||
|
||||
//Callback to display the packet latency
|
||||
context = Names::FindName(n0) + ":" + Names::FindName(net0);
|
||||
net0->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n1) + ":" + Names::FindName(net1);
|
||||
net1->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n2) + ":" + Names::FindName(net2);
|
||||
net2->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
context = Names::FindName(n3) + ":" + Names::FindName(net3);
|
||||
net3->TraceConnectWithoutContext("Latency", MakeBoundCallback(&LatencyCallback, context));
|
||||
|
||||
//Callback to display PLCA state evolution
|
||||
swnet1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(swnet1)));
|
||||
// net1->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net1)));
|
||||
// net2->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net2)));
|
||||
// net3->TraceConnectWithoutContext("PLCAState", MakeBoundCallback(&PLCAStateCallback, Names::FindName(net3)));
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
358
contrib/tsn/examples/tsn-switched-withFRER-activeSid.cc
Normal file
358
contrib/tsn/examples/tsn-switched-withFRER-activeSid.cc
Normal file
@@ -0,0 +1,358 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/trace-helper.h"
|
||||
#include <fstream>
|
||||
|
||||
#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/stream-identification-function-active-dest-mac-vlan.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"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 4SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage. To be more specific this example use the SW1 to do the replication
|
||||
* using mulitcast and SW4 to do the elimination. The stream identification is
|
||||
* done by the active mac dest and vlan 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 and 101 flow use FRER mechanisms.
|
||||
* To be more specific ESsource send a VLAN 100 packet that is replicated toward
|
||||
* SW 2 with VLAN 100 and toward SW 3 with VLAN 101. A non replicated packet
|
||||
* using VLAN 102 cross the network.
|
||||
*
|
||||
* / ==== SW2 ==== \
|
||||
* ESsource ==== SW1 SW4 ==== ESdest
|
||||
* \ ==== SW3 ==== /
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("ActiveDestMacVlanStreamIdentificationFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//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"), 101, {net4_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {net5_3});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {net5_3});
|
||||
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 102, {net2_2});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 102, {net3_2});
|
||||
sw4->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 102, {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);
|
||||
//Active Stream identification to change the vlan on net2_3
|
||||
Ptr<ActiveDestMacVlanStreamIdentificationFunction> sif1 = CreateObject<ActiveDestMacVlanStreamIdentificationFunction>();
|
||||
sif1->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif1->SetAttribute("UpdateVlanID", UintegerValue(101));
|
||||
sif1->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif1->SetAttribute("UpdateAddress", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif1->SetAttribute("UpdatePCP", UintegerValue(1));
|
||||
n2->AddStreamIdentificationFunction(StreamHandle, sif1, {}, {}, {}, {net2_3});
|
||||
|
||||
//Last switch
|
||||
//Stream identification
|
||||
Ptr<NullStreamIdentificationFunction> sif2 = CreateObject<NullStreamIdentificationFunction>();
|
||||
StreamHandle = 1;
|
||||
sif2->SetAttribute("VlanID", UintegerValue(100));
|
||||
sif2->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif2, {}, {}, {net5_3}, {});
|
||||
|
||||
Ptr<NullStreamIdentificationFunction> sif3 = CreateObject<NullStreamIdentificationFunction>();
|
||||
sif3->SetAttribute("VlanID", UintegerValue(101));
|
||||
sif3->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif3, {}, {}, {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);
|
||||
//Active stream identification to change back vlanId (optional)
|
||||
Ptr<ActiveDestMacVlanStreamIdentificationFunction> sif4 = CreateObject<ActiveDestMacVlanStreamIdentificationFunction>();
|
||||
sif4->SetAttribute("VlanID", UintegerValue(101));
|
||||
sif4->SetAttribute("UpdateVlanID", UintegerValue(100));
|
||||
sif4->SetAttribute("Address", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif4->SetAttribute("UpdateAddress", AddressValue(Mac48Address("ff:ff:ff:ff:ff:ff")));
|
||||
sif4->SetAttribute("UpdatePCP", UintegerValue(1));
|
||||
n5->AddStreamIdentificationFunction(StreamHandle, sif4, {}, {}, {}, {net5_3});
|
||||
|
||||
//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(10)));
|
||||
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(1400));
|
||||
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app1->SetAttribute("PCP", UintegerValue(0));
|
||||
app1->SetAttribute("VlanID", UintegerValue(102));
|
||||
n0->AddApplication(app1);
|
||||
app1->SetStartTime(Seconds(0));
|
||||
app1->SetStopTime(MilliSeconds(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
net5_3->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(net5_3)));
|
||||
|
||||
//Enable pcap generation
|
||||
PcapHelper pcapHelper;
|
||||
std::string pcapFilename;
|
||||
std::string prefix = "Active-stream-identification";
|
||||
Ptr<PcapFileWrapper> file;
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net0);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net0, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net2_2);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net2_2, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net2_3);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net2_3, "Sniffer", file);
|
||||
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net1);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net1, "Sniffer", file);
|
||||
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
362
contrib/tsn/examples/tsn-switched-withFRER-recoveryAlgo.cc
Normal file
362
contrib/tsn/examples/tsn-switched-withFRER-recoveryAlgo.cc
Normal file
@@ -0,0 +1,362 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#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"
|
||||
#include "ns3/frer-vector-recovery-function.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 3ES connected 4SW in a 1Gb/s full duplex link to demonstrate
|
||||
* the difference between two FRER sub-mechanisms : the match recovery algorithm
|
||||
* and the vector recovery algorithm. To be more specific this example use the
|
||||
* SW1 to do the replication using mulitcast and SW4 to do the elimination for
|
||||
* the flow with VlanId = 100. 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. The Vlan 100 flow go from
|
||||
* ESsource to ESdest and Vlan 101 flow go from ESPerturbation1 to ESdest.
|
||||
*
|
||||
* ESPerturbation1
|
||||
* ||
|
||||
* / ==== SW2 ==== \
|
||||
* ESsource ==== SW1 SW4 ==== ESdest
|
||||
* \ ==== SW3 ==== /
|
||||
*
|
||||
* When using match recovery algorithm, we can note that some packet are received
|
||||
* multiple times (pkt #2, #3, #4, #5, ..., #9) because Vlan 100 flow is bursty
|
||||
* and disrupt by the Vlan 101 flow. This behavior is not observed with vector
|
||||
* recovery algorithm because it store multiple FRER sequence number to do
|
||||
* the elimination.
|
||||
*
|
||||
*
|
||||
* This example script can be run using one of this two following commands
|
||||
* according to the algorithm needed :
|
||||
* ./ns3 run <path to the script> -- --match
|
||||
* ./ns3 run <path to the script> -- --vector
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("VectorRecoveryFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("MatchRecoveryFunction", LOG_LEVEL_INFO);
|
||||
|
||||
//Command line interpretation
|
||||
bool enableMatch = false;
|
||||
bool enableVector = false;
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.AddValue("match", "Enable match recovery algorithm", enableMatch);
|
||||
cmd.AddValue("vector", "Enable vector recovery algorithm", enableVector);
|
||||
cmd.Parse(argc, argv);
|
||||
if (enableMatch && enableVector)
|
||||
{
|
||||
NS_LOG_INFO("Only one recovery algorithm can be selected");
|
||||
return 0;
|
||||
}
|
||||
else if (!enableMatch && !enableVector)
|
||||
{
|
||||
NS_LOG_INFO("A recovery algorithm must be selected using '--match' or '--vector' ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Create seven 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);
|
||||
Ptr<TsnNode> n6 = CreateObject<TsnNode>();
|
||||
Names::Add("ESPerturbation1", n6);
|
||||
|
||||
//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> net6 = CreateObject<TsnNetDevice>();
|
||||
n6->AddDevice(net6);
|
||||
Names::Add("ESPerturbation1#01", net6);
|
||||
|
||||
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> net3_3 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(net3_3);
|
||||
|
||||
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);
|
||||
Ptr<EthernetChannel> l6 = CreateObject<EthernetChannel>();
|
||||
l6->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
net3_3->Attach(l6);
|
||||
net6->Attach(l6);
|
||||
|
||||
//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);
|
||||
sw2->AddSwitchPort(net3_3);
|
||||
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>>());
|
||||
net3_3->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>>());
|
||||
net6->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});
|
||||
|
||||
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<BaseRecoveryFunction> recf0 = nullptr;
|
||||
if (enableVector){
|
||||
recf0 = CreateObject<VectorRecoveryFunction>();
|
||||
recf0->SetAttribute("HistoryLenght", UintegerValue(10));
|
||||
}
|
||||
else if(enableMatch)
|
||||
{
|
||||
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(10));
|
||||
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(net6);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(3));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app1->SetAttribute("Period", TimeValue(MilliSeconds(20)));
|
||||
app1->SetAttribute("PCP", UintegerValue(2));
|
||||
app1->SetAttribute("VlanID", UintegerValue(101));
|
||||
app1->SetAttribute("Offset", TimeValue(MicroSeconds(40)));
|
||||
n6->AddApplication(app1);
|
||||
app1->SetStartTime(MicroSeconds(0));
|
||||
app1->SetStopTime(MilliSeconds(20));
|
||||
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net6->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n6) + ":" + Names::FindName(net6)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
net5_3->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(net5_3)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(40));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
320
contrib/tsn/examples/tsn-switched-withFRER.cc
Normal file
320
contrib/tsn/examples/tsn-switched-withFRER.cc
Normal file
@@ -0,0 +1,320 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
#include "ns3/trace-helper.h"
|
||||
|
||||
#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"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 4SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage. To be more specific this example 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.
|
||||
*
|
||||
* / ==== SW2 ==== \
|
||||
* ESsource ==== SW1 SW4 ==== ESdest
|
||||
* \ ==== SW3 ==== /
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNetDevice", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("StreamIdEntry", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("NullStreamIdentificationFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("SequenceGenerationFunction", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("SequenceEncodeDecodeFunction", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//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);
|
||||
Names::Add("SW1#01", 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(10)));
|
||||
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(1400));
|
||||
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(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(net0)));
|
||||
net1->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(net1)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
net5_3->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(net5_3)));
|
||||
|
||||
PcapHelper pcapHelper;
|
||||
std::string pcapFilename;
|
||||
std::string prefix = "example";
|
||||
Ptr<PcapFileWrapper> file;
|
||||
pcapFilename = pcapHelper.GetFilenameFromDevice(prefix, net2_2);
|
||||
file = pcapHelper.CreateFile(pcapFilename, std::ios::out, PcapHelper::DLT_EN10MB);
|
||||
pcapHelper.HookDefaultSink<EthernetNetDevice>(net2_2, "Sniffer", file);
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
285
contrib/tsn/examples/tsn-switched-withFRERonES-aggregation.cc
Normal file
285
contrib/tsn/examples/tsn-switched-withFRERonES-aggregation.cc
Normal file
@@ -0,0 +1,285 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/tsn-aggregated-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"
|
||||
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 2SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage when replication and elimation are done on the ES. To be more
|
||||
* specific this example use the ESsource to do the replication using mulitcast
|
||||
* and ESdest 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.
|
||||
*
|
||||
* / ==== SW1 ==== \
|
||||
* ESsource ESdest
|
||||
* \ ==== SW2 ==== /
|
||||
*
|
||||
* Although mutliple ways of implementing elimination and replication on ES are
|
||||
* describe in the standard (IEEE802.1CB-2017 - Annex C), here we implement the
|
||||
* one describe in "IEEE802.1CB-2017 - Annex C - C.1 Example 1: End-to-end FRER"
|
||||
* . This ways is based on the use of IEEE802.1AX for port aggregation.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnAggregatedNetDevice", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//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);
|
||||
|
||||
//Create and add a netDevices to each node
|
||||
Ptr<TsnNetDevice> n0_net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(n0_net0);
|
||||
Names::Add("ESsource#01", n0_net0);
|
||||
Ptr<TsnNetDevice> n0_net1 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(n0_net1);
|
||||
Names::Add("ESsource#02", n0_net1);
|
||||
Ptr<TsnAggregatedNetDevice> n0_netagg = CreateObject<TsnAggregatedNetDevice>();
|
||||
n0_netagg->AddNetDevice(n0_net0);
|
||||
n0_netagg->AddNetDevice(n0_net1);
|
||||
n0->AddDevice(n0_netagg);
|
||||
|
||||
Ptr<TsnNetDevice> n1_net0 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(n1_net0);
|
||||
Names::Add("ESdest#01", n1_net0);
|
||||
Ptr<TsnNetDevice> n1_net1 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(n1_net1);
|
||||
Names::Add("ESdest#02", n1_net1);
|
||||
Ptr<TsnAggregatedNetDevice> n1_netagg = CreateObject<TsnAggregatedNetDevice>();
|
||||
n1_netagg->AddNetDevice(n1_net0);
|
||||
n1_netagg->AddNetDevice(n1_net1);
|
||||
n1->AddDevice(n1_netagg);
|
||||
|
||||
Ptr<TsnNetDevice> n2_net0 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net0);
|
||||
Ptr<TsnNetDevice> n2_net1 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net1);
|
||||
|
||||
Ptr<TsnNetDevice> n3_net0 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net0);
|
||||
Ptr<TsnNetDevice> n3_net1 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net1);
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_net0->Attach(l0);
|
||||
n2_net0->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n2_net1->Attach(l1);
|
||||
n1_net0->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_net1->Attach(l2);
|
||||
n3_net0->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n3_net1->Attach(l3);
|
||||
n1_net1->Attach(l3);
|
||||
|
||||
//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(n2_net0);
|
||||
sw1->AddSwitchPort(n2_net1);
|
||||
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
|
||||
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw2);
|
||||
sw2->AddSwitchPort(n3_net0);
|
||||
sw2->AddSwitchPort(n3_net1);
|
||||
|
||||
//Allocate a Mac address
|
||||
n0_net0->SetAddress(Mac48Address::Allocate());
|
||||
n0_net1->SetAddress(Mac48Address::Allocate());
|
||||
n1_net0->SetAddress(Mac48Address::Allocate());
|
||||
n1_net1->SetAddress(Mac48Address::Allocate());
|
||||
sw1->SetAddress(Mac48Address::Allocate());
|
||||
sw2->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
n0_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
n2_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n2_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n2_net1});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n3_net1});
|
||||
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n2_net1});
|
||||
|
||||
//Stream Indentification + FRER
|
||||
//On aggregated interface of ESsource
|
||||
//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")));
|
||||
n0->AddStreamIdentificationFunction(StreamHandle, sif0, {}, {}, {n0_netagg}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqf0->SetStreamHandle({StreamHandle});
|
||||
n0->AddSequenceGenerationFunction(seqf0);
|
||||
//Sequence encode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc0 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc0->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqEnc0->SetAttribute("Active", BooleanValue(true));
|
||||
seqEnc0->SetStreamHandle({StreamHandle});
|
||||
seqEnc0->SetPort(n0_netagg);
|
||||
n0->AddSequenceEncodeDecodeFunction(seqEnc0);
|
||||
|
||||
// On aggregated interface of ESdest
|
||||
//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")));
|
||||
n1->AddStreamIdentificationFunction(StreamHandle, sif1, {n1_netagg}, {}, {}, {});
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({StreamHandle});
|
||||
seqEnc1->SetPort(n1_netagg);
|
||||
n1->AddSequenceEncodeDecodeFunction(seqEnc1);
|
||||
//Sequencing : Sequence recovery
|
||||
Ptr<SequenceRecoveryFunction> seqfreco0 = CreateObject<SequenceRecoveryFunction>();
|
||||
seqfreco0->SetAttribute("Direction", BooleanValue(true)); //out-facing
|
||||
seqfreco0->SetAttribute("TakeNoSequence", BooleanValue(false));
|
||||
seqfreco0->SetAttribute("IndividualRecovery", BooleanValue(false));
|
||||
seqfreco0->SetStreamHandle({StreamHandle});
|
||||
seqfreco0->SetPorts({n1_netagg});
|
||||
n1->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(n0_netagg);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(10)));
|
||||
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(n0_net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
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(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
Packet::EnablePrinting();
|
||||
n0_net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(n0_net0)));
|
||||
n0_net1->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(n0_net1)));
|
||||
n1_netagg->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(n1_netagg)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
n1_netagg->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(n1_netagg)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
324
contrib/tsn/examples/tsn-switched-withFRERonES-integratedSW.cc
Normal file
324
contrib/tsn/examples/tsn-switched-withFRERonES-integratedSW.cc
Normal file
@@ -0,0 +1,324 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#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"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example with 2ES connected 2SW in a 1Gb/s full duplex link to demonstrate
|
||||
* FRER usage when replication and elimation are done on the ES. To be more
|
||||
* specific this example use the ESsource to do the replication using mulitcast
|
||||
* and ESdest 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.
|
||||
*
|
||||
* / ==== SW1 ==== \
|
||||
* ESsource ESdest
|
||||
* \ ==== SW2 ==== /
|
||||
*
|
||||
* Although mutliple ways of implementing elimination and replication on ES are
|
||||
* describe in the standard (IEEE802.1CB-2017 - Annex C), here we implement the
|
||||
* one describe in "IEEE802.1CB-2017 - Annex C - C.6 Example 6: Chained two-port
|
||||
* end systems". This ways is based on the use of a 3-port switch integrated
|
||||
* into the ES to interface between the ES and the network as described below
|
||||
*
|
||||
* /===
|
||||
* ES == Integrated SW
|
||||
* \===
|
||||
*/
|
||||
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
//A callback to log the pkt reception
|
||||
static void
|
||||
MacRxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") received !");
|
||||
}
|
||||
|
||||
//A callback to log the pkt emission
|
||||
static void
|
||||
PhyTxCallback(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
Ptr<Packet> originalPacket = p->Copy();
|
||||
EthernetHeader2 ethHeader;
|
||||
originalPacket->RemoveHeader(ethHeader);
|
||||
|
||||
NS_LOG_INFO((Simulator::Now()).As(Time::S) << " \t" << context << " : Pkt #" << p->GetUid() << " (VID:" << ethHeader.GetVid() << ") begin transmission !");
|
||||
}
|
||||
|
||||
//A callback to log pkt elimination
|
||||
static void
|
||||
FrerDrop(std::string context, Ptr<const Packet> p)
|
||||
{
|
||||
NS_LOG_INFO(context << " : An instance of Packet #"<< p->GetUid() <<" was dropped by FRER recovery function");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("EthernetGenerator", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create six nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource", n0);
|
||||
Ptr<TsnNode> n0_SW = CreateObject<TsnNode>();
|
||||
Names::Add("ESsource_SW", n0_SW);
|
||||
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest", n1);
|
||||
Ptr<TsnNode> n1_SW = CreateObject<TsnNode>();
|
||||
Names::Add("ESdest_SW", n1_SW);
|
||||
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW2", n3);
|
||||
|
||||
//Create and add a netDevices to each node
|
||||
Ptr<TsnNetDevice> n0_net0 = CreateObject<TsnNetDevice>();
|
||||
n0->AddDevice(n0_net0);
|
||||
Names::Add("ESsource#01", n0_net0);
|
||||
|
||||
Ptr<TsnNetDevice> n0_SW_net0 = CreateObject<TsnNetDevice>();
|
||||
n0_SW->AddDevice(n0_SW_net0);
|
||||
Names::Add("ESsource_SW#01", n0_SW_net0);
|
||||
Ptr<TsnNetDevice> n0_SW_net1 = CreateObject<TsnNetDevice>();
|
||||
n0_SW->AddDevice(n0_SW_net1);
|
||||
Names::Add("ESsource_SW#02", n0_SW_net1);
|
||||
Ptr<TsnNetDevice> n0_SW_net2 = CreateObject<TsnNetDevice>();
|
||||
n0_SW->AddDevice(n0_SW_net2);
|
||||
Names::Add("ESsource_SW#03", n0_SW_net2);
|
||||
|
||||
Ptr<TsnNetDevice> n1_net0 = CreateObject<TsnNetDevice>();
|
||||
n1->AddDevice(n1_net0);
|
||||
Names::Add("ESdest#01", n1_net0);
|
||||
|
||||
Ptr<TsnNetDevice> n1_SW_net0 = CreateObject<TsnNetDevice>();
|
||||
n1_SW->AddDevice(n1_SW_net0);
|
||||
Names::Add("ESdest_SW#01", n1_SW_net0);
|
||||
Ptr<TsnNetDevice> n1_SW_net1 = CreateObject<TsnNetDevice>();
|
||||
n1_SW->AddDevice(n1_SW_net1);
|
||||
Names::Add("ESdest_SW#02", n1_SW_net1);
|
||||
Ptr<TsnNetDevice> n1_SW_net2 = CreateObject<TsnNetDevice>();
|
||||
n1_SW->AddDevice(n1_SW_net2);
|
||||
Names::Add("ESdest_SW#03", n1_SW_net2);
|
||||
|
||||
Ptr<TsnNetDevice> n2_net0 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net0);
|
||||
Ptr<TsnNetDevice> n2_net1 = CreateObject<TsnNetDevice>();
|
||||
n2->AddDevice(n2_net1);
|
||||
|
||||
Ptr<TsnNetDevice> n3_net0 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net0);
|
||||
Ptr<TsnNetDevice> n3_net1 = CreateObject<TsnNetDevice>();
|
||||
n3->AddDevice(n3_net1);
|
||||
|
||||
//Create Ethernet Channels and attach it to the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_net0->Attach(l0);
|
||||
n0_SW_net0->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_SW_net1->Attach(l1);
|
||||
n2_net0->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n0_SW_net2->Attach(l2);
|
||||
n3_net0->Attach(l2);
|
||||
Ptr<EthernetChannel> l3 = CreateObject<EthernetChannel>();
|
||||
l3->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n1_net0->Attach(l3);
|
||||
n1_SW_net0->Attach(l3);
|
||||
Ptr<EthernetChannel> l4 = CreateObject<EthernetChannel>();
|
||||
l4->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n1_SW_net1->Attach(l4);
|
||||
n2_net1->Attach(l4);
|
||||
Ptr<EthernetChannel> l5 = CreateObject<EthernetChannel>();
|
||||
l5->SetAttribute("Delay", TimeValue(MicroSeconds(0)));
|
||||
n1_SW_net2->Attach(l5);
|
||||
n3_net1->Attach(l5);
|
||||
|
||||
//Create and add switche net devices to the switch nodes
|
||||
Ptr<SwitchNetDevice> n0_SW_sw = CreateObject<SwitchNetDevice>();
|
||||
n0_SW_sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n0_SW_sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n0_SW->AddDevice(n0_SW_sw);
|
||||
n0_SW_sw->AddSwitchPort(n0_SW_net0);
|
||||
n0_SW_sw->AddSwitchPort(n0_SW_net1);
|
||||
n0_SW_sw->AddSwitchPort(n0_SW_net2);
|
||||
Ptr<SwitchNetDevice> n1_SW_sw = CreateObject<SwitchNetDevice>();
|
||||
n1_SW_sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n1_SW_sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(0)));
|
||||
n1_SW->AddDevice(n1_SW_sw);
|
||||
n1_SW_sw->AddSwitchPort(n1_SW_net0);
|
||||
n1_SW_sw->AddSwitchPort(n1_SW_net1);
|
||||
n1_SW_sw->AddSwitchPort(n1_SW_net2);
|
||||
Ptr<SwitchNetDevice> sw1 = CreateObject<SwitchNetDevice>();
|
||||
sw1->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw1->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n2->AddDevice(sw1);
|
||||
sw1->AddSwitchPort(n2_net0);
|
||||
sw1->AddSwitchPort(n2_net1);
|
||||
Ptr<SwitchNetDevice> sw2 = CreateObject<SwitchNetDevice>();
|
||||
sw2->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw2->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw2);
|
||||
sw2->AddSwitchPort(n3_net0);
|
||||
sw2->AddSwitchPort(n3_net1);
|
||||
|
||||
//Allocate a Mac address
|
||||
n0_net0->SetAddress(Mac48Address::Allocate());
|
||||
n1_net0->SetAddress(Mac48Address::Allocate());
|
||||
n0_SW_sw->SetAddress(Mac48Address::Allocate());
|
||||
n1_SW_sw->SetAddress(Mac48Address::Allocate());
|
||||
sw1->SetAddress(Mac48Address::Allocate());
|
||||
sw2->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Create and add eight FIFO on each net device
|
||||
for (int i=0; i<8; i++)
|
||||
{
|
||||
n0_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_SW_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_SW_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n0_SW_net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_SW_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_SW_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n1_SW_net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n2_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n2_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
n3_net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
}
|
||||
|
||||
//Add forwarding table
|
||||
n0_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n0_SW_net1, n0_SW_net2});
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n2_net1});
|
||||
sw2->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n3_net1});
|
||||
n1_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 100, {n1_SW_net0});
|
||||
|
||||
n0_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n0_SW_net1});
|
||||
sw1->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n2_net1});
|
||||
n1_SW_sw->AddForwardingTableEntry(Mac48Address("ff:ff:ff:ff:ff:ff"), 101, {n1_SW_net0});
|
||||
|
||||
//Stream Indentification + FRER
|
||||
//Integrated SW on ESsource
|
||||
//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")));
|
||||
n0_SW->AddStreamIdentificationFunction(StreamHandle, sif0, {n0_SW_net0}, {}, {}, {});
|
||||
//Sequencing : Sequence generation
|
||||
Ptr<SequenceGenerationFunction> seqf0 = CreateObject<SequenceGenerationFunction>();
|
||||
seqf0->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqf0->SetStreamHandle({StreamHandle});
|
||||
n0_SW->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(n0_SW_net0);
|
||||
n0_SW->AddSequenceEncodeDecodeFunction(seqEnc0);
|
||||
|
||||
//Integrated SW on ESdest
|
||||
//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")));
|
||||
n1_SW->AddStreamIdentificationFunction(StreamHandle, sif1, {}, {}, {n1_SW_net0}, {});
|
||||
//Sequence Decode
|
||||
Ptr<SequenceEncodeDecodeFunction> seqEnc1 = CreateObject<SequenceEncodeDecodeFunction>();
|
||||
seqEnc1->SetAttribute("Direction", BooleanValue(false)); //in-facing
|
||||
seqEnc1->SetAttribute("Active", BooleanValue(false));
|
||||
seqEnc1->SetStreamHandle({StreamHandle});
|
||||
seqEnc1->SetPort(n1_SW_net0);
|
||||
n1_SW->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({n1_SW_net0});
|
||||
n1_SW->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(n0_net0);
|
||||
app0->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app0->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
app0->SetAttribute("Period", TimeValue(MilliSeconds(10)));
|
||||
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(n0_net0);
|
||||
app1->SetAttribute("BurstSize", UintegerValue(1));
|
||||
app1->SetAttribute("PayloadSize", UintegerValue(1400));
|
||||
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(41));
|
||||
|
||||
//Callback to display the packet transmitted and received log
|
||||
//Packet::EnablePrinting();
|
||||
n0_net0->TraceConnectWithoutContext("PhyTxBegin", MakeBoundCallback(&PhyTxCallback, Names::FindName(n0) + ":" + Names::FindName(n0_net0)));
|
||||
n1_net0->TraceConnectWithoutContext("MacRx", MakeBoundCallback(&MacRxCallback, Names::FindName(n1) + ":" + Names::FindName(n1_net0)));
|
||||
|
||||
//Callback to display the packet elimination on last output port
|
||||
n1_SW_net0->TraceConnectWithoutContext("FrerDrop", MakeBoundCallback(&FrerDrop, Names::FindName(n1_SW_net0)));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(MilliSeconds(50));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
209
contrib/tsn/examples/tsn-switched-withGPTP.cc
Normal file
209
contrib/tsn/examples/tsn-switched-withGPTP.cc
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "ns3/core-module.h"
|
||||
#include "ns3/applications-module.h"
|
||||
#include "ns3/command-line.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/node.h"
|
||||
#include "ns3/drop-tail-queue.h"
|
||||
|
||||
#include "ns3/tsn-node.h"
|
||||
#include "ns3/tsn-net-device.h"
|
||||
#include "ns3/switch-net-device.h"
|
||||
#include "ns3/ethernet-channel.h"
|
||||
#include "ns3/clock.h"
|
||||
#include "ns3/clock-constant-drift.h"
|
||||
#include "ns3/gPTP.h"
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Example of the use of gPTP on a network composed of three end-stations
|
||||
* and connected by a 1Gb/s full duplex network through a switch. ES1 is the
|
||||
* GPTP Grandmaster.
|
||||
* ES1 === SW1 === ES3
|
||||
* ||
|
||||
* ES2
|
||||
*/
|
||||
|
||||
using namespace ns3;
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("Example");
|
||||
|
||||
static void
|
||||
PdelayCallback(std::string context, Ptr<TsnNetDevice> net, double pdelay)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << "/" << Names::FindName(net) << " computed pdelay = " << pdelay);
|
||||
}
|
||||
|
||||
static void
|
||||
ClockAfterCorrectionCallback(std::string context, Ptr<Clock> gmClock, Time clockValue)
|
||||
{
|
||||
NS_LOG_INFO("[GPTP] At " << Simulator::Now() << " on "<< context << " clock value after correction = " << clockValue.GetNanoSeconds() << "ns (error = "<< (gmClock->GetLocalTime()-clockValue).GetNanoSeconds() << "ns)");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
//Enable logging
|
||||
LogComponentEnable("Example", LOG_LEVEL_INFO);
|
||||
LogComponentEnable("TsnNode", LOG_LEVEL_INFO);
|
||||
|
||||
CommandLine cmd(__FILE__);
|
||||
cmd.Parse(argc, argv);
|
||||
|
||||
//Create nodes
|
||||
Ptr<TsnNode> n0 = CreateObject<TsnNode>();
|
||||
Names::Add("ES1", n0);
|
||||
Ptr<TsnNode> n1 = CreateObject<TsnNode>();
|
||||
Names::Add("ES2", n1);
|
||||
Ptr<TsnNode> n2 = CreateObject<TsnNode>();
|
||||
Names::Add("ES3", n2);
|
||||
Ptr<TsnNode> n3 = CreateObject<TsnNode>();
|
||||
Names::Add("SW1", n3);
|
||||
|
||||
|
||||
//Create and add clock to TsnNode
|
||||
Ptr<ConstantDriftClock> c0 = CreateObject<ConstantDriftClock>();
|
||||
c0->SetAttribute("InitialOffset", TimeValue(Seconds(112)));
|
||||
c0->SetAttribute("DriftRate", DoubleValue(-15));
|
||||
c0->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n0->SetMainClock(c0);
|
||||
|
||||
Ptr<ConstantDriftClock> c1 = CreateObject<ConstantDriftClock>();
|
||||
c1->SetAttribute("InitialOffset", TimeValue(Seconds(3)));
|
||||
c1->SetAttribute("DriftRate", DoubleValue(10));
|
||||
c1->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n1->SetMainClock(c1);
|
||||
|
||||
Ptr<ConstantDriftClock> c2 = CreateObject<ConstantDriftClock>();
|
||||
c2->SetAttribute("InitialOffset", TimeValue(Seconds(1.5)));
|
||||
c2->SetAttribute("DriftRate", DoubleValue(-8));
|
||||
c2->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n2->SetMainClock(c2);
|
||||
|
||||
Ptr<ConstantDriftClock> c3 = CreateObject<ConstantDriftClock>();
|
||||
c3->SetAttribute("InitialOffset", TimeValue(Seconds(5)));
|
||||
c3->SetAttribute("DriftRate", DoubleValue(-5));
|
||||
c3->SetAttribute("Granularity", TimeValue(NanoSeconds(10)));
|
||||
n3->SetMainClock(c3);
|
||||
|
||||
|
||||
//Create and add a netDevice to each node
|
||||
Ptr<TsnNetDevice> net0 = CreateObject<TsnNetDevice>();
|
||||
net0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n0->AddDevice(net0);
|
||||
Names::Add("ES1#01", net0);
|
||||
Ptr<TsnNetDevice> net1 = CreateObject<TsnNetDevice>();
|
||||
net1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n1->AddDevice(net1);
|
||||
Names::Add("ES2#01", net1);
|
||||
Ptr<TsnNetDevice> net2 = CreateObject<TsnNetDevice>();
|
||||
net2->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n2->AddDevice(net2);
|
||||
Names::Add("ES3#01", net2);
|
||||
|
||||
Ptr<TsnNetDevice> net3_0 = CreateObject<TsnNetDevice>();
|
||||
net3_0->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n3->AddDevice(net3_0);
|
||||
Names::Add("SW1#01", net3_0);
|
||||
Ptr<TsnNetDevice> net3_1 = CreateObject<TsnNetDevice>();
|
||||
net3_1->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n3->AddDevice(net3_1);
|
||||
Names::Add("SW1#02", net3_1);
|
||||
Ptr<TsnNetDevice> net3_2 = CreateObject<TsnNetDevice>();
|
||||
net3_2->SetAttribute("DataRate", DataRateValue(DataRate("1Gb/s")));
|
||||
n3->AddDevice(net3_2);
|
||||
Names::Add("SW1#03", net3_2);
|
||||
|
||||
//Create and add a switch net device to the switch node
|
||||
Ptr<SwitchNetDevice> sw = CreateObject<SwitchNetDevice>();
|
||||
sw->SetAttribute("MinForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
sw->SetAttribute("MaxForwardingLatency", TimeValue(MicroSeconds(10)));
|
||||
n3->AddDevice(sw);
|
||||
sw->AddSwitchPort(net3_0);
|
||||
sw->AddSwitchPort(net3_1);
|
||||
sw->AddSwitchPort(net3_2);
|
||||
|
||||
//Create Ethernet Channel and attach it two the netDevices
|
||||
Ptr<EthernetChannel> l0 = CreateObject<EthernetChannel>();
|
||||
l0->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net0->Attach(l0);
|
||||
net3_0->Attach(l0);
|
||||
Ptr<EthernetChannel> l1 = CreateObject<EthernetChannel>();
|
||||
l1->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net1->Attach(l1);
|
||||
net3_1->Attach(l1);
|
||||
Ptr<EthernetChannel> l2 = CreateObject<EthernetChannel>();
|
||||
l2->SetAttribute("Delay", TimeValue(Time(NanoSeconds(200))));
|
||||
net2->Attach(l2);
|
||||
net3_2->Attach(l2);
|
||||
|
||||
//Allocate a Mac address
|
||||
net0->SetAddress(Mac48Address::Allocate());
|
||||
net1->SetAddress(Mac48Address::Allocate());
|
||||
net2->SetAddress(Mac48Address::Allocate());
|
||||
sw->SetAddress(Mac48Address::Allocate());
|
||||
net3_0->SetAddress(Mac48Address::Allocate());
|
||||
net3_1->SetAddress(Mac48Address::Allocate());
|
||||
net3_2->SetAddress(Mac48Address::Allocate());
|
||||
|
||||
//Add one fifo per netdevice.
|
||||
net0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_0->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_1->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
net3_2->SetQueue(CreateObject<DropTailQueue<Packet>>());
|
||||
|
||||
//Add and configure GPTP
|
||||
Ptr<GPTP> gPTP0 = CreateObject<GPTP>();
|
||||
gPTP0->SetNode(n0);
|
||||
gPTP0->SetMainClock(c0);
|
||||
gPTP0->AddDomain(0);
|
||||
gPTP0->AddPort(net0, GPTP::MASTER, 0);
|
||||
gPTP0->SetAttribute("SyncInterval", TimeValue(Seconds(0.125))); //This line is not mandatory because 0.125s is the default value
|
||||
gPTP0->SetAttribute("PdelayInterval", TimeValue(Seconds(1))); //This line is not mandatory because 1s is the default value
|
||||
gPTP0->SetAttribute("Priority", UintegerValue(0));
|
||||
n0->AddApplication(gPTP0);
|
||||
gPTP0->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP1 = CreateObject<GPTP>();
|
||||
gPTP1->SetNode(n1);
|
||||
gPTP1->SetMainClock(c1);
|
||||
gPTP1->AddDomain(0);
|
||||
gPTP1->AddPort(net1, GPTP::SLAVE, 0);
|
||||
gPTP1->SetAttribute("Priority", UintegerValue(0));
|
||||
n1->AddApplication(gPTP1);
|
||||
gPTP1->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP2 = CreateObject<GPTP>();
|
||||
gPTP2->SetNode(n2);
|
||||
gPTP2->SetMainClock(c2);
|
||||
gPTP2->AddDomain(0);
|
||||
gPTP2->AddPort(net2, GPTP::SLAVE, 0);
|
||||
gPTP2->SetAttribute("Priority", UintegerValue(0));
|
||||
n2->AddApplication(gPTP2);
|
||||
gPTP2->SetStartTime(Seconds(0));
|
||||
|
||||
Ptr<GPTP> gPTP3 = CreateObject<GPTP>();
|
||||
gPTP3->SetNode(n3);
|
||||
gPTP3->SetMainClock(c3);
|
||||
gPTP3->AddDomain(0);
|
||||
gPTP3->AddPort(net3_0, GPTP::SLAVE, 0);
|
||||
gPTP3->AddPort(net3_1, GPTP::MASTER, 0);
|
||||
gPTP3->AddPort(net3_2, GPTP::MASTER, 0);
|
||||
gPTP3->SetAttribute("Priority", UintegerValue(0));
|
||||
n3->AddApplication(gPTP3);
|
||||
gPTP3->SetStartTime(Seconds(0));
|
||||
|
||||
//Callback to displa information about GPTP execution
|
||||
gPTP1->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n1)));
|
||||
gPTP3->TraceConnectWithoutContext("Pdelay", MakeBoundCallback(&PdelayCallback, Names::FindName(n3)));
|
||||
gPTP1->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n1), c0));
|
||||
gPTP3->TraceConnectWithoutContext("ClockAfterCorrection", MakeBoundCallback(&ClockAfterCorrectionCallback, Names::FindName(n3), c0));
|
||||
|
||||
//Execute the simulation
|
||||
Simulator::Stop(Seconds(3));
|
||||
Simulator::Run();
|
||||
Simulator::Destroy();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user