Update README and add contrib dir

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

View File

@@ -0,0 +1,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()

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View File

@@ -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;
}

View 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;
}

View 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;
}

View File

@@ -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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}